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

Generated by: LCOV version 1.14