PostgreSQL Source Code git master
Loading...
Searching...
No Matches
tlist.c File Reference
#include "postgres.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/cost.h"
#include "optimizer/optimizer.h"
#include "optimizer/tlist.h"
#include "rewrite/rewriteManip.h"
Include dependency graph for tlist.c:

Go to the source code of this file.

Data Structures

struct  split_pathtarget_item
 
struct  split_pathtarget_context
 

Macros

#define IS_SRF_CALL(node)
 

Functions

static void split_pathtarget_at_srfs_extended (PlannerInfo *root, PathTarget *target, PathTarget *input_target, List **targets, List **targets_contain_srfs, bool is_grouping_target)
 
static bool split_pathtarget_walker (Node *node, split_pathtarget_context *context)
 
static void add_sp_item_to_pathtarget (PathTarget *target, split_pathtarget_item *item)
 
static void add_sp_items_to_pathtarget (PathTarget *target, List *items)
 
TargetEntrytlist_member (Expr *node, List *targetlist)
 
static TargetEntrytlist_member_match_var (Var *var, List *targetlist)
 
Listadd_to_flat_tlist (List *tlist, List *exprs)
 
Listget_tlist_exprs (List *tlist, bool includeJunk)
 
int count_nonjunk_tlist_entries (List *tlist)
 
bool tlist_same_exprs (List *tlist1, List *tlist2)
 
bool tlist_same_datatypes (List *tlist, List *colTypes, bool junkOK)
 
bool tlist_same_collations (List *tlist, List *colCollations, bool junkOK)
 
void apply_tlist_labeling (List *dest_tlist, List *src_tlist)
 
TargetEntryget_sortgroupref_tle (Index sortref, List *targetList)
 
TargetEntryget_sortgroupclause_tle (SortGroupClause *sgClause, List *targetList)
 
Nodeget_sortgroupclause_expr (SortGroupClause *sgClause, List *targetList)
 
Listget_sortgrouplist_exprs (List *sgClauses, List *targetList)
 
SortGroupClauseget_sortgroupref_clause (Index sortref, List *clauses)
 
SortGroupClauseget_sortgroupref_clause_noerr (Index sortref, List *clauses)
 
Oidextract_grouping_ops (List *groupClause)
 
Oidextract_grouping_collations (List *groupClause, List *tlist)
 
AttrNumberextract_grouping_cols (List *groupClause, List *tlist)
 
bool grouping_is_sortable (List *groupClause)
 
bool grouping_is_hashable (List *groupClause)
 
PathTargetmake_pathtarget_from_tlist (List *tlist)
 
Listmake_tlist_from_pathtarget (PathTarget *target)
 
PathTargetcopy_pathtarget (PathTarget *src)
 
PathTargetcreate_empty_pathtarget (void)
 
void add_column_to_pathtarget (PathTarget *target, Expr *expr, Index sortgroupref)
 
void add_new_column_to_pathtarget (PathTarget *target, Expr *expr)
 
void add_new_columns_to_pathtarget (PathTarget *target, List *exprs)
 
void apply_pathtarget_labeling_to_tlist (List *tlist, PathTarget *target)
 
void split_pathtarget_at_srfs (PlannerInfo *root, PathTarget *target, PathTarget *input_target, List **targets, List **targets_contain_srfs)
 
void split_pathtarget_at_srfs_grouping (PlannerInfo *root, PathTarget *target, PathTarget *input_target, List **targets, List **targets_contain_srfs)
 

Macro Definition Documentation

◆ IS_SRF_CALL

#define IS_SRF_CALL (   node)
Value:
((IsA(node, FuncExpr) && ((FuncExpr *) (node))->funcretset) || \
(IsA(node, OpExpr) && ((OpExpr *) (node))->opretset))
#define IsA(nodeptr, _type_)
Definition nodes.h:164
static int fb(int x)

Definition at line 32 of file tlist.c.

