aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/planner.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2025-03-11 11:19:54 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2025-03-11 11:19:54 -0400
commit8b1b342544b69b281ffd3aafe594aec629ec4d3c (patch)
tree6239ec69a949ffb5397fc4f7a5f50128d446d477 /src/backend/optimizer/plan/planner.c
parent426ea611171da4e60ab4f3863fa3cc3683ae9547 (diff)
downloadpostgresql-8b1b342544b69b281ffd3aafe594aec629ec4d3c.tar.gz
postgresql-8b1b342544b69b281ffd3aafe594aec629ec4d3c.zip
Improve EXPLAIN's display of window functions.
Up to now we just punted on showing the window definitions used in a plan, with window function calls represented as "OVER (?)". To improve that, show the window definition implemented by each WindowAgg plan node, and reference their window names in OVER. For nameless window clauses generated by "OVER (...)", assign unique names w1, w2, etc. In passing, re-order the properties shown for a WindowAgg node so that the Run Condition (if any) appears after the Window property and before the Filter (if any). This seems more sensible since the Run Condition is associated with the Window and acts before the Filter. Thanks to David G. Johnston and Álvaro Herrera for design suggestions. Author: Tom Lane <tgl@sss.pgh.pa.us> Reviewed-by: David Rowley <dgrowleyml@gmail.com> Discussion: https://postgr.es/m/144530.1741469955@sss.pgh.pa.us
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r--src/backend/optimizer/plan/planner.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 014e80c30e6..a4d523dcb0f 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -214,6 +214,7 @@ static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist);
static void optimize_window_clauses(PlannerInfo *root,
WindowFuncLists *wflists);
static List *select_active_windows(PlannerInfo *root, WindowFuncLists *wflists);
+static void name_active_windows(List *activeWindows);
static PathTarget *make_window_input_target(PlannerInfo *root,
PathTarget *final_target,
List *activeWindows);
@@ -1539,7 +1540,11 @@ grouping_planner(PlannerInfo *root, double tuple_fraction,
*/
optimize_window_clauses(root, wflists);
+ /* Extract the list of windows actually in use. */
activeWindows = select_active_windows(root, wflists);
+
+ /* Make sure they all have names, for EXPLAIN's use. */
+ name_active_windows(activeWindows);
}
else
parse->hasWindowFuncs = false;
@@ -5915,6 +5920,52 @@ select_active_windows(PlannerInfo *root, WindowFuncLists *wflists)
}
/*
+ * name_active_windows
+ * Ensure all active windows have unique names.
+ *
+ * The parser will have checked that user-assigned window names are unique
+ * within the Query. Here we assign made-up names to any unnamed
+ * WindowClauses for the benefit of EXPLAIN. (We don't want to do this
+ * at parse time, because it'd mess up decompilation of views.)
+ *
+ * activeWindows: result of select_active_windows
+ */
+static void
+name_active_windows(List *activeWindows)
+{
+ int next_n = 1;
+ char newname[16];
+ ListCell *lc;
+
+ foreach(lc, activeWindows)
+ {
+ WindowClause *wc = lfirst_node(WindowClause, lc);
+
+ /* Nothing to do if it has a name already. */
+ if (wc->name)
+ continue;
+
+ /* Select a name not currently present in the list. */
+ for (;;)
+ {
+ ListCell *lc2;
+
+ snprintf(newname, sizeof(newname), "w%d", next_n++);
+ foreach(lc2, activeWindows)
+ {
+ WindowClause *wc2 = lfirst_node(WindowClause, lc2);
+
+ if (wc2->name && strcmp(wc2->name, newname) == 0)
+ break; /* matched */
+ }
+ if (lc2 == NULL)
+ break; /* reached the end with no match */
+ }
+ wc->name = pstrdup(newname);
+ }
+}
+
+/*
* common_prefix_cmp
* QSort comparison function for WindowClauseSortData
*