LCOV - code coverage report
Current view: top level - src/backend/optimizer/util - tlist.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 93.3 % 508 474
Test Date: 2026-01-26 10:56:24 Functions: 97.1 % 34 33
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 80.9 % 424 343

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * tlist.c
       4                 :             :  *        Target list manipulation routines
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *        src/backend/optimizer/util/tlist.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : #include "postgres.h"
      16                 :             : 
      17                 :             : #include "nodes/makefuncs.h"
      18                 :             : #include "nodes/nodeFuncs.h"
      19                 :             : #include "optimizer/cost.h"
      20                 :             : #include "optimizer/optimizer.h"
      21                 :             : #include "optimizer/tlist.h"
      22                 :             : #include "rewrite/rewriteManip.h"
      23                 :             : 
      24                 :             : 
      25                 :             : /*
      26                 :             :  * Test if an expression node represents a SRF call.  Beware multiple eval!
      27                 :             :  *
      28                 :             :  * Please note that this is only meant for use in split_pathtarget_at_srfs();
      29                 :             :  * if you use it anywhere else, your code is almost certainly wrong for SRFs
      30                 :             :  * nested within expressions.  Use expression_returns_set() instead.
      31                 :             :  */
      32                 :             : #define IS_SRF_CALL(node) \
      33                 :             :         ((IsA(node, FuncExpr) && ((FuncExpr *) (node))->funcretset) || \
      34                 :             :          (IsA(node, OpExpr) && ((OpExpr *) (node))->opretset))
      35                 :             : 
      36                 :             : /*
      37                 :             :  * Data structures for split_pathtarget_at_srfs().  To preserve the identity
      38                 :             :  * of sortgroupref items even if they are textually equal(), what we track is
      39                 :             :  * not just bare expressions but expressions plus their sortgroupref indexes.
      40                 :             :  */
      41                 :             : typedef struct
      42                 :             : {
      43                 :             :         Node       *expr;                       /* some subexpression of a PathTarget */
      44                 :             :         Index           sortgroupref;   /* its sortgroupref, or 0 if none */
      45                 :             : } split_pathtarget_item;
      46                 :             : 
      47                 :             : typedef struct
      48                 :             : {
      49                 :             :         PlannerInfo *root;
      50                 :             :         bool            is_grouping_target; /* true if processing grouping target */
      51                 :             :         /* This is a List of bare expressions: */
      52                 :             :         List       *input_target_exprs; /* exprs available from input */
      53                 :             :         /* These are Lists of Lists of split_pathtarget_items: */
      54                 :             :         List       *level_srfs;         /* SRF exprs to evaluate at each level */
      55                 :             :         List       *level_input_vars;   /* input vars needed at each level */
      56                 :             :         List       *level_input_srfs;   /* input SRFs needed at each level */
      57                 :             :         /* These are Lists of split_pathtarget_items: */
      58                 :             :         List       *current_input_vars; /* vars needed in current subexpr */
      59                 :             :         List       *current_input_srfs; /* SRFs needed in current subexpr */
      60                 :             :         /* Auxiliary data for current split_pathtarget_walker traversal: */
      61                 :             :         int                     current_depth;  /* max SRF depth in current subexpr */
      62                 :             :         Index           current_sgref;  /* current subexpr's sortgroupref, or 0 */
      63                 :             : } split_pathtarget_context;
      64                 :             : 
      65                 :             : static void split_pathtarget_at_srfs_extended(PlannerInfo *root,
      66                 :             :                                                                                           PathTarget *target,
      67                 :             :                                                                                           PathTarget *input_target,
      68                 :             :                                                                                           List **targets,
      69                 :             :                                                                                           List **targets_contain_srfs,
      70                 :             :                                                                                           bool is_grouping_target);
      71                 :             : static bool split_pathtarget_walker(Node *node,
      72                 :             :                                                                         split_pathtarget_context *context);
      73                 :             : static void add_sp_item_to_pathtarget(PathTarget *target,
      74                 :             :                                                                           split_pathtarget_item *item);
      75                 :             : static void add_sp_items_to_pathtarget(PathTarget *target, List *items);
      76                 :             : 
      77                 :             : 
      78                 :             : /*****************************************************************************
      79                 :             :  *              Target list creation and searching utilities
      80                 :             :  *****************************************************************************/
      81                 :             : 
      82                 :             : /*
      83                 :             :  * tlist_member
      84                 :             :  *        Finds the (first) member of the given tlist whose expression is
      85                 :             :  *        equal() to the given expression.  Result is NULL if no such member.
      86                 :             :  */
      87                 :             : TargetEntry *
      88                 :        6332 : tlist_member(Expr *node, List *targetlist)
      89                 :             : {
      90                 :        6332 :         ListCell   *temp;
      91                 :             : 
      92   [ +  +  +  +  :       23782 :         foreach(temp, targetlist)
             +  +  +  + ]
      93                 :             :         {
      94                 :       17450 :                 TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
      95                 :             : 
      96         [ +  + ]:       17450 :                 if (equal(node, tlentry->expr))
      97                 :        1797 :                         return tlentry;
      98         [ +  + ]:       17450 :         }
      99                 :        4535 :         return NULL;
     100                 :        6332 : }
     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                 :         371 : tlist_member_match_var(Var *var, List *targetlist)
     112                 :             : {
     113                 :         371 :         ListCell   *temp;
     114                 :             : 
     115   [ +  -  -  +  :        1511 :         foreach(temp, targetlist)
             -  +  +  - ]
     116                 :             :         {
     117                 :        1140 :                 TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
     118                 :        1140 :                 Var                *tlvar = (Var *) tlentry->expr;
     119                 :             : 
     120   [ +  -  -  + ]:        1140 :                 if (!tlvar || !IsA(tlvar, Var))
     121                 :           0 :                         continue;
     122         [ +  - ]:        1140 :                 if (var->varno == tlvar->varno &&
     123         [ +  + ]:        1140 :                         var->varattno == tlvar->varattno &&
     124   [ +  -  -  + ]:         371 :                         var->varlevelsup == tlvar->varlevelsup &&
     125                 :         371 :                         var->vartype == tlvar->vartype)
     126                 :         371 :                         return tlentry;
     127      [ -  +  + ]:        1140 :         }
     128                 :           0 :         return NULL;
     129                 :         371 : }
     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                 :           0 : add_to_flat_tlist(List *tlist, List *exprs)
     142                 :             : {
     143                 :           0 :         int                     next_resno = list_length(tlist) + 1;
     144                 :           0 :         ListCell   *lc;
     145                 :             : 
     146   [ #  #  #  #  :           0 :         foreach(lc, exprs)
                   #  # ]
     147                 :             :         {
     148                 :           0 :                 Expr       *expr = (Expr *) lfirst(lc);
     149                 :             : 
     150         [ #  # ]:           0 :                 if (!tlist_member(expr, tlist))
     151                 :             :                 {
     152                 :           0 :                         TargetEntry *tle;
     153                 :             : 
     154                 :           0 :                         tle = makeTargetEntry(copyObject(expr), /* copy needed?? */
     155                 :           0 :                                                                   next_resno++,
     156                 :             :                                                                   NULL,
     157                 :             :                                                                   false);
     158                 :           0 :                         tlist = lappend(tlist, tle);
     159                 :           0 :                 }
     160                 :           0 :         }
     161                 :           0 :         return tlist;
     162                 :           0 : }
     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                 :         223 : get_tlist_exprs(List *tlist, bool includeJunk)
     173                 :             : {
     174                 :         223 :         List       *result = NIL;
     175                 :         223 :         ListCell   *l;
     176                 :             : 
     177   [ +  +  +  +  :         952 :         foreach(l, tlist)
                   +  + ]
     178                 :             :         {
     179                 :         729 :                 TargetEntry *tle = (TargetEntry *) lfirst(l);
     180                 :             : 
     181   [ -  +  #  # ]:         729 :                 if (tle->resjunk && !includeJunk)
     182                 :           0 :                         continue;
     183                 :             : 
     184                 :         729 :                 result = lappend(result, tle->expr);
     185      [ -  -  + ]:         729 :         }
     186                 :         446 :         return result;
     187                 :         223 : }
     188                 :             : 
     189                 :             : 
     190                 :             : /*
     191                 :             :  * count_nonjunk_tlist_entries
     192                 :             :  *              What it says ...
     193                 :             :  */
     194                 :             : int
     195                 :        3425 : count_nonjunk_tlist_entries(List *tlist)
     196                 :             : {
     197                 :        3425 :         int                     len = 0;
     198                 :        3425 :         ListCell   *l;
     199                 :             : 
     200   [ +  +  +  +  :        6960 :         foreach(l, tlist)
                   +  + ]
     201                 :             :         {
     202                 :        3535 :                 TargetEntry *tle = (TargetEntry *) lfirst(l);
     203                 :             : 
     204         [ +  + ]:        3535 :                 if (!tle->resjunk)
     205                 :        3451 :                         len++;
     206                 :        3535 :         }
     207                 :        6850 :         return len;
     208                 :        3425 : }
     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                 :         186 : tlist_same_exprs(List *tlist1, List *tlist2)
     228                 :             : {
     229                 :         186 :         ListCell   *lc1,
     230                 :             :                            *lc2;
     231                 :             : 
     232         [ +  + ]:         186 :         if (list_length(tlist1) != list_length(tlist2))
     233                 :          73 :                 return false;                   /* not same length, so can't match */
     234                 :             : 
     235   [ +  -  +  +  :         247 :         forboth(lc1, tlist1, lc2, tlist2)
          +  -  +  +  +  
             +  +  +  +  
                      + ]
     236                 :             :         {
     237                 :         134 :                 TargetEntry *tle1 = (TargetEntry *) lfirst(lc1);
     238                 :         134 :                 TargetEntry *tle2 = (TargetEntry *) lfirst(lc2);
     239                 :             : 
     240         [ +  + ]:         134 :                 if (!equal(tle1->expr, tle2->expr))
     241                 :          89 :                         return false;
     242         [ +  + ]:         134 :         }
     243                 :             : 
     244                 :          24 :         return true;
     245                 :         186 : }
     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                 :        2200 : tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
     258                 :             : {
     259                 :        2200 :         ListCell   *l;
     260                 :        2200 :         ListCell   *curColType = list_head(colTypes);
     261                 :             : 
     262   [ +  +  +  +  :        6474 :         foreach(l, tlist)
             +  +  +  + ]
     263                 :             :         {
     264                 :        4274 :                 TargetEntry *tle = (TargetEntry *) lfirst(l);
     265                 :             : 
     266         [ +  + ]:        4274 :                 if (tle->resjunk)
     267                 :             :                 {
     268         [ +  - ]:           2 :                         if (!junkOK)
     269                 :           0 :                                 return false;
     270                 :           2 :                 }
     271                 :             :                 else
     272                 :             :                 {
     273         [ +  - ]:        4272 :                         if (curColType == NULL)
     274                 :           0 :                                 return false;   /* tlist longer than colTypes */
     275         [ +  + ]:        4272 :                         if (exprType((Node *) tle->expr) != lfirst_oid(curColType))
     276                 :          25 :                                 return false;
     277                 :        4247 :                         curColType = lnext(colTypes, curColType);
     278                 :             :                 }
     279         [ +  + ]:        4274 :         }
     280         [ -  + ]:        2175 :         if (curColType != NULL)
     281                 :           0 :                 return false;                   /* tlist shorter than colTypes */
     282                 :        2175 :         return true;
     283                 :        2200 : }
     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                 :         750 : tlist_same_collations(List *tlist, List *colCollations, bool junkOK)
     292                 :             : {
     293                 :         750 :         ListCell   *l;
     294                 :         750 :         ListCell   *curColColl = list_head(colCollations);
     295                 :             : 
     296   [ +  +  +  +  :        2818 :         foreach(l, tlist)
             +  +  -  + ]
     297                 :             :         {
     298                 :        2068 :                 TargetEntry *tle = (TargetEntry *) lfirst(l);
     299                 :             : 
     300         [ -  + ]:        2068 :                 if (tle->resjunk)
     301                 :             :                 {
     302         [ #  # ]:           0 :                         if (!junkOK)
     303                 :           0 :                                 return false;
     304                 :           0 :                 }
     305                 :             :                 else
     306                 :             :                 {
     307         [ +  - ]:        2068 :                         if (curColColl == NULL)
     308                 :           0 :                                 return false;   /* tlist longer than colCollations */
     309         [ -  + ]:        2068 :                         if (exprCollation((Node *) tle->expr) != lfirst_oid(curColColl))
     310                 :           0 :                                 return false;
     311                 :        2068 :                         curColColl = lnext(colCollations, curColColl);
     312                 :             :                 }
     313         [ -  + ]:        2068 :         }
     314         [ -  + ]:         750 :         if (curColColl != NULL)
     315                 :           0 :                 return false;                   /* tlist shorter than colCollations */
     316                 :         750 :         return true;
     317                 :         750 : }
     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                 :       54300 : apply_tlist_labeling(List *dest_tlist, List *src_tlist)
     328                 :             : {
     329                 :       54300 :         ListCell   *ld,
     330                 :             :                            *ls;
     331                 :             : 
     332         [ +  - ]:       54300 :         Assert(list_length(dest_tlist) == list_length(src_tlist));
     333   [ +  +  +  +  :      193887 :         forboth(ld, dest_tlist, ls, src_tlist)
          +  +  +  +  +  
                +  +  + ]
     334                 :             :         {
     335                 :      139587 :                 TargetEntry *dest_tle = (TargetEntry *) lfirst(ld);
     336                 :      139587 :                 TargetEntry *src_tle = (TargetEntry *) lfirst(ls);
     337                 :             : 
     338         [ +  - ]:      139587 :                 Assert(dest_tle->resno == src_tle->resno);
     339                 :      139587 :                 dest_tle->resname = src_tle->resname;
     340                 :      139587 :                 dest_tle->ressortgroupref = src_tle->ressortgroupref;
     341                 :      139587 :                 dest_tle->resorigtbl = src_tle->resorigtbl;
     342                 :      139587 :                 dest_tle->resorigcol = src_tle->resorigcol;
     343                 :      139587 :                 dest_tle->resjunk = src_tle->resjunk;
     344                 :      139587 :         }
     345                 :       54300 : }
     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                 :       37190 : get_sortgroupref_tle(Index sortref, List *targetList)
     355                 :             : {
     356                 :       37190 :         ListCell   *l;
     357                 :             : 
     358   [ +  -  -  +  :      134255 :         foreach(l, targetList)
             +  -  +  - ]
     359                 :             :         {
     360                 :       97065 :                 TargetEntry *tle = (TargetEntry *) lfirst(l);
     361                 :             : 
     362         [ +  + ]:       97065 :                 if (tle->ressortgroupref == sortref)
     363                 :       37190 :                         return tle;
     364         [ +  + ]:       97065 :         }
     365                 :             : 
     366   [ #  #  #  # ]:           0 :         elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
     367                 :           0 :         return NULL;                            /* keep compiler quiet */
     368                 :       37190 : }
     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                 :       37040 : get_sortgroupclause_tle(SortGroupClause *sgClause,
     377                 :             :                                                 List *targetList)
     378                 :             : {
     379                 :       37040 :         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                 :       30038 : get_sortgroupclause_expr(SortGroupClause *sgClause, List *targetList)
     389                 :             : {
     390                 :       30038 :         TargetEntry *tle = get_sortgroupclause_tle(sgClause, targetList);
     391                 :             : 
     392                 :       60076 :         return (Node *) tle->expr;
     393                 :       30038 : }
     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                 :        2543 : get_sortgrouplist_exprs(List *sgClauses, List *targetList)
     402                 :             : {
     403                 :        2543 :         List       *result = NIL;
     404                 :        2543 :         ListCell   *l;
     405                 :             : 
     406   [ +  +  +  +  :        5927 :         foreach(l, sgClauses)
                   +  + ]
     407                 :             :         {
     408                 :        3384 :                 SortGroupClause *sortcl = (SortGroupClause *) lfirst(l);
     409                 :        3384 :                 Node       *sortexpr;
     410                 :             : 
     411                 :        3384 :                 sortexpr = get_sortgroupclause_expr(sortcl, targetList);
     412                 :        3384 :                 result = lappend(result, sortexpr);
     413                 :        3384 :         }
     414                 :        5086 :         return result;
     415                 :        2543 : }
     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                 :        1828 : get_sortgroupref_clause(Index sortref, List *clauses)
     432                 :             : {
     433                 :        1828 :         ListCell   *l;
     434                 :             : 
     435   [ +  -  -  +  :        4669 :         foreach(l, clauses)
             +  -  +  - ]
     436                 :             :         {
     437                 :        2841 :                 SortGroupClause *cl = (SortGroupClause *) lfirst(l);
     438                 :             : 
     439         [ +  + ]:        2841 :                 if (cl->tleSortGroupRef == sortref)
     440                 :        1828 :                         return cl;
     441         [ +  + ]:        2841 :         }
     442                 :             : 
     443   [ #  #  #  # ]:           0 :         elog(ERROR, "ORDER/GROUP BY expression not found in list");
     444                 :           0 :         return NULL;                            /* keep compiler quiet */
     445                 :        1828 : }
     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                 :        2313 : get_sortgroupref_clause_noerr(Index sortref, List *clauses)
     453                 :             : {
     454                 :        2313 :         ListCell   *l;
     455                 :             : 
     456   [ +  -  +  +  :        5747 :         foreach(l, clauses)
             +  +  +  + ]
     457                 :             :         {
     458                 :        3434 :                 SortGroupClause *cl = (SortGroupClause *) lfirst(l);
     459                 :             : 
     460         [ +  + ]:        3434 :                 if (cl->tleSortGroupRef == sortref)
     461                 :        1702 :                         return cl;
     462         [ +  + ]:        3434 :         }
     463                 :             : 
     464                 :         611 :         return NULL;
     465                 :        2313 : }
     466                 :             : 
     467                 :             : /*
     468                 :             :  * extract_grouping_ops - make an array of the equality operator OIDs
     469                 :             :  *              for a SortGroupClause list
     470                 :             :  */
     471                 :             : Oid *
     472                 :        5727 : extract_grouping_ops(List *groupClause)
     473                 :             : {
     474                 :        5727 :         int                     numCols = list_length(groupClause);
     475                 :        5727 :         int                     colno = 0;
     476                 :        5727 :         Oid                *groupOperators;
     477                 :        5727 :         ListCell   *glitem;
     478                 :             : 
     479                 :        5727 :         groupOperators = palloc_array(Oid, numCols);
     480                 :             : 
     481   [ +  +  +  +  :        7627 :         foreach(glitem, groupClause)
                   +  + ]
     482                 :             :         {
     483                 :        1900 :                 SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
     484                 :             : 
     485                 :        1900 :                 groupOperators[colno] = groupcl->eqop;
     486         [ +  - ]:        1900 :                 Assert(OidIsValid(groupOperators[colno]));
     487                 :        1900 :                 colno++;
     488                 :        1900 :         }
     489                 :             : 
     490                 :       11454 :         return groupOperators;
     491                 :        5727 : }
     492                 :             : 
     493                 :             : /*
     494                 :             :  * extract_grouping_collations - make an array of the grouping column collations
     495                 :             :  *              for a SortGroupClause list
     496                 :             :  */
     497                 :             : Oid *
     498                 :        5727 : extract_grouping_collations(List *groupClause, List *tlist)
     499                 :             : {
     500                 :        5727 :         int                     numCols = list_length(groupClause);
     501                 :        5727 :         int                     colno = 0;
     502                 :        5727 :         Oid                *grpCollations;
     503                 :        5727 :         ListCell   *glitem;
     504                 :             : 
     505                 :        5727 :         grpCollations = palloc_array(Oid, numCols);
     506                 :             : 
     507   [ +  +  +  +  :        7627 :         foreach(glitem, groupClause)
                   +  + ]
     508                 :             :         {
     509                 :        1900 :                 SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
     510                 :        1900 :                 TargetEntry *tle = get_sortgroupclause_tle(groupcl, tlist);
     511                 :             : 
     512                 :        1900 :                 grpCollations[colno++] = exprCollation((Node *) tle->expr);
     513                 :        1900 :         }
     514                 :             : 
     515                 :       11454 :         return grpCollations;
     516                 :        5727 : }
     517                 :             : 
     518                 :             : /*
     519                 :             :  * extract_grouping_cols - make an array of the grouping column resnos
     520                 :             :  *              for a SortGroupClause list
     521                 :             :  */
     522                 :             : AttrNumber *
     523                 :        5391 : extract_grouping_cols(List *groupClause, List *tlist)
     524                 :             : {
     525                 :        5391 :         AttrNumber *grpColIdx;
     526                 :        5391 :         int                     numCols = list_length(groupClause);
     527                 :        5391 :         int                     colno = 0;
     528                 :        5391 :         ListCell   *glitem;
     529                 :             : 
     530                 :        5391 :         grpColIdx = palloc_array(AttrNumber, numCols);
     531                 :             : 
     532   [ +  +  +  +  :        6858 :         foreach(glitem, groupClause)
                   +  + ]
     533                 :             :         {
     534                 :        1467 :                 SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
     535                 :        1467 :                 TargetEntry *tle = get_sortgroupclause_tle(groupcl, tlist);
     536                 :             : 
     537                 :        1467 :                 grpColIdx[colno++] = tle->resno;
     538                 :        1467 :         }
     539                 :             : 
     540                 :       10782 :         return grpColIdx;
     541                 :        5391 : }
     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                 :        8537 : grouping_is_sortable(List *groupClause)
     550                 :             : {
     551                 :        8537 :         ListCell   *glitem;
     552                 :             : 
     553   [ +  +  +  +  :       14806 :         foreach(glitem, groupClause)
             +  +  +  + ]
     554                 :             :         {
     555                 :        6269 :                 SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
     556                 :             : 
     557         [ +  + ]:        6269 :                 if (!OidIsValid(groupcl->sortop))
     558                 :           6 :                         return false;
     559         [ +  + ]:        6269 :         }
     560                 :        8531 :         return true;
     561                 :        8537 : }
     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                 :        1569 : grouping_is_hashable(List *groupClause)
     570                 :             : {
     571                 :        1569 :         ListCell   *glitem;
     572                 :             : 
     573   [ +  +  +  +  :        4845 :         foreach(glitem, groupClause)
             +  +  +  + ]
     574                 :             :         {
     575                 :        3276 :                 SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
     576                 :             : 
     577         [ +  + ]:        3276 :                 if (!groupcl->hashable)
     578                 :          23 :                         return false;
     579         [ +  + ]:        3276 :         }
     580                 :        1546 :         return true;
     581                 :        1569 : }
     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                 :       54586 : make_pathtarget_from_tlist(List *tlist)
     601                 :             : {
     602                 :       54586 :         PathTarget *target = makeNode(PathTarget);
     603                 :       54586 :         int                     i;
     604                 :       54586 :         ListCell   *lc;
     605                 :             : 
     606                 :       54586 :         target->sortgrouprefs = (Index *) palloc(list_length(tlist) * sizeof(Index));
     607                 :             : 
     608                 :       54586 :         i = 0;
     609   [ +  +  +  +  :      195094 :         foreach(lc, tlist)
                   +  + ]
     610                 :             :         {
     611                 :      140508 :                 TargetEntry *tle = (TargetEntry *) lfirst(lc);
     612                 :             : 
     613                 :      140508 :                 target->exprs = lappend(target->exprs, tle->expr);
     614                 :      140508 :                 target->sortgrouprefs[i] = tle->ressortgroupref;
     615                 :      140508 :                 i++;
     616                 :      140508 :         }
     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                 :       54586 :         target->has_volatile_expr = VOLATILITY_UNKNOWN;
     624                 :             : 
     625                 :      109172 :         return target;
     626                 :       54586 : }
     627                 :             : 
     628                 :             : /*
     629                 :             :  * make_tlist_from_pathtarget
     630                 :             :  *        Construct a targetlist from a PathTarget.
     631                 :             :  */
     632                 :             : List *
     633                 :        8148 : make_tlist_from_pathtarget(PathTarget *target)
     634                 :             : {
     635                 :        8148 :         List       *tlist = NIL;
     636                 :        8148 :         int                     i;
     637                 :        8148 :         ListCell   *lc;
     638                 :             : 
     639                 :        8148 :         i = 0;
     640   [ +  +  +  +  :       31551 :         foreach(lc, target->exprs)
                   +  + ]
     641                 :             :         {
     642                 :       23403 :                 Expr       *expr = (Expr *) lfirst(lc);
     643                 :       23403 :                 TargetEntry *tle;
     644                 :             : 
     645                 :       46806 :                 tle = makeTargetEntry(expr,
     646                 :       23403 :                                                           i + 1,
     647                 :             :                                                           NULL,
     648                 :             :                                                           false);
     649         [ +  + ]:       23403 :                 if (target->sortgrouprefs)
     650                 :       22351 :                         tle->ressortgroupref = target->sortgrouprefs[i];
     651                 :       23403 :                 tlist = lappend(tlist, tle);
     652                 :       23403 :                 i++;
     653                 :       23403 :         }
     654                 :             : 
     655                 :       16296 :         return tlist;
     656                 :        8148 : }
     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                 :        3912 : copy_pathtarget(PathTarget *src)
     667                 :             : {
     668                 :        3912 :         PathTarget *dst = makeNode(PathTarget);
     669                 :             : 
     670                 :             :         /* Copy scalar fields */
     671                 :        3912 :         memcpy(dst, src, sizeof(PathTarget));
     672                 :             :         /* Shallow-copy the expression list */
     673                 :        3912 :         dst->exprs = list_copy(src->exprs);
     674                 :             :         /* Duplicate sortgrouprefs if any (if not, the memcpy handled this) */
     675         [ +  + ]:        3912 :         if (src->sortgrouprefs)
     676                 :             :         {
     677                 :        3707 :                 Size            nbytes = list_length(src->exprs) * sizeof(Index);
     678                 :             : 
     679                 :        3707 :                 dst->sortgrouprefs = (Index *) palloc(nbytes);
     680                 :        3707 :                 memcpy(dst->sortgrouprefs, src->sortgrouprefs, nbytes);
     681                 :        3707 :         }
     682                 :        7824 :         return dst;
     683                 :        3912 : }
     684                 :             : 
     685                 :             : /*
     686                 :             :  * create_empty_pathtarget
     687                 :             :  *        Create an empty (zero columns, zero cost) PathTarget.
     688                 :             :  */
     689                 :             : PathTarget *
     690                 :      177487 : create_empty_pathtarget(void)
     691                 :             : {
     692                 :             :         /* This is easy, but we don't want callers to hard-wire this ... */
     693                 :      177487 :         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                 :       11760 : add_column_to_pathtarget(PathTarget *target, Expr *expr, Index sortgroupref)
     705                 :             : {
     706                 :             :         /* Updating the exprs list is easy ... */
     707                 :       11760 :         target->exprs = lappend(target->exprs, expr);
     708                 :             :         /* ... the sortgroupref data, a bit less so */
     709         [ +  + ]:       11760 :         if (target->sortgrouprefs)
     710                 :             :         {
     711                 :        4263 :                 int                     nexprs = list_length(target->exprs);
     712                 :             : 
     713                 :             :                 /* This might look inefficient, but actually it's usually cheap */
     714                 :        4263 :                 target->sortgrouprefs = (Index *)
     715                 :        4263 :                         repalloc(target->sortgrouprefs, nexprs * sizeof(Index));
     716                 :        4263 :                 target->sortgrouprefs[nexprs - 1] = sortgroupref;
     717                 :        4263 :         }
     718         [ +  + ]:        7497 :         else if (sortgroupref)
     719                 :             :         {
     720                 :             :                 /* Adding sortgroupref labeling to a previously unlabeled target */
     721                 :        3139 :                 int                     nexprs = list_length(target->exprs);
     722                 :             : 
     723                 :        3139 :                 target->sortgrouprefs = (Index *) palloc0(nexprs * sizeof(Index));
     724                 :        3139 :                 target->sortgrouprefs[nexprs - 1] = sortgroupref;
     725                 :        3139 :         }
     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         [ +  - ]:       11760 :         if (target->has_volatile_expr == VOLATILITY_NOVOLATILE)
     735                 :           0 :                 target->has_volatile_expr = VOLATILITY_UNKNOWN;
     736                 :       11760 : }
     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                 :        7332 : add_new_column_to_pathtarget(PathTarget *target, Expr *expr)
     751                 :             : {
     752         [ +  + ]:        7332 :         if (!list_member(target->exprs, expr))
     753                 :        6011 :                 add_column_to_pathtarget(target, expr, 0);
     754                 :        7332 : }
     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                 :        6033 : add_new_columns_to_pathtarget(PathTarget *target, List *exprs)
     762                 :             : {
     763                 :        6033 :         ListCell   *lc;
     764                 :             : 
     765   [ +  +  +  +  :       12580 :         foreach(lc, exprs)
                   +  + ]
     766                 :             :         {
     767                 :        6547 :                 Expr       *expr = (Expr *) lfirst(lc);
     768                 :             : 
     769                 :        6547 :                 add_new_column_to_pathtarget(target, expr);
     770                 :        6547 :         }
     771                 :        6033 : }
     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                 :        1450 : apply_pathtarget_labeling_to_tlist(List *tlist, PathTarget *target)
     784                 :             : {
     785                 :        1450 :         int                     i;
     786                 :        1450 :         ListCell   *lc;
     787                 :             : 
     788                 :             :         /* Nothing to do if PathTarget has no sortgrouprefs data */
     789         [ +  + ]:        1450 :         if (target->sortgrouprefs == NULL)
     790                 :        1201 :                 return;
     791                 :             : 
     792                 :         249 :         i = 0;
     793   [ +  -  +  +  :         726 :         foreach(lc, target->exprs)
                   +  + ]
     794                 :             :         {
     795                 :         477 :                 Expr       *expr = (Expr *) lfirst(lc);
     796                 :         477 :                 TargetEntry *tle;
     797                 :             : 
     798         [ +  + ]:         477 :                 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   [ +  -  -  + ]:         371 :                         if (expr && IsA(expr, Var))
     810                 :         371 :                                 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         [ +  - ]:         371 :                         if (!tle)
     821   [ #  #  #  # ]:           0 :                                 elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
     822   [ +  +  +  - ]:         371 :                         if (tle->ressortgroupref != 0 &&
     823                 :           2 :                                 tle->ressortgroupref != target->sortgrouprefs[i])
     824   [ #  #  #  # ]:           0 :                                 elog(ERROR, "targetlist item has multiple sortgroupref labels");
     825                 :             : 
     826                 :         371 :                         tle->ressortgroupref = target->sortgrouprefs[i];
     827                 :         371 :                 }
     828                 :         477 :                 i++;
     829                 :         477 :         }
     830         [ -  + ]:        1450 : }
     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                 :        4938 : split_pathtarget_at_srfs(PlannerInfo *root,
     846                 :             :                                                  PathTarget *target, PathTarget *input_target,
     847                 :             :                                                  List **targets, List **targets_contain_srfs)
     848                 :             : {
     849                 :        9876 :         split_pathtarget_at_srfs_extended(root, target, input_target,
     850                 :        4938 :                                                                           targets, targets_contain_srfs,
     851                 :             :                                                                           false);
     852                 :        4938 : }
     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                 :        1646 : split_pathtarget_at_srfs_grouping(PlannerInfo *root,
     869                 :             :                                                                   PathTarget *target, PathTarget *input_target,
     870                 :             :                                                                   List **targets, List **targets_contain_srfs)
     871                 :             : {
     872                 :        3292 :         split_pathtarget_at_srfs_extended(root, target, input_target,
     873                 :        1646 :                                                                           targets, targets_contain_srfs,
     874                 :             :                                                                           true);
     875                 :        1646 : }
     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                 :        6584 : 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                 :        6584 :         split_pathtarget_context context;
     948                 :        6584 :         int                     max_depth;
     949                 :        6584 :         bool            need_extra_projection;
     950                 :        6584 :         List       *prev_level_tlist;
     951                 :        6584 :         int                     lci;
     952                 :        6584 :         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         [ +  + ]:        6584 :         if (target == input_target)
     964                 :             :         {
     965                 :        4897 :                 *targets = list_make1(target);
     966                 :        4897 :                 *targets_contain_srfs = list_make1_int(false);
     967                 :        4897 :                 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                 :        1687 :         context.root = root;
     975                 :        1687 :         context.is_grouping_target = is_grouping_target;
     976         [ +  + ]:        1687 :         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                 :        1687 :         context.level_srfs = list_make1(NIL);
     986                 :        1687 :         context.level_input_vars = list_make1(NIL);
     987                 :        1687 :         context.level_input_srfs = list_make1(NIL);
     988                 :             : 
     989                 :             :         /* Initialize data we'll accumulate across all the target expressions */
     990                 :        1687 :         context.current_input_vars = NIL;
     991                 :        1687 :         context.current_input_srfs = NIL;
     992                 :        1687 :         max_depth = 0;
     993                 :        1687 :         need_extra_projection = false;
     994                 :             : 
     995                 :             :         /* Scan each expression in the PathTarget looking for SRFs */
     996                 :        1687 :         lci = 0;
     997   [ +  -  +  +  :        3755 :         foreach(lc, target->exprs)
                   +  + ]
     998                 :             :         {
     999                 :        2068 :                 Node       *node = (Node *) lfirst(lc);
    1000                 :             : 
    1001                 :             :                 /* Tell split_pathtarget_walker about this expr's sortgroupref */
    1002         [ +  + ]:        2068 :                 context.current_sgref = get_pathtarget_sortgroupref(target, lci);
    1003                 :        2068 :                 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                 :        2068 :                 context.current_depth = 0;
    1010                 :        2068 :                 split_pathtarget_walker(node, &context);
    1011                 :             : 
    1012                 :             :                 /* An expression containing no SRFs is of no further interest */
    1013         [ +  + ]:        2068 :                 if (context.current_depth == 0)
    1014                 :         321 :                         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         [ +  + ]:        1747 :                 if (max_depth < context.current_depth)
    1023                 :             :                 {
    1024                 :        1648 :                         max_depth = context.current_depth;
    1025                 :        1648 :                         need_extra_projection = false;
    1026                 :        1648 :                 }
    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   [ +  +  +  +  :        1747 :                 if (max_depth == context.current_depth && !IS_SRF_CALL(node))
             +  +  +  + ]
    1034                 :         133 :                         need_extra_projection = true;
    1035         [ +  + ]:        2068 :         }
    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         [ +  + ]:        1687 :         if (max_depth == 0)
    1043                 :             :         {
    1044                 :          41 :                 *targets = list_make1(target);
    1045                 :          41 :                 *targets_contain_srfs = list_make1_int(false);
    1046                 :          41 :                 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         [ +  + ]:        1646 :         if (need_extra_projection)
    1055                 :             :         {
    1056                 :          68 :                 context.level_srfs = lappend(context.level_srfs, NIL);
    1057                 :         136 :                 context.level_input_vars = lappend(context.level_input_vars,
    1058                 :          68 :                                                                                    context.current_input_vars);
    1059                 :         136 :                 context.level_input_srfs = lappend(context.level_input_srfs,
    1060                 :          68 :                                                                                    context.current_input_srfs);
    1061                 :          68 :         }
    1062                 :             :         else
    1063                 :             :         {
    1064                 :        1578 :                 lc = list_nth_cell(context.level_input_vars, max_depth);
    1065                 :        1578 :                 lfirst(lc) = list_concat(lfirst(lc), context.current_input_vars);
    1066                 :        1578 :                 lc = list_nth_cell(context.level_input_srfs, max_depth);
    1067                 :        1578 :                 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                 :        1646 :         *targets = *targets_contain_srfs = NIL;
    1077                 :        1646 :         prev_level_tlist = NIL;
    1078                 :             : 
    1079   [ +  -  +  +  :        5016 :         forthree(lc1, context.level_srfs,
          +  -  +  +  +  
          -  +  +  +  +  
             -  +  +  + ]
    1080                 :             :                          lc2, context.level_input_vars,
    1081                 :             :                          lc3, context.level_input_srfs)
    1082                 :             :         {
    1083                 :        3370 :                 List       *level_srfs = (List *) lfirst(lc1);
    1084                 :        3370 :                 PathTarget *ntarget;
    1085                 :             : 
    1086         [ +  + ]:        3370 :                 if (lnext(context.level_srfs, lc1) == NULL)
    1087                 :             :                 {
    1088                 :        1646 :                         ntarget = target;
    1089                 :        1646 :                 }
    1090                 :             :                 else
    1091                 :             :                 {
    1092                 :        1724 :                         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                 :        1724 :                         add_sp_items_to_pathtarget(ntarget, level_srfs);
    1101   [ +  -  +  +  :        3532 :                         for_each_cell(lc, context.level_input_vars,
                   +  + ]
    1102                 :             :                                                   lnext(context.level_input_vars, lc2))
    1103                 :             :                         {
    1104                 :        1808 :                                 List       *input_vars = (List *) lfirst(lc);
    1105                 :             : 
    1106                 :        1808 :                                 add_sp_items_to_pathtarget(ntarget, input_vars);
    1107                 :        1808 :                         }
    1108   [ +  -  +  +  :        3532 :                         for_each_cell(lc, context.level_input_srfs,
                   +  + ]
    1109                 :             :                                                   lnext(context.level_input_srfs, lc3))
    1110                 :             :                         {
    1111                 :        1808 :                                 List       *input_srfs = (List *) lfirst(lc);
    1112                 :        1808 :                                 ListCell   *lcx;
    1113                 :             : 
    1114   [ +  +  +  +  :        3747 :                                 foreach(lcx, input_srfs)
                   +  + ]
    1115                 :             :                                 {
    1116                 :        1939 :                                         split_pathtarget_item *item = lfirst(lcx);
    1117                 :             : 
    1118         [ +  + ]:        1939 :                                         if (list_member(prev_level_tlist, item->expr))
    1119                 :           6 :                                                 add_sp_item_to_pathtarget(ntarget, item);
    1120                 :        1939 :                                 }
    1121                 :        1808 :                         }
    1122                 :        1724 :                         set_pathtarget_cost_width(root, ntarget);
    1123                 :             :                 }
    1124                 :             : 
    1125                 :             :                 /*
    1126                 :             :                  * Add current target and does-it-compute-SRFs flag to output lists.
    1127                 :             :                  */
    1128                 :        3370 :                 *targets = lappend(*targets, ntarget);
    1129                 :        6740 :                 *targets_contain_srfs = lappend_int(*targets_contain_srfs,
    1130                 :        3370 :                                                                                         (level_srfs != NIL));
    1131                 :             : 
    1132                 :             :                 /* Remember this level's output for next pass */
    1133                 :        3370 :                 prev_level_tlist = ntarget->exprs;
    1134                 :        3370 :         }
    1135                 :        6584 : }
    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                 :        6746 : split_pathtarget_walker(Node *node, split_pathtarget_context *context)
    1145                 :             : {
    1146                 :        6746 :         Node       *sanitized_node = node;
    1147                 :             : 
    1148         [ +  + ]:        6746 :         if (node == NULL)
    1149                 :           2 :                 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         [ +  + ]:        6744 :         if (context->is_grouping_target &&
    1158   [ +  +  +  + ]:         112 :                 context->root->parse->hasGroupRTE &&
    1159                 :         101 :                 context->root->parse->groupingSets != NIL)
    1160                 :             :         {
    1161                 :          39 :                 sanitized_node =
    1162                 :          78 :                         remove_nulling_relids(node,
    1163                 :          39 :                                                                   bms_make_singleton(context->root->group_rtindex),
    1164                 :             :                                                                   NULL);
    1165                 :          39 :         }
    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         [ +  + ]:        6744 :         if (list_member(context->input_target_exprs, sanitized_node))
    1176                 :             :         {
    1177                 :          72 :                 split_pathtarget_item *item = palloc_object(split_pathtarget_item);
    1178                 :             : 
    1179                 :          72 :                 item->expr = node;
    1180                 :          72 :                 item->sortgroupref = context->current_sgref;
    1181                 :         144 :                 context->current_input_vars = lappend(context->current_input_vars,
    1182                 :          72 :                                                                                           item);
    1183                 :          72 :                 return false;
    1184                 :          72 :         }
    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         [ +  + ]:        6672 :         if (IsA(node, Var) ||
    1192         [ +  + ]:        6280 :                 IsA(node, PlaceHolderVar) ||
    1193         [ +  + ]:        6272 :                 IsA(node, Aggref) ||
    1194   [ +  -  +  + ]:        6243 :                 IsA(node, GroupingFunc) ||
    1195                 :        6243 :                 IsA(node, WindowFunc))
    1196                 :             :         {
    1197                 :         432 :                 split_pathtarget_item *item = palloc_object(split_pathtarget_item);
    1198                 :             : 
    1199                 :         432 :                 item->expr = node;
    1200                 :         432 :                 item->sortgroupref = context->current_sgref;
    1201                 :         864 :                 context->current_input_vars = lappend(context->current_input_vars,
    1202                 :         432 :                                                                                           item);
    1203                 :         432 :                 return false;
    1204                 :         432 :         }
    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   [ +  +  +  +  :        6240 :         if (IS_SRF_CALL(node))
                   +  + ]
    1211                 :             :         {
    1212                 :        1758 :                 split_pathtarget_item *item = palloc_object(split_pathtarget_item);
    1213                 :        1758 :                 List       *save_input_vars = context->current_input_vars;
    1214                 :        1758 :                 List       *save_input_srfs = context->current_input_srfs;
    1215                 :        1758 :                 int                     save_current_depth = context->current_depth;
    1216                 :        1758 :                 int                     srf_depth;
    1217                 :        1758 :                 ListCell   *lc;
    1218                 :             : 
    1219                 :        1758 :                 item->expr = node;
    1220                 :        1758 :                 item->sortgroupref = context->current_sgref;
    1221                 :             : 
    1222                 :        1758 :                 context->current_input_vars = NIL;
    1223                 :        1758 :                 context->current_input_srfs = NIL;
    1224                 :        1758 :                 context->current_depth = 0;
    1225                 :        1758 :                 context->current_sgref = 0; /* subexpressions are not sortgroup items */
    1226                 :             : 
    1227                 :        1758 :                 (void) expression_tree_walker(node, split_pathtarget_walker, context);
    1228                 :             : 
    1229                 :             :                 /* Depth is one more than any SRF below it */
    1230                 :        1758 :                 srf_depth = context->current_depth + 1;
    1231                 :             : 
    1232                 :             :                 /* If new record depth, initialize another level of output lists */
    1233         [ +  + ]:        1758 :                 if (srf_depth >= list_length(context->level_srfs))
    1234                 :             :                 {
    1235                 :        1656 :                         context->level_srfs = lappend(context->level_srfs, NIL);
    1236                 :        1656 :                         context->level_input_vars = lappend(context->level_input_vars, NIL);
    1237                 :        1656 :                         context->level_input_srfs = lappend(context->level_input_srfs, NIL);
    1238                 :        1656 :                 }
    1239                 :             : 
    1240                 :             :                 /* Record this SRF as needing to be evaluated at appropriate level */
    1241                 :        1758 :                 lc = list_nth_cell(context->level_srfs, srf_depth);
    1242                 :        1758 :                 lfirst(lc) = lappend(lfirst(lc), item);
    1243                 :             : 
    1244                 :             :                 /* Record its inputs as being needed at the same level */
    1245                 :        1758 :                 lc = list_nth_cell(context->level_input_vars, srf_depth);
    1246                 :        1758 :                 lfirst(lc) = list_concat(lfirst(lc), context->current_input_vars);
    1247                 :        1758 :                 lc = list_nth_cell(context->level_input_srfs, srf_depth);
    1248                 :        1758 :                 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                 :        1758 :                 context->current_input_vars = save_input_vars;
    1256                 :        1758 :                 context->current_input_srfs = lappend(save_input_srfs, item);
    1257         [ -  + ]:        1758 :                 context->current_depth = Max(save_current_depth, srf_depth);
    1258                 :             : 
    1259                 :             :                 /* We're done here */
    1260                 :        1758 :                 return false;
    1261                 :        1758 :         }
    1262                 :             : 
    1263                 :             :         /*
    1264                 :             :          * Otherwise, the node is a scalar (non-set) expression, so recurse to
    1265                 :             :          * examine its inputs.
    1266                 :             :          */
    1267                 :        4482 :         context->current_sgref = 0; /* subexpressions are not sortgroup items */
    1268                 :        4482 :         return expression_tree_walker(node, split_pathtarget_walker, context);
    1269                 :        6746 : }
    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                 :         652 : add_sp_item_to_pathtarget(PathTarget *target, split_pathtarget_item *item)
    1286                 :             : {
    1287                 :         652 :         int                     lci;
    1288                 :         652 :         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                 :         652 :         lci = 0;
    1295   [ +  +  +  +  :        1316 :         foreach(lc, target->exprs)
             +  +  +  + ]
    1296                 :             :         {
    1297                 :         664 :                 Node       *node = (Node *) lfirst(lc);
    1298         [ +  + ]:         664 :                 Index           sgref = get_pathtarget_sortgroupref(target, lci);
    1299                 :             : 
    1300         [ +  + ]:         664 :                 if ((item->sortgroupref == sgref ||
    1301         [ +  + ]:          50 :                          item->sortgroupref == 0 ||
    1302         [ +  + ]:         664 :                          sgref == 0) &&
    1303                 :         630 :                         equal(item->expr, node))
    1304                 :             :                 {
    1305                 :             :                         /* Found a match.  Assign item's sortgroupref if it has one. */
    1306         [ +  + ]:         212 :                         if (item->sortgroupref)
    1307                 :             :                         {
    1308         [ +  + ]:           4 :                                 if (target->sortgrouprefs == NULL)
    1309                 :             :                                 {
    1310                 :           2 :                                         target->sortgrouprefs = (Index *)
    1311                 :           2 :                                                 palloc0(list_length(target->exprs) * sizeof(Index));
    1312                 :           2 :                                 }
    1313                 :           4 :                                 target->sortgrouprefs[lci] = item->sortgroupref;
    1314                 :           4 :                         }
    1315                 :         212 :                         return;
    1316                 :             :                 }
    1317                 :         452 :                 lci++;
    1318         [ +  + ]:         664 :         }
    1319                 :             : 
    1320                 :             :         /*
    1321                 :             :          * No match, so add item to PathTarget.  Copy the expr for safety.
    1322                 :             :          */
    1323                 :         880 :         add_column_to_pathtarget(target, (Expr *) copyObject(item->expr),
    1324                 :         440 :                                                          item->sortgroupref);
    1325         [ -  + ]:         652 : }
    1326                 :             : 
    1327                 :             : /*
    1328                 :             :  * Apply add_sp_item_to_pathtarget to each element of list.
    1329                 :             :  */
    1330                 :             : static void
    1331                 :        3532 : add_sp_items_to_pathtarget(PathTarget *target, List *items)
    1332                 :             : {
    1333                 :        3532 :         ListCell   *lc;
    1334                 :             : 
    1335   [ +  +  +  +  :        4178 :         foreach(lc, items)
                   +  + ]
    1336                 :             :         {
    1337                 :         646 :                 split_pathtarget_item *item = lfirst(lc);
    1338                 :             : 
    1339                 :         646 :                 add_sp_item_to_pathtarget(target, item);
    1340                 :         646 :         }
    1341                 :        3532 : }
        

Generated by: LCOV version 2.3.2-1