@@ -90,8 +90,8 @@ static void locate_grouping_columns(PlannerInfo *root,
90
90
AttrNumber * groupColIdx );
91
91
static List * postprocess_setop_tlist (List * new_tlist , List * orig_tlist );
92
92
static List * select_active_windows (PlannerInfo * root , WindowFuncLists * wflists );
93
- static List * add_volatile_sort_exprs ( List * window_tlist , List * tlist ,
94
- List * activeWindows );
93
+ static List * make_windowInputTargetList ( PlannerInfo * root ,
94
+ List * tlist , List * activeWindows );
95
95
static List * make_pathkeys_for_window (PlannerInfo * root , WindowClause * wc ,
96
96
List * tlist , bool canonicalize );
97
97
static void get_column_info_for_window (PlannerInfo * root , WindowClause * wc ,
@@ -1555,31 +1555,25 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
1555
1555
1556
1556
/*
1557
1557
* The "base" targetlist for all steps of the windowing process is
1558
- * a flat tlist of all Vars and Aggs needed in the result. (In
1558
+ * a flat tlist of all Vars and Aggs needed in the result. (In
1559
1559
* some cases we wouldn't need to propagate all of these all the
1560
1560
* way to the top, since they might only be needed as inputs to
1561
1561
* WindowFuncs. It's probably not worth trying to optimize that
1562
- * though.) We also need any volatile sort expressions, because
1563
- * make_sort_from_pathkeys won't add those on its own, and anyway
1564
- * we want them evaluated only once at the bottom of the stack. As
1565
- * we climb up the stack, we add outputs for the WindowFuncs
1566
- * computed at each level. Also, each input tlist has to present
1567
- * all the columns needed to sort the data for the next WindowAgg
1568
- * step. That's handled internally by make_sort_from_pathkeys,
1569
- * but we need the copyObject steps here to ensure that each plan
1570
- * node has a separately modifiable tlist.
1571
- *
1572
- * Note: it's essential here to use PVC_INCLUDE_AGGREGATES so that
1573
- * Vars mentioned only in aggregate expressions aren't pulled out
1574
- * as separate targetlist entries. Otherwise we could be putting
1575
- * ungrouped Vars directly into an Agg node's tlist, resulting in
1576
- * undefined behavior.
1562
+ * though.) We also add window partitioning and sorting
1563
+ * expressions to the base tlist, to ensure they're computed only
1564
+ * once at the bottom of the stack (that's critical for volatile
1565
+ * functions). As we climb up the stack, we'll add outputs for
1566
+ * the WindowFuncs computed at each level.
1567
+ */
1568
+ window_tlist = make_windowInputTargetList (root ,
1569
+ tlist ,
1570
+ activeWindows );
1571
+
1572
+ /*
1573
+ * The copyObject steps here are needed to ensure that each plan
1574
+ * node has a separately modifiable tlist. (XXX wouldn't a
1575
+ * shallow list copy do for that?)
1577
1576
*/
1578
- window_tlist = flatten_tlist (tlist ,
1579
- PVC_INCLUDE_AGGREGATES ,
1580
- PVC_INCLUDE_PLACEHOLDERS );
1581
- window_tlist = add_volatile_sort_exprs (window_tlist , tlist ,
1582
- activeWindows );
1583
1577
result_plan -> targetlist = (List * ) copyObject (window_tlist );
1584
1578
1585
1579
foreach (l , activeWindows )
@@ -1603,9 +1597,11 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
1603
1597
* really have to sort. Even when no explicit sort is needed,
1604
1598
* we need to have suitable resjunk items added to the input
1605
1599
* plan's tlist for any partitioning or ordering columns that
1606
- * aren't plain Vars. Furthermore, this way we can use
1607
- * existing infrastructure to identify which input columns are
1608
- * the interesting ones.
1600
+ * aren't plain Vars. (In theory, make_windowInputTargetList
1601
+ * should have provided all such columns, but let's not assume
1602
+ * that here.) Furthermore, this way we can use existing
1603
+ * infrastructure to identify which input columns are the
1604
+ * interesting ones.
1609
1605
*/
1610
1606
if (window_pathkeys )
1611
1607
{
@@ -3006,18 +3002,57 @@ select_active_windows(PlannerInfo *root, WindowFuncLists *wflists)
3006
3002
}
3007
3003
3008
3004
/*
3009
- * add_volatile_sort_exprs
3010
- * Identify any volatile sort/group expressions used by the active
3011
- * windows, and add them to window_tlist if not already present.
3012
- * Return the modified window_tlist.
3005
+ * make_windowInputTargetList
3006
+ * Generate appropriate target list for initial input to WindowAgg nodes.
3007
+ *
3008
+ * When grouping_planner inserts one or more WindowAgg nodes into the plan,
3009
+ * this function computes the initial target list to be computed by the node
3010
+ * just below the first WindowAgg. This list must contain all values needed
3011
+ * to evaluate the window functions, compute the final target list, and
3012
+ * perform any required final sort step. If multiple WindowAggs are needed,
3013
+ * each intermediate one adds its window function results onto this tlist;
3014
+ * only the topmost WindowAgg computes the actual desired target list.
3015
+ *
3016
+ * This function is much like make_subplanTargetList, though not quite enough
3017
+ * like it to share code. As in that function, we flatten most expressions
3018
+ * into their component variables. But we do not want to flatten window
3019
+ * PARTITION BY/ORDER BY clauses, since that might result in multiple
3020
+ * evaluations of them, which would be bad (possibly even resulting in
3021
+ * inconsistent answers, if they contain volatile functions). Also, we must
3022
+ * not flatten GROUP BY clauses that were left unflattened by
3023
+ * make_subplanTargetList, because we may no longer have access to the
3024
+ * individual Vars in them.
3025
+ *
3026
+ * Another key difference from make_subplanTargetList is that we don't flatten
3027
+ * Aggref expressions, since those are to be computed below the window
3028
+ * functions and just referenced like Vars above that.
3029
+ *
3030
+ * 'tlist' is the query's final target list.
3031
+ * 'activeWindows' is the list of active windows previously identified by
3032
+ * select_active_windows.
3033
+ *
3034
+ * The result is the targetlist to be computed by the plan node immediately
3035
+ * below the first WindowAgg node.
3013
3036
*/
3014
3037
static List *
3015
- add_volatile_sort_exprs (List * window_tlist , List * tlist , List * activeWindows )
3038
+ make_windowInputTargetList (PlannerInfo * root ,
3039
+ List * tlist ,
3040
+ List * activeWindows )
3016
3041
{
3017
- Bitmapset * sgrefs = NULL ;
3042
+ Query * parse = root -> parse ;
3043
+ Bitmapset * sgrefs ;
3044
+ List * new_tlist ;
3045
+ List * flattenable_cols ;
3046
+ List * flattenable_vars ;
3018
3047
ListCell * lc ;
3019
3048
3020
- /* First, collect the sortgrouprefs of the windows into a bitmapset */
3049
+ Assert (parse -> hasWindowFuncs );
3050
+
3051
+ /*
3052
+ * Collect the sortgroupref numbers of window PARTITION/ORDER BY clauses
3053
+ * into a bitmapset for convenient reference below.
3054
+ */
3055
+ sgrefs = NULL ;
3021
3056
foreach (lc , activeWindows )
3022
3057
{
3023
3058
WindowClause * wc = (WindowClause * ) lfirst (lc );
@@ -3037,34 +3072,74 @@ add_volatile_sort_exprs(List *window_tlist, List *tlist, List *activeWindows)
3037
3072
}
3038
3073
}
3039
3074
3075
+ /* Add in sortgroupref numbers of GROUP BY clauses, too */
3076
+ foreach (lc , parse -> groupClause )
3077
+ {
3078
+ SortGroupClause * grpcl = (SortGroupClause * ) lfirst (lc );
3079
+
3080
+ sgrefs = bms_add_member (sgrefs , grpcl -> tleSortGroupRef );
3081
+ }
3082
+
3040
3083
/*
3041
- * Now scan the original tlist to find the referenced expressions. Any
3042
- * that are volatile must be added to window_tlist.
3043
- *
3044
- * Note: we know that the input window_tlist contains no items marked with
3045
- * ressortgrouprefs, so we don't have to worry about collisions of the
3046
- * reference numbers.
3084
+ * Construct a tlist containing all the non-flattenable tlist items, and
3085
+ * save aside the others for a moment.
3047
3086
*/
3087
+ new_tlist = NIL ;
3088
+ flattenable_cols = NIL ;
3089
+
3048
3090
foreach (lc , tlist )
3049
3091
{
3050
3092
TargetEntry * tle = (TargetEntry * ) lfirst (lc );
3051
3093
3094
+ /*
3095
+ * Don't want to deconstruct window clauses or GROUP BY items. (Note
3096
+ * that such items can't contain window functions, so it's okay to
3097
+ * compute them below the WindowAgg nodes.)
3098
+ */
3052
3099
if (tle -> ressortgroupref != 0 &&
3053
- bms_is_member (tle -> ressortgroupref , sgrefs ) &&
3054
- contain_volatile_functions ((Node * ) tle -> expr ))
3100
+ bms_is_member (tle -> ressortgroupref , sgrefs ))
3055
3101
{
3102
+ /* Don't want to deconstruct this value, so add to new_tlist */
3056
3103
TargetEntry * newtle ;
3057
3104
3058
3105
newtle = makeTargetEntry (tle -> expr ,
3059
- list_length (window_tlist ) + 1 ,
3106
+ list_length (new_tlist ) + 1 ,
3060
3107
NULL ,
3061
3108
false);
3109
+ /* Preserve its sortgroupref marking, in case it's volatile */
3062
3110
newtle -> ressortgroupref = tle -> ressortgroupref ;
3063
- window_tlist = lappend (window_tlist , newtle );
3111
+ new_tlist = lappend (new_tlist , newtle );
3112
+ }
3113
+ else
3114
+ {
3115
+ /*
3116
+ * Column is to be flattened, so just remember the expression for
3117
+ * later call to pull_var_clause. There's no need for
3118
+ * pull_var_clause to examine the TargetEntry node itself.
3119
+ */
3120
+ flattenable_cols = lappend (flattenable_cols , tle -> expr );
3064
3121
}
3065
3122
}
3066
3123
3067
- return window_tlist ;
3124
+ /*
3125
+ * Pull out all the Vars and Aggrefs mentioned in flattenable columns, and
3126
+ * add them to the result tlist if not already present. (Some might be
3127
+ * there already because they're used directly as window/group clauses.)
3128
+ *
3129
+ * Note: it's essential to use PVC_INCLUDE_AGGREGATES here, so that the
3130
+ * Aggrefs are placed in the Agg node's tlist and not left to be computed
3131
+ * at higher levels.
3132
+ */
3133
+ flattenable_vars = pull_var_clause ((Node * ) flattenable_cols ,
3134
+ PVC_INCLUDE_AGGREGATES ,
3135
+ PVC_INCLUDE_PLACEHOLDERS );
3136
+ new_tlist = add_to_flat_tlist (new_tlist , flattenable_vars );
3137
+
3138
+ /* clean up cruft */
3139
+ list_free (flattenable_vars );
3140
+ list_free (flattenable_cols );
3141
+
3142
+ return new_tlist ;
3068
3143
}
3069
3144
3070
3145
/*
0 commit comments