LCOV - code coverage report
Current view: top level - src/backend/optimizer/util - tlist.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 364 380 95.8 %
Date: 2026-01-12 00:17:24 Functions: 34 34 100.0 %
Legend: Lines: hit not hit

          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 : }

Generated by: LCOV version 1.16