41{
42 Node *expr; /* some subexpression of a PathTarget */
43 Index sortgroupref; /* its sortgroupref, or 0 if none */
45
46typedef struct
47{
49 bool is_grouping_target; /* true if processing grouping target */
50 /* This is a List of bare expressions: */
51 List *input_target_exprs; /* exprs available from input */
52 /* These are Lists of Lists of split_pathtarget_items: */
53 List *level_srfs; /* SRF exprs to evaluate at each level */
54 List *level_input_vars; /* input vars needed at each level */
55 List *level_input_srfs; /* input SRFs needed at each level */
56 /* These are Lists of split_pathtarget_items: */
57 List *current_input_vars; /* vars needed in current subexpr */
58 List *current_input_srfs; /* SRFs needed in current subexpr */
59 /* Auxiliary data for current split_pathtarget_walker traversal: */
60 int current_depth; /* max SRF depth in current subexpr */
61 Index current_sgref; /* current subexpr's sortgroupref, or 0 */
63
65 PathTarget *target,
67 List **targets,
69 bool is_grouping_target);
70static bool split_pathtarget_walker(Node *node,
72static void add_sp_item_to_pathtarget(PathTarget *target,
74static void add_sp_items_to_pathtarget(PathTarget *target, List *items);
75
76
77/*****************************************************************************
78 * Target list creation and searching utilities
79 *****************************************************************************/
80
81/*
82 * tlist_member
83 * Finds the (first) member of the given tlist whose expression is
84 * equal() to the given expression. Result is NULL if no such member.
85 */
87tlist_member(Expr *node, List *targetlist)
88{
90
91 foreach(temp, targetlist)
92 {
94
95 if (equal(node, tlentry->expr))
96 return tlentry;
97 }
98 return NULL;
99}
100
101/*
102 * tlist_member_match_var
103 * Same as above, except that we match the provided Var on the basis
104 * of varno/varattno/varlevelsup/vartype only, rather than full equal().
105 *
106 * This is needed in some cases where we can't be sure of an exact typmod
107 * match. For safety, though, we insist on vartype match.
108 */
109static TargetEntry *
110tlist_member_match_var(Var *var, List *targetlist)
111{
112 ListCell *temp;
113
114 foreach(temp, targetlist)
115 {
117 Var *tlvar = (Var *) tlentry->expr;
118
119 if (!tlvar || !IsA(tlvar, Var))
120 continue;
121 if (var->varno == tlvar->varno &&
122 var->varattno == tlvar->varattno &&
123 var->varlevelsup == tlvar->varlevelsup &&
124 var->vartype == tlvar->vartype)
125 return tlentry;
126 }
127 return NULL;
128}
129
130/*
131 * add_to_flat_tlist
132 * Add more items to a flattened tlist (if they're not already in it)
133 *
134 * 'tlist' is the flattened tlist
135 * 'exprs' is a list of expressions (usually, but not necessarily, Vars)
136 *
137 * Returns the extended tlist.
138 */
139List *
140add_to_flat_tlist(List *tlist, List *exprs)
141{
142 int next_resno = list_length(tlist) + 1;
143 ListCell *lc;
144
145 foreach(lc, exprs)
146 {
147 Expr *expr = (Expr *) lfirst(lc);
148
149 if (!tlist_member(expr, tlist))
150 {
152
153 tle = makeTargetEntry(copyObject(expr), /* copy needed?? */
154 next_resno++,
155 NULL,
156 false);
157 tlist = lappend(tlist, tle);
158 }
159 }
160 return tlist;
161}
162
163
164/*
165 * get_tlist_exprs
166 * Get just the expression subtrees of a tlist
167 *
168 * Resjunk columns are ignored unless includeJunk is true
169 */
170List *
171get_tlist_exprs(List *tlist, bool includeJunk)
172{
173 List *result = NIL;
174 ListCell *l;
175
176 foreach(l, tlist)
177 {
179
180 if (tle->resjunk && !includeJunk)
181 continue;
182
183 result = lappend(result, tle->expr);
184 }
185 return result;
186}
187
188
189/*
190 * count_nonjunk_tlist_entries
191 * What it says ...
192 */
193int
195{
196 int len = 0;
197 ListCell *l;
198
199 foreach(l, tlist)
200 {
202
203 if (!tle->resjunk)
204 len++;
205 }
206 return len;
207}
208
209
210/*
211 * tlist_same_exprs
212 * Check whether two target lists contain the same expressions
213 *
214 * Note: this function is used to decide whether it's safe to jam a new tlist
215 * into a non-projection-capable plan node. Obviously we can't do that unless
216 * the node's tlist shows it already returns the column values we want.
217 * However, we can ignore the TargetEntry attributes resname, ressortgroupref,
218 * resorigtbl, resorigcol, and resjunk, because those are only labelings that
219 * don't affect the row values computed by the node. (Moreover, if we didn't
220 * ignore them, we'd frequently fail to make the desired optimization, since
221 * the planner tends to not bother to make resname etc. valid in intermediate
222 * plan nodes.) Note that on success, the caller must still jam the desired
223 * tlist into the plan node, else it won't have the desired labeling fields.
224 */
225bool
227{
228 ListCell *lc1,
229 *lc2;
230
232 return false; /* not same length, so can't match */
233
235 {
238
239 if (!equal(tle1->expr, tle2->expr))
240 return false;
241 }
242
243 return true;
244}
245
246
247/*
248 * Does tlist have same output datatypes as listed in colTypes?
249 *
250 * Resjunk columns are ignored if junkOK is true; otherwise presence of
251 * a resjunk column will always cause a 'false' result.
252 *
253 * Note: currently no callers care about comparing typmods.
254 */
255bool
257{
258 ListCell *l;
260
261 foreach(l, tlist)
262 {
264
265 if (tle->resjunk)
266 {
267 if (!junkOK)
268 return false;
269 }
270 else
271 {
272 if (curColType == NULL)
273 return false; /* tlist longer than colTypes */
274 if (exprType((Node *) tle->expr) != lfirst_oid(curColType))
275 return false;
277 }
278 }
279 if (curColType != NULL)
280 return false; /* tlist shorter than colTypes */
281 return true;
282}
283
284/*
285 * Does tlist have same exposed collations as listed in colCollations?
286 *
287 * Identical logic to the above, but for collations.
288 */
289bool
291{
292 ListCell *l;
294
295 foreach(l, tlist)
296 {
298
299 if (tle->resjunk)
300 {
301 if (!junkOK)
302 return false;
303 }
304 else
305 {
306 if (curColColl == NULL)
307 return false; /* tlist longer than colCollations */
308 if (exprCollation((Node *) tle->expr) != lfirst_oid(curColColl))
309 return false;
311 }
312 }
313 if (curColColl != NULL)
314 return false; /* tlist shorter than colCollations */
315 return true;
316}
317
318/*
319 * apply_tlist_labeling
320 * Apply the TargetEntry labeling attributes of src_tlist to dest_tlist
321 *
322 * This is useful for reattaching column names etc to a plan's final output
323 * targetlist.
324 */
325void
327{
328 ListCell *ld,
329 *ls;
330
333 {
336
337 Assert(dest_tle->resno == src_tle->resno);
338 dest_tle->resname = src_tle->resname;
339 dest_tle->ressortgroupref = src_tle->ressortgroupref;
340 dest_tle->resorigtbl = src_tle->resorigtbl;
341 dest_tle->resorigcol = src_tle->resorigcol;
342 dest_tle->resjunk = src_tle->resjunk;
343 }
344}
345
346
347/*
348 * get_sortgroupref_tle
349 * Find the targetlist entry matching the given SortGroupRef index,
350 * and return it.
351 */
354{
355 ListCell *l;
356
357 foreach(l, targetList)
358 {
360
361 if (tle->ressortgroupref == sortref)
362 return tle;
363 }
364
365 elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
366 return NULL; /* keep compiler quiet */
367}
368
369/*
370 * get_sortgroupclause_tle
371 * Find the targetlist entry matching the given SortGroupClause
372 * by ressortgroupref, and return it.
373 */
376 List *targetList)
377{
378 return get_sortgroupref_tle(sgClause->tleSortGroupRef, targetList);
379}
380
381/*
382 * get_sortgroupclause_expr
383 * Find the targetlist entry matching the given SortGroupClause
384 * by ressortgroupref, and return its expression.
385 */
386Node *
388{
390
391 return (Node *) tle->expr;
392}
393
394/*
395 * get_sortgrouplist_exprs
396 * Given a list of SortGroupClauses, build a list
397 * of the referenced targetlist expressions.
398 */
399List *
401{
402 List *result = NIL;
403 ListCell *l;
404
405 foreach(l, sgClauses)
406 {
408 Node *sortexpr;
409
411 result = lappend(result, sortexpr);
412 }
413 return result;
414}
415
416
417/*****************************************************************************
418 * Functions to extract data from a list of SortGroupClauses
419 *
420 * These don't really belong in tlist.c, but they are sort of related to the
421 * functions just above, and they don't seem to deserve their own file.
422 *****************************************************************************/
423
424/*
425 * get_sortgroupref_clause
426 * Find the SortGroupClause matching the given SortGroupRef index,
427 * and return it.
428 */
431{
432 ListCell *l;
433
434 foreach(l, clauses)
435 {
437
438 if (cl->tleSortGroupRef == sortref)
439 return cl;
440 }
441
442 elog(ERROR, "ORDER/GROUP BY expression not found in list");
443 return NULL; /* keep compiler quiet */
444}
445
446/*
447 * get_sortgroupref_clause_noerr
448 * As above, but return NULL rather than throwing an error if not found.
449 */
452{
453 ListCell *l;
454
455 foreach(l, clauses)
456 {
458
459 if (cl->tleSortGroupRef == sortref)
460 return cl;
461 }
462
463 return NULL;
464}
465
466/*
467 * extract_grouping_ops - make an array of the equality operator OIDs
468 * for a SortGroupClause list
469 */
470Oid *
471extract_grouping_ops(List *groupClause)
472{
473 int numCols = list_length(groupClause);
474 int colno = 0;
477
478 groupOperators = palloc_array(Oid, numCols);
479
480 foreach(glitem, groupClause)
481 {
483
484 groupOperators[colno] = groupcl->eqop;
486 colno++;
487 }
488
489 return groupOperators;
490}
491
492/*
493 * extract_grouping_collations - make an array of the grouping column collations
494 * for a SortGroupClause list
495 */
496Oid *
497extract_grouping_collations(List *groupClause, List *tlist)
498{
499 int numCols = list_length(groupClause);
500 int colno = 0;
503
504 grpCollations = palloc_array(Oid, numCols);
505
506 foreach(glitem, groupClause)
507 {
510
511 grpCollations[colno++] = exprCollation((Node *) tle->expr);
512 }
513
514 return grpCollations;
515}
516
517/*
518 * extract_grouping_cols - make an array of the grouping column resnos
519 * for a SortGroupClause list
520 */
522extract_grouping_cols(List *groupClause, List *tlist)
523{
525 int numCols = list_length(groupClause);
526 int colno = 0;
528
530
531 foreach(glitem, groupClause)
532 {
535
536 grpColIdx[colno++] = tle->resno;
537 }
538
539 return grpColIdx;
540}
541
542/*
543 * grouping_is_sortable - is it possible to implement grouping list by sorting?
544 *
545 * This is easy since the parser will have included a sortop if one exists.
546 */
547bool
548grouping_is_sortable(List *groupClause)
549{
551
552 foreach(glitem, groupClause)
553 {
555
556 if (!OidIsValid(groupcl->sortop))
557 return false;
558 }
559 return true;
560}
561
562/*
563 * grouping_is_hashable - is it possible to implement grouping list by hashing?
564 *
565 * We rely on the parser to have set the hashable flag correctly.
566 */
567bool
568grouping_is_hashable(List *groupClause)
569{
571
572 foreach(glitem, groupClause)
573 {
575
576 if (!groupcl->hashable)
577 return false;
578 }
579 return true;
580}
581
582
583/*****************************************************************************
584 * PathTarget manipulation functions
585 *
586 * PathTarget is a somewhat stripped-down version of a full targetlist; it
587 * omits all the TargetEntry decoration except (optionally) sortgroupref data,
588 * and it adds evaluation cost and output data width info.
589 *****************************************************************************/
590
591/*
592 * make_pathtarget_from_tlist
593 * Construct a PathTarget equivalent to the given targetlist.
594 *
595 * This leaves the cost and width fields as zeroes. Most callers will want
596 * to use create_pathtarget(), so as to get those set.
597 */
600{
601 PathTarget *target = makeNode(PathTarget);
602 int i;
603 ListCell *lc;
604
605 target->sortgrouprefs = (Index *) palloc(list_length(tlist) * sizeof(Index));
606
607 i = 0;
608 foreach(lc, tlist)
609 {
611
612 target->exprs = lappend(target->exprs, tle->expr);
613 target->sortgrouprefs[i] = tle->ressortgroupref;
614 i++;
615 }
616
617 /*
618 * Mark volatility as unknown. The contain_volatile_functions function
619 * will determine if there are any volatile functions when called for the
620 * first time with this PathTarget.
621 */
623
624 return target;
625}
626
627/*
628 * make_tlist_from_pathtarget
629 * Construct a targetlist from a PathTarget.
630 */
631List *
633{
634 List *tlist = NIL;
635 int i;
636 ListCell *lc;
637
638 i = 0;
639 foreach(lc, target->exprs)
640 {
641 Expr *expr = (Expr *) lfirst(lc);
643
644 tle = makeTargetEntry(expr,
645 i + 1,
646 NULL,
647 false);
648 if (target->sortgrouprefs)
649 tle->ressortgroupref = target->sortgrouprefs[i];
650 tlist = lappend(tlist, tle);
651 i++;
652 }
653
654 return tlist;
655}
656
657/*
658 * copy_pathtarget
659 * Copy a PathTarget.
660 *
661 * The new PathTarget has its own exprs List, but shares the underlying
662 * target expression trees with the old one.
663 */
666{
668
669 /* Copy scalar fields */
670 memcpy(dst, src, sizeof(PathTarget));
671 /* Shallow-copy the expression list */
672 dst->exprs = list_copy(src->exprs);
673 /* Duplicate sortgrouprefs if any (if not, the memcpy handled this) */
674 if (src->sortgrouprefs)
675 {
676 Size nbytes = list_length(src->exprs) * sizeof(Index);
677
678 dst->sortgrouprefs = (Index *) palloc(nbytes);
679 memcpy(dst->sortgrouprefs, src->sortgrouprefs, nbytes);
680 }
681 return dst;
682}
683
684/*
685 * create_empty_pathtarget
686 * Create an empty (zero columns, zero cost) PathTarget.
687 */
690{
691 /* This is easy, but we don't want callers to hard-wire this ... */
692 return makeNode(PathTarget);
693}
694
695/*
696 * add_column_to_pathtarget
697 * Append a target column to the PathTarget.
698 *
699 * As with make_pathtarget_from_tlist, we leave it to the caller to update
700 * the cost and width fields.
701 */
702void
703add_column_to_pathtarget(PathTarget *target, Expr *expr, Index sortgroupref)
704{
705 /* Updating the exprs list is easy ... */
706 target->exprs = lappend(target->exprs, expr);
707 /* ... the sortgroupref data, a bit less so */
708 if (target->sortgrouprefs)
709 {
710 int nexprs = list_length(target->exprs);
711
712 /* This might look inefficient, but actually it's usually cheap */
713 target->sortgrouprefs = (Index *)
714 repalloc(target->sortgrouprefs, nexprs * sizeof(Index));
715 target->sortgrouprefs[nexprs - 1] = sortgroupref;
716 }
717 else if (sortgroupref)
718 {
719 /* Adding sortgroupref labeling to a previously unlabeled target */
720 int nexprs = list_length(target->exprs);
721
722 target->sortgrouprefs = (Index *) palloc0(nexprs * sizeof(Index));
723 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 */
735}
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 */
748void
750{
751 if (!list_member(target->exprs, expr))
752 add_column_to_pathtarget(target, expr, 0);
753}
754
755/*
756 * add_new_columns_to_pathtarget
757 * Apply add_new_column_to_pathtarget() for each element of the list.
758 */
759void
761{
762 ListCell *lc;
763
764 foreach(lc, exprs)
765 {
766 Expr *expr = (Expr *) lfirst(lc);
767
768 add_new_column_to_pathtarget(target, expr);
769 }
770}
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 */
781void
783{
784 int i;
785 ListCell *lc;
786
787 /* Nothing to do if PathTarget has no sortgrouprefs data */
788 if (target->sortgrouprefs == NULL)
789 return;
790
791 i = 0;
792 foreach(lc, target->exprs)
793 {
794 Expr *expr = (Expr *) lfirst(lc);
796
797 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 if (expr && IsA(expr, Var))
809 tle = tlist_member_match_var((Var *) expr, tlist);
810 else
811 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 if (!tle)
820 elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
821 if (tle->ressortgroupref != 0 &&
822 tle->ressortgroupref != target->sortgrouprefs[i])
823 elog(ERROR, "targetlist item has multiple sortgroupref labels");
824
825 tle->ressortgroupref = target->sortgrouprefs[i];
826 }
827 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 */
843void
847{
850 false);
851}
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 */
866void
870{
873 true);
874}
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 */
940static void
944 bool is_grouping_target)
945{
947 int max_depth;
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 if (target == input_target)
963 {
964 *targets = list_make1(target);
966 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 context.root = root;
974 context.is_grouping_target = is_grouping_target;
975 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 context.level_srfs = list_make1(NIL);
987
988 /* Initialize data we'll accumulate across all the target expressions */
989 context.current_input_vars = NIL;
990 context.current_input_srfs = NIL;
991 max_depth = 0;
992 need_extra_projection = false;
993
994 /* Scan each expression in the PathTarget looking for SRFs */
995 lci = 0;
996 foreach(lc, target->exprs)
997 {
998 Node *node = (Node *) lfirst(lc);
999
1000 /* Tell split_pathtarget_walker about this expr's sortgroupref */
1002 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 context.current_depth = 0;
1009 split_pathtarget_walker(node, &context);
1010
1011 /* An expression containing no SRFs is of no further interest */
1012 if (context.current_depth == 0)
1013 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 if (max_depth < context.current_depth)
1022 {
1023 max_depth = context.current_depth;
1024 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 if (max_depth == context.current_depth && !IS_SRF_CALL(node))
1033 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 if (max_depth == 0)
1042 {
1043 *targets = list_make1(target);
1045 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 */
1054 {
1055 context.level_srfs = lappend(context.level_srfs, NIL);
1056 context.level_input_vars = lappend(context.level_input_vars,
1057 context.current_input_vars);
1058 context.level_input_srfs = lappend(context.level_input_srfs,
1059 context.current_input_srfs);
1060 }
1061 else
1062 {
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 */
1077
1078 forthree(lc1, context.level_srfs,
1079 lc2, context.level_input_vars,
1080 lc3, context.level_input_srfs)
1081 {
1082 List *level_srfs = (List *) lfirst(lc1);
1084
1085 if (lnext(context.level_srfs, lc1) == NULL)
1086 {
1087 ntarget = target;
1088 }
1089 else
1090 {
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 */
1101 lnext(context.level_input_vars, lc2))
1102 {
1103 List *input_vars = (List *) lfirst(lc);
1104
1106 }
1108 lnext(context.level_input_srfs, lc3))
1109 {
1110 List *input_srfs = (List *) lfirst(lc);
1111 ListCell *lcx;
1112
1113 foreach(lcx, input_srfs)
1114 {
1116
1117 if (list_member(prev_level_tlist, item->expr))
1119 }
1120 }
1122 }
1123
1124 /*
1125 * Add current target and does-it-compute-SRFs flag to output lists.
1126 */
1129 (level_srfs != NIL));
1130
1131 /* Remember this level's output for next pass */
1132 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 */
1142static bool
1144{
1145 Node *sanitized_node = node;
1146
1147 if (node == NULL)
1148 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 if (context->is_grouping_target &&
1157 context->root->parse->hasGroupRTE &&
1158 context->root->parse->groupingSets != NIL)
1159 {
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 */
1175 {
1177
1178 item->expr = node;
1179 item->sortgroupref = context->current_sgref;
1180 context->current_input_vars = lappend(context->current_input_vars,
1181 item);
1182 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 if (IsA(node, Var) ||
1191 IsA(node, PlaceHolderVar) ||
1192 IsA(node, Aggref) ||
1193 IsA(node, GroupingFunc) ||
1194 IsA(node, WindowFunc))
1195 {
1197
1198 item->expr = node;
1199 item->sortgroupref = context->current_sgref;
1200 context->current_input_vars = lappend(context->current_input_vars,
1201 item);
1202 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 if (IS_SRF_CALL(node))
1210 {
1214 int save_current_depth = context->current_depth;
1215 int srf_depth;
1216 ListCell *lc;
1217
1218 item->expr = node;
1219 item->sortgroupref = context->current_sgref;
1220
1221 context->current_input_vars = NIL;
1222 context->current_input_srfs = NIL;
1223 context->current_depth = 0;
1224 context->current_sgref = 0; /* subexpressions are not sortgroup items */
1225
1227
1228 /* Depth is one more than any SRF below it */
1229 srf_depth = context->current_depth + 1;
1230
1231 /* If new record depth, initialize another level of output lists */
1232 if (srf_depth >= list_length(context->level_srfs))
1233 {
1234 context->level_srfs = lappend(context->level_srfs, NIL);
1235 context->level_input_vars = lappend(context->level_input_vars, NIL);
1236 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 lc = list_nth_cell(context->level_srfs, srf_depth);
1241 lfirst(lc) = lappend(lfirst(lc), item);
1242
1243 /* Record its inputs as being needed at the same level */
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 */
1255 context->current_input_srfs = lappend(save_input_srfs, item);
1257
1258 /* We're done here */
1259 return false;
1260 }
1261
1262 /*
1263 * Otherwise, the node is a scalar (non-set) expression, so recurse to
1264 * examine its inputs.
1265 */
1266 context->current_sgref = 0; /* subexpressions are not sortgroup items */
1267 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 */
1283static void
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 lci = 0;
1294 foreach(lc, target->exprs)
1295 {
1296 Node *node = (Node *) lfirst(lc);
1298
1299 if ((item->sortgroupref == sgref ||
1300 item->sortgroupref == 0 ||
1301 sgref == 0) &&
1302 equal(item->expr, node))
1303 {
1304 /* Found a match. Assign item's sortgroupref if it has one. */
1305 if (item->sortgroupref)
1306 {
1307 if (target->sortgrouprefs == NULL)
1308 {
1309 target->sortgrouprefs = (Index *)
1310 palloc0(list_length(target->exprs) * sizeof(Index));
1311 }
1312 target->sortgrouprefs[lci] = item->sortgroupref;
1313 }
1314 return;
1315 }
1316 lci++;
1317 }
1318
1319 /*
1320 * No match, so add item to PathTarget. Copy the expr for safety.
1321 */
1322 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 */
1329static void
1331{
1332 ListCell *lc;
1333
1334 foreach(lc, items)
1335 {
1337
1338 add_sp_item_to_pathtarget(target, item);
1339 }
1340}
int16 AttrNumber
Definition attnum.h:21
Bitmapset * bms_make_singleton(int x)
Definition bitmapset.c:216
#define Max(x, y)
Definition c.h:991
#define Assert(condition)
Definition c.h:873
unsigned int Index
Definition c.h:628
#define OidIsValid(objectId)
Definition c.h:788
size_t Size
Definition c.h:619
PathTarget * set_pathtarget_cost_width(PlannerInfo *root, PathTarget *target)
Definition costsize.c:6514
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
bool equal(const void *a, const void *b)
Definition equalfuncs.c:223
#define palloc_object(type)
Definition fe_memutils.h:74
#define palloc_array(type, count)
Definition fe_memutils.h:76
int i
Definition isn.c:77
List * lappend(List *list, void *datum)
Definition list.c:339
List * list_concat(List *list1, const List *list2)
Definition list.c:561
List * list_copy(const List *oldlist)
Definition list.c:1573
List * lappend_int(List *list, int datum)
Definition list.c:357
bool list_member(const List *list, const void *datum)
Definition list.c:661
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition makefuncs.c:289
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1632
void * palloc0(Size size)
Definition mcxt.c:1417
void * palloc(Size size)
Definition mcxt.c:1387
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
Oid exprCollation(const Node *expr)
Definition nodeFuncs.c:821
#define expression_tree_walker(n, w, c)
Definition nodeFuncs.h:153
#define copyObject(obj)
Definition nodes.h:232
#define makeNode(_type_)
Definition nodes.h:161
#define get_pathtarget_sortgroupref(target, colno)
Definition pathnodes.h:1874
@ VOLATILITY_NOVOLATILE
Definition pathnodes.h:1825
@ VOLATILITY_UNKNOWN
Definition pathnodes.h:1823
const void size_t len
#define lfirst(lc)
Definition pg_list.h:172
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
#define forboth(cell1, list1, cell2, list2)
Definition pg_list.h:518
#define list_make1(x1)
Definition pg_list.h:212
#define forthree(cell1, list1, cell2, list2, cell3, list3)
Definition pg_list.h:563
#define for_each_cell(cell, lst, initcell)
Definition pg_list.h:438
static ListCell * list_nth_cell(const List *list, int n)
Definition pg_list.h:277
static ListCell * list_head(const List *l)
Definition pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition pg_list.h:343
#define list_make1_int(x1)
Definition pg_list.h:227
#define lfirst_oid(lc)
Definition pg_list.h:174
unsigned int Oid
tree ctl root
Definition radixtree.h:1857
Node * remove_nulling_relids(Node *node, const Bitmapset *removable_relids, const Bitmapset *except_relids)
Definition pg_list.h:54
Definition nodes.h:135
VolatileFunctionStatus has_volatile_expr
Definition pathnodes.h:1870
List * exprs
Definition pathnodes.h:1858
Query * parse
Definition pathnodes.h:303
int group_rtindex
Definition pathnodes.h:631
List * groupingSets
Definition parsenodes.h:220
AttrNumber varattno
Definition primnodes.h:274
int varno
Definition primnodes.h:269
Index varlevelsup
Definition primnodes.h:294
PlannerInfo * root
Definition tlist.c:49
List * current_input_srfs
Definition tlist.c:59
List * input_target_exprs
Definition tlist.c:52
List * current_input_vars
Definition tlist.c:58
static ItemArray items
void split_pathtarget_at_srfs_grouping(PlannerInfo *root, PathTarget *target, PathTarget *input_target, List **targets, List **targets_contain_srfs)
Definition tlist.c:868
bool tlist_same_collations(List *tlist, List *colCollations, bool junkOK)
Definition tlist.c:291
Oid * extract_grouping_ops(List *groupClause)
Definition tlist.c:472
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition tlist.c:88
bool tlist_same_exprs(List *tlist1, List *tlist2)
Definition tlist.c:227
void apply_tlist_labeling(List *dest_tlist, List *src_tlist)
Definition tlist.c:327
SortGroupClause * get_sortgroupref_clause_noerr(Index sortref, List *clauses)
Definition tlist.c:452
SortGroupClause * get_sortgroupref_clause(Index sortref, List *clauses)
Definition tlist.c:431
void apply_pathtarget_labeling_to_tlist(List *tlist, PathTarget *target)
Definition tlist.c:783
#define IS_SRF_CALL(node)
Definition tlist.c:32
bool grouping_is_sortable(List *groupClause)
Definition tlist.c:549
PathTarget * make_pathtarget_from_tlist(List *tlist)
Definition tlist.c:600
static void split_pathtarget_at_srfs_extended(PlannerInfo *root, PathTarget *target, PathTarget *input_target, List **targets, List **targets_contain_srfs, bool is_grouping_target)
Definition tlist.c:942
List * make_tlist_from_pathtarget(PathTarget *target)
Definition tlist.c:633
PathTarget * copy_pathtarget(PathTarget *src)
Definition tlist.c:666
static void add_sp_item_to_pathtarget(PathTarget *target, split_pathtarget_item *item)
Definition tlist.c:1285
static bool split_pathtarget_walker(Node *node, split_pathtarget_context *context)
Definition tlist.c:1144
AttrNumber * extract_grouping_cols(List *groupClause, List *tlist)
Definition tlist.c:523
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition tlist.c:376
void add_new_columns_to_pathtarget(PathTarget *target, List *exprs)
Definition tlist.c:761
static void add_sp_items_to_pathtarget(PathTarget *target, List *items)
Definition tlist.c:1331
PathTarget * create_empty_pathtarget(void)
Definition tlist.c:690
List * get_sortgrouplist_exprs(List *sgClauses, List *targetList)
Definition tlist.c:401
TargetEntry * get_sortgroupref_tle(Index sortref, List *targetList)
Definition tlist.c:354
List * add_to_flat_tlist(List *tlist, List *exprs)
Definition tlist.c:141
int count_nonjunk_tlist_entries(List *tlist)
Definition tlist.c:195
List * get_tlist_exprs(List *tlist, bool includeJunk)
Definition tlist.c:172
void add_new_column_to_pathtarget(PathTarget *target, Expr *expr)
Definition tlist.c:750
void split_pathtarget_at_srfs(PlannerInfo *root, PathTarget *target, PathTarget *input_target, List **targets, List **targets_contain_srfs)
Definition tlist.c:845
bool grouping_is_hashable(List *groupClause)
Definition tlist.c:569
Oid * extract_grouping_collations(List *groupClause, List *tlist)
Definition tlist.c:498
static TargetEntry * tlist_member_match_var(Var *var, List *targetlist)
Definition tlist.c:111
void add_column_to_pathtarget(PathTarget *target, Expr *expr, Index sortgroupref)
Definition tlist.c:704
Node * get_sortgroupclause_expr(SortGroupClause *sgClause, List *targetList)
Definition tlist.c:388
bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
Definition tlist.c:257

Function Documentation

◆ add_column_to_pathtarget()

void add_column_to_pathtarget ( PathTarget target,
Expr expr,
Index  sortgroupref 
)

Definition at line 704 of file tlist.c.

705{
706 /* Updating the exprs list is easy ... */
707 target->exprs = lappend(target->exprs, expr);
708 /* ... the sortgroupref data, a bit less so */
709 if (target->sortgrouprefs)
710 {
711 int nexprs = list_length(target->exprs);
712
713 /* This might look inefficient, but actually it's usually cheap */
714 target->sortgrouprefs = (Index *)
715 repalloc(target->sortgrouprefs, nexprs * sizeof(Index));
716 target->sortgrouprefs[nexprs - 1] = sortgroupref;
717 }
718 else if (sortgroupref)
719 {
720 /* Adding sortgroupref labeling to a previously unlabeled target */
721 int nexprs = list_length(target->exprs);
722
723 target->sortgrouprefs = (Index *) palloc0(nexprs * sizeof(Index));
724 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 */
736}

References PathTarget::exprs, fb(), PathTarget::has_volatile_expr, lappend(), list_length(), palloc0(), repalloc(), VOLATILITY_NOVOLATILE, and VOLATILITY_UNKNOWN.

Referenced by add_new_column_to_pathtarget(), add_sp_item_to_pathtarget(), create_one_window_path(), create_rel_agg_info(), init_grouping_targets(), make_group_input_target(), make_partial_grouping_target(), make_sort_input_target(), and make_window_input_target().

◆ add_new_column_to_pathtarget()

void add_new_column_to_pathtarget ( PathTarget target,
Expr expr 
)

Definition at line 750 of file tlist.c.

751{
752 if (!list_member(target->exprs, expr))
753 add_column_to_pathtarget(target, expr, 0);
754}

References add_column_to_pathtarget(), PathTarget::exprs, and list_member().

Referenced by add_new_columns_to_pathtarget(), and init_grouping_targets().

◆ add_new_columns_to_pathtarget()

void add_new_columns_to_pathtarget ( PathTarget target,
List exprs 
)

Definition at line 761 of file tlist.c.

762{
763 ListCell *lc;
764
765 foreach(lc, exprs)
766 {
767 Expr *expr = (Expr *) lfirst(lc);
768
769 add_new_column_to_pathtarget(target, expr);
770 }
771}

References add_new_column_to_pathtarget(), fb(), and lfirst.

Referenced by add_paths_with_pathkeys_for_rel(), make_group_input_target(), make_partial_grouping_target(), make_sort_input_target(), and make_window_input_target().

◆ add_sp_item_to_pathtarget()

static void add_sp_item_to_pathtarget ( PathTarget target,
split_pathtarget_item item 
)
static

Definition at line 1285 of file tlist.c.

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 lci = 0;
1295 foreach(lc, target->exprs)
1296 {
1297 Node *node = (Node *) lfirst(lc);
1299
1300 if ((item->sortgroupref == sgref ||
1301 item->sortgroupref == 0 ||
1302 sgref == 0) &&
1303 equal(item->expr, node))
1304 {
1305 /* Found a match. Assign item's sortgroupref if it has one. */
1306 if (item->sortgroupref)
1307 {
1308 if (target->sortgrouprefs == NULL)
1309 {
1310 target->sortgrouprefs = (Index *)
1311 palloc0(list_length(target->exprs) * sizeof(Index));
1312 }
1313 target->sortgrouprefs[lci] = item->sortgroupref;
1314 }
1315 return;
1316 }
1317 lci++;
1318 }
1319
1320 /*
1321 * No match, so add item to PathTarget. Copy the expr for safety.
1322 */
1323 add_column_to_pathtarget(target, (Expr *) copyObject(item->expr),
1324 item->sortgroupref);
1325}

References add_column_to_pathtarget(), copyObject, equal(), split_pathtarget_item::expr, PathTarget::exprs, fb(), get_pathtarget_sortgroupref, lfirst, list_length(), palloc0(), and split_pathtarget_item::sortgroupref.

Referenced by add_sp_items_to_pathtarget(), and split_pathtarget_at_srfs_extended().

◆ add_sp_items_to_pathtarget()

static void add_sp_items_to_pathtarget ( PathTarget target,
List items 
)
static

Definition at line 1331 of file tlist.c.

1332{
1333 ListCell *lc;
1334
1335 foreach(lc, items)
1336 {
1338
1339 add_sp_item_to_pathtarget(target, item);
1340 }
1341}

References add_sp_item_to_pathtarget(), fb(), items, and lfirst.

Referenced by split_pathtarget_at_srfs_extended().

◆ add_to_flat_tlist()

List * add_to_flat_tlist ( List tlist,
List exprs 
)

Definition at line 141 of file tlist.c.

142{
143 int next_resno = list_length(tlist) + 1;
144 ListCell *lc;
145
146 foreach(lc, exprs)
147 {
148 Expr *expr = (Expr *) lfirst(lc);
149
150 if (!tlist_member(expr, tlist))
151 {
153
154 tle = makeTargetEntry(copyObject(expr), /* copy needed?? */
155 next_resno++,
156 NULL,
157 false);
158 tlist = lappend(tlist, tle);
159 }
160 }
161 return tlist;
162}

References copyObject, fb(), lappend(), lfirst, list_length(), makeTargetEntry(), and tlist_member().

Referenced by build_tlist_to_deparse(), and foreign_grouping_ok().

◆ apply_pathtarget_labeling_to_tlist()

void apply_pathtarget_labeling_to_tlist ( List tlist,
PathTarget target 
)

Definition at line 783 of file tlist.c.

784{
785 int i;
786 ListCell *lc;
787
788 /* Nothing to do if PathTarget has no sortgrouprefs data */
789 if (target->sortgrouprefs == NULL)
790 return;
791
792 i = 0;
793 foreach(lc, target->exprs)
794 {
795 Expr *expr = (Expr *) lfirst(lc);
797
798 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 if (expr && IsA(expr, Var))
810 tle = tlist_member_match_var((Var *) expr, tlist);
811 else
812 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 if (!tle)
821 elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
822 if (tle->ressortgroupref != 0 &&
823 tle->ressortgroupref != target->sortgrouprefs[i])
824 elog(ERROR, "targetlist item has multiple sortgroupref labels");
825
826 tle->ressortgroupref = target->sortgrouprefs[i];
827 }
828 i++;
829 }
830}

References elog, ERROR, PathTarget::exprs, fb(), i, IsA, lfirst, tlist_member(), and tlist_member_match_var().

Referenced by create_projection_plan(), and create_scan_plan().

◆ apply_tlist_labeling()

void apply_tlist_labeling ( List dest_tlist,
List src_tlist 
)

Definition at line 327 of file tlist.c.

328{
329 ListCell *ld,
330 *ls;
331
334 {
337
338 Assert(dest_tle->resno == src_tle->resno);
339 dest_tle->resname = src_tle->resname;
340 dest_tle->ressortgroupref = src_tle->ressortgroupref;
341 dest_tle->resorigtbl = src_tle->resorigtbl;
342 dest_tle->resorigcol = src_tle->resorigcol;
343 dest_tle->resjunk = src_tle->resjunk;
344 }
345}

References Assert, fb(), forboth, lfirst, and list_length().

Referenced by clean_up_removed_plan_level(), create_modifytable_plan(), and create_plan().

◆ copy_pathtarget()

PathTarget * copy_pathtarget ( PathTarget src)

Definition at line 666 of file tlist.c.

667{
669
670 /* Copy scalar fields */
671 memcpy(dst, src, sizeof(PathTarget));
672 /* Shallow-copy the expression list */
673 dst->exprs = list_copy(src->exprs);
674 /* Duplicate sortgrouprefs if any (if not, the memcpy handled this) */
675 if (src->sortgrouprefs)
676 {
677 Size nbytes = list_length(src->exprs) * sizeof(Index);
678
679 dst->sortgrouprefs = (Index *) palloc(nbytes);
680 memcpy(dst->sortgrouprefs, src->sortgrouprefs, nbytes);
681 }
682 return dst;
683}

References PathTarget::exprs, fb(), list_copy(), list_length(), makeNode, and palloc().

Referenced by add_paths_with_pathkeys_for_rel(), apply_scanjoin_target_to_paths(), create_one_window_path(), create_partitionwise_grouping_paths(), create_unique_paths(), and reparameterize_path_by_child().

◆ count_nonjunk_tlist_entries()

int count_nonjunk_tlist_entries ( List tlist)

Definition at line 195 of file tlist.c.

196{
197 int len = 0;
198 ListCell *l;
199
200 foreach(l, tlist)
201 {
203
204 if (!tle->resjunk)
205 len++;
206 }
207 return len;
208}

References fb(), len, and lfirst.

Referenced by get_update_query_targetlist_def(), transformJsonArrayQueryConstructor(), transformMultiAssignRef(), and transformSubLink().

◆ create_empty_pathtarget()

PathTarget * create_empty_pathtarget ( void  )

◆ extract_grouping_collations()

Oid * extract_grouping_collations ( List groupClause,
List tlist 
)

Definition at line 498 of file tlist.c.

499{
500 int numCols = list_length(groupClause);
501 int colno = 0;
504
505 grpCollations = palloc_array(Oid, numCols);
506
507 foreach(glitem, groupClause)
508 {
511
512 grpCollations[colno++] = exprCollation((Node *) tle->expr);
513 }
514
515 return grpCollations;
516}

References exprCollation(), fb(), get_sortgroupclause_tle(), lfirst, list_length(), and palloc_array.

Referenced by create_agg_plan(), create_group_plan(), and create_groupingsets_plan().

◆ extract_grouping_cols()

AttrNumber * extract_grouping_cols ( List groupClause,
List tlist 
)

Definition at line 523 of file tlist.c.

524{
526 int numCols = list_length(groupClause);
527 int colno = 0;
529
531
532 foreach(glitem, groupClause)
533 {
536
537 grpColIdx[colno++] = tle->resno;
538 }
539
540 return grpColIdx;
541}

References fb(), get_sortgroupclause_tle(), lfirst, list_length(), and palloc_array.

Referenced by create_agg_plan(), and create_group_plan().

◆ extract_grouping_ops()

Oid * extract_grouping_ops ( List groupClause)

Definition at line 472 of file tlist.c.

473{
474 int numCols = list_length(groupClause);
475 int colno = 0;
478
479 groupOperators = palloc_array(Oid, numCols);
480
481 foreach(glitem, groupClause)
482 {
484
485 groupOperators[colno] = groupcl->eqop;
487 colno++;
488 }
489
490 return groupOperators;
491}

References Assert, SortGroupClause::eqop, fb(), lfirst, list_length(), OidIsValid, and palloc_array.

Referenced by create_agg_plan(), create_group_plan(), and create_groupingsets_plan().

◆ get_sortgroupclause_expr()

Node * get_sortgroupclause_expr ( SortGroupClause sgClause,
List targetList 
)

Definition at line 388 of file tlist.c.

389{
391
392 return (Node *) tle->expr;
393}

References fb(), and get_sortgroupclause_tle().

Referenced by get_sortgrouplist_exprs(), make_pathkeys_for_sortclauses_extended(), transformAggregateCall(), and transformWindowDefinitions().

◆ get_sortgroupclause_tle()

◆ get_sortgrouplist_exprs()

List * get_sortgrouplist_exprs ( List sgClauses,
List targetList 
)

Definition at line 401 of file tlist.c.

402{
403 List *result = NIL;
404 ListCell *l;
405
406 foreach(l, sgClauses)
407 {
409 Node *sortexpr;
410
412 result = lappend(result, sortexpr);
413 }
414 return result;
415}

References fb(), get_sortgroupclause_expr(), lappend(), lfirst, and NIL.

Referenced by create_final_distinct_paths(), create_partial_distinct_paths(), estimate_path_cost_size(), get_number_of_groups(), get_windowclause_startup_tuples(), and group_by_has_partkey().

◆ get_sortgroupref_clause()

SortGroupClause * get_sortgroupref_clause ( Index  sortref,
List clauses 
)

Definition at line 431 of file tlist.c.

432{
433 ListCell *l;
434
435 foreach(l, clauses)
436 {
438
439 if (cl->tleSortGroupRef == sortref)
440 return cl;
441 }
442
443 elog(ERROR, "ORDER/GROUP BY expression not found in list");
444 return NULL; /* keep compiler quiet */
445}

References elog, ERROR, fb(), and lfirst.

Referenced by init_grouping_targets(), and preprocess_groupclause().

◆ get_sortgroupref_clause_noerr()

SortGroupClause * get_sortgroupref_clause_noerr ( Index  sortref,
List clauses 
)

Definition at line 452 of file tlist.c.

453{
454 ListCell *l;
455
456 foreach(l, clauses)
457 {
459
460 if (cl->tleSortGroupRef == sortref)
461 return cl;
462 }
463
464 return NULL;
465}

References fb(), and lfirst.

Referenced by find_em_for_rel_target(), foreign_grouping_ok(), group_keys_reorder_by_pathkeys(), make_group_input_target(), and make_partial_grouping_target().

◆ get_sortgroupref_tle()

TargetEntry * get_sortgroupref_tle ( Index  sortref,
List targetList 
)

Definition at line 354 of file tlist.c.

355{
356 ListCell *l;
357
358 foreach(l, targetList)
359 {
361
362 if (tle->ressortgroupref == sortref)
363 return tle;
364 }
365
366 elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
367 return NULL; /* keep compiler quiet */
368}

References elog, ERROR, fb(), and lfirst.

Referenced by convert_subquery_pathkeys(), deparseSortGroupClause(), foreign_expr_walker(), get_rule_sortgroupclause(), get_sortgroupclause_tle(), make_unique_from_pathkeys(), prepare_sort_from_pathkeys(), and transformDistinctOnClause().

◆ get_tlist_exprs()

List * get_tlist_exprs ( List tlist,
bool  includeJunk 
)

Definition at line 172 of file tlist.c.

173{
174 List *result = NIL;
175 ListCell *l;
176
177 foreach(l, tlist)
178 {
180
181 if (tle->resjunk && !includeJunk)
182 continue;
183
184 result = lappend(result, tle->expr);
185 }
186 return result;
187}

References fb(), lappend(), lfirst, and NIL.

Referenced by build_setop_child_paths().

◆ grouping_is_hashable()

bool grouping_is_hashable ( List groupClause)

Definition at line 569 of file tlist.c.

570{
572
573 foreach(glitem, groupClause)
574 {
576
577 if (!groupcl->hashable)
578 return false;
579 }
580 return true;
581}

References fb(), and lfirst.

Referenced by create_final_distinct_paths(), create_grouping_paths(), create_partial_distinct_paths(), generate_grouped_paths(), generate_nonunion_paths(), generate_recursion_path(), and generate_union_paths().

◆ grouping_is_sortable()

bool grouping_is_sortable ( List groupClause)

◆ make_pathtarget_from_tlist()

PathTarget * make_pathtarget_from_tlist ( List tlist)

Definition at line 600 of file tlist.c.

601{
602 PathTarget *target = makeNode(PathTarget);
603 int i;
604 ListCell *lc;
605
606 target->sortgrouprefs = (Index *) palloc(list_length(tlist) * sizeof(Index));
607
608 i = 0;
609 foreach(lc, tlist)
610 {
612
613 target->exprs = lappend(target->exprs, tle->expr);
614 target->sortgrouprefs[i] = tle->ressortgroupref;
615 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 */
624
625 return target;
626}

References PathTarget::exprs, fb(), PathTarget::has_volatile_expr, i, lappend(), lfirst, list_length(), makeNode, palloc(), and VOLATILITY_UNKNOWN.

◆ make_tlist_from_pathtarget()

List * make_tlist_from_pathtarget ( PathTarget target)

Definition at line 633 of file tlist.c.

634{
635 List *tlist = NIL;
636 int i;
637 ListCell *lc;
638
639 i = 0;
640 foreach(lc, target->exprs)
641 {
642 Expr *expr = (Expr *) lfirst(lc);
644
645 tle = makeTargetEntry(expr,
646 i + 1,
647 NULL,
648 false);
649 if (target->sortgrouprefs)
650 tle->ressortgroupref = target->sortgrouprefs[i];
651 tlist = lappend(tlist, tle);
652 i++;
653 }
654
655 return tlist;
656}

References PathTarget::exprs, fb(), i, lappend(), lfirst, makeTargetEntry(), and NIL.

Referenced by build_setop_child_paths(), create_unique_paths(), generate_grouped_paths(), and set_subquery_pathlist().

◆ split_pathtarget_at_srfs()

void split_pathtarget_at_srfs ( PlannerInfo root,
PathTarget target,
PathTarget input_target,
List **  targets,
List **  targets_contain_srfs 
)

Definition at line 845 of file tlist.c.

References fb(), root, and split_pathtarget_at_srfs_extended().

Referenced by grouping_planner().

◆ split_pathtarget_at_srfs_extended()

static void split_pathtarget_at_srfs_extended ( PlannerInfo root,
PathTarget target,
PathTarget input_target,
List **  targets,
List **  targets_contain_srfs,
bool  is_grouping_target 
)
static

Definition at line 942 of file tlist.c.

946{
948 int max_depth;
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 if (target == input_target)
964 {
965 *targets = list_make1(target);
967 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 context.root = root;
975 context.is_grouping_target = is_grouping_target;
976 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 context.level_srfs = list_make1(NIL);
988
989 /* Initialize data we'll accumulate across all the target expressions */
990 context.current_input_vars = NIL;
991 context.current_input_srfs = NIL;
992 max_depth = 0;
993 need_extra_projection = false;
994
995 /* Scan each expression in the PathTarget looking for SRFs */
996 lci = 0;
997 foreach(lc, target->exprs)
998 {
999 Node *node = (Node *) lfirst(lc);
1000
1001 /* Tell split_pathtarget_walker about this expr's sortgroupref */
1003 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 context.current_depth = 0;
1010 split_pathtarget_walker(node, &context);
1011
1012 /* An expression containing no SRFs is of no further interest */
1013 if (context.current_depth == 0)
1014 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 if (max_depth < context.current_depth)
1023 {
1024 max_depth = context.current_depth;
1025 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 if (max_depth == context.current_depth && !IS_SRF_CALL(node))
1034 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 if (max_depth == 0)
1043 {
1044 *targets = list_make1(target);
1046 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 */
1055 {
1056 context.level_srfs = lappend(context.level_srfs, NIL);
1057 context.level_input_vars = lappend(context.level_input_vars,
1058 context.current_input_vars);
1059 context.level_input_srfs = lappend(context.level_input_srfs,
1060 context.current_input_srfs);
1061 }
1062 else
1063 {
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 */
1078
1079 forthree(lc1, context.level_srfs,
1080 lc2, context.level_input_vars,
1081 lc3, context.level_input_srfs)
1082 {
1083 List *level_srfs = (List *) lfirst(lc1);
1085
1086 if (lnext(context.level_srfs, lc1) == NULL)
1087 {
1088 ntarget = target;
1089 }
1090 else
1091 {
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 */
1102 lnext(context.level_input_vars, lc2))
1103 {
1104 List *input_vars = (List *) lfirst(lc);
1105
1107 }
1109 lnext(context.level_input_srfs, lc3))
1110 {
1111 List *input_srfs = (List *) lfirst(lc);
1112 ListCell *lcx;
1113
1114 foreach(lcx, input_srfs)
1115 {
1117
1118 if (list_member(prev_level_tlist, item->expr))
1120 }
1121 }
1123 }
1124
1125 /*
1126 * Add current target and does-it-compute-SRFs flag to output lists.
1127 */
1130 (level_srfs != NIL));
1131
1132 /* Remember this level's output for next pass */
1133 prev_level_tlist = ntarget->exprs;
1134 }
1135}

References add_sp_item_to_pathtarget(), add_sp_items_to_pathtarget(), create_empty_pathtarget(), split_pathtarget_context::current_depth, split_pathtarget_context::current_input_srfs, split_pathtarget_context::current_input_vars, split_pathtarget_context::current_sgref, split_pathtarget_item::expr, PathTarget::exprs, fb(), for_each_cell, forthree, get_pathtarget_sortgroupref, split_pathtarget_context::input_target_exprs, split_pathtarget_context::is_grouping_target, IS_SRF_CALL, lappend(), lappend_int(), split_pathtarget_context::level_input_srfs, split_pathtarget_context::level_input_vars, split_pathtarget_context::level_srfs, lfirst, list_concat(), list_make1, list_make1_int, list_member(), list_nth_cell(), lnext(), NIL, split_pathtarget_context::root, root, set_pathtarget_cost_width(), and split_pathtarget_walker().

Referenced by split_pathtarget_at_srfs(), and split_pathtarget_at_srfs_grouping().

◆ split_pathtarget_at_srfs_grouping()

void split_pathtarget_at_srfs_grouping ( PlannerInfo root,
PathTarget target,
PathTarget input_target,
List **  targets,
List **  targets_contain_srfs 
)

Definition at line 868 of file tlist.c.

References fb(), root, and split_pathtarget_at_srfs_extended().

Referenced by grouping_planner().

◆ split_pathtarget_walker()

static bool split_pathtarget_walker ( Node node,
split_pathtarget_context context 
)
static

Definition at line 1144 of file tlist.c.

1145{
1146 Node *sanitized_node = node;
1147
1148 if (node == NULL)
1149 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 if (context->is_grouping_target &&
1158 context->root->parse->hasGroupRTE &&
1159 context->root->parse->groupingSets != NIL)
1160 {
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 */
1176 {
1178
1179 item->expr = node;
1180 item->sortgroupref = context->current_sgref;
1181 context->current_input_vars = lappend(context->current_input_vars,
1182 item);
1183 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 if (IsA(node, Var) ||
1192 IsA(node, PlaceHolderVar) ||
1193 IsA(node, Aggref) ||
1194 IsA(node, GroupingFunc) ||
1195 IsA(node, WindowFunc))
1196 {
1198
1199 item->expr = node;
1200 item->sortgroupref = context->current_sgref;
1201 context->current_input_vars = lappend(context->current_input_vars,
1202 item);
1203 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 if (IS_SRF_CALL(node))
1211 {
1215 int save_current_depth = context->current_depth;
1216 int srf_depth;
1217 ListCell *lc;
1218
1219 item->expr = node;
1220 item->sortgroupref = context->current_sgref;
1221
1222 context->current_input_vars = NIL;
1223 context->current_input_srfs = NIL;
1224 context->current_depth = 0;
1225 context->current_sgref = 0; /* subexpressions are not sortgroup items */
1226
1228
1229 /* Depth is one more than any SRF below it */
1230 srf_depth = context->current_depth + 1;
1231
1232 /* If new record depth, initialize another level of output lists */
1233 if (srf_depth >= list_length(context->level_srfs))
1234 {
1235 context->level_srfs = lappend(context->level_srfs, NIL);
1236 context->level_input_vars = lappend(context->level_input_vars, NIL);
1237 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 lc = list_nth_cell(context->level_srfs, srf_depth);
1242 lfirst(lc) = lappend(lfirst(lc), item);
1243
1244 /* Record its inputs as being needed at the same level */
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 */
1256 context->current_input_srfs = lappend(save_input_srfs, item);
1258
1259 /* We're done here */
1260 return false;
1261 }
1262
1263 /*
1264 * Otherwise, the node is a scalar (non-set) expression, so recurse to
1265 * examine its inputs.
1266 */
1267 context->current_sgref = 0; /* subexpressions are not sortgroup items */
1268 return expression_tree_walker(node, split_pathtarget_walker, context);
1269}

References bms_make_singleton(), split_pathtarget_context::current_depth, split_pathtarget_context::current_input_srfs, split_pathtarget_context::current_input_vars, split_pathtarget_context::current_sgref, split_pathtarget_item::expr, expression_tree_walker, fb(), PlannerInfo::group_rtindex, Query::groupingSets, split_pathtarget_context::input_target_exprs, split_pathtarget_context::is_grouping_target, IS_SRF_CALL, IsA, lappend(), split_pathtarget_context::level_input_srfs, split_pathtarget_context::level_input_vars, split_pathtarget_context::level_srfs, lfirst, list_concat(), list_length(), list_member(), list_nth_cell(), Max, NIL, palloc_object, PlannerInfo::parse, remove_nulling_relids(), split_pathtarget_context::root, split_pathtarget_item::sortgroupref, and split_pathtarget_walker().

Referenced by split_pathtarget_at_srfs_extended(), and split_pathtarget_walker().

◆ tlist_member()

TargetEntry * tlist_member ( Expr node,
List targetlist 
)

Definition at line 88 of file tlist.c.

89{
91
92 foreach(temp, targetlist)
93 {
95
96 if (equal(node, tlentry->expr))
97 return tlentry;
98 }
99 return NULL;
100}

References equal(), fb(), and lfirst.

Referenced by add_to_flat_tlist(), apply_pathtarget_labeling_to_tlist(), build_remote_returning(), create_nestloop_plan(), create_unique_paths(), preprocess_targetlist(), rebuild_fdw_scan_tlist(), and search_indexed_tlist_for_non_var().

◆ tlist_member_match_var()

static TargetEntry * tlist_member_match_var ( Var var,
List targetlist 
)
static

Definition at line 111 of file tlist.c.

112{
113 ListCell *temp;
114
115 foreach(temp, targetlist)
116 {
118 Var *tlvar = (Var *) tlentry->expr;
119
120 if (!tlvar || !IsA(tlvar, Var))
121 continue;
122 if (var->varno == tlvar->varno &&
123 var->varattno == tlvar->varattno &&
124 var->varlevelsup == tlvar->varlevelsup &&
125 var->vartype == tlvar->vartype)
126 return tlentry;
127 }
128 return NULL;
129}

References fb(), IsA, lfirst, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by apply_pathtarget_labeling_to_tlist().

◆ tlist_same_collations()

bool tlist_same_collations ( List tlist,
List colCollations,
bool  junkOK 
)

Definition at line 291 of file tlist.c.

292{
293 ListCell *l;
295
296 foreach(l, tlist)
297 {
299
300 if (tle->resjunk)
301 {
302 if (!junkOK)
303 return false;
304 }
305 else
306 {
307 if (curColColl == NULL)
308 return false; /* tlist longer than colCollations */
309 if (exprCollation((Node *) tle->expr) != lfirst_oid(curColColl))
310 return false;
312 }
313 }
314 if (curColColl != NULL)
315 return false; /* tlist shorter than colCollations */
316 return true;
317}

References exprCollation(), fb(), lfirst, lfirst_oid, list_head(), and lnext().

Referenced by recurse_set_operations().

◆ tlist_same_datatypes()

bool tlist_same_datatypes ( List tlist,
List colTypes,
bool  junkOK 
)

Definition at line 257 of file tlist.c.

258{
259 ListCell *l;
261
262 foreach(l, tlist)
263 {
265
266 if (tle->resjunk)
267 {
268 if (!junkOK)
269 return false;
270 }
271 else
272 {
273 if (curColType == NULL)
274 return false; /* tlist longer than colTypes */
275 if (exprType((Node *) tle->expr) != lfirst_oid(curColType))
276 return false;
278 }
279 }
280 if (curColType != NULL)
281 return false; /* tlist shorter than colTypes */
282 return true;
283}

References exprType(), fb(), lfirst, lfirst_oid, list_head(), and lnext().

Referenced by is_simple_union_all_recurse(), and recurse_set_operations().

◆ tlist_same_exprs()

bool tlist_same_exprs ( List tlist1,
List tlist2 
)

Definition at line 227 of file tlist.c.

228{
229 ListCell *lc1,
230 *lc2;
231
233 return false; /* not same length, so can't match */
234
236 {
239
240 if (!equal(tle1->expr, tle2->expr))
241 return false;
242 }
243
244 return true;
245}

References equal(), fb(), forboth, lfirst, and list_length().

Referenced by apply_scanjoin_target_to_paths(), change_plan_targetlist(), and create_projection_plan().