Branch data Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * tlist.c
4 : : * Target list manipulation routines
5 : : *
6 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/optimizer/util/tlist.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : #include "postgres.h"
16 : :
17 : : #include "nodes/makefuncs.h"
18 : : #include "nodes/nodeFuncs.h"
19 : : #include "optimizer/cost.h"
20 : : #include "optimizer/optimizer.h"
21 : : #include "optimizer/tlist.h"
22 : : #include "rewrite/rewriteManip.h"
23 : :
24 : :
25 : : /*
26 : : * Test if an expression node represents a SRF call. Beware multiple eval!
27 : : *
28 : : * Please note that this is only meant for use in split_pathtarget_at_srfs();
29 : : * if you use it anywhere else, your code is almost certainly wrong for SRFs
30 : : * nested within expressions. Use expression_returns_set() instead.
31 : : */
32 : : #define IS_SRF_CALL(node) \
33 : : ((IsA(node, FuncExpr) && ((FuncExpr *) (node))->funcretset) || \
34 : : (IsA(node, OpExpr) && ((OpExpr *) (node))->opretset))
35 : :
36 : : /*
37 : : * Data structures for split_pathtarget_at_srfs(). To preserve the identity
38 : : * of sortgroupref items even if they are textually equal(), what we track is
39 : : * not just bare expressions but expressions plus their sortgroupref indexes.
40 : : */
41 : : typedef struct
42 : : {
43 : : Node *expr; /* some subexpression of a PathTarget */
44 : : Index sortgroupref; /* its sortgroupref, or 0 if none */
45 : : } split_pathtarget_item;
46 : :
47 : : typedef struct
48 : : {
49 : : PlannerInfo *root;
50 : : bool is_grouping_target; /* true if processing grouping target */
51 : : /* This is a List of bare expressions: */
52 : : List *input_target_exprs; /* exprs available from input */
53 : : /* These are Lists of Lists of split_pathtarget_items: */
54 : : List *level_srfs; /* SRF exprs to evaluate at each level */
55 : : List *level_input_vars; /* input vars needed at each level */
56 : : List *level_input_srfs; /* input SRFs needed at each level */
57 : : /* These are Lists of split_pathtarget_items: */
58 : : List *current_input_vars; /* vars needed in current subexpr */
59 : : List *current_input_srfs; /* SRFs needed in current subexpr */
60 : : /* Auxiliary data for current split_pathtarget_walker traversal: */
61 : : int current_depth; /* max SRF depth in current subexpr */
62 : : Index current_sgref; /* current subexpr's sortgroupref, or 0 */
63 : : } split_pathtarget_context;
64 : :
65 : : static void split_pathtarget_at_srfs_extended(PlannerInfo *root,
66 : : PathTarget *target,
67 : : PathTarget *input_target,
68 : : List **targets,
69 : : List **targets_contain_srfs,
70 : : bool is_grouping_target);
71 : : static bool split_pathtarget_walker(Node *node,
72 : : split_pathtarget_context *context);
73 : : static void add_sp_item_to_pathtarget(PathTarget *target,
74 : : split_pathtarget_item *item);
75 : : static void add_sp_items_to_pathtarget(PathTarget *target, List *items);
76 : :
77 : :
78 : : /*****************************************************************************
79 : : * Target list creation and searching utilities
80 : : *****************************************************************************/
81 : :
82 : : /*
83 : : * tlist_member
84 : : * Finds the (first) member of the given tlist whose expression is
85 : : * equal() to the given expression. Result is NULL if no such member.
86 : : */
87 : : TargetEntry *
88 : 6332 : tlist_member(Expr *node, List *targetlist)
89 : : {
90 : 6332 : ListCell *temp;
91 : :
92 [ + + + + : 23782 : foreach(temp, targetlist)
+ + + + ]
93 : : {
94 : 17450 : TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
95 : :
96 [ + + ]: 17450 : if (equal(node, tlentry->expr))
97 : 1797 : return tlentry;
98 [ + + ]: 17450 : }
99 : 4535 : return NULL;
100 : 6332 : }
101 : :
102 : : /*
103 : : * tlist_member_match_var
104 : : * Same as above, except that we match the provided Var on the basis
105 : : * of varno/varattno/varlevelsup/vartype only, rather than full equal().
106 : : *
107 : : * This is needed in some cases where we can't be sure of an exact typmod
108 : : * match. For safety, though, we insist on vartype match.
109 : : */
110 : : static TargetEntry *
111 : 371 : tlist_member_match_var(Var *var, List *targetlist)
112 : : {
113 : 371 : ListCell *temp;
114 : :
115 [ + - - + : 1511 : foreach(temp, targetlist)
- + + - ]
116 : : {
117 : 1140 : TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
118 : 1140 : Var *tlvar = (Var *) tlentry->expr;
119 : :
120 [ + - - + ]: 1140 : if (!tlvar || !IsA(tlvar, Var))
121 : 0 : continue;
122 [ + - ]: 1140 : if (var->varno == tlvar->varno &&
123 [ + + ]: 1140 : var->varattno == tlvar->varattno &&
124 [ + - - + ]: 371 : var->varlevelsup == tlvar->varlevelsup &&
125 : 371 : var->vartype == tlvar->vartype)
126 : 371 : return tlentry;
127 [ - + + ]: 1140 : }
128 : 0 : return NULL;
129 : 371 : }
130 : :
131 : : /*
132 : : * add_to_flat_tlist
133 : : * Add more items to a flattened tlist (if they're not already in it)
134 : : *
135 : : * 'tlist' is the flattened tlist
136 : : * 'exprs' is a list of expressions (usually, but not necessarily, Vars)
137 : : *
138 : : * Returns the extended tlist.
139 : : */
140 : : List *
141 : 0 : add_to_flat_tlist(List *tlist, List *exprs)
142 : : {
143 : 0 : int next_resno = list_length(tlist) + 1;
144 : 0 : ListCell *lc;
145 : :
146 [ # # # # : 0 : foreach(lc, exprs)
# # ]
147 : : {
148 : 0 : Expr *expr = (Expr *) lfirst(lc);
149 : :
150 [ # # ]: 0 : if (!tlist_member(expr, tlist))
151 : : {
152 : 0 : TargetEntry *tle;
153 : :
154 : 0 : tle = makeTargetEntry(copyObject(expr), /* copy needed?? */
155 : 0 : next_resno++,
156 : : NULL,
157 : : false);
158 : 0 : tlist = lappend(tlist, tle);
159 : 0 : }
160 : 0 : }
161 : 0 : return tlist;
162 : 0 : }
163 : :
164 : :
165 : : /*
166 : : * get_tlist_exprs
167 : : * Get just the expression subtrees of a tlist
168 : : *
169 : : * Resjunk columns are ignored unless includeJunk is true
170 : : */
171 : : List *
172 : 223 : get_tlist_exprs(List *tlist, bool includeJunk)
173 : : {
174 : 223 : List *result = NIL;
175 : 223 : ListCell *l;
176 : :
177 [ + + + + : 952 : foreach(l, tlist)
+ + ]
178 : : {
179 : 729 : TargetEntry *tle = (TargetEntry *) lfirst(l);
180 : :
181 [ - + # # ]: 729 : if (tle->resjunk && !includeJunk)
182 : 0 : continue;
183 : :
184 : 729 : result = lappend(result, tle->expr);
185 [ - - + ]: 729 : }
186 : 446 : return result;
187 : 223 : }
188 : :
189 : :
190 : : /*
191 : : * count_nonjunk_tlist_entries
192 : : * What it says ...
193 : : */
194 : : int
195 : 3425 : count_nonjunk_tlist_entries(List *tlist)
196 : : {
197 : 3425 : int len = 0;
198 : 3425 : ListCell *l;
199 : :
200 [ + + + + : 6960 : foreach(l, tlist)
+ + ]
201 : : {
202 : 3535 : TargetEntry *tle = (TargetEntry *) lfirst(l);
203 : :
204 [ + + ]: 3535 : if (!tle->resjunk)
205 : 3451 : len++;
206 : 3535 : }
207 : 6850 : return len;
208 : 3425 : }
209 : :
210 : :
211 : : /*
212 : : * tlist_same_exprs
213 : : * Check whether two target lists contain the same expressions
214 : : *
215 : : * Note: this function is used to decide whether it's safe to jam a new tlist
216 : : * into a non-projection-capable plan node. Obviously we can't do that unless
217 : : * the node's tlist shows it already returns the column values we want.
218 : : * However, we can ignore the TargetEntry attributes resname, ressortgroupref,
219 : : * resorigtbl, resorigcol, and resjunk, because those are only labelings that
220 : : * don't affect the row values computed by the node. (Moreover, if we didn't
221 : : * ignore them, we'd frequently fail to make the desired optimization, since
222 : : * the planner tends to not bother to make resname etc. valid in intermediate
223 : : * plan nodes.) Note that on success, the caller must still jam the desired
224 : : * tlist into the plan node, else it won't have the desired labeling fields.
225 : : */
226 : : bool
227 : 186 : tlist_same_exprs(List *tlist1, List *tlist2)
228 : : {
229 : 186 : ListCell *lc1,
230 : : *lc2;
231 : :
232 [ + + ]: 186 : if (list_length(tlist1) != list_length(tlist2))
233 : 73 : return false; /* not same length, so can't match */
234 : :
235 [ + - + + : 247 : forboth(lc1, tlist1, lc2, tlist2)
+ - + + +
+ + + +
+ ]
236 : : {
237 : 134 : TargetEntry *tle1 = (TargetEntry *) lfirst(lc1);
238 : 134 : TargetEntry *tle2 = (TargetEntry *) lfirst(lc2);
239 : :
240 [ + + ]: 134 : if (!equal(tle1->expr, tle2->expr))
241 : 89 : return false;
242 [ + + ]: 134 : }
243 : :
244 : 24 : return true;
245 : 186 : }
246 : :
247 : :
248 : : /*
249 : : * Does tlist have same output datatypes as listed in colTypes?
250 : : *
251 : : * Resjunk columns are ignored if junkOK is true; otherwise presence of
252 : : * a resjunk column will always cause a 'false' result.
253 : : *
254 : : * Note: currently no callers care about comparing typmods.
255 : : */
256 : : bool
257 : 2200 : tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
258 : : {
259 : 2200 : ListCell *l;
260 : 2200 : ListCell *curColType = list_head(colTypes);
261 : :
262 [ + + + + : 6474 : foreach(l, tlist)
+ + + + ]
263 : : {
264 : 4274 : TargetEntry *tle = (TargetEntry *) lfirst(l);
265 : :
266 [ + + ]: 4274 : if (tle->resjunk)
267 : : {
268 [ + - ]: 2 : if (!junkOK)
269 : 0 : return false;
270 : 2 : }
271 : : else
272 : : {
273 [ + - ]: 4272 : if (curColType == NULL)
274 : 0 : return false; /* tlist longer than colTypes */
275 [ + + ]: 4272 : if (exprType((Node *) tle->expr) != lfirst_oid(curColType))
276 : 25 : return false;
277 : 4247 : curColType = lnext(colTypes, curColType);
278 : : }
279 [ + + ]: 4274 : }
280 [ - + ]: 2175 : if (curColType != NULL)
281 : 0 : return false; /* tlist shorter than colTypes */
282 : 2175 : return true;
283 : 2200 : }
284 : :
285 : : /*
286 : : * Does tlist have same exposed collations as listed in colCollations?
287 : : *
288 : : * Identical logic to the above, but for collations.
289 : : */
290 : : bool
291 : 750 : tlist_same_collations(List *tlist, List *colCollations, bool junkOK)
292 : : {
293 : 750 : ListCell *l;
294 : 750 : ListCell *curColColl = list_head(colCollations);
295 : :
296 [ + + + + : 2818 : foreach(l, tlist)
+ + - + ]
297 : : {
298 : 2068 : TargetEntry *tle = (TargetEntry *) lfirst(l);
299 : :
300 [ - + ]: 2068 : if (tle->resjunk)
301 : : {
302 [ # # ]: 0 : if (!junkOK)
303 : 0 : return false;
304 : 0 : }
305 : : else
306 : : {
307 [ + - ]: 2068 : if (curColColl == NULL)
308 : 0 : return false; /* tlist longer than colCollations */
309 [ - + ]: 2068 : if (exprCollation((Node *) tle->expr) != lfirst_oid(curColColl))
310 : 0 : return false;
311 : 2068 : curColColl = lnext(colCollations, curColColl);
312 : : }
313 [ - + ]: 2068 : }
314 [ - + ]: 750 : if (curColColl != NULL)
315 : 0 : return false; /* tlist shorter than colCollations */
316 : 750 : return true;
317 : 750 : }
318 : :
319 : : /*
320 : : * apply_tlist_labeling
321 : : * Apply the TargetEntry labeling attributes of src_tlist to dest_tlist
322 : : *
323 : : * This is useful for reattaching column names etc to a plan's final output
324 : : * targetlist.
325 : : */
326 : : void
327 : 54300 : apply_tlist_labeling(List *dest_tlist, List *src_tlist)
328 : : {
329 : 54300 : ListCell *ld,
330 : : *ls;
331 : :
332 [ + - ]: 54300 : Assert(list_length(dest_tlist) == list_length(src_tlist));
333 [ + + + + : 193887 : forboth(ld, dest_tlist, ls, src_tlist)
+ + + + +
+ + + ]
334 : : {
335 : 139587 : TargetEntry *dest_tle = (TargetEntry *) lfirst(ld);
336 : 139587 : TargetEntry *src_tle = (TargetEntry *) lfirst(ls);
337 : :
338 [ + - ]: 139587 : Assert(dest_tle->resno == src_tle->resno);
339 : 139587 : dest_tle->resname = src_tle->resname;
340 : 139587 : dest_tle->ressortgroupref = src_tle->ressortgroupref;
341 : 139587 : dest_tle->resorigtbl = src_tle->resorigtbl;
342 : 139587 : dest_tle->resorigcol = src_tle->resorigcol;
343 : 139587 : dest_tle->resjunk = src_tle->resjunk;
344 : 139587 : }
345 : 54300 : }
346 : :
347 : :
348 : : /*
349 : : * get_sortgroupref_tle
350 : : * Find the targetlist entry matching the given SortGroupRef index,
351 : : * and return it.
352 : : */
353 : : TargetEntry *
354 : 37190 : get_sortgroupref_tle(Index sortref, List *targetList)
355 : : {
356 : 37190 : ListCell *l;
357 : :
358 [ + - - + : 134255 : foreach(l, targetList)
+ - + - ]
359 : : {
360 : 97065 : TargetEntry *tle = (TargetEntry *) lfirst(l);
361 : :
362 [ + + ]: 97065 : if (tle->ressortgroupref == sortref)
363 : 37190 : return tle;
364 [ + + ]: 97065 : }
365 : :
366 [ # # # # ]: 0 : elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
367 : 0 : return NULL; /* keep compiler quiet */
368 : 37190 : }
369 : :
370 : : /*
371 : : * get_sortgroupclause_tle
372 : : * Find the targetlist entry matching the given SortGroupClause
373 : : * by ressortgroupref, and return it.
374 : : */
375 : : TargetEntry *
376 : 37040 : get_sortgroupclause_tle(SortGroupClause *sgClause,
377 : : List *targetList)
378 : : {
379 : 37040 : return get_sortgroupref_tle(sgClause->tleSortGroupRef, targetList);
380 : : }
381 : :
382 : : /*
383 : : * get_sortgroupclause_expr
384 : : * Find the targetlist entry matching the given SortGroupClause
385 : : * by ressortgroupref, and return its expression.
386 : : */
387 : : Node *
388 : 30038 : get_sortgroupclause_expr(SortGroupClause *sgClause, List *targetList)
389 : : {
390 : 30038 : TargetEntry *tle = get_sortgroupclause_tle(sgClause, targetList);
391 : :
392 : 60076 : return (Node *) tle->expr;
393 : 30038 : }
394 : :
395 : : /*
396 : : * get_sortgrouplist_exprs
397 : : * Given a list of SortGroupClauses, build a list
398 : : * of the referenced targetlist expressions.
399 : : */
400 : : List *
401 : 2543 : get_sortgrouplist_exprs(List *sgClauses, List *targetList)
402 : : {
403 : 2543 : List *result = NIL;
404 : 2543 : ListCell *l;
405 : :
406 [ + + + + : 5927 : foreach(l, sgClauses)
+ + ]
407 : : {
408 : 3384 : SortGroupClause *sortcl = (SortGroupClause *) lfirst(l);
409 : 3384 : Node *sortexpr;
410 : :
411 : 3384 : sortexpr = get_sortgroupclause_expr(sortcl, targetList);
412 : 3384 : result = lappend(result, sortexpr);
413 : 3384 : }
414 : 5086 : return result;
415 : 2543 : }
416 : :
417 : :
418 : : /*****************************************************************************
419 : : * Functions to extract data from a list of SortGroupClauses
420 : : *
421 : : * These don't really belong in tlist.c, but they are sort of related to the
422 : : * functions just above, and they don't seem to deserve their own file.
423 : : *****************************************************************************/
424 : :
425 : : /*
426 : : * get_sortgroupref_clause
427 : : * Find the SortGroupClause matching the given SortGroupRef index,
428 : : * and return it.
429 : : */
430 : : SortGroupClause *
431 : 1828 : get_sortgroupref_clause(Index sortref, List *clauses)
432 : : {
433 : 1828 : ListCell *l;
434 : :
435 [ + - - + : 4669 : foreach(l, clauses)
+ - + - ]
436 : : {
437 : 2841 : SortGroupClause *cl = (SortGroupClause *) lfirst(l);
438 : :
439 [ + + ]: 2841 : if (cl->tleSortGroupRef == sortref)
440 : 1828 : return cl;
441 [ + + ]: 2841 : }
442 : :
443 [ # # # # ]: 0 : elog(ERROR, "ORDER/GROUP BY expression not found in list");
444 : 0 : return NULL; /* keep compiler quiet */
445 : 1828 : }
446 : :
447 : : /*
448 : : * get_sortgroupref_clause_noerr
449 : : * As above, but return NULL rather than throwing an error if not found.
450 : : */
451 : : SortGroupClause *
452 : 2313 : get_sortgroupref_clause_noerr(Index sortref, List *clauses)
453 : : {
454 : 2313 : ListCell *l;
455 : :
456 [ + - + + : 5747 : foreach(l, clauses)
+ + + + ]
457 : : {
458 : 3434 : SortGroupClause *cl = (SortGroupClause *) lfirst(l);
459 : :
460 [ + + ]: 3434 : if (cl->tleSortGroupRef == sortref)
461 : 1702 : return cl;
462 [ + + ]: 3434 : }
463 : :
464 : 611 : return NULL;
465 : 2313 : }
466 : :
467 : : /*
468 : : * extract_grouping_ops - make an array of the equality operator OIDs
469 : : * for a SortGroupClause list
470 : : */
471 : : Oid *
472 : 5727 : extract_grouping_ops(List *groupClause)
473 : : {
474 : 5727 : int numCols = list_length(groupClause);
475 : 5727 : int colno = 0;
476 : 5727 : Oid *groupOperators;
477 : 5727 : ListCell *glitem;
478 : :
479 : 5727 : groupOperators = palloc_array(Oid, numCols);
480 : :
481 [ + + + + : 7627 : foreach(glitem, groupClause)
+ + ]
482 : : {
483 : 1900 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
484 : :
485 : 1900 : groupOperators[colno] = groupcl->eqop;
486 [ + - ]: 1900 : Assert(OidIsValid(groupOperators[colno]));
487 : 1900 : colno++;
488 : 1900 : }
489 : :
490 : 11454 : return groupOperators;
491 : 5727 : }
492 : :
493 : : /*
494 : : * extract_grouping_collations - make an array of the grouping column collations
495 : : * for a SortGroupClause list
496 : : */
497 : : Oid *
498 : 5727 : extract_grouping_collations(List *groupClause, List *tlist)
499 : : {
500 : 5727 : int numCols = list_length(groupClause);
501 : 5727 : int colno = 0;
502 : 5727 : Oid *grpCollations;
503 : 5727 : ListCell *glitem;
504 : :
505 : 5727 : grpCollations = palloc_array(Oid, numCols);
506 : :
507 [ + + + + : 7627 : foreach(glitem, groupClause)
+ + ]
508 : : {
509 : 1900 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
510 : 1900 : TargetEntry *tle = get_sortgroupclause_tle(groupcl, tlist);
511 : :
512 : 1900 : grpCollations[colno++] = exprCollation((Node *) tle->expr);
513 : 1900 : }
514 : :
515 : 11454 : return grpCollations;
516 : 5727 : }
517 : :
518 : : /*
519 : : * extract_grouping_cols - make an array of the grouping column resnos
520 : : * for a SortGroupClause list
521 : : */
522 : : AttrNumber *
523 : 5391 : extract_grouping_cols(List *groupClause, List *tlist)
524 : : {
525 : 5391 : AttrNumber *grpColIdx;
526 : 5391 : int numCols = list_length(groupClause);
527 : 5391 : int colno = 0;
528 : 5391 : ListCell *glitem;
529 : :
530 : 5391 : grpColIdx = palloc_array(AttrNumber, numCols);
531 : :
532 [ + + + + : 6858 : foreach(glitem, groupClause)
+ + ]
533 : : {
534 : 1467 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
535 : 1467 : TargetEntry *tle = get_sortgroupclause_tle(groupcl, tlist);
536 : :
537 : 1467 : grpColIdx[colno++] = tle->resno;
538 : 1467 : }
539 : :
540 : 10782 : return grpColIdx;
541 : 5391 : }
542 : :
543 : : /*
544 : : * grouping_is_sortable - is it possible to implement grouping list by sorting?
545 : : *
546 : : * This is easy since the parser will have included a sortop if one exists.
547 : : */
548 : : bool
549 : 8537 : grouping_is_sortable(List *groupClause)
550 : : {
551 : 8537 : ListCell *glitem;
552 : :
553 [ + + + + : 14806 : foreach(glitem, groupClause)
+ + + + ]
554 : : {
555 : 6269 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
556 : :
557 [ + + ]: 6269 : if (!OidIsValid(groupcl->sortop))
558 : 6 : return false;
559 [ + + ]: 6269 : }
560 : 8531 : return true;
561 : 8537 : }
562 : :
563 : : /*
564 : : * grouping_is_hashable - is it possible to implement grouping list by hashing?
565 : : *
566 : : * We rely on the parser to have set the hashable flag correctly.
567 : : */
568 : : bool
569 : 1569 : grouping_is_hashable(List *groupClause)
570 : : {
571 : 1569 : ListCell *glitem;
572 : :
573 [ + + + + : 4845 : foreach(glitem, groupClause)
+ + + + ]
574 : : {
575 : 3276 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
576 : :
577 [ + + ]: 3276 : if (!groupcl->hashable)
578 : 23 : return false;
579 [ + + ]: 3276 : }
580 : 1546 : return true;
581 : 1569 : }
582 : :
583 : :
584 : : /*****************************************************************************
585 : : * PathTarget manipulation functions
586 : : *
587 : : * PathTarget is a somewhat stripped-down version of a full targetlist; it
588 : : * omits all the TargetEntry decoration except (optionally) sortgroupref data,
589 : : * and it adds evaluation cost and output data width info.
590 : : *****************************************************************************/
591 : :
592 : : /*
593 : : * make_pathtarget_from_tlist
594 : : * Construct a PathTarget equivalent to the given targetlist.
595 : : *
596 : : * This leaves the cost and width fields as zeroes. Most callers will want
597 : : * to use create_pathtarget(), so as to get those set.
598 : : */
599 : : PathTarget *
600 : 54586 : make_pathtarget_from_tlist(List *tlist)
601 : : {
602 : 54586 : PathTarget *target = makeNode(PathTarget);
603 : 54586 : int i;
604 : 54586 : ListCell *lc;
605 : :
606 : 54586 : target->sortgrouprefs = (Index *) palloc(list_length(tlist) * sizeof(Index));
607 : :
608 : 54586 : i = 0;
609 [ + + + + : 195094 : foreach(lc, tlist)
+ + ]
610 : : {
611 : 140508 : TargetEntry *tle = (TargetEntry *) lfirst(lc);
612 : :
613 : 140508 : target->exprs = lappend(target->exprs, tle->expr);
614 : 140508 : target->sortgrouprefs[i] = tle->ressortgroupref;
615 : 140508 : i++;
616 : 140508 : }
617 : :
618 : : /*
619 : : * Mark volatility as unknown. The contain_volatile_functions function
620 : : * will determine if there are any volatile functions when called for the
621 : : * first time with this PathTarget.
622 : : */
623 : 54586 : target->has_volatile_expr = VOLATILITY_UNKNOWN;
624 : :
625 : 109172 : return target;
626 : 54586 : }
627 : :
628 : : /*
629 : : * make_tlist_from_pathtarget
630 : : * Construct a targetlist from a PathTarget.
631 : : */
632 : : List *
633 : 8148 : make_tlist_from_pathtarget(PathTarget *target)
634 : : {
635 : 8148 : List *tlist = NIL;
636 : 8148 : int i;
637 : 8148 : ListCell *lc;
638 : :
639 : 8148 : i = 0;
640 [ + + + + : 31551 : foreach(lc, target->exprs)
+ + ]
641 : : {
642 : 23403 : Expr *expr = (Expr *) lfirst(lc);
643 : 23403 : TargetEntry *tle;
644 : :
645 : 46806 : tle = makeTargetEntry(expr,
646 : 23403 : i + 1,
647 : : NULL,
648 : : false);
649 [ + + ]: 23403 : if (target->sortgrouprefs)
650 : 22351 : tle->ressortgroupref = target->sortgrouprefs[i];
651 : 23403 : tlist = lappend(tlist, tle);
652 : 23403 : i++;
653 : 23403 : }
654 : :
655 : 16296 : return tlist;
656 : 8148 : }
657 : :
658 : : /*
659 : : * copy_pathtarget
660 : : * Copy a PathTarget.
661 : : *
662 : : * The new PathTarget has its own exprs List, but shares the underlying
663 : : * target expression trees with the old one.
664 : : */
665 : : PathTarget *
666 : 3912 : copy_pathtarget(PathTarget *src)
667 : : {
668 : 3912 : PathTarget *dst = makeNode(PathTarget);
669 : :
670 : : /* Copy scalar fields */
671 : 3912 : memcpy(dst, src, sizeof(PathTarget));
672 : : /* Shallow-copy the expression list */
673 : 3912 : dst->exprs = list_copy(src->exprs);
674 : : /* Duplicate sortgrouprefs if any (if not, the memcpy handled this) */
675 [ + + ]: 3912 : if (src->sortgrouprefs)
676 : : {
677 : 3707 : Size nbytes = list_length(src->exprs) * sizeof(Index);
678 : :
679 : 3707 : dst->sortgrouprefs = (Index *) palloc(nbytes);
680 : 3707 : memcpy(dst->sortgrouprefs, src->sortgrouprefs, nbytes);
681 : 3707 : }
682 : 7824 : return dst;
683 : 3912 : }
684 : :
685 : : /*
686 : : * create_empty_pathtarget
687 : : * Create an empty (zero columns, zero cost) PathTarget.
688 : : */
689 : : PathTarget *
690 : 177487 : create_empty_pathtarget(void)
691 : : {
692 : : /* This is easy, but we don't want callers to hard-wire this ... */
693 : 177487 : return makeNode(PathTarget);
694 : : }
695 : :
696 : : /*
697 : : * add_column_to_pathtarget
698 : : * Append a target column to the PathTarget.
699 : : *
700 : : * As with make_pathtarget_from_tlist, we leave it to the caller to update
701 : : * the cost and width fields.
702 : : */
703 : : void
704 : 11760 : add_column_to_pathtarget(PathTarget *target, Expr *expr, Index sortgroupref)
705 : : {
706 : : /* Updating the exprs list is easy ... */
707 : 11760 : target->exprs = lappend(target->exprs, expr);
708 : : /* ... the sortgroupref data, a bit less so */
709 [ + + ]: 11760 : if (target->sortgrouprefs)
710 : : {
711 : 4263 : int nexprs = list_length(target->exprs);
712 : :
713 : : /* This might look inefficient, but actually it's usually cheap */
714 : 4263 : target->sortgrouprefs = (Index *)
715 : 4263 : repalloc(target->sortgrouprefs, nexprs * sizeof(Index));
716 : 4263 : target->sortgrouprefs[nexprs - 1] = sortgroupref;
717 : 4263 : }
718 [ + + ]: 7497 : else if (sortgroupref)
719 : : {
720 : : /* Adding sortgroupref labeling to a previously unlabeled target */
721 : 3139 : int nexprs = list_length(target->exprs);
722 : :
723 : 3139 : target->sortgrouprefs = (Index *) palloc0(nexprs * sizeof(Index));
724 : 3139 : target->sortgrouprefs[nexprs - 1] = sortgroupref;
725 : 3139 : }
726 : :
727 : : /*
728 : : * Reset has_volatile_expr to UNKNOWN. We just leave it up to
729 : : * contain_volatile_functions to set this properly again. Technically we
730 : : * could save some effort here and just check the new Expr, but it seems
731 : : * better to keep the logic for setting this flag in one location rather
732 : : * than duplicating the logic here.
733 : : */
734 [ + - ]: 11760 : if (target->has_volatile_expr == VOLATILITY_NOVOLATILE)
735 : 0 : target->has_volatile_expr = VOLATILITY_UNKNOWN;
736 : 11760 : }
737 : :
738 : : /*
739 : : * add_new_column_to_pathtarget
740 : : * Append a target column to the PathTarget, but only if it's not
741 : : * equal() to any pre-existing target expression.
742 : : *
743 : : * The caller cannot specify a sortgroupref, since it would be unclear how
744 : : * to merge that with a pre-existing column.
745 : : *
746 : : * As with make_pathtarget_from_tlist, we leave it to the caller to update
747 : : * the cost and width fields.
748 : : */
749 : : void
750 : 7332 : add_new_column_to_pathtarget(PathTarget *target, Expr *expr)
751 : : {
752 [ + + ]: 7332 : if (!list_member(target->exprs, expr))
753 : 6011 : add_column_to_pathtarget(target, expr, 0);
754 : 7332 : }
755 : :
756 : : /*
757 : : * add_new_columns_to_pathtarget
758 : : * Apply add_new_column_to_pathtarget() for each element of the list.
759 : : */
760 : : void
761 : 6033 : add_new_columns_to_pathtarget(PathTarget *target, List *exprs)
762 : : {
763 : 6033 : ListCell *lc;
764 : :
765 [ + + + + : 12580 : foreach(lc, exprs)
+ + ]
766 : : {
767 : 6547 : Expr *expr = (Expr *) lfirst(lc);
768 : :
769 : 6547 : add_new_column_to_pathtarget(target, expr);
770 : 6547 : }
771 : 6033 : }
772 : :
773 : : /*
774 : : * apply_pathtarget_labeling_to_tlist
775 : : * Apply any sortgrouprefs in the PathTarget to matching tlist entries
776 : : *
777 : : * Here, we do not assume that the tlist entries are one-for-one with the
778 : : * PathTarget. The intended use of this function is to deal with cases
779 : : * where createplan.c has decided to use some other tlist and we have
780 : : * to identify what matches exist.
781 : : */
782 : : void
783 : 1450 : apply_pathtarget_labeling_to_tlist(List *tlist, PathTarget *target)
784 : : {
785 : 1450 : int i;
786 : 1450 : ListCell *lc;
787 : :
788 : : /* Nothing to do if PathTarget has no sortgrouprefs data */
789 [ + + ]: 1450 : if (target->sortgrouprefs == NULL)
790 : 1201 : return;
791 : :
792 : 249 : i = 0;
793 [ + - + + : 726 : foreach(lc, target->exprs)
+ + ]
794 : : {
795 : 477 : Expr *expr = (Expr *) lfirst(lc);
796 : 477 : TargetEntry *tle;
797 : :
798 [ + + ]: 477 : if (target->sortgrouprefs[i])
799 : : {
800 : : /*
801 : : * For Vars, use tlist_member_match_var's weakened matching rule;
802 : : * this allows us to deal with some cases where a set-returning
803 : : * function has been inlined, so that we now have more knowledge
804 : : * about what it returns than we did when the original Var was
805 : : * created. Otherwise, use regular equal() to find the matching
806 : : * TLE. (In current usage, only the Var case is actually needed;
807 : : * but it seems best to have sane behavior here for non-Vars too.)
808 : : */
809 [ + - - + ]: 371 : if (expr && IsA(expr, Var))
810 : 371 : tle = tlist_member_match_var((Var *) expr, tlist);
811 : : else
812 : 0 : tle = tlist_member(expr, tlist);
813 : :
814 : : /*
815 : : * Complain if noplace for the sortgrouprefs label, or if we'd
816 : : * have to label a column twice. (The case where it already has
817 : : * the desired label probably can't happen, but we may as well
818 : : * allow for it.)
819 : : */
820 [ + - ]: 371 : if (!tle)
821 [ # # # # ]: 0 : elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
822 [ + + + - ]: 371 : if (tle->ressortgroupref != 0 &&
823 : 2 : tle->ressortgroupref != target->sortgrouprefs[i])
824 [ # # # # ]: 0 : elog(ERROR, "targetlist item has multiple sortgroupref labels");
825 : :
826 : 371 : tle->ressortgroupref = target->sortgrouprefs[i];
827 : 371 : }
828 : 477 : i++;
829 : 477 : }
830 [ - + ]: 1450 : }
831 : :
832 : : /*
833 : : * split_pathtarget_at_srfs
834 : : * Split given PathTarget into multiple levels to position SRFs safely,
835 : : * performing exact matching against input_target.
836 : : *
837 : : * This is a wrapper for split_pathtarget_at_srfs_extended() that is used when
838 : : * both targets are on the same side of the grouping boundary (i.e., both are
839 : : * pre-grouping or both are post-grouping). In this case, no special handling
840 : : * for the grouping nulling bit is required.
841 : : *
842 : : * See split_pathtarget_at_srfs_extended() for more details.
843 : : */
844 : : void
845 : 4938 : split_pathtarget_at_srfs(PlannerInfo *root,
846 : : PathTarget *target, PathTarget *input_target,
847 : : List **targets, List **targets_contain_srfs)
848 : : {
849 : 9876 : split_pathtarget_at_srfs_extended(root, target, input_target,
850 : 4938 : targets, targets_contain_srfs,
851 : : false);
852 : 4938 : }
853 : :
854 : : /*
855 : : * split_pathtarget_at_srfs_grouping
856 : : * Split given PathTarget into multiple levels to position SRFs safely,
857 : : * ignoring the grouping nulling bit when matching against input_target.
858 : : *
859 : : * This variant is used when the targets cross the grouping boundary (i.e.,
860 : : * target is post-grouping while input_target is pre-grouping). In this case,
861 : : * we need to ignore the grouping nulling bit when checking for expression
862 : : * availability to avoid incorrectly re-evaluating SRFs that have already been
863 : : * computed in input_target.
864 : : *
865 : : * See split_pathtarget_at_srfs_extended() for more details.
866 : : */
867 : : void
868 : 1646 : split_pathtarget_at_srfs_grouping(PlannerInfo *root,
869 : : PathTarget *target, PathTarget *input_target,
870 : : List **targets, List **targets_contain_srfs)
871 : : {
872 : 3292 : split_pathtarget_at_srfs_extended(root, target, input_target,
873 : 1646 : targets, targets_contain_srfs,
874 : : true);
875 : 1646 : }
876 : :
877 : : /*
878 : : * split_pathtarget_at_srfs_extended
879 : : * Split given PathTarget into multiple levels to position SRFs safely
880 : : *
881 : : * The executor can only handle set-returning functions that appear at the
882 : : * top level of the targetlist of a ProjectSet plan node. If we have any SRFs
883 : : * that are not at top level, we need to split up the evaluation into multiple
884 : : * plan levels in which each level satisfies this constraint. This function
885 : : * creates appropriate PathTarget(s) for each level.
886 : : *
887 : : * As an example, consider the tlist expression
888 : : * x + srf1(srf2(y + z))
889 : : * This expression should appear as-is in the top PathTarget, but below that
890 : : * we must have a PathTarget containing
891 : : * x, srf1(srf2(y + z))
892 : : * and below that, another PathTarget containing
893 : : * x, srf2(y + z)
894 : : * and below that, another PathTarget containing
895 : : * x, y, z
896 : : * When these tlists are processed by setrefs.c, subexpressions that match
897 : : * output expressions of the next lower tlist will be replaced by Vars,
898 : : * so that what the executor gets are tlists looking like
899 : : * Var1 + Var2
900 : : * Var1, srf1(Var2)
901 : : * Var1, srf2(Var2 + Var3)
902 : : * x, y, z
903 : : * which satisfy the desired property.
904 : : *
905 : : * Another example is
906 : : * srf1(x), srf2(srf3(y))
907 : : * That must appear as-is in the top PathTarget, but below that we need
908 : : * srf1(x), srf3(y)
909 : : * That is, each SRF must be computed at a level corresponding to the nesting
910 : : * depth of SRFs within its arguments.
911 : : *
912 : : * In some cases, a SRF has already been evaluated in some previous plan level
913 : : * and we shouldn't expand it again (that is, what we see in the target is
914 : : * already meant as a reference to a lower subexpression). So, don't expand
915 : : * any tlist expressions that appear in input_target, if that's not NULL.
916 : : *
917 : : * This check requires extra care when processing the grouping target
918 : : * (indicated by the is_grouping_target flag). In this case input_target is
919 : : * pre-grouping while target is post-grouping, so the latter may carry
920 : : * nullingrels bits from the grouping step that are absent in the former. We
921 : : * must ignore those bits to correctly recognize that the tlist expressions are
922 : : * available in input_target.
923 : : *
924 : : * It's also important that we preserve any sortgroupref annotation appearing
925 : : * in the given target, especially on expressions matching input_target items.
926 : : *
927 : : * The outputs of this function are two parallel lists, one a list of
928 : : * PathTargets and the other an integer list of bool flags indicating
929 : : * whether the corresponding PathTarget contains any evaluable SRFs.
930 : : * The lists are given in the order they'd need to be evaluated in, with
931 : : * the "lowest" PathTarget first. So the last list entry is always the
932 : : * originally given PathTarget, and any entries before it indicate evaluation
933 : : * levels that must be inserted below it. The first list entry must not
934 : : * contain any SRFs (other than ones duplicating input_target entries), since
935 : : * it will typically be attached to a plan node that cannot evaluate SRFs.
936 : : *
937 : : * Note: using a list for the flags may seem like overkill, since there
938 : : * are only a few possible patterns for which levels contain SRFs.
939 : : * But this representation decouples callers from that knowledge.
940 : : */
941 : : static void
942 : 6584 : split_pathtarget_at_srfs_extended(PlannerInfo *root,
943 : : PathTarget *target, PathTarget *input_target,
944 : : List **targets, List **targets_contain_srfs,
945 : : bool is_grouping_target)
946 : : {
947 : 6584 : split_pathtarget_context context;
948 : 6584 : int max_depth;
949 : 6584 : bool need_extra_projection;
950 : 6584 : List *prev_level_tlist;
951 : 6584 : int lci;
952 : 6584 : ListCell *lc,
953 : : *lc1,
954 : : *lc2,
955 : : *lc3;
956 : :
957 : : /*
958 : : * It's not unusual for planner.c to pass us two physically identical
959 : : * targets, in which case we can conclude without further ado that all
960 : : * expressions are available from the input. (The logic below would
961 : : * arrive at the same conclusion, but much more tediously.)
962 : : */
963 [ + + ]: 6584 : if (target == input_target)
964 : : {
965 : 4897 : *targets = list_make1(target);
966 : 4897 : *targets_contain_srfs = list_make1_int(false);
967 : 4897 : return;
968 : : }
969 : :
970 : : /*
971 : : * Pass 'root', the is_grouping_target flag, and any input_target exprs
972 : : * down to split_pathtarget_walker().
973 : : */
974 : 1687 : context.root = root;
975 : 1687 : context.is_grouping_target = is_grouping_target;
976 [ + + ]: 1687 : context.input_target_exprs = input_target ? input_target->exprs : NIL;
977 : :
978 : : /*
979 : : * Initialize with empty level-zero lists, and no levels after that.
980 : : * (Note: we could dispense with representing level zero explicitly, since
981 : : * it will never receive any SRFs, but then we'd have to special-case that
982 : : * level when we get to building result PathTargets. Level zero describes
983 : : * the SRF-free PathTarget that will be given to the input plan node.)
984 : : */
985 : 1687 : context.level_srfs = list_make1(NIL);
986 : 1687 : context.level_input_vars = list_make1(NIL);
987 : 1687 : context.level_input_srfs = list_make1(NIL);
988 : :
989 : : /* Initialize data we'll accumulate across all the target expressions */
990 : 1687 : context.current_input_vars = NIL;
991 : 1687 : context.current_input_srfs = NIL;
992 : 1687 : max_depth = 0;
993 : 1687 : need_extra_projection = false;
994 : :
995 : : /* Scan each expression in the PathTarget looking for SRFs */
996 : 1687 : lci = 0;
997 [ + - + + : 3755 : foreach(lc, target->exprs)
+ + ]
998 : : {
999 : 2068 : Node *node = (Node *) lfirst(lc);
1000 : :
1001 : : /* Tell split_pathtarget_walker about this expr's sortgroupref */
1002 [ + + ]: 2068 : context.current_sgref = get_pathtarget_sortgroupref(target, lci);
1003 : 2068 : lci++;
1004 : :
1005 : : /*
1006 : : * Find all SRFs and Vars (and Var-like nodes) in this expression, and
1007 : : * enter them into appropriate lists within the context struct.
1008 : : */
1009 : 2068 : context.current_depth = 0;
1010 : 2068 : split_pathtarget_walker(node, &context);
1011 : :
1012 : : /* An expression containing no SRFs is of no further interest */
1013 [ + + ]: 2068 : if (context.current_depth == 0)
1014 : 321 : continue;
1015 : :
1016 : : /*
1017 : : * Track max SRF nesting depth over the whole PathTarget. Also, if
1018 : : * this expression establishes a new max depth, we no longer care
1019 : : * whether previous expressions contained nested SRFs; we can handle
1020 : : * any required projection for them in the final ProjectSet node.
1021 : : */
1022 [ + + ]: 1747 : if (max_depth < context.current_depth)
1023 : : {
1024 : 1648 : max_depth = context.current_depth;
1025 : 1648 : need_extra_projection = false;
1026 : 1648 : }
1027 : :
1028 : : /*
1029 : : * If any maximum-depth SRF is not at the top level of its expression,
1030 : : * we'll need an extra Result node to compute the top-level scalar
1031 : : * expression.
1032 : : */
1033 [ + + + + : 1747 : if (max_depth == context.current_depth && !IS_SRF_CALL(node))
+ + + + ]
1034 : 133 : need_extra_projection = true;
1035 [ + + ]: 2068 : }
1036 : :
1037 : : /*
1038 : : * If we found no SRFs needing evaluation (maybe they were all present in
1039 : : * input_target, or maybe they were all removed by const-simplification),
1040 : : * then no ProjectSet is needed; fall out.
1041 : : */
1042 [ + + ]: 1687 : if (max_depth == 0)
1043 : : {
1044 : 41 : *targets = list_make1(target);
1045 : 41 : *targets_contain_srfs = list_make1_int(false);
1046 : 41 : return;
1047 : : }
1048 : :
1049 : : /*
1050 : : * The Vars and SRF outputs needed at top level can be added to the last
1051 : : * level_input lists if we don't need an extra projection step. If we do
1052 : : * need one, add a SRF-free level to the lists.
1053 : : */
1054 [ + + ]: 1646 : if (need_extra_projection)
1055 : : {
1056 : 68 : context.level_srfs = lappend(context.level_srfs, NIL);
1057 : 136 : context.level_input_vars = lappend(context.level_input_vars,
1058 : 68 : context.current_input_vars);
1059 : 136 : context.level_input_srfs = lappend(context.level_input_srfs,
1060 : 68 : context.current_input_srfs);
1061 : 68 : }
1062 : : else
1063 : : {
1064 : 1578 : lc = list_nth_cell(context.level_input_vars, max_depth);
1065 : 1578 : lfirst(lc) = list_concat(lfirst(lc), context.current_input_vars);
1066 : 1578 : lc = list_nth_cell(context.level_input_srfs, max_depth);
1067 : 1578 : lfirst(lc) = list_concat(lfirst(lc), context.current_input_srfs);
1068 : : }
1069 : :
1070 : : /*
1071 : : * Now construct the output PathTargets. The original target can be used
1072 : : * as-is for the last one, but we need to construct a new SRF-free target
1073 : : * representing what the preceding plan node has to emit, as well as a
1074 : : * target for each intermediate ProjectSet node.
1075 : : */
1076 : 1646 : *targets = *targets_contain_srfs = NIL;
1077 : 1646 : prev_level_tlist = NIL;
1078 : :
1079 [ + - + + : 5016 : forthree(lc1, context.level_srfs,
+ - + + +
- + + + +
- + + + ]
1080 : : lc2, context.level_input_vars,
1081 : : lc3, context.level_input_srfs)
1082 : : {
1083 : 3370 : List *level_srfs = (List *) lfirst(lc1);
1084 : 3370 : PathTarget *ntarget;
1085 : :
1086 [ + + ]: 3370 : if (lnext(context.level_srfs, lc1) == NULL)
1087 : : {
1088 : 1646 : ntarget = target;
1089 : 1646 : }
1090 : : else
1091 : : {
1092 : 1724 : ntarget = create_empty_pathtarget();
1093 : :
1094 : : /*
1095 : : * This target should actually evaluate any SRFs of the current
1096 : : * level, and it needs to propagate forward any Vars needed by
1097 : : * later levels, as well as SRFs computed earlier and needed by
1098 : : * later levels.
1099 : : */
1100 : 1724 : add_sp_items_to_pathtarget(ntarget, level_srfs);
1101 [ + - + + : 3532 : for_each_cell(lc, context.level_input_vars,
+ + ]
1102 : : lnext(context.level_input_vars, lc2))
1103 : : {
1104 : 1808 : List *input_vars = (List *) lfirst(lc);
1105 : :
1106 : 1808 : add_sp_items_to_pathtarget(ntarget, input_vars);
1107 : 1808 : }
1108 [ + - + + : 3532 : for_each_cell(lc, context.level_input_srfs,
+ + ]
1109 : : lnext(context.level_input_srfs, lc3))
1110 : : {
1111 : 1808 : List *input_srfs = (List *) lfirst(lc);
1112 : 1808 : ListCell *lcx;
1113 : :
1114 [ + + + + : 3747 : foreach(lcx, input_srfs)
+ + ]
1115 : : {
1116 : 1939 : split_pathtarget_item *item = lfirst(lcx);
1117 : :
1118 [ + + ]: 1939 : if (list_member(prev_level_tlist, item->expr))
1119 : 6 : add_sp_item_to_pathtarget(ntarget, item);
1120 : 1939 : }
1121 : 1808 : }
1122 : 1724 : set_pathtarget_cost_width(root, ntarget);
1123 : : }
1124 : :
1125 : : /*
1126 : : * Add current target and does-it-compute-SRFs flag to output lists.
1127 : : */
1128 : 3370 : *targets = lappend(*targets, ntarget);
1129 : 6740 : *targets_contain_srfs = lappend_int(*targets_contain_srfs,
1130 : 3370 : (level_srfs != NIL));
1131 : :
1132 : : /* Remember this level's output for next pass */
1133 : 3370 : prev_level_tlist = ntarget->exprs;
1134 : 3370 : }
1135 : 6584 : }
1136 : :
1137 : : /*
1138 : : * Recursively examine expressions for split_pathtarget_at_srfs.
1139 : : *
1140 : : * Note we make no effort here to prevent duplicate entries in the output
1141 : : * lists. Duplicates will be gotten rid of later.
1142 : : */
1143 : : static bool
1144 : 6746 : split_pathtarget_walker(Node *node, split_pathtarget_context *context)
1145 : : {
1146 : 6746 : Node *sanitized_node = node;
1147 : :
1148 [ + + ]: 6746 : if (node == NULL)
1149 : 2 : return false;
1150 : :
1151 : : /*
1152 : : * If we are crossing the grouping boundary (post-grouping target vs
1153 : : * pre-grouping input_target), we must ignore the grouping nulling bit to
1154 : : * correctly check if the subexpression is available in input_target. This
1155 : : * aligns with the matching logic in set_upper_references().
1156 : : */
1157 [ + + ]: 6744 : if (context->is_grouping_target &&
1158 [ + + + + ]: 112 : context->root->parse->hasGroupRTE &&
1159 : 101 : context->root->parse->groupingSets != NIL)
1160 : : {
1161 : 39 : sanitized_node =
1162 : 78 : remove_nulling_relids(node,
1163 : 39 : bms_make_singleton(context->root->group_rtindex),
1164 : : NULL);
1165 : 39 : }
1166 : :
1167 : : /*
1168 : : * A subexpression that matches an expression already computed in
1169 : : * input_target can be treated like a Var (which indeed it will be after
1170 : : * setrefs.c gets done with it), even if it's actually a SRF. Record it
1171 : : * as being needed for the current expression, and ignore any
1172 : : * substructure. (Note in particular that this preserves the identity of
1173 : : * any expressions that appear as sortgrouprefs in input_target.)
1174 : : */
1175 [ + + ]: 6744 : if (list_member(context->input_target_exprs, sanitized_node))
1176 : : {
1177 : 72 : split_pathtarget_item *item = palloc_object(split_pathtarget_item);
1178 : :
1179 : 72 : item->expr = node;
1180 : 72 : item->sortgroupref = context->current_sgref;
1181 : 144 : context->current_input_vars = lappend(context->current_input_vars,
1182 : 72 : item);
1183 : 72 : return false;
1184 : 72 : }
1185 : :
1186 : : /*
1187 : : * Vars and Var-like constructs are expected to be gotten from the input,
1188 : : * too. We assume that these constructs cannot contain any SRFs (if one
1189 : : * does, there will be an executor failure from a misplaced SRF).
1190 : : */
1191 [ + + ]: 6672 : if (IsA(node, Var) ||
1192 [ + + ]: 6280 : IsA(node, PlaceHolderVar) ||
1193 [ + + ]: 6272 : IsA(node, Aggref) ||
1194 [ + - + + ]: 6243 : IsA(node, GroupingFunc) ||
1195 : 6243 : IsA(node, WindowFunc))
1196 : : {
1197 : 432 : split_pathtarget_item *item = palloc_object(split_pathtarget_item);
1198 : :
1199 : 432 : item->expr = node;
1200 : 432 : item->sortgroupref = context->current_sgref;
1201 : 864 : context->current_input_vars = lappend(context->current_input_vars,
1202 : 432 : item);
1203 : 432 : return false;
1204 : 432 : }
1205 : :
1206 : : /*
1207 : : * If it's a SRF, recursively examine its inputs, determine its level, and
1208 : : * make appropriate entries in the output lists.
1209 : : */
1210 [ + + + + : 6240 : if (IS_SRF_CALL(node))
+ + ]
1211 : : {
1212 : 1758 : split_pathtarget_item *item = palloc_object(split_pathtarget_item);
1213 : 1758 : List *save_input_vars = context->current_input_vars;
1214 : 1758 : List *save_input_srfs = context->current_input_srfs;
1215 : 1758 : int save_current_depth = context->current_depth;
1216 : 1758 : int srf_depth;
1217 : 1758 : ListCell *lc;
1218 : :
1219 : 1758 : item->expr = node;
1220 : 1758 : item->sortgroupref = context->current_sgref;
1221 : :
1222 : 1758 : context->current_input_vars = NIL;
1223 : 1758 : context->current_input_srfs = NIL;
1224 : 1758 : context->current_depth = 0;
1225 : 1758 : context->current_sgref = 0; /* subexpressions are not sortgroup items */
1226 : :
1227 : 1758 : (void) expression_tree_walker(node, split_pathtarget_walker, context);
1228 : :
1229 : : /* Depth is one more than any SRF below it */
1230 : 1758 : srf_depth = context->current_depth + 1;
1231 : :
1232 : : /* If new record depth, initialize another level of output lists */
1233 [ + + ]: 1758 : if (srf_depth >= list_length(context->level_srfs))
1234 : : {
1235 : 1656 : context->level_srfs = lappend(context->level_srfs, NIL);
1236 : 1656 : context->level_input_vars = lappend(context->level_input_vars, NIL);
1237 : 1656 : context->level_input_srfs = lappend(context->level_input_srfs, NIL);
1238 : 1656 : }
1239 : :
1240 : : /* Record this SRF as needing to be evaluated at appropriate level */
1241 : 1758 : lc = list_nth_cell(context->level_srfs, srf_depth);
1242 : 1758 : lfirst(lc) = lappend(lfirst(lc), item);
1243 : :
1244 : : /* Record its inputs as being needed at the same level */
1245 : 1758 : lc = list_nth_cell(context->level_input_vars, srf_depth);
1246 : 1758 : lfirst(lc) = list_concat(lfirst(lc), context->current_input_vars);
1247 : 1758 : lc = list_nth_cell(context->level_input_srfs, srf_depth);
1248 : 1758 : lfirst(lc) = list_concat(lfirst(lc), context->current_input_srfs);
1249 : :
1250 : : /*
1251 : : * Restore caller-level state and update it for presence of this SRF.
1252 : : * Notice we report the SRF itself as being needed for evaluation of
1253 : : * surrounding expression.
1254 : : */
1255 : 1758 : context->current_input_vars = save_input_vars;
1256 : 1758 : context->current_input_srfs = lappend(save_input_srfs, item);
1257 [ - + ]: 1758 : context->current_depth = Max(save_current_depth, srf_depth);
1258 : :
1259 : : /* We're done here */
1260 : 1758 : return false;
1261 : 1758 : }
1262 : :
1263 : : /*
1264 : : * Otherwise, the node is a scalar (non-set) expression, so recurse to
1265 : : * examine its inputs.
1266 : : */
1267 : 4482 : context->current_sgref = 0; /* subexpressions are not sortgroup items */
1268 : 4482 : return expression_tree_walker(node, split_pathtarget_walker, context);
1269 : 6746 : }
1270 : :
1271 : : /*
1272 : : * Add a split_pathtarget_item to the PathTarget, unless a matching item is
1273 : : * already present. This is like add_new_column_to_pathtarget, but allows
1274 : : * for sortgrouprefs to be handled. An item having zero sortgroupref can
1275 : : * be merged with one that has a sortgroupref, acquiring the latter's
1276 : : * sortgroupref.
1277 : : *
1278 : : * Note that we don't worry about possibly adding duplicate sortgrouprefs
1279 : : * to the PathTarget. That would be bad, but it should be impossible unless
1280 : : * the target passed to split_pathtarget_at_srfs already had duplicates.
1281 : : * As long as it didn't, we can have at most one split_pathtarget_item with
1282 : : * any particular nonzero sortgroupref.
1283 : : */
1284 : : static void
1285 : 652 : add_sp_item_to_pathtarget(PathTarget *target, split_pathtarget_item *item)
1286 : : {
1287 : 652 : int lci;
1288 : 652 : ListCell *lc;
1289 : :
1290 : : /*
1291 : : * Look for a pre-existing entry that is equal() and does not have a
1292 : : * conflicting sortgroupref already.
1293 : : */
1294 : 652 : lci = 0;
1295 [ + + + + : 1316 : foreach(lc, target->exprs)
+ + + + ]
1296 : : {
1297 : 664 : Node *node = (Node *) lfirst(lc);
1298 [ + + ]: 664 : Index sgref = get_pathtarget_sortgroupref(target, lci);
1299 : :
1300 [ + + ]: 664 : if ((item->sortgroupref == sgref ||
1301 [ + + ]: 50 : item->sortgroupref == 0 ||
1302 [ + + ]: 664 : sgref == 0) &&
1303 : 630 : equal(item->expr, node))
1304 : : {
1305 : : /* Found a match. Assign item's sortgroupref if it has one. */
1306 [ + + ]: 212 : if (item->sortgroupref)
1307 : : {
1308 [ + + ]: 4 : if (target->sortgrouprefs == NULL)
1309 : : {
1310 : 2 : target->sortgrouprefs = (Index *)
1311 : 2 : palloc0(list_length(target->exprs) * sizeof(Index));
1312 : 2 : }
1313 : 4 : target->sortgrouprefs[lci] = item->sortgroupref;
1314 : 4 : }
1315 : 212 : return;
1316 : : }
1317 : 452 : lci++;
1318 [ + + ]: 664 : }
1319 : :
1320 : : /*
1321 : : * No match, so add item to PathTarget. Copy the expr for safety.
1322 : : */
1323 : 880 : add_column_to_pathtarget(target, (Expr *) copyObject(item->expr),
1324 : 440 : item->sortgroupref);
1325 [ - + ]: 652 : }
1326 : :
1327 : : /*
1328 : : * Apply add_sp_item_to_pathtarget to each element of list.
1329 : : */
1330 : : static void
1331 : 3532 : add_sp_items_to_pathtarget(PathTarget *target, List *items)
1332 : : {
1333 : 3532 : ListCell *lc;
1334 : :
1335 [ + + + + : 4178 : foreach(lc, items)
+ + ]
1336 : : {
1337 : 646 : split_pathtarget_item *item = lfirst(lc);
1338 : :
1339 : 646 : add_sp_item_to_pathtarget(target, item);
1340 : 646 : }
1341 : 3532 : }
|