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 : 40498 : tlist_member(Expr *node, List *targetlist)
89 : : {
90 : : ListCell *temp;
91 : :
92 [ + + + + : 141995 : foreach(temp, targetlist)
+ + ]
93 : : {
94 : 112365 : TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
95 : :
96 [ + + ]: 112365 : if (equal(node, tlentry->expr))
97 : 10868 : return tlentry;
98 : : }
99 : 29630 : return NULL;
100 : : }
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 : 2372 : tlist_member_match_var(Var *var, List *targetlist)
112 : : {
113 : : ListCell *temp;
114 : :
115 [ + - + - : 6720 : foreach(temp, targetlist)
+ - ]
116 : : {
117 : 6720 : TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
118 : 6720 : Var *tlvar = (Var *) tlentry->expr;
119 : :
120 [ + - - + ]: 6720 : if (!tlvar || !IsA(tlvar, Var))
121 : 0 : continue;
122 [ + - ]: 6720 : if (var->varno == tlvar->varno &&
123 [ + + ]: 6720 : var->varattno == tlvar->varattno &&
124 [ + - ]: 2372 : var->varlevelsup == tlvar->varlevelsup &&
125 [ + - ]: 2372 : var->vartype == tlvar->vartype)
126 : 2372 : return tlentry;
127 : : }
128 : 0 : return NULL;
129 : : }
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 : 889 : add_to_flat_tlist(List *tlist, List *exprs)
142 : : {
143 : 889 : int next_resno = list_length(tlist) + 1;
144 : : ListCell *lc;
145 : :
146 [ + + + + : 4795 : foreach(lc, exprs)
+ + ]
147 : : {
148 : 3906 : Expr *expr = (Expr *) lfirst(lc);
149 : :
150 [ + + ]: 3906 : if (!tlist_member(expr, tlist))
151 : : {
152 : : TargetEntry *tle;
153 : :
154 : 3886 : tle = makeTargetEntry(copyObject(expr), /* copy needed?? */
155 : 3886 : next_resno++,
156 : : NULL,
157 : : false);
158 : 3886 : tlist = lappend(tlist, tle);
159 : : }
160 : : }
161 : 889 : return tlist;
162 : : }
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 : 10817 : get_tlist_exprs(List *tlist, bool includeJunk)
173 : : {
174 : 10817 : List *result = NIL;
175 : : ListCell *l;
176 : :
177 [ + + + + : 42250 : foreach(l, tlist)
+ + ]
178 : : {
179 : 31433 : TargetEntry *tle = (TargetEntry *) lfirst(l);
180 : :
181 [ - + - - ]: 31433 : if (tle->resjunk && !includeJunk)
182 : 0 : continue;
183 : :
184 : 31433 : result = lappend(result, tle->expr);
185 : : }
186 : 10817 : return result;
187 : : }
188 : :
189 : :
190 : : /*
191 : : * count_nonjunk_tlist_entries
192 : : * What it says ...
193 : : */
194 : : int
195 : 22454 : count_nonjunk_tlist_entries(List *tlist)
196 : : {
197 : 22454 : int len = 0;
198 : : ListCell *l;
199 : :
200 [ + + + + : 46280 : foreach(l, tlist)
+ + ]
201 : : {
202 : 23826 : TargetEntry *tle = (TargetEntry *) lfirst(l);
203 : :
204 [ + + ]: 23826 : if (!tle->resjunk)
205 : 22560 : len++;
206 : : }
207 : 22454 : return len;
208 : : }
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 : 1496 : tlist_same_exprs(List *tlist1, List *tlist2)
228 : : {
229 : : ListCell *lc1,
230 : : *lc2;
231 : :
232 [ + + ]: 1496 : if (list_length(tlist1) != list_length(tlist2))
233 : 649 : return false; /* not same length, so can't match */
234 : :
235 [ + - + + : 1146 : forboth(lc1, tlist1, lc2, tlist2)
+ - + + +
+ + - +
+ ]
236 : : {
237 : 1012 : TargetEntry *tle1 = (TargetEntry *) lfirst(lc1);
238 : 1012 : TargetEntry *tle2 = (TargetEntry *) lfirst(lc2);
239 : :
240 [ + + ]: 1012 : if (!equal(tle1->expr, tle2->expr))
241 : 713 : return false;
242 : : }
243 : :
244 : 134 : return true;
245 : : }
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 : 17567 : tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
258 : : {
259 : : ListCell *l;
260 : 17567 : ListCell *curColType = list_head(colTypes);
261 : :
262 [ + + + + : 68115 : foreach(l, tlist)
+ + ]
263 : : {
264 : 51024 : TargetEntry *tle = (TargetEntry *) lfirst(l);
265 : :
266 [ + + ]: 51024 : if (tle->resjunk)
267 : : {
268 [ - + ]: 10 : if (!junkOK)
269 : 476 : return false;
270 : : }
271 : : else
272 : : {
273 [ - + ]: 51014 : if (curColType == NULL)
274 : 0 : return false; /* tlist longer than colTypes */
275 [ + + ]: 51014 : if (exprType((Node *) tle->expr) != lfirst_oid(curColType))
276 : 476 : return false;
277 : 50538 : curColType = lnext(colTypes, curColType);
278 : : }
279 : : }
280 [ - + ]: 17091 : if (curColType != NULL)
281 : 0 : return false; /* tlist shorter than colTypes */
282 : 17091 : return true;
283 : : }
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 : 4482 : tlist_same_collations(List *tlist, List *colCollations, bool junkOK)
292 : : {
293 : : ListCell *l;
294 : 4482 : ListCell *curColColl = list_head(colCollations);
295 : :
296 [ + + + + : 17284 : foreach(l, tlist)
+ + ]
297 : : {
298 : 12802 : TargetEntry *tle = (TargetEntry *) lfirst(l);
299 : :
300 [ - + ]: 12802 : if (tle->resjunk)
301 : : {
302 [ # # ]: 0 : if (!junkOK)
303 : 0 : return false;
304 : : }
305 : : else
306 : : {
307 [ - + ]: 12802 : if (curColColl == NULL)
308 : 0 : return false; /* tlist longer than colCollations */
309 [ - + ]: 12802 : if (exprCollation((Node *) tle->expr) != lfirst_oid(curColColl))
310 : 0 : return false;
311 : 12802 : curColColl = lnext(colCollations, curColColl);
312 : : }
313 : : }
314 [ - + ]: 4482 : if (curColColl != NULL)
315 : 0 : return false; /* tlist shorter than colCollations */
316 : 4482 : return true;
317 : : }
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 : 416929 : apply_tlist_labeling(List *dest_tlist, List *src_tlist)
328 : : {
329 : : ListCell *ld,
330 : : *ls;
331 : :
332 : : Assert(list_length(dest_tlist) == list_length(src_tlist));
333 [ + + + + : 1512746 : forboth(ld, dest_tlist, ls, src_tlist)
+ + + + +
+ + - +
+ ]
334 : : {
335 : 1095817 : TargetEntry *dest_tle = (TargetEntry *) lfirst(ld);
336 : 1095817 : TargetEntry *src_tle = (TargetEntry *) lfirst(ls);
337 : :
338 : : Assert(dest_tle->resno == src_tle->resno);
339 : 1095817 : dest_tle->resname = src_tle->resname;
340 : 1095817 : dest_tle->ressortgroupref = src_tle->ressortgroupref;
341 : 1095817 : dest_tle->resorigtbl = src_tle->resorigtbl;
342 : 1095817 : dest_tle->resorigcol = src_tle->resorigcol;
343 : 1095817 : dest_tle->resjunk = src_tle->resjunk;
344 : : }
345 : 416929 : }
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 : 228767 : get_sortgroupref_tle(Index sortref, List *targetList)
355 : : {
356 : : ListCell *l;
357 : :
358 [ + - + - : 580379 : foreach(l, targetList)
+ - ]
359 : : {
360 : 580379 : TargetEntry *tle = (TargetEntry *) lfirst(l);
361 : :
362 [ + + ]: 580379 : if (tle->ressortgroupref == sortref)
363 : 228767 : return tle;
364 : : }
365 : :
366 [ # # ]: 0 : elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
367 : : return NULL; /* keep compiler quiet */
368 : : }
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 : 227582 : get_sortgroupclause_tle(SortGroupClause *sgClause,
377 : : List *targetList)
378 : : {
379 : 227582 : 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 : 185790 : get_sortgroupclause_expr(SortGroupClause *sgClause, List *targetList)
389 : : {
390 : 185790 : TargetEntry *tle = get_sortgroupclause_tle(sgClause, targetList);
391 : :
392 : 185790 : return (Node *) tle->expr;
393 : : }
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 : 14939 : get_sortgrouplist_exprs(List *sgClauses, List *targetList)
402 : : {
403 : 14939 : List *result = NIL;
404 : : ListCell *l;
405 : :
406 [ + + + + : 34810 : foreach(l, sgClauses)
+ + ]
407 : : {
408 : 19871 : SortGroupClause *sortcl = (SortGroupClause *) lfirst(l);
409 : : Node *sortexpr;
410 : :
411 : 19871 : sortexpr = get_sortgroupclause_expr(sortcl, targetList);
412 : 19871 : result = lappend(result, sortexpr);
413 : : }
414 : 14939 : return result;
415 : : }
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 : 9459 : get_sortgroupref_clause(Index sortref, List *clauses)
432 : : {
433 : : ListCell *l;
434 : :
435 [ + - + - : 14793 : foreach(l, clauses)
+ - ]
436 : : {
437 : 14793 : SortGroupClause *cl = (SortGroupClause *) lfirst(l);
438 : :
439 [ + + ]: 14793 : if (cl->tleSortGroupRef == sortref)
440 : 9459 : return cl;
441 : : }
442 : :
443 [ # # ]: 0 : elog(ERROR, "ORDER/GROUP BY expression not found in list");
444 : : return NULL; /* keep compiler quiet */
445 : : }
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 : 12846 : get_sortgroupref_clause_noerr(Index sortref, List *clauses)
453 : : {
454 : : ListCell *l;
455 : :
456 [ + + + + : 21903 : foreach(l, clauses)
+ + ]
457 : : {
458 : 18728 : SortGroupClause *cl = (SortGroupClause *) lfirst(l);
459 : :
460 [ + + ]: 18728 : if (cl->tleSortGroupRef == sortref)
461 : 9671 : return cl;
462 : : }
463 : :
464 : 3175 : return NULL;
465 : : }
466 : :
467 : : /*
468 : : * extract_grouping_ops - make an array of the equality operator OIDs
469 : : * for a SortGroupClause list
470 : : */
471 : : Oid *
472 : 38538 : extract_grouping_ops(List *groupClause)
473 : : {
474 : 38538 : int numCols = list_length(groupClause);
475 : 38538 : int colno = 0;
476 : : Oid *groupOperators;
477 : : ListCell *glitem;
478 : :
479 : 38538 : groupOperators = palloc_array(Oid, numCols);
480 : :
481 [ + + + + : 50510 : foreach(glitem, groupClause)
+ + ]
482 : : {
483 : 11972 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
484 : :
485 : 11972 : groupOperators[colno] = groupcl->eqop;
486 : : Assert(OidIsValid(groupOperators[colno]));
487 : 11972 : colno++;
488 : : }
489 : :
490 : 38538 : return groupOperators;
491 : : }
492 : :
493 : : /*
494 : : * extract_grouping_collations - make an array of the grouping column collations
495 : : * for a SortGroupClause list
496 : : */
497 : : Oid *
498 : 38538 : extract_grouping_collations(List *groupClause, List *tlist)
499 : : {
500 : 38538 : int numCols = list_length(groupClause);
501 : 38538 : int colno = 0;
502 : : Oid *grpCollations;
503 : : ListCell *glitem;
504 : :
505 : 38538 : grpCollations = palloc_array(Oid, numCols);
506 : :
507 [ + + + + : 50510 : foreach(glitem, groupClause)
+ + ]
508 : : {
509 : 11972 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
510 : 11972 : TargetEntry *tle = get_sortgroupclause_tle(groupcl, tlist);
511 : :
512 : 11972 : grpCollations[colno++] = exprCollation((Node *) tle->expr);
513 : : }
514 : :
515 : 38538 : return grpCollations;
516 : : }
517 : :
518 : : /*
519 : : * extract_grouping_cols - make an array of the grouping column resnos
520 : : * for a SortGroupClause list
521 : : */
522 : : AttrNumber *
523 : 36713 : extract_grouping_cols(List *groupClause, List *tlist)
524 : : {
525 : : AttrNumber *grpColIdx;
526 : 36713 : int numCols = list_length(groupClause);
527 : 36713 : int colno = 0;
528 : : ListCell *glitem;
529 : :
530 : 36713 : grpColIdx = palloc_array(AttrNumber, numCols);
531 : :
532 [ + + + + : 46359 : foreach(glitem, groupClause)
+ + ]
533 : : {
534 : 9646 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
535 : 9646 : TargetEntry *tle = get_sortgroupclause_tle(groupcl, tlist);
536 : :
537 : 9646 : grpColIdx[colno++] = tle->resno;
538 : : }
539 : :
540 : 36713 : return grpColIdx;
541 : : }
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 : 54543 : grouping_is_sortable(List *groupClause)
550 : : {
551 : : ListCell *glitem;
552 : :
553 [ + + + + : 90896 : foreach(glitem, groupClause)
+ + ]
554 : : {
555 : 36481 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
556 : :
557 [ + + ]: 36481 : if (!OidIsValid(groupcl->sortop))
558 : 128 : return false;
559 : : }
560 : 54415 : return true;
561 : : }
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 : 10140 : grouping_is_hashable(List *groupClause)
570 : : {
571 : : ListCell *glitem;
572 : :
573 [ + + + + : 30648 : foreach(glitem, groupClause)
+ + ]
574 : : {
575 : 20625 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
576 : :
577 [ + + ]: 20625 : if (!groupcl->hashable)
578 : 117 : return false;
579 : : }
580 : 10023 : return true;
581 : : }
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 : 415333 : make_pathtarget_from_tlist(List *tlist)
601 : : {
602 : 415333 : PathTarget *target = makeNode(PathTarget);
603 : : int i;
604 : : ListCell *lc;
605 : :
606 : 415333 : target->sortgrouprefs = palloc_array(Index, list_length(tlist));
607 : :
608 : 415333 : i = 0;
609 [ + + + + : 1509576 : foreach(lc, tlist)
+ + ]
610 : : {
611 : 1094243 : TargetEntry *tle = (TargetEntry *) lfirst(lc);
612 : :
613 : 1094243 : target->exprs = lappend(target->exprs, tle->expr);
614 : 1094243 : target->sortgrouprefs[i] = tle->ressortgroupref;
615 : 1094243 : i++;
616 : : }
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 : 415333 : target->has_volatile_expr = VOLATILITY_UNKNOWN;
624 : :
625 : 415333 : return target;
626 : : }
627 : :
628 : : /*
629 : : * make_tlist_from_pathtarget
630 : : * Construct a targetlist from a PathTarget.
631 : : */
632 : : List *
633 : 55658 : make_tlist_from_pathtarget(PathTarget *target)
634 : : {
635 : 55658 : List *tlist = NIL;
636 : : int i;
637 : : ListCell *lc;
638 : :
639 : 55658 : i = 0;
640 [ + + + + : 240523 : foreach(lc, target->exprs)
+ + ]
641 : : {
642 : 184865 : Expr *expr = (Expr *) lfirst(lc);
643 : : TargetEntry *tle;
644 : :
645 : 184865 : tle = makeTargetEntry(expr,
646 : 184865 : i + 1,
647 : : NULL,
648 : : false);
649 [ + + ]: 184865 : if (target->sortgrouprefs)
650 : 179140 : tle->ressortgroupref = target->sortgrouprefs[i];
651 : 184865 : tlist = lappend(tlist, tle);
652 : 184865 : i++;
653 : : }
654 : :
655 : 55658 : return tlist;
656 : : }
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 : 22861 : copy_pathtarget(PathTarget *src)
667 : : {
668 : 22861 : PathTarget *dst = makeNode(PathTarget);
669 : :
670 : : /* Copy scalar fields */
671 : 22861 : memcpy(dst, src, sizeof(PathTarget));
672 : : /* Shallow-copy the expression list */
673 : 22861 : dst->exprs = list_copy(src->exprs);
674 : : /* Duplicate sortgrouprefs if any (if not, the memcpy handled this) */
675 [ + + ]: 22861 : if (src->sortgrouprefs)
676 : : {
677 : 21153 : Size nbytes = list_length(src->exprs) * sizeof(Index);
678 : :
679 : 21153 : dst->sortgrouprefs = (Index *) palloc(nbytes);
680 : 21153 : memcpy(dst->sortgrouprefs, src->sortgrouprefs, nbytes);
681 : : }
682 : 22861 : return dst;
683 : : }
684 : :
685 : : /*
686 : : * create_empty_pathtarget
687 : : * Create an empty (zero columns, zero cost) PathTarget.
688 : : */
689 : : PathTarget *
690 : 1363844 : create_empty_pathtarget(void)
691 : : {
692 : : /* This is easy, but we don't want callers to hard-wire this ... */
693 : 1363844 : 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 : 66569 : add_column_to_pathtarget(PathTarget *target, Expr *expr, Index sortgroupref)
705 : : {
706 : : /* Updating the exprs list is easy ... */
707 : 66569 : target->exprs = lappend(target->exprs, expr);
708 : : /* ... the sortgroupref data, a bit less so */
709 [ + + ]: 66569 : if (target->sortgrouprefs)
710 : : {
711 : 21959 : int nexprs = list_length(target->exprs);
712 : :
713 : : /* This might look inefficient, but actually it's usually cheap */
714 : 21959 : target->sortgrouprefs = repalloc_array(target->sortgrouprefs, Index, nexprs);
715 : 21959 : target->sortgrouprefs[nexprs - 1] = sortgroupref;
716 : : }
717 [ + + ]: 44610 : else if (sortgroupref)
718 : : {
719 : : /* Adding sortgroupref labeling to a previously unlabeled target */
720 : 16450 : int nexprs = list_length(target->exprs);
721 : :
722 : 16450 : target->sortgrouprefs = palloc0_array(Index, nexprs);
723 : 16450 : target->sortgrouprefs[nexprs - 1] = sortgroupref;
724 : : }
725 : :
726 : : /*
727 : : * Reset has_volatile_expr to UNKNOWN. We just leave it up to
728 : : * contain_volatile_functions to set this properly again. Technically we
729 : : * could save some effort here and just check the new Expr, but it seems
730 : : * better to keep the logic for setting this flag in one location rather
731 : : * than duplicating the logic here.
732 : : */
733 [ - + ]: 66569 : if (target->has_volatile_expr == VOLATILITY_NOVOLATILE)
734 : 0 : target->has_volatile_expr = VOLATILITY_UNKNOWN;
735 : 66569 : }
736 : :
737 : : /*
738 : : * add_new_column_to_pathtarget
739 : : * Append a target column to the PathTarget, but only if it's not
740 : : * equal() to any pre-existing target expression.
741 : : *
742 : : * The caller cannot specify a sortgroupref, since it would be unclear how
743 : : * to merge that with a pre-existing column.
744 : : *
745 : : * As with make_pathtarget_from_tlist, we leave it to the caller to update
746 : : * the cost and width fields.
747 : : */
748 : : void
749 : 43999 : add_new_column_to_pathtarget(PathTarget *target, Expr *expr)
750 : : {
751 [ + + ]: 43999 : if (!list_member(target->exprs, expr))
752 : 35882 : add_column_to_pathtarget(target, expr, 0);
753 : 43999 : }
754 : :
755 : : /*
756 : : * add_new_columns_to_pathtarget
757 : : * Apply add_new_column_to_pathtarget() for each element of the list.
758 : : */
759 : : void
760 : 40092 : add_new_columns_to_pathtarget(PathTarget *target, List *exprs)
761 : : {
762 : : ListCell *lc;
763 : :
764 [ + + + + : 80139 : foreach(lc, exprs)
+ + ]
765 : : {
766 : 40047 : Expr *expr = (Expr *) lfirst(lc);
767 : :
768 : 40047 : add_new_column_to_pathtarget(target, expr);
769 : : }
770 : 40092 : }
771 : :
772 : : /*
773 : : * apply_pathtarget_labeling_to_tlist
774 : : * Apply any sortgrouprefs in the PathTarget to matching tlist entries
775 : : *
776 : : * Here, we do not assume that the tlist entries are one-for-one with the
777 : : * PathTarget. The intended use of this function is to deal with cases
778 : : * where createplan.c has decided to use some other tlist and we have
779 : : * to identify what matches exist.
780 : : */
781 : : void
782 : 15054 : apply_pathtarget_labeling_to_tlist(List *tlist, PathTarget *target)
783 : : {
784 : : int i;
785 : : ListCell *lc;
786 : :
787 : : /* Nothing to do if PathTarget has no sortgrouprefs data */
788 [ + + ]: 15054 : if (target->sortgrouprefs == NULL)
789 : 13344 : return;
790 : :
791 : 1710 : i = 0;
792 [ + - + + : 4658 : foreach(lc, target->exprs)
+ + ]
793 : : {
794 : 2948 : Expr *expr = (Expr *) lfirst(lc);
795 : : TargetEntry *tle;
796 : :
797 [ + + ]: 2948 : if (target->sortgrouprefs[i])
798 : : {
799 : : /*
800 : : * For Vars, use tlist_member_match_var's weakened matching rule;
801 : : * this allows us to deal with some cases where a set-returning
802 : : * function has been inlined, so that we now have more knowledge
803 : : * about what it returns than we did when the original Var was
804 : : * created. Otherwise, use regular equal() to find the matching
805 : : * TLE. (In current usage, only the Var case is actually needed;
806 : : * but it seems best to have sane behavior here for non-Vars too.)
807 : : */
808 [ + - + - ]: 2372 : if (expr && IsA(expr, Var))
809 : 2372 : tle = tlist_member_match_var((Var *) expr, tlist);
810 : : else
811 : 0 : tle = tlist_member(expr, tlist);
812 : :
813 : : /*
814 : : * Complain if noplace for the sortgrouprefs label, or if we'd
815 : : * have to label a column twice. (The case where it already has
816 : : * the desired label probably can't happen, but we may as well
817 : : * allow for it.)
818 : : */
819 [ - + ]: 2372 : if (!tle)
820 [ # # ]: 0 : elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
821 [ + + ]: 2372 : if (tle->ressortgroupref != 0 &&
822 [ - + ]: 10 : tle->ressortgroupref != target->sortgrouprefs[i])
823 [ # # ]: 0 : elog(ERROR, "targetlist item has multiple sortgroupref labels");
824 : :
825 : 2372 : tle->ressortgroupref = target->sortgrouprefs[i];
826 : : }
827 : 2948 : i++;
828 : : }
829 : : }
830 : :
831 : : /*
832 : : * split_pathtarget_at_srfs
833 : : * Split given PathTarget into multiple levels to position SRFs safely,
834 : : * performing exact matching against input_target.
835 : : *
836 : : * This is a wrapper for split_pathtarget_at_srfs_extended() that is used when
837 : : * both targets are on the same side of the grouping boundary (i.e., both are
838 : : * pre-grouping or both are post-grouping). In this case, no special handling
839 : : * for the grouping nulling bit is required.
840 : : *
841 : : * See split_pathtarget_at_srfs_extended() for more details.
842 : : */
843 : : void
844 : 30810 : split_pathtarget_at_srfs(PlannerInfo *root,
845 : : PathTarget *target, PathTarget *input_target,
846 : : List **targets, List **targets_contain_srfs)
847 : : {
848 : 30810 : split_pathtarget_at_srfs_extended(root, target, input_target,
849 : : targets, targets_contain_srfs,
850 : : false);
851 : 30810 : }
852 : :
853 : : /*
854 : : * split_pathtarget_at_srfs_grouping
855 : : * Split given PathTarget into multiple levels to position SRFs safely,
856 : : * ignoring the grouping nulling bit when matching against input_target.
857 : : *
858 : : * This variant is used when the targets cross the grouping boundary (i.e.,
859 : : * target is post-grouping while input_target is pre-grouping). In this case,
860 : : * we need to ignore the grouping nulling bit when checking for expression
861 : : * availability to avoid incorrectly re-evaluating SRFs that have already been
862 : : * computed in input_target.
863 : : *
864 : : * See split_pathtarget_at_srfs_extended() for more details.
865 : : */
866 : : void
867 : 10270 : split_pathtarget_at_srfs_grouping(PlannerInfo *root,
868 : : PathTarget *target, PathTarget *input_target,
869 : : List **targets, List **targets_contain_srfs)
870 : : {
871 : 10270 : split_pathtarget_at_srfs_extended(root, target, input_target,
872 : : targets, targets_contain_srfs,
873 : : true);
874 : 10270 : }
875 : :
876 : : /*
877 : : * split_pathtarget_at_srfs_extended
878 : : * Split given PathTarget into multiple levels to position SRFs safely
879 : : *
880 : : * The executor can only handle set-returning functions that appear at the
881 : : * top level of the targetlist of a ProjectSet plan node. If we have any SRFs
882 : : * that are not at top level, we need to split up the evaluation into multiple
883 : : * plan levels in which each level satisfies this constraint. This function
884 : : * creates appropriate PathTarget(s) for each level.
885 : : *
886 : : * As an example, consider the tlist expression
887 : : * x + srf1(srf2(y + z))
888 : : * This expression should appear as-is in the top PathTarget, but below that
889 : : * we must have a PathTarget containing
890 : : * x, srf1(srf2(y + z))
891 : : * and below that, another PathTarget containing
892 : : * x, srf2(y + z)
893 : : * and below that, another PathTarget containing
894 : : * x, y, z
895 : : * When these tlists are processed by setrefs.c, subexpressions that match
896 : : * output expressions of the next lower tlist will be replaced by Vars,
897 : : * so that what the executor gets are tlists looking like
898 : : * Var1 + Var2
899 : : * Var1, srf1(Var2)
900 : : * Var1, srf2(Var2 + Var3)
901 : : * x, y, z
902 : : * which satisfy the desired property.
903 : : *
904 : : * Another example is
905 : : * srf1(x), srf2(srf3(y))
906 : : * That must appear as-is in the top PathTarget, but below that we need
907 : : * srf1(x), srf3(y)
908 : : * That is, each SRF must be computed at a level corresponding to the nesting
909 : : * depth of SRFs within its arguments.
910 : : *
911 : : * In some cases, a SRF has already been evaluated in some previous plan level
912 : : * and we shouldn't expand it again (that is, what we see in the target is
913 : : * already meant as a reference to a lower subexpression). So, don't expand
914 : : * any tlist expressions that appear in input_target, if that's not NULL.
915 : : *
916 : : * This check requires extra care when processing the grouping target
917 : : * (indicated by the is_grouping_target flag). In this case input_target is
918 : : * pre-grouping while target is post-grouping, so the latter may carry
919 : : * nullingrels bits from the grouping step that are absent in the former. We
920 : : * must ignore those bits to correctly recognize that the tlist expressions are
921 : : * available in input_target.
922 : : *
923 : : * It's also important that we preserve any sortgroupref annotation appearing
924 : : * in the given target, especially on expressions matching input_target items.
925 : : *
926 : : * The outputs of this function are two parallel lists, one a list of
927 : : * PathTargets and the other an integer list of bool flags indicating
928 : : * whether the corresponding PathTarget contains any evaluable SRFs.
929 : : * The lists are given in the order they'd need to be evaluated in, with
930 : : * the "lowest" PathTarget first. So the last list entry is always the
931 : : * originally given PathTarget, and any entries before it indicate evaluation
932 : : * levels that must be inserted below it. The first list entry must not
933 : : * contain any SRFs (other than ones duplicating input_target entries), since
934 : : * it will typically be attached to a plan node that cannot evaluate SRFs.
935 : : *
936 : : * Note: using a list for the flags may seem like overkill, since there
937 : : * are only a few possible patterns for which levels contain SRFs.
938 : : * But this representation decouples callers from that knowledge.
939 : : */
940 : : static void
941 : 41080 : split_pathtarget_at_srfs_extended(PlannerInfo *root,
942 : : PathTarget *target, PathTarget *input_target,
943 : : List **targets, List **targets_contain_srfs,
944 : : bool is_grouping_target)
945 : : {
946 : : split_pathtarget_context context;
947 : : int max_depth;
948 : : bool need_extra_projection;
949 : : List *prev_level_tlist;
950 : : int lci;
951 : : ListCell *lc,
952 : : *lc1,
953 : : *lc2,
954 : : *lc3;
955 : :
956 : : /*
957 : : * It's not unusual for planner.c to pass us two physically identical
958 : : * targets, in which case we can conclude without further ado that all
959 : : * expressions are available from the input. (The logic below would
960 : : * arrive at the same conclusion, but much more tediously.)
961 : : */
962 [ + + ]: 41080 : if (target == input_target)
963 : : {
964 : 30451 : *targets = list_make1(target);
965 : 30451 : *targets_contain_srfs = list_make1_int(false);
966 : 30810 : return;
967 : : }
968 : :
969 : : /*
970 : : * Pass 'root', the is_grouping_target flag, and any input_target exprs
971 : : * down to split_pathtarget_walker().
972 : : */
973 : 10629 : context.root = root;
974 : 10629 : context.is_grouping_target = is_grouping_target;
975 [ + + ]: 10629 : context.input_target_exprs = input_target ? input_target->exprs : NIL;
976 : :
977 : : /*
978 : : * Initialize with empty level-zero lists, and no levels after that.
979 : : * (Note: we could dispense with representing level zero explicitly, since
980 : : * it will never receive any SRFs, but then we'd have to special-case that
981 : : * level when we get to building result PathTargets. Level zero describes
982 : : * the SRF-free PathTarget that will be given to the input plan node.)
983 : : */
984 : 10629 : context.level_srfs = list_make1(NIL);
985 : 10629 : context.level_input_vars = list_make1(NIL);
986 : 10629 : context.level_input_srfs = list_make1(NIL);
987 : :
988 : : /* Initialize data we'll accumulate across all the target expressions */
989 : 10629 : context.current_input_vars = NIL;
990 : 10629 : context.current_input_srfs = NIL;
991 : 10629 : max_depth = 0;
992 : 10629 : need_extra_projection = false;
993 : :
994 : : /* Scan each expression in the PathTarget looking for SRFs */
995 : 10629 : lci = 0;
996 [ + - + + : 24381 : foreach(lc, target->exprs)
+ + ]
997 : : {
998 : 13752 : Node *node = (Node *) lfirst(lc);
999 : :
1000 : : /* Tell split_pathtarget_walker about this expr's sortgroupref */
1001 [ + + ]: 13752 : context.current_sgref = get_pathtarget_sortgroupref(target, lci);
1002 : 13752 : lci++;
1003 : :
1004 : : /*
1005 : : * Find all SRFs and Vars (and Var-like nodes) in this expression, and
1006 : : * enter them into appropriate lists within the context struct.
1007 : : */
1008 : 13752 : context.current_depth = 0;
1009 : 13752 : split_pathtarget_walker(node, &context);
1010 : :
1011 : : /* An expression containing no SRFs is of no further interest */
1012 [ + + ]: 13752 : if (context.current_depth == 0)
1013 : 2183 : continue;
1014 : :
1015 : : /*
1016 : : * Track max SRF nesting depth over the whole PathTarget. Also, if
1017 : : * this expression establishes a new max depth, we no longer care
1018 : : * whether previous expressions contained nested SRFs; we can handle
1019 : : * any required projection for them in the final ProjectSet node.
1020 : : */
1021 [ + + ]: 11569 : if (max_depth < context.current_depth)
1022 : : {
1023 : 10280 : max_depth = context.current_depth;
1024 : 10280 : need_extra_projection = false;
1025 : : }
1026 : :
1027 : : /*
1028 : : * If any maximum-depth SRF is not at the top level of its expression,
1029 : : * we'll need an extra Result node to compute the top-level scalar
1030 : : * expression.
1031 : : */
1032 [ + + + + : 11569 : if (max_depth == context.current_depth && !IS_SRF_CALL(node))
+ + + + +
+ ]
1033 : 1602 : need_extra_projection = true;
1034 : : }
1035 : :
1036 : : /*
1037 : : * If we found no SRFs needing evaluation (maybe they were all present in
1038 : : * input_target, or maybe they were all removed by const-simplification),
1039 : : * then no ProjectSet is needed; fall out.
1040 : : */
1041 [ + + ]: 10629 : if (max_depth == 0)
1042 : : {
1043 : 359 : *targets = list_make1(target);
1044 : 359 : *targets_contain_srfs = list_make1_int(false);
1045 : 359 : return;
1046 : : }
1047 : :
1048 : : /*
1049 : : * The Vars and SRF outputs needed at top level can be added to the last
1050 : : * level_input lists if we don't need an extra projection step. If we do
1051 : : * need one, add a SRF-free level to the lists.
1052 : : */
1053 [ + + ]: 10270 : if (need_extra_projection)
1054 : : {
1055 : 725 : context.level_srfs = lappend(context.level_srfs, NIL);
1056 : 1450 : context.level_input_vars = lappend(context.level_input_vars,
1057 : 725 : context.current_input_vars);
1058 : 725 : context.level_input_srfs = lappend(context.level_input_srfs,
1059 : 725 : context.current_input_srfs);
1060 : : }
1061 : : else
1062 : : {
1063 : 9545 : lc = list_nth_cell(context.level_input_vars, max_depth);
1064 : 9545 : lfirst(lc) = list_concat(lfirst(lc), context.current_input_vars);
1065 : 9545 : lc = list_nth_cell(context.level_input_srfs, max_depth);
1066 : 9545 : lfirst(lc) = list_concat(lfirst(lc), context.current_input_srfs);
1067 : : }
1068 : :
1069 : : /*
1070 : : * Now construct the output PathTargets. The original target can be used
1071 : : * as-is for the last one, but we need to construct a new SRF-free target
1072 : : * representing what the preceding plan node has to emit, as well as a
1073 : : * target for each intermediate ProjectSet node.
1074 : : */
1075 : 10270 : *targets = *targets_contain_srfs = NIL;
1076 : 10270 : prev_level_tlist = NIL;
1077 : :
1078 [ + - + + : 31585 : forthree(lc1, context.level_srfs,
+ - + + +
- + + + +
+ - + - +
+ ]
1079 : : lc2, context.level_input_vars,
1080 : : lc3, context.level_input_srfs)
1081 : : {
1082 : 21315 : List *level_srfs = (List *) lfirst(lc1);
1083 : : PathTarget *ntarget;
1084 : :
1085 [ + + ]: 21315 : if (lnext(context.level_srfs, lc1) == NULL)
1086 : : {
1087 : 10270 : ntarget = target;
1088 : : }
1089 : : else
1090 : : {
1091 : 11045 : ntarget = create_empty_pathtarget();
1092 : :
1093 : : /*
1094 : : * This target should actually evaluate any SRFs of the current
1095 : : * level, and it needs to propagate forward any Vars needed by
1096 : : * later levels, as well as SRFs computed earlier and needed by
1097 : : * later levels.
1098 : : */
1099 : 11045 : add_sp_items_to_pathtarget(ntarget, level_srfs);
1100 [ + - + + : 22895 : for_each_cell(lc, context.level_input_vars,
+ + ]
1101 : : lnext(context.level_input_vars, lc2))
1102 : : {
1103 : 11850 : List *input_vars = (List *) lfirst(lc);
1104 : :
1105 : 11850 : add_sp_items_to_pathtarget(ntarget, input_vars);
1106 : : }
1107 [ + - + + : 22895 : for_each_cell(lc, context.level_input_srfs,
+ + ]
1108 : : lnext(context.level_input_srfs, lc3))
1109 : : {
1110 : 11850 : List *input_srfs = (List *) lfirst(lc);
1111 : : ListCell *lcx;
1112 : :
1113 [ + + + + : 25316 : foreach(lcx, input_srfs)
+ + ]
1114 : : {
1115 : 13466 : split_pathtarget_item *item = lfirst(lcx);
1116 : :
1117 [ + + ]: 13466 : if (list_member(prev_level_tlist, item->expr))
1118 : 30 : add_sp_item_to_pathtarget(ntarget, item);
1119 : : }
1120 : : }
1121 : 11045 : set_pathtarget_cost_width(root, ntarget);
1122 : : }
1123 : :
1124 : : /*
1125 : : * Add current target and does-it-compute-SRFs flag to output lists.
1126 : : */
1127 : 21315 : *targets = lappend(*targets, ntarget);
1128 : 21315 : *targets_contain_srfs = lappend_int(*targets_contain_srfs,
1129 : : (level_srfs != NIL));
1130 : :
1131 : : /* Remember this level's output for next pass */
1132 : 21315 : prev_level_tlist = ntarget->exprs;
1133 : : }
1134 : : }
1135 : :
1136 : : /*
1137 : : * Recursively examine expressions for split_pathtarget_at_srfs.
1138 : : *
1139 : : * Note we make no effort here to prevent duplicate entries in the output
1140 : : * lists. Duplicates will be gotten rid of later.
1141 : : */
1142 : : static bool
1143 : 44272 : split_pathtarget_walker(Node *node, split_pathtarget_context *context)
1144 : : {
1145 : 44272 : Node *sanitized_node = node;
1146 : :
1147 [ + + ]: 44272 : if (node == NULL)
1148 : 60 : return false;
1149 : :
1150 : : /*
1151 : : * If we are crossing the grouping boundary (post-grouping target vs
1152 : : * pre-grouping input_target), we must ignore the grouping nulling bit to
1153 : : * correctly check if the subexpression is available in input_target. This
1154 : : * aligns with the matching logic in set_upper_references().
1155 : : */
1156 [ + + ]: 44212 : if (context->is_grouping_target &&
1157 [ + + ]: 2518 : context->root->parse->hasGroupRTE &&
1158 [ + + ]: 495 : context->root->parse->groupingSets != NIL)
1159 : : {
1160 : : sanitized_node =
1161 : 195 : remove_nulling_relids(node,
1162 : 195 : bms_make_singleton(context->root->group_rtindex),
1163 : : NULL);
1164 : : }
1165 : :
1166 : : /*
1167 : : * A subexpression that matches an expression already computed in
1168 : : * input_target can be treated like a Var (which indeed it will be after
1169 : : * setrefs.c gets done with it), even if it's actually a SRF. Record it
1170 : : * as being needed for the current expression, and ignore any
1171 : : * substructure. (Note in particular that this preserves the identity of
1172 : : * any expressions that appear as sortgrouprefs in input_target.)
1173 : : */
1174 [ + + ]: 44212 : if (list_member(context->input_target_exprs, sanitized_node))
1175 : : {
1176 : 350 : split_pathtarget_item *item = palloc_object(split_pathtarget_item);
1177 : :
1178 : 350 : item->expr = node;
1179 : 350 : item->sortgroupref = context->current_sgref;
1180 : 350 : context->current_input_vars = lappend(context->current_input_vars,
1181 : : item);
1182 : 350 : return false;
1183 : : }
1184 : :
1185 : : /*
1186 : : * Vars and Var-like constructs are expected to be gotten from the input,
1187 : : * too. We assume that these constructs cannot contain any SRFs (if one
1188 : : * does, there will be an executor failure from a misplaced SRF).
1189 : : */
1190 [ + + ]: 43862 : if (IsA(node, Var) ||
1191 [ + + ]: 41059 : IsA(node, PlaceHolderVar) ||
1192 [ + + ]: 41019 : IsA(node, Aggref) ||
1193 [ + - ]: 40223 : IsA(node, GroupingFunc) ||
1194 [ + + ]: 40223 : IsA(node, WindowFunc))
1195 : : {
1196 : 3649 : split_pathtarget_item *item = palloc_object(split_pathtarget_item);
1197 : :
1198 : 3649 : item->expr = node;
1199 : 3649 : item->sortgroupref = context->current_sgref;
1200 : 3649 : context->current_input_vars = lappend(context->current_input_vars,
1201 : : item);
1202 : 3649 : return false;
1203 : : }
1204 : :
1205 : : /*
1206 : : * If it's a SRF, recursively examine its inputs, determine its level, and
1207 : : * make appropriate entries in the output lists.
1208 : : */
1209 [ + + + + : 40213 : if (IS_SRF_CALL(node))
+ + + + ]
1210 : : {
1211 : 11624 : split_pathtarget_item *item = palloc_object(split_pathtarget_item);
1212 : 11624 : List *save_input_vars = context->current_input_vars;
1213 : 11624 : List *save_input_srfs = context->current_input_srfs;
1214 : 11624 : int save_current_depth = context->current_depth;
1215 : : int srf_depth;
1216 : : ListCell *lc;
1217 : :
1218 : 11624 : item->expr = node;
1219 : 11624 : item->sortgroupref = context->current_sgref;
1220 : :
1221 : 11624 : context->current_input_vars = NIL;
1222 : 11624 : context->current_input_srfs = NIL;
1223 : 11624 : context->current_depth = 0;
1224 : 11624 : context->current_sgref = 0; /* subexpressions are not sortgroup items */
1225 : :
1226 : 11624 : (void) expression_tree_walker(node, split_pathtarget_walker, context);
1227 : :
1228 : : /* Depth is one more than any SRF below it */
1229 : 11624 : srf_depth = context->current_depth + 1;
1230 : :
1231 : : /* If new record depth, initialize another level of output lists */
1232 [ + + ]: 11624 : if (srf_depth >= list_length(context->level_srfs))
1233 : : {
1234 : 10320 : context->level_srfs = lappend(context->level_srfs, NIL);
1235 : 10320 : context->level_input_vars = lappend(context->level_input_vars, NIL);
1236 : 10320 : context->level_input_srfs = lappend(context->level_input_srfs, NIL);
1237 : : }
1238 : :
1239 : : /* Record this SRF as needing to be evaluated at appropriate level */
1240 : 11624 : lc = list_nth_cell(context->level_srfs, srf_depth);
1241 : 11624 : lfirst(lc) = lappend(lfirst(lc), item);
1242 : :
1243 : : /* Record its inputs as being needed at the same level */
1244 : 11624 : lc = list_nth_cell(context->level_input_vars, srf_depth);
1245 : 11624 : lfirst(lc) = list_concat(lfirst(lc), context->current_input_vars);
1246 : 11624 : lc = list_nth_cell(context->level_input_srfs, srf_depth);
1247 : 11624 : lfirst(lc) = list_concat(lfirst(lc), context->current_input_srfs);
1248 : :
1249 : : /*
1250 : : * Restore caller-level state and update it for presence of this SRF.
1251 : : * Notice we report the SRF itself as being needed for evaluation of
1252 : : * surrounding expression.
1253 : : */
1254 : 11624 : context->current_input_vars = save_input_vars;
1255 : 11624 : context->current_input_srfs = lappend(save_input_srfs, item);
1256 : 11624 : context->current_depth = Max(save_current_depth, srf_depth);
1257 : :
1258 : : /* We're done here */
1259 : 11624 : return false;
1260 : : }
1261 : :
1262 : : /*
1263 : : * Otherwise, the node is a scalar (non-set) expression, so recurse to
1264 : : * examine its inputs.
1265 : : */
1266 : 28589 : context->current_sgref = 0; /* subexpressions are not sortgroup items */
1267 : 28589 : return expression_tree_walker(node, split_pathtarget_walker, context);
1268 : : }
1269 : :
1270 : : /*
1271 : : * Add a split_pathtarget_item to the PathTarget, unless a matching item is
1272 : : * already present. This is like add_new_column_to_pathtarget, but allows
1273 : : * for sortgrouprefs to be handled. An item having zero sortgroupref can
1274 : : * be merged with one that has a sortgroupref, acquiring the latter's
1275 : : * sortgroupref.
1276 : : *
1277 : : * Note that we don't worry about possibly adding duplicate sortgrouprefs
1278 : : * to the PathTarget. That would be bad, but it should be impossible unless
1279 : : * the target passed to split_pathtarget_at_srfs already had duplicates.
1280 : : * As long as it didn't, we can have at most one split_pathtarget_item with
1281 : : * any particular nonzero sortgroupref.
1282 : : */
1283 : : static void
1284 : 5592 : add_sp_item_to_pathtarget(PathTarget *target, split_pathtarget_item *item)
1285 : : {
1286 : : int lci;
1287 : : ListCell *lc;
1288 : :
1289 : : /*
1290 : : * Look for a pre-existing entry that is equal() and does not have a
1291 : : * conflicting sortgroupref already.
1292 : : */
1293 : 5592 : lci = 0;
1294 [ + + + + : 8446 : foreach(lc, target->exprs)
+ + ]
1295 : : {
1296 : 5098 : Node *node = (Node *) lfirst(lc);
1297 [ + + ]: 5098 : Index sgref = get_pathtarget_sortgroupref(target, lci);
1298 : :
1299 [ + + ]: 5098 : if ((item->sortgroupref == sgref ||
1300 [ + + + + ]: 250 : item->sortgroupref == 0 ||
1301 [ + + ]: 5053 : sgref == 0) &&
1302 : 5053 : equal(item->expr, node))
1303 : : {
1304 : : /* Found a match. Assign item's sortgroupref if it has one. */
1305 [ + + ]: 2244 : if (item->sortgroupref)
1306 : : {
1307 [ + + ]: 20 : if (target->sortgrouprefs == NULL)
1308 : : {
1309 : 10 : target->sortgrouprefs = palloc0_array(Index,
1310 : : list_length(target->exprs));
1311 : : }
1312 : 20 : target->sortgrouprefs[lci] = item->sortgroupref;
1313 : : }
1314 : 2244 : return;
1315 : : }
1316 : 2854 : lci++;
1317 : : }
1318 : :
1319 : : /*
1320 : : * No match, so add item to PathTarget. Copy the expr for safety.
1321 : : */
1322 : 3348 : add_column_to_pathtarget(target, (Expr *) copyObject(item->expr),
1323 : : item->sortgroupref);
1324 : : }
1325 : :
1326 : : /*
1327 : : * Apply add_sp_item_to_pathtarget to each element of list.
1328 : : */
1329 : : static void
1330 : 22895 : add_sp_items_to_pathtarget(PathTarget *target, List *items)
1331 : : {
1332 : : ListCell *lc;
1333 : :
1334 [ + + + + : 28457 : foreach(lc, items)
+ + ]
1335 : : {
1336 : 5562 : split_pathtarget_item *item = lfirst(lc);
1337 : :
1338 : 5562 : add_sp_item_to_pathtarget(target, item);
1339 : : }
1340 : 22895 : }
|