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 53244 : tlist_member(Expr *node, List *targetlist)
89 : {
90 : ListCell *temp;
91 :
92 189400 : foreach(temp, targetlist)
93 : {
94 150056 : TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
95 :
96 150056 : if (equal(node, tlentry->expr))
97 13900 : return tlentry;
98 : }
99 39344 : 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 2716 : tlist_member_match_var(Var *var, List *targetlist)
112 : {
113 : ListCell *temp;
114 :
115 7476 : foreach(temp, targetlist)
116 : {
117 7476 : TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
118 7476 : Var *tlvar = (Var *) tlentry->expr;
119 :
120 7476 : if (!tlvar || !IsA(tlvar, Var))
121 0 : continue;
122 7476 : if (var->varno == tlvar->varno &&
123 7476 : var->varattno == tlvar->varattno &&
124 2716 : var->varlevelsup == tlvar->varlevelsup &&
125 2716 : var->vartype == tlvar->vartype)
126 2716 : 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 1718 : add_to_flat_tlist(List *tlist, List *exprs)
142 : {
143 1718 : int next_resno = list_length(tlist) + 1;
144 : ListCell *lc;
145 :
146 9396 : foreach(lc, exprs)
147 : {
148 7678 : Expr *expr = (Expr *) lfirst(lc);
149 :
150 7678 : if (!tlist_member(expr, tlist))
151 : {
152 : TargetEntry *tle;
153 :
154 7638 : tle = makeTargetEntry(copyObject(expr), /* copy needed?? */
155 7638 : next_resno++,
156 : NULL,
157 : false);
158 7638 : tlist = lappend(tlist, tle);
159 : }
160 : }
161 1718 : 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 1354 : get_tlist_exprs(List *tlist, bool includeJunk)
173 : {
174 1354 : List *result = NIL;
175 : ListCell *l;
176 :
177 5856 : foreach(l, tlist)
178 : {
179 4502 : TargetEntry *tle = (TargetEntry *) lfirst(l);
180 :
181 4502 : if (tle->resjunk && !includeJunk)
182 0 : continue;
183 :
184 4502 : result = lappend(result, tle->expr);
185 : }
186 1354 : return result;
187 : }
188 :
189 :
190 : /*
191 : * count_nonjunk_tlist_entries
192 : * What it says ...
193 : */
194 : int
195 36340 : count_nonjunk_tlist_entries(List *tlist)
196 : {
197 36340 : int len = 0;
198 : ListCell *l;
199 :
200 75102 : foreach(l, tlist)
201 : {
202 38762 : TargetEntry *tle = (TargetEntry *) lfirst(l);
203 :
204 38762 : if (!tle->resjunk)
205 36500 : len++;
206 : }
207 36340 : 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 1936 : tlist_same_exprs(List *tlist1, List *tlist2)
228 : {
229 : ListCell *lc1,
230 : *lc2;
231 :
232 1936 : if (list_length(tlist1) != list_length(tlist2))
233 794 : return false; /* not same length, so can't match */
234 :
235 1530 : forboth(lc1, tlist1, lc2, tlist2)
236 : {
237 1358 : TargetEntry *tle1 = (TargetEntry *) lfirst(lc1);
238 1358 : TargetEntry *tle2 = (TargetEntry *) lfirst(lc2);
239 :
240 1358 : if (!equal(tle1->expr, tle2->expr))
241 970 : return false;
242 : }
243 :
244 172 : 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 23226 : tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
258 : {
259 : ListCell *l;
260 23226 : ListCell *curColType = list_head(colTypes);
261 :
262 99698 : foreach(l, tlist)
263 : {
264 77246 : TargetEntry *tle = (TargetEntry *) lfirst(l);
265 :
266 77246 : if (tle->resjunk)
267 : {
268 12 : if (!junkOK)
269 774 : return false;
270 : }
271 : else
272 : {
273 77234 : if (curColType == NULL)
274 0 : return false; /* tlist longer than colTypes */
275 77234 : if (exprType((Node *) tle->expr) != lfirst_oid(curColType))
276 774 : return false;
277 76460 : curColType = lnext(colTypes, curColType);
278 : }
279 : }
280 22452 : if (curColType != NULL)
281 0 : return false; /* tlist shorter than colTypes */
282 22452 : 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 5420 : tlist_same_collations(List *tlist, List *colCollations, bool junkOK)
292 : {
293 : ListCell *l;
294 5420 : ListCell *curColColl = list_head(colCollations);
295 :
296 21154 : foreach(l, tlist)
297 : {
298 15734 : TargetEntry *tle = (TargetEntry *) lfirst(l);
299 :
300 15734 : if (tle->resjunk)
301 : {
302 0 : if (!junkOK)
303 0 : return false;
304 : }
305 : else
306 : {
307 15734 : if (curColColl == NULL)
308 0 : return false; /* tlist longer than colCollations */
309 15734 : if (exprCollation((Node *) tle->expr) != lfirst_oid(curColColl))
310 0 : return false;
311 15734 : curColColl = lnext(colCollations, curColColl);
312 : }
313 : }
314 5420 : if (curColColl != NULL)
315 0 : return false; /* tlist shorter than colCollations */
316 5420 : 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 567644 : 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 2055258 : forboth(ld, dest_tlist, ls, src_tlist)
334 : {
335 1487614 : TargetEntry *dest_tle = (TargetEntry *) lfirst(ld);
336 1487614 : TargetEntry *src_tle = (TargetEntry *) lfirst(ls);
337 :
338 : Assert(dest_tle->resno == src_tle->resno);
339 1487614 : dest_tle->resname = src_tle->resname;
340 1487614 : dest_tle->ressortgroupref = src_tle->ressortgroupref;
341 1487614 : dest_tle->resorigtbl = src_tle->resorigtbl;
342 1487614 : dest_tle->resorigcol = src_tle->resorigcol;
343 1487614 : dest_tle->resjunk = src_tle->resjunk;
344 : }
345 567644 : }
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 277212 : get_sortgroupref_tle(Index sortref, List *targetList)
355 : {
356 : ListCell *l;
357 :
358 703476 : foreach(l, targetList)
359 : {
360 703476 : TargetEntry *tle = (TargetEntry *) lfirst(l);
361 :
362 703476 : if (tle->ressortgroupref == sortref)
363 277212 : 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 275476 : get_sortgroupclause_tle(SortGroupClause *sgClause,
377 : List *targetList)
378 : {
379 275476 : 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 224808 : get_sortgroupclause_expr(SortGroupClause *sgClause, List *targetList)
389 : {
390 224808 : TargetEntry *tle = get_sortgroupclause_tle(sgClause, targetList);
391 :
392 224808 : 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 18184 : get_sortgrouplist_exprs(List *sgClauses, List *targetList)
402 : {
403 18184 : List *result = NIL;
404 : ListCell *l;
405 :
406 42606 : foreach(l, sgClauses)
407 : {
408 24422 : SortGroupClause *sortcl = (SortGroupClause *) lfirst(l);
409 : Node *sortexpr;
410 :
411 24422 : sortexpr = get_sortgroupclause_expr(sortcl, targetList);
412 24422 : result = lappend(result, sortexpr);
413 : }
414 18184 : 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 11150 : get_sortgroupref_clause(Index sortref, List *clauses)
432 : {
433 : ListCell *l;
434 :
435 17316 : foreach(l, clauses)
436 : {
437 17316 : SortGroupClause *cl = (SortGroupClause *) lfirst(l);
438 :
439 17316 : if (cl->tleSortGroupRef == sortref)
440 11150 : 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 15548 : get_sortgroupref_clause_noerr(Index sortref, List *clauses)
453 : {
454 : ListCell *l;
455 :
456 26542 : foreach(l, clauses)
457 : {
458 22626 : SortGroupClause *cl = (SortGroupClause *) lfirst(l);
459 :
460 22626 : if (cl->tleSortGroupRef == sortref)
461 11632 : return cl;
462 : }
463 :
464 3916 : 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 50486 : extract_grouping_ops(List *groupClause)
473 : {
474 50486 : int numCols = list_length(groupClause);
475 50486 : int colno = 0;
476 : Oid *groupOperators;
477 : ListCell *glitem;
478 :
479 50486 : groupOperators = palloc_array(Oid, numCols);
480 :
481 64994 : foreach(glitem, groupClause)
482 : {
483 14508 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
484 :
485 14508 : groupOperators[colno] = groupcl->eqop;
486 : Assert(OidIsValid(groupOperators[colno]));
487 14508 : colno++;
488 : }
489 :
490 50486 : 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 50486 : extract_grouping_collations(List *groupClause, List *tlist)
499 : {
500 50486 : int numCols = list_length(groupClause);
501 50486 : int colno = 0;
502 : Oid *grpCollations;
503 : ListCell *glitem;
504 :
505 50486 : grpCollations = palloc_array(Oid, numCols);
506 :
507 64994 : foreach(glitem, groupClause)
508 : {
509 14508 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
510 14508 : TargetEntry *tle = get_sortgroupclause_tle(groupcl, tlist);
511 :
512 14508 : grpCollations[colno++] = exprCollation((Node *) tle->expr);
513 : }
514 :
515 50486 : 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 48418 : extract_grouping_cols(List *groupClause, List *tlist)
524 : {
525 : AttrNumber *grpColIdx;
526 48418 : int numCols = list_length(groupClause);
527 48418 : int colno = 0;
528 : ListCell *glitem;
529 :
530 48418 : grpColIdx = palloc_array(AttrNumber, numCols);
531 :
532 60270 : foreach(glitem, groupClause)
533 : {
534 11852 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
535 11852 : TargetEntry *tle = get_sortgroupclause_tle(groupcl, tlist);
536 :
537 11852 : grpColIdx[colno++] = tle->resno;
538 : }
539 :
540 48418 : 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 69510 : grouping_is_sortable(List *groupClause)
550 : {
551 : ListCell *glitem;
552 :
553 113244 : foreach(glitem, groupClause)
554 : {
555 43954 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
556 :
557 43954 : if (!OidIsValid(groupcl->sortop))
558 220 : return false;
559 : }
560 69290 : 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 12588 : grouping_is_hashable(List *groupClause)
570 : {
571 : ListCell *glitem;
572 :
573 37880 : foreach(glitem, groupClause)
574 : {
575 25434 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
576 :
577 25434 : if (!groupcl->hashable)
578 142 : return false;
579 : }
580 12446 : 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 564882 : make_pathtarget_from_tlist(List *tlist)
601 : {
602 564882 : PathTarget *target = makeNode(PathTarget);
603 : int i;
604 : ListCell *lc;
605 :
606 564882 : target->sortgrouprefs = (Index *) palloc(list_length(tlist) * sizeof(Index));
607 :
608 564882 : i = 0;
609 2051032 : foreach(lc, tlist)
610 : {
611 1486150 : TargetEntry *tle = (TargetEntry *) lfirst(lc);
612 :
613 1486150 : target->exprs = lappend(target->exprs, tle->expr);
614 1486150 : target->sortgrouprefs[i] = tle->ressortgroupref;
615 1486150 : 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 564882 : target->has_volatile_expr = VOLATILITY_UNKNOWN;
624 :
625 564882 : return target;
626 : }
627 :
628 : /*
629 : * make_tlist_from_pathtarget
630 : * Construct a targetlist from a PathTarget.
631 : */
632 : List *
633 69790 : make_tlist_from_pathtarget(PathTarget *target)
634 : {
635 69790 : List *tlist = NIL;
636 : int i;
637 : ListCell *lc;
638 :
639 69790 : i = 0;
640 299372 : foreach(lc, target->exprs)
641 : {
642 229582 : Expr *expr = (Expr *) lfirst(lc);
643 : TargetEntry *tle;
644 :
645 229582 : tle = makeTargetEntry(expr,
646 229582 : i + 1,
647 : NULL,
648 : false);
649 229582 : if (target->sortgrouprefs)
650 222566 : tle->ressortgroupref = target->sortgrouprefs[i];
651 229582 : tlist = lappend(tlist, tle);
652 229582 : i++;
653 : }
654 :
655 69790 : 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 28022 : copy_pathtarget(PathTarget *src)
667 : {
668 28022 : PathTarget *dst = makeNode(PathTarget);
669 :
670 : /* Copy scalar fields */
671 28022 : memcpy(dst, src, sizeof(PathTarget));
672 : /* Shallow-copy the expression list */
673 28022 : dst->exprs = list_copy(src->exprs);
674 : /* Duplicate sortgrouprefs if any (if not, the memcpy handled this) */
675 28022 : if (src->sortgrouprefs)
676 : {
677 26702 : Size nbytes = list_length(src->exprs) * sizeof(Index);
678 :
679 26702 : dst->sortgrouprefs = (Index *) palloc(nbytes);
680 26702 : memcpy(dst->sortgrouprefs, src->sortgrouprefs, nbytes);
681 : }
682 28022 : return dst;
683 : }
684 :
685 : /*
686 : * create_empty_pathtarget
687 : * Create an empty (zero columns, zero cost) PathTarget.
688 : */
689 : PathTarget *
690 1799294 : create_empty_pathtarget(void)
691 : {
692 : /* This is easy, but we don't want callers to hard-wire this ... */
693 1799294 : 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 79866 : add_column_to_pathtarget(PathTarget *target, Expr *expr, Index sortgroupref)
705 : {
706 : /* Updating the exprs list is easy ... */
707 79866 : target->exprs = lappend(target->exprs, expr);
708 : /* ... the sortgroupref data, a bit less so */
709 79866 : if (target->sortgrouprefs)
710 : {
711 26200 : int nexprs = list_length(target->exprs);
712 :
713 : /* This might look inefficient, but actually it's usually cheap */
714 26200 : target->sortgrouprefs = (Index *)
715 26200 : repalloc(target->sortgrouprefs, nexprs * sizeof(Index));
716 26200 : target->sortgrouprefs[nexprs - 1] = sortgroupref;
717 : }
718 53666 : else if (sortgroupref)
719 : {
720 : /* Adding sortgroupref labeling to a previously unlabeled target */
721 19444 : int nexprs = list_length(target->exprs);
722 :
723 19444 : target->sortgrouprefs = (Index *) palloc0(nexprs * sizeof(Index));
724 19444 : target->sortgrouprefs[nexprs - 1] = sortgroupref;
725 : }
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 79866 : if (target->has_volatile_expr == VOLATILITY_NOVOLATILE)
735 0 : target->has_volatile_expr = VOLATILITY_UNKNOWN;
736 79866 : }
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 52968 : add_new_column_to_pathtarget(PathTarget *target, Expr *expr)
751 : {
752 52968 : if (!list_member(target->exprs, expr))
753 42812 : add_column_to_pathtarget(target, expr, 0);
754 52968 : }
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 51560 : add_new_columns_to_pathtarget(PathTarget *target, List *exprs)
762 : {
763 : ListCell *lc;
764 :
765 99784 : foreach(lc, exprs)
766 : {
767 48224 : Expr *expr = (Expr *) lfirst(lc);
768 :
769 48224 : add_new_column_to_pathtarget(target, expr);
770 : }
771 51560 : }
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 22394 : apply_pathtarget_labeling_to_tlist(List *tlist, PathTarget *target)
784 : {
785 : int i;
786 : ListCell *lc;
787 :
788 : /* Nothing to do if PathTarget has no sortgrouprefs data */
789 22394 : if (target->sortgrouprefs == NULL)
790 20430 : return;
791 :
792 1964 : i = 0;
793 5398 : foreach(lc, target->exprs)
794 : {
795 3434 : Expr *expr = (Expr *) lfirst(lc);
796 : TargetEntry *tle;
797 :
798 3434 : 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 2716 : if (expr && IsA(expr, Var))
810 2716 : 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 2716 : if (!tle)
821 0 : elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
822 2716 : if (tle->ressortgroupref != 0 &&
823 12 : tle->ressortgroupref != target->sortgrouprefs[i])
824 0 : elog(ERROR, "targetlist item has multiple sortgroupref labels");
825 :
826 2716 : tle->ressortgroupref = target->sortgrouprefs[i];
827 : }
828 3434 : i++;
829 : }
830 : }
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 36150 : split_pathtarget_at_srfs(PlannerInfo *root,
846 : PathTarget *target, PathTarget *input_target,
847 : List **targets, List **targets_contain_srfs)
848 : {
849 36150 : split_pathtarget_at_srfs_extended(root, target, input_target,
850 : targets, targets_contain_srfs,
851 : false);
852 36150 : }
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 12050 : split_pathtarget_at_srfs_grouping(PlannerInfo *root,
869 : PathTarget *target, PathTarget *input_target,
870 : List **targets, List **targets_contain_srfs)
871 : {
872 12050 : split_pathtarget_at_srfs_extended(root, target, input_target,
873 : targets, targets_contain_srfs,
874 : true);
875 12050 : }
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 48200 : 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 : split_pathtarget_context context;
948 : int max_depth;
949 : bool need_extra_projection;
950 : List *prev_level_tlist;
951 : int lci;
952 : 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 48200 : if (target == input_target)
964 : {
965 35602 : *targets = list_make1(target);
966 35602 : *targets_contain_srfs = list_make1_int(false);
967 35602 : 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 12598 : context.root = root;
975 12598 : context.is_grouping_target = is_grouping_target;
976 12598 : 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 12598 : context.level_srfs = list_make1(NIL);
986 12598 : context.level_input_vars = list_make1(NIL);
987 12598 : context.level_input_srfs = list_make1(NIL);
988 :
989 : /* Initialize data we'll accumulate across all the target expressions */
990 12598 : context.current_input_vars = NIL;
991 12598 : context.current_input_srfs = NIL;
992 12598 : max_depth = 0;
993 12598 : need_extra_projection = false;
994 :
995 : /* Scan each expression in the PathTarget looking for SRFs */
996 12598 : lci = 0;
997 28924 : foreach(lc, target->exprs)
998 : {
999 16326 : Node *node = (Node *) lfirst(lc);
1000 :
1001 : /* Tell split_pathtarget_walker about this expr's sortgroupref */
1002 16326 : context.current_sgref = get_pathtarget_sortgroupref(target, lci);
1003 16326 : 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 16326 : context.current_depth = 0;
1010 16326 : split_pathtarget_walker(node, &context);
1011 :
1012 : /* An expression containing no SRFs is of no further interest */
1013 16326 : if (context.current_depth == 0)
1014 2730 : 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 13596 : if (max_depth < context.current_depth)
1023 : {
1024 12062 : max_depth = context.current_depth;
1025 12062 : need_extra_projection = false;
1026 : }
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 13596 : if (max_depth == context.current_depth && !IS_SRF_CALL(node))
1034 2456 : need_extra_projection = true;
1035 : }
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 12598 : if (max_depth == 0)
1043 : {
1044 548 : *targets = list_make1(target);
1045 548 : *targets_contain_srfs = list_make1_int(false);
1046 548 : 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 12050 : if (need_extra_projection)
1055 : {
1056 1124 : context.level_srfs = lappend(context.level_srfs, NIL);
1057 2248 : context.level_input_vars = lappend(context.level_input_vars,
1058 1124 : context.current_input_vars);
1059 1124 : context.level_input_srfs = lappend(context.level_input_srfs,
1060 1124 : context.current_input_srfs);
1061 : }
1062 : else
1063 : {
1064 10926 : lc = list_nth_cell(context.level_input_vars, max_depth);
1065 10926 : lfirst(lc) = list_concat(lfirst(lc), context.current_input_vars);
1066 10926 : lc = list_nth_cell(context.level_input_srfs, max_depth);
1067 10926 : 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 12050 : *targets = *targets_contain_srfs = NIL;
1077 12050 : prev_level_tlist = NIL;
1078 :
1079 37334 : forthree(lc1, context.level_srfs,
1080 : lc2, context.level_input_vars,
1081 : lc3, context.level_input_srfs)
1082 : {
1083 25284 : List *level_srfs = (List *) lfirst(lc1);
1084 : PathTarget *ntarget;
1085 :
1086 25284 : if (lnext(context.level_srfs, lc1) == NULL)
1087 : {
1088 12050 : ntarget = target;
1089 : }
1090 : else
1091 : {
1092 13234 : 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 13234 : add_sp_items_to_pathtarget(ntarget, level_srfs);
1101 27688 : for_each_cell(lc, context.level_input_vars,
1102 : lnext(context.level_input_vars, lc2))
1103 : {
1104 14454 : List *input_vars = (List *) lfirst(lc);
1105 :
1106 14454 : add_sp_items_to_pathtarget(ntarget, input_vars);
1107 : }
1108 27688 : for_each_cell(lc, context.level_input_srfs,
1109 : lnext(context.level_input_srfs, lc3))
1110 : {
1111 14454 : List *input_srfs = (List *) lfirst(lc);
1112 : ListCell *lcx;
1113 :
1114 30860 : foreach(lcx, input_srfs)
1115 : {
1116 16406 : split_pathtarget_item *item = lfirst(lcx);
1117 :
1118 16406 : if (list_member(prev_level_tlist, item->expr))
1119 36 : add_sp_item_to_pathtarget(ntarget, item);
1120 : }
1121 : }
1122 13234 : set_pathtarget_cost_width(root, ntarget);
1123 : }
1124 :
1125 : /*
1126 : * Add current target and does-it-compute-SRFs flag to output lists.
1127 : */
1128 25284 : *targets = lappend(*targets, ntarget);
1129 25284 : *targets_contain_srfs = lappend_int(*targets_contain_srfs,
1130 : (level_srfs != NIL));
1131 :
1132 : /* Remember this level's output for next pass */
1133 25284 : prev_level_tlist = ntarget->exprs;
1134 : }
1135 : }
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 51464 : split_pathtarget_walker(Node *node, split_pathtarget_context *context)
1145 : {
1146 51464 : Node *sanitized_node = node;
1147 :
1148 51464 : if (node == NULL)
1149 106 : 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 51358 : if (context->is_grouping_target &&
1158 4416 : context->root->parse->hasGroupRTE &&
1159 582 : context->root->parse->groupingSets != NIL)
1160 : {
1161 : sanitized_node =
1162 234 : remove_nulling_relids(node,
1163 234 : bms_make_singleton(context->root->group_rtindex),
1164 : NULL);
1165 : }
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 51358 : if (list_member(context->input_target_exprs, sanitized_node))
1176 : {
1177 420 : split_pathtarget_item *item = palloc_object(split_pathtarget_item);
1178 :
1179 420 : item->expr = node;
1180 420 : item->sortgroupref = context->current_sgref;
1181 420 : context->current_input_vars = lappend(context->current_input_vars,
1182 : item);
1183 420 : return false;
1184 : }
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 50938 : if (IsA(node, Var) ||
1192 47556 : IsA(node, PlaceHolderVar) ||
1193 47508 : IsA(node, Aggref) ||
1194 46090 : IsA(node, GroupingFunc) ||
1195 46090 : IsA(node, WindowFunc))
1196 : {
1197 4866 : split_pathtarget_item *item = palloc_object(split_pathtarget_item);
1198 :
1199 4866 : item->expr = node;
1200 4866 : item->sortgroupref = context->current_sgref;
1201 4866 : context->current_input_vars = lappend(context->current_input_vars,
1202 : item);
1203 4866 : return false;
1204 : }
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 46072 : if (IS_SRF_CALL(node))
1211 : {
1212 13662 : split_pathtarget_item *item = palloc_object(split_pathtarget_item);
1213 13662 : List *save_input_vars = context->current_input_vars;
1214 13662 : List *save_input_srfs = context->current_input_srfs;
1215 13662 : int save_current_depth = context->current_depth;
1216 : int srf_depth;
1217 : ListCell *lc;
1218 :
1219 13662 : item->expr = node;
1220 13662 : item->sortgroupref = context->current_sgref;
1221 :
1222 13662 : context->current_input_vars = NIL;
1223 13662 : context->current_input_srfs = NIL;
1224 13662 : context->current_depth = 0;
1225 13662 : context->current_sgref = 0; /* subexpressions are not sortgroup items */
1226 :
1227 13662 : (void) expression_tree_walker(node, split_pathtarget_walker, context);
1228 :
1229 : /* Depth is one more than any SRF below it */
1230 13662 : srf_depth = context->current_depth + 1;
1231 :
1232 : /* If new record depth, initialize another level of output lists */
1233 13662 : if (srf_depth >= list_length(context->level_srfs))
1234 : {
1235 12110 : context->level_srfs = lappend(context->level_srfs, NIL);
1236 12110 : context->level_input_vars = lappend(context->level_input_vars, NIL);
1237 12110 : context->level_input_srfs = lappend(context->level_input_srfs, NIL);
1238 : }
1239 :
1240 : /* Record this SRF as needing to be evaluated at appropriate level */
1241 13662 : lc = list_nth_cell(context->level_srfs, srf_depth);
1242 13662 : lfirst(lc) = lappend(lfirst(lc), item);
1243 :
1244 : /* Record its inputs as being needed at the same level */
1245 13662 : lc = list_nth_cell(context->level_input_vars, srf_depth);
1246 13662 : lfirst(lc) = list_concat(lfirst(lc), context->current_input_vars);
1247 13662 : lc = list_nth_cell(context->level_input_srfs, srf_depth);
1248 13662 : 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 13662 : context->current_input_vars = save_input_vars;
1256 13662 : context->current_input_srfs = lappend(save_input_srfs, item);
1257 13662 : context->current_depth = Max(save_current_depth, srf_depth);
1258 :
1259 : /* We're done here */
1260 13662 : return false;
1261 : }
1262 :
1263 : /*
1264 : * Otherwise, the node is a scalar (non-set) expression, so recurse to
1265 : * examine its inputs.
1266 : */
1267 32410 : context->current_sgref = 0; /* subexpressions are not sortgroup items */
1268 32410 : return expression_tree_walker(node, split_pathtarget_walker, context);
1269 : }
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 7542 : add_sp_item_to_pathtarget(PathTarget *target, split_pathtarget_item *item)
1286 : {
1287 : int lci;
1288 : 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 7542 : lci = 0;
1295 10428 : foreach(lc, target->exprs)
1296 : {
1297 6042 : Node *node = (Node *) lfirst(lc);
1298 6042 : Index sgref = get_pathtarget_sortgroupref(target, lci);
1299 :
1300 6042 : if ((item->sortgroupref == sgref ||
1301 300 : item->sortgroupref == 0 ||
1302 5988 : sgref == 0) &&
1303 5988 : equal(item->expr, node))
1304 : {
1305 : /* Found a match. Assign item's sortgroupref if it has one. */
1306 3156 : if (item->sortgroupref)
1307 : {
1308 24 : if (target->sortgrouprefs == NULL)
1309 : {
1310 12 : target->sortgrouprefs = (Index *)
1311 12 : palloc0(list_length(target->exprs) * sizeof(Index));
1312 : }
1313 24 : target->sortgrouprefs[lci] = item->sortgroupref;
1314 : }
1315 3156 : return;
1316 : }
1317 2886 : lci++;
1318 : }
1319 :
1320 : /*
1321 : * No match, so add item to PathTarget. Copy the expr for safety.
1322 : */
1323 4386 : add_column_to_pathtarget(target, (Expr *) copyObject(item->expr),
1324 : item->sortgroupref);
1325 : }
1326 :
1327 : /*
1328 : * Apply add_sp_item_to_pathtarget to each element of list.
1329 : */
1330 : static void
1331 27688 : add_sp_items_to_pathtarget(PathTarget *target, List *items)
1332 : {
1333 : ListCell *lc;
1334 :
1335 35194 : foreach(lc, items)
1336 : {
1337 7506 : split_pathtarget_item *item = lfirst(lc);
1338 :
1339 7506 : add_sp_item_to_pathtarget(target, item);
1340 : }
1341 27688 : }
|