2525 ((IsA(node, FuncExpr) && ((FuncExpr *) (node))->funcretset) || \
2626 (IsA(node, OpExpr) && ((OpExpr *) (node))->opretset))
2727
28- /* Workspace for split_pathtarget_walker */
28+ /*
29+ * Data structures for split_pathtarget_at_srfs(). To preserve the identity
30+ * of sortgroupref items even if they are textually equal(), what we track is
31+ * not just bare expressions but expressions plus their sortgroupref indexes.
32+ */
33+ typedef struct
34+ {
35+ Node * expr ; /* some subexpression of a PathTarget */
36+ Index sortgroupref ; /* its sortgroupref, or 0 if none */
37+ } split_pathtarget_item ;
38+
2939typedef struct
3040{
41+ /* This is a List of bare expressions: */
3142 List * input_target_exprs ; /* exprs available from input */
32- List * level_srfs ; /* list of lists of SRF exprs */
33- List * level_input_vars ; /* vars needed by SRFs of each level */
34- List * level_input_srfs ; /* SRFs needed by SRFs of each level */
43+ /* These are Lists of Lists of split_pathtarget_items: */
44+ List * level_srfs ; /* SRF exprs to evaluate at each level */
45+ List * level_input_vars ; /* input vars needed at each level */
46+ List * level_input_srfs ; /* input SRFs needed at each level */
47+ /* These are Lists of split_pathtarget_items: */
3548 List * current_input_vars ; /* vars needed in current subexpr */
3649 List * current_input_srfs ; /* SRFs needed in current subexpr */
50+ /* Auxiliary data for current split_pathtarget_walker traversal: */
3751 int current_depth ; /* max SRF depth in current subexpr */
52+ Index current_sgref ; /* current subexpr's sortgroupref, or 0 */
3853} split_pathtarget_context ;
3954
4055static bool split_pathtarget_walker (Node * node ,
4156 split_pathtarget_context * context );
57+ static void add_sp_item_to_pathtarget (PathTarget * target ,
58+ split_pathtarget_item * item );
59+ static void add_sp_items_to_pathtarget (PathTarget * target , List * items );
4260
4361
4462/*****************************************************************************
@@ -822,6 +840,9 @@ apply_pathtarget_labeling_to_tlist(List *tlist, PathTarget *target)
822840 * already meant as a reference to a lower subexpression). So, don't expand
823841 * any tlist expressions that appear in input_target, if that's not NULL.
824842 *
843+ * It's also important that we preserve any sortgroupref annotation appearing
844+ * in the given target, especially on expressions matching input_target items.
845+ *
825846 * The outputs of this function are two parallel lists, one a list of
826847 * PathTargets and the other an integer list of bool flags indicating
827848 * whether the corresponding PathTarget contains any evaluatable SRFs.
@@ -845,6 +866,7 @@ split_pathtarget_at_srfs(PlannerInfo *root,
845866 int max_depth ;
846867 bool need_extra_projection ;
847868 List * prev_level_tlist ;
869+ int lci ;
848870 ListCell * lc ,
849871 * lc1 ,
850872 * lc2 ,
@@ -884,10 +906,15 @@ split_pathtarget_at_srfs(PlannerInfo *root,
884906 need_extra_projection = false;
885907
886908 /* Scan each expression in the PathTarget looking for SRFs */
909+ lci = 0 ;
887910 foreach (lc , target -> exprs )
888911 {
889912 Node * node = (Node * ) lfirst (lc );
890913
914+ /* Tell split_pathtarget_walker about this expr's sortgroupref */
915+ context .current_sgref = get_pathtarget_sortgroupref (target , lci );
916+ lci ++ ;
917+
891918 /*
892919 * Find all SRFs and Vars (and Var-like nodes) in this expression, and
893920 * enter them into appropriate lists within the context struct.
@@ -981,16 +1008,14 @@ split_pathtarget_at_srfs(PlannerInfo *root,
9811008 * This target should actually evaluate any SRFs of the current
9821009 * level, and it needs to propagate forward any Vars needed by
9831010 * later levels, as well as SRFs computed earlier and needed by
984- * later levels. We rely on add_new_columns_to_pathtarget() to
985- * remove duplicate items. Also, for safety, make a separate copy
986- * of each item for each PathTarget.
1011+ * later levels.
9871012 */
988- add_new_columns_to_pathtarget (ntarget , copyObject ( level_srfs ) );
1013+ add_sp_items_to_pathtarget (ntarget , level_srfs );
9891014 for_each_cell (lc , lnext (lc2 ))
9901015 {
9911016 List * input_vars = (List * ) lfirst (lc );
9921017
993- add_new_columns_to_pathtarget (ntarget , copyObject ( input_vars ) );
1018+ add_sp_items_to_pathtarget (ntarget , input_vars );
9941019 }
9951020 for_each_cell (lc , lnext (lc3 ))
9961021 {
@@ -999,10 +1024,10 @@ split_pathtarget_at_srfs(PlannerInfo *root,
9991024
10001025 foreach (lcx , input_srfs )
10011026 {
1002- Expr * srf = ( Expr * ) lfirst (lcx );
1027+ split_pathtarget_item * item = lfirst (lcx );
10031028
1004- if (list_member (prev_level_tlist , srf ))
1005- add_new_column_to_pathtarget (ntarget , copyObject ( srf ) );
1029+ if (list_member (prev_level_tlist , item -> expr ))
1030+ add_sp_item_to_pathtarget (ntarget , item );
10061031 }
10071032 }
10081033 set_pathtarget_cost_width (root , ntarget );
@@ -1037,12 +1062,17 @@ split_pathtarget_walker(Node *node, split_pathtarget_context *context)
10371062 * input_target can be treated like a Var (which indeed it will be after
10381063 * setrefs.c gets done with it), even if it's actually a SRF. Record it
10391064 * as being needed for the current expression, and ignore any
1040- * substructure.
1065+ * substructure. (Note in particular that this preserves the identity of
1066+ * any expressions that appear as sortgrouprefs in input_target.)
10411067 */
10421068 if (list_member (context -> input_target_exprs , node ))
10431069 {
1070+ split_pathtarget_item * item = palloc (sizeof (split_pathtarget_item ));
1071+
1072+ item -> expr = node ;
1073+ item -> sortgroupref = context -> current_sgref ;
10441074 context -> current_input_vars = lappend (context -> current_input_vars ,
1045- node );
1075+ item );
10461076 return false;
10471077 }
10481078
@@ -1057,8 +1087,12 @@ split_pathtarget_walker(Node *node, split_pathtarget_context *context)
10571087 IsA (node , GroupingFunc ) ||
10581088 IsA (node , WindowFunc ))
10591089 {
1090+ split_pathtarget_item * item = palloc (sizeof (split_pathtarget_item ));
1091+
1092+ item -> expr = node ;
1093+ item -> sortgroupref = context -> current_sgref ;
10601094 context -> current_input_vars = lappend (context -> current_input_vars ,
1061- node );
1095+ item );
10621096 return false;
10631097 }
10641098
@@ -1068,15 +1102,20 @@ split_pathtarget_walker(Node *node, split_pathtarget_context *context)
10681102 */
10691103 if (IS_SRF_CALL (node ))
10701104 {
1105+ split_pathtarget_item * item = palloc (sizeof (split_pathtarget_item ));
10711106 List * save_input_vars = context -> current_input_vars ;
10721107 List * save_input_srfs = context -> current_input_srfs ;
10731108 int save_current_depth = context -> current_depth ;
10741109 int srf_depth ;
10751110 ListCell * lc ;
10761111
1112+ item -> expr = node ;
1113+ item -> sortgroupref = context -> current_sgref ;
1114+
10771115 context -> current_input_vars = NIL ;
10781116 context -> current_input_srfs = NIL ;
10791117 context -> current_depth = 0 ;
1118+ context -> current_sgref = 0 ; /* subexpressions are not sortgroup items */
10801119
10811120 (void ) expression_tree_walker (node , split_pathtarget_walker ,
10821121 (void * ) context );
@@ -1094,7 +1133,7 @@ split_pathtarget_walker(Node *node, split_pathtarget_context *context)
10941133
10951134 /* Record this SRF as needing to be evaluated at appropriate level */
10961135 lc = list_nth_cell (context -> level_srfs , srf_depth );
1097- lfirst (lc ) = lappend (lfirst (lc ), node );
1136+ lfirst (lc ) = lappend (lfirst (lc ), item );
10981137
10991138 /* Record its inputs as being needed at the same level */
11001139 lc = list_nth_cell (context -> level_input_vars , srf_depth );
@@ -1108,7 +1147,7 @@ split_pathtarget_walker(Node *node, split_pathtarget_context *context)
11081147 * surrounding expression.
11091148 */
11101149 context -> current_input_vars = save_input_vars ;
1111- context -> current_input_srfs = lappend (save_input_srfs , node );
1150+ context -> current_input_srfs = lappend (save_input_srfs , item );
11121151 context -> current_depth = Max (save_current_depth , srf_depth );
11131152
11141153 /* We're done here */
@@ -1119,6 +1158,79 @@ split_pathtarget_walker(Node *node, split_pathtarget_context *context)
11191158 * Otherwise, the node is a scalar (non-set) expression, so recurse to
11201159 * examine its inputs.
11211160 */
1161+ context -> current_sgref = 0 ; /* subexpressions are not sortgroup items */
11221162 return expression_tree_walker (node , split_pathtarget_walker ,
11231163 (void * ) context );
11241164}
1165+
1166+ /*
1167+ * Add a split_pathtarget_item to the PathTarget, unless a matching item is
1168+ * already present. This is like add_new_column_to_pathtarget, but allows
1169+ * for sortgrouprefs to be handled. An item having zero sortgroupref can
1170+ * be merged with one that has a sortgroupref, acquiring the latter's
1171+ * sortgroupref.
1172+ *
1173+ * Note that we don't worry about possibly adding duplicate sortgrouprefs
1174+ * to the PathTarget. That would be bad, but it should be impossible unless
1175+ * the target passed to split_pathtarget_at_srfs already had duplicates.
1176+ * As long as it didn't, we can have at most one split_pathtarget_item with
1177+ * any particular nonzero sortgroupref.
1178+ */
1179+ static void
1180+ add_sp_item_to_pathtarget (PathTarget * target , split_pathtarget_item * item )
1181+ {
1182+ int lci ;
1183+ ListCell * lc ;
1184+
1185+ /*
1186+ * Look for a pre-existing entry that is equal() and does not have a
1187+ * conflicting sortgroupref already.
1188+ */
1189+ lci = 0 ;
1190+ foreach (lc , target -> exprs )
1191+ {
1192+ Node * node = (Node * ) lfirst (lc );
1193+ Index sgref = get_pathtarget_sortgroupref (target , lci );
1194+
1195+ if ((item -> sortgroupref == sgref ||
1196+ item -> sortgroupref == 0 ||
1197+ sgref == 0 ) &&
1198+ equal (item -> expr , node ))
1199+ {
1200+ /* Found a match. Assign item's sortgroupref if it has one. */
1201+ if (item -> sortgroupref )
1202+ {
1203+ if (target -> sortgrouprefs == NULL )
1204+ {
1205+ target -> sortgrouprefs = (Index * )
1206+ palloc0 (list_length (target -> exprs ) * sizeof (Index ));
1207+ }
1208+ target -> sortgrouprefs [lci ] = item -> sortgroupref ;
1209+ }
1210+ return ;
1211+ }
1212+ lci ++ ;
1213+ }
1214+
1215+ /*
1216+ * No match, so add item to PathTarget. Copy the expr for safety.
1217+ */
1218+ add_column_to_pathtarget (target , (Expr * ) copyObject (item -> expr ),
1219+ item -> sortgroupref );
1220+ }
1221+
1222+ /*
1223+ * Apply add_sp_item_to_pathtarget to each element of list.
1224+ */
1225+ static void
1226+ add_sp_items_to_pathtarget (PathTarget * target , List * items )
1227+ {
1228+ ListCell * lc ;
1229+
1230+ foreach (lc , items )
1231+ {
1232+ split_pathtarget_item * item = lfirst (lc );
1233+
1234+ add_sp_item_to_pathtarget (target , item );
1235+ }
1236+ }
0 commit comments