@@ -86,8 +86,8 @@ static void locate_grouping_columns(PlannerInfo *root,
86
86
AttrNumber * groupColIdx );
87
87
static List * postprocess_setop_tlist (List * new_tlist , List * orig_tlist );
88
88
static List * select_active_windows (PlannerInfo * root , WindowFuncLists * wflists );
89
- static List * add_volatile_sort_exprs ( List * window_tlist , List * tlist ,
90
- List * activeWindows );
89
+ static List * make_windowInputTargetList ( PlannerInfo * root ,
90
+ List * tlist , List * activeWindows );
91
91
static List * make_pathkeys_for_window (PlannerInfo * root , WindowClause * wc ,
92
92
List * tlist , bool canonicalize );
93
93
static void get_column_info_for_window (PlannerInfo * root , WindowClause * wc ,
@@ -1512,31 +1512,25 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
1512
1512
1513
1513
/*
1514
1514
* The "base" targetlist for all steps of the windowing process is
1515
- * a flat tlist of all Vars and Aggs needed in the result. (In
1515
+ * a flat tlist of all Vars and Aggs needed in the result. (In
1516
1516
* some cases we wouldn't need to propagate all of these all the
1517
1517
* way to the top, since they might only be needed as inputs to
1518
1518
* WindowFuncs. It's probably not worth trying to optimize that
1519
- * though.) We also need any volatile sort expressions, because
1520
- * make_sort_from_pathkeys won't add those on its own, and anyway
1521
- * we want them evaluated only once at the bottom of the stack. As
1522
- * we climb up the stack, we add outputs for the WindowFuncs
1523
- * computed at each level. Also, each input tlist has to present
1524
- * all the columns needed to sort the data for the next WindowAgg
1525
- * step. That's handled internally by make_sort_from_pathkeys,
1526
- * but we need the copyObject steps here to ensure that each plan
1527
- * node has a separately modifiable tlist.
1528
- *
1529
- * Note: it's essential here to use PVC_INCLUDE_AGGREGATES so that
1530
- * Vars mentioned only in aggregate expressions aren't pulled out
1531
- * as separate targetlist entries. Otherwise we could be putting
1532
- * ungrouped Vars directly into an Agg node's tlist, resulting in
1533
- * undefined behavior.
1519
+ * though.) We also add window partitioning and sorting
1520
+ * expressions to the base tlist, to ensure they're computed only
1521
+ * once at the bottom of the stack (that's critical for volatile
1522
+ * functions). As we climb up the stack, we'll add outputs for
1523
+ * the WindowFuncs computed at each level.
1524
+ */
1525
+ window_tlist = make_windowInputTargetList (root ,
1526
+ tlist ,
1527
+ activeWindows );
1528
+
1529
+ /*
1530
+ * The copyObject steps here are needed to ensure that each plan
1531
+ * node has a separately modifiable tlist. (XXX wouldn't a
1532
+ * shallow list copy do for that?)
1534
1533
*/
1535
- window_tlist = flatten_tlist (tlist ,
1536
- PVC_INCLUDE_AGGREGATES ,
1537
- PVC_INCLUDE_PLACEHOLDERS );
1538
- window_tlist = add_volatile_sort_exprs (window_tlist , tlist ,
1539
- activeWindows );
1540
1534
result_plan -> targetlist = (List * ) copyObject (window_tlist );
1541
1535
1542
1536
foreach (l , activeWindows )
@@ -1560,9 +1554,11 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
1560
1554
* really have to sort. Even when no explicit sort is needed,
1561
1555
* we need to have suitable resjunk items added to the input
1562
1556
* plan's tlist for any partitioning or ordering columns that
1563
- * aren't plain Vars. Furthermore, this way we can use
1564
- * existing infrastructure to identify which input columns are
1565
- * the interesting ones.
1557
+ * aren't plain Vars. (In theory, make_windowInputTargetList
1558
+ * should have provided all such columns, but let's not assume
1559
+ * that here.) Furthermore, this way we can use existing
1560
+ * infrastructure to identify which input columns are the
1561
+ * interesting ones.
1566
1562
*/
1567
1563
if (window_pathkeys )
1568
1564
{
@@ -2963,18 +2959,57 @@ select_active_windows(PlannerInfo *root, WindowFuncLists *wflists)
2963
2959
}
2964
2960
2965
2961
/*
2966
- * add_volatile_sort_exprs
2967
- * Identify any volatile sort/group expressions used by the active
2968
- * windows, and add them to window_tlist if not already present.
2969
- * Return the modified window_tlist.
2962
+ * make_windowInputTargetList
2963
+ * Generate appropriate target list for initial input to WindowAgg nodes.
2964
+ *
2965
+ * When grouping_planner inserts one or more WindowAgg nodes into the plan,
2966
+ * this function computes the initial target list to be computed by the node
2967
+ * just below the first WindowAgg. This list must contain all values needed
2968
+ * to evaluate the window functions, compute the final target list, and
2969
+ * perform any required final sort step. If multiple WindowAggs are needed,
2970
+ * each intermediate one adds its window function results onto this tlist;
2971
+ * only the topmost WindowAgg computes the actual desired target list.
2972
+ *
2973
+ * This function is much like make_subplanTargetList, though not quite enough
2974
+ * like it to share code. As in that function, we flatten most expressions
2975
+ * into their component variables. But we do not want to flatten window
2976
+ * PARTITION BY/ORDER BY clauses, since that might result in multiple
2977
+ * evaluations of them, which would be bad (possibly even resulting in
2978
+ * inconsistent answers, if they contain volatile functions). Also, we must
2979
+ * not flatten GROUP BY clauses that were left unflattened by
2980
+ * make_subplanTargetList, because we may no longer have access to the
2981
+ * individual Vars in them.
2982
+ *
2983
+ * Another key difference from make_subplanTargetList is that we don't flatten
2984
+ * Aggref expressions, since those are to be computed below the window
2985
+ * functions and just referenced like Vars above that.
2986
+ *
2987
+ * 'tlist' is the query's final target list.
2988
+ * 'activeWindows' is the list of active windows previously identified by
2989
+ * select_active_windows.
2990
+ *
2991
+ * The result is the targetlist to be computed by the plan node immediately
2992
+ * below the first WindowAgg node.
2970
2993
*/
2971
2994
static List *
2972
- add_volatile_sort_exprs (List * window_tlist , List * tlist , List * activeWindows )
2995
+ make_windowInputTargetList (PlannerInfo * root ,
2996
+ List * tlist ,
2997
+ List * activeWindows )
2973
2998
{
2974
- Bitmapset * sgrefs = NULL ;
2999
+ Query * parse = root -> parse ;
3000
+ Bitmapset * sgrefs ;
3001
+ List * new_tlist ;
3002
+ List * flattenable_cols ;
3003
+ List * flattenable_vars ;
2975
3004
ListCell * lc ;
2976
3005
2977
- /* First, collect the sortgrouprefs of the windows into a bitmapset */
3006
+ Assert (parse -> hasWindowFuncs );
3007
+
3008
+ /*
3009
+ * Collect the sortgroupref numbers of window PARTITION/ORDER BY clauses
3010
+ * into a bitmapset for convenient reference below.
3011
+ */
3012
+ sgrefs = NULL ;
2978
3013
foreach (lc , activeWindows )
2979
3014
{
2980
3015
WindowClause * wc = (WindowClause * ) lfirst (lc );
@@ -2994,34 +3029,74 @@ add_volatile_sort_exprs(List *window_tlist, List *tlist, List *activeWindows)
2994
3029
}
2995
3030
}
2996
3031
3032
+ /* Add in sortgroupref numbers of GROUP BY clauses, too */
3033
+ foreach (lc , parse -> groupClause )
3034
+ {
3035
+ SortGroupClause * grpcl = (SortGroupClause * ) lfirst (lc );
3036
+
3037
+ sgrefs = bms_add_member (sgrefs , grpcl -> tleSortGroupRef );
3038
+ }
3039
+
2997
3040
/*
2998
- * Now scan the original tlist to find the referenced expressions. Any
2999
- * that are volatile must be added to window_tlist.
3000
- *
3001
- * Note: we know that the input window_tlist contains no items marked with
3002
- * ressortgrouprefs, so we don't have to worry about collisions of the
3003
- * reference numbers.
3041
+ * Construct a tlist containing all the non-flattenable tlist items, and
3042
+ * save aside the others for a moment.
3004
3043
*/
3044
+ new_tlist = NIL ;
3045
+ flattenable_cols = NIL ;
3046
+
3005
3047
foreach (lc , tlist )
3006
3048
{
3007
3049
TargetEntry * tle = (TargetEntry * ) lfirst (lc );
3008
3050
3051
+ /*
3052
+ * Don't want to deconstruct window clauses or GROUP BY items. (Note
3053
+ * that such items can't contain window functions, so it's okay to
3054
+ * compute them below the WindowAgg nodes.)
3055
+ */
3009
3056
if (tle -> ressortgroupref != 0 &&
3010
- bms_is_member (tle -> ressortgroupref , sgrefs ) &&
3011
- contain_volatile_functions ((Node * ) tle -> expr ))
3057
+ bms_is_member (tle -> ressortgroupref , sgrefs ))
3012
3058
{
3059
+ /* Don't want to deconstruct this value, so add to new_tlist */
3013
3060
TargetEntry * newtle ;
3014
3061
3015
3062
newtle = makeTargetEntry (tle -> expr ,
3016
- list_length (window_tlist ) + 1 ,
3063
+ list_length (new_tlist ) + 1 ,
3017
3064
NULL ,
3018
3065
false);
3066
+ /* Preserve its sortgroupref marking, in case it's volatile */
3019
3067
newtle -> ressortgroupref = tle -> ressortgroupref ;
3020
- window_tlist = lappend (window_tlist , newtle );
3068
+ new_tlist = lappend (new_tlist , newtle );
3069
+ }
3070
+ else
3071
+ {
3072
+ /*
3073
+ * Column is to be flattened, so just remember the expression for
3074
+ * later call to pull_var_clause. There's no need for
3075
+ * pull_var_clause to examine the TargetEntry node itself.
3076
+ */
3077
+ flattenable_cols = lappend (flattenable_cols , tle -> expr );
3021
3078
}
3022
3079
}
3023
3080
3024
- return window_tlist ;
3081
+ /*
3082
+ * Pull out all the Vars and Aggrefs mentioned in flattenable columns, and
3083
+ * add them to the result tlist if not already present. (Some might be
3084
+ * there already because they're used directly as window/group clauses.)
3085
+ *
3086
+ * Note: it's essential to use PVC_INCLUDE_AGGREGATES here, so that the
3087
+ * Aggrefs are placed in the Agg node's tlist and not left to be computed
3088
+ * at higher levels.
3089
+ */
3090
+ flattenable_vars = pull_var_clause ((Node * ) flattenable_cols ,
3091
+ PVC_INCLUDE_AGGREGATES ,
3092
+ PVC_INCLUDE_PLACEHOLDERS );
3093
+ new_tlist = add_to_flat_tlist (new_tlist , flattenable_vars );
3094
+
3095
+ /* clean up cruft */
3096
+ list_free (flattenable_vars );
3097
+ list_free (flattenable_cols );
3098
+
3099
+ return new_tlist ;
3025
3100
}
3026
3101
3027
3102
/*
0 commit comments