LCOV - code coverage report
Current view: top level - src/backend/optimizer/plan - setrefs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 890 941 94.6 %
Date: 2020-06-05 18:07:03 Functions: 40 41 97.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * setrefs.c
       4             :  *    Post-processing of a completed plan tree: fix references to subplan
       5             :  *    vars, compute regproc values for operators, etc
       6             :  *
       7             :  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
       8             :  * Portions Copyright (c) 1994, Regents of the University of California
       9             :  *
      10             :  *
      11             :  * IDENTIFICATION
      12             :  *    src/backend/optimizer/plan/setrefs.c
      13             :  *
      14             :  *-------------------------------------------------------------------------
      15             :  */
      16             : #include "postgres.h"
      17             : 
      18             : #include "access/transam.h"
      19             : #include "catalog/pg_type.h"
      20             : #include "nodes/makefuncs.h"
      21             : #include "nodes/nodeFuncs.h"
      22             : #include "optimizer/optimizer.h"
      23             : #include "optimizer/pathnode.h"
      24             : #include "optimizer/planmain.h"
      25             : #include "optimizer/planner.h"
      26             : #include "optimizer/tlist.h"
      27             : #include "tcop/utility.h"
      28             : #include "utils/lsyscache.h"
      29             : #include "utils/syscache.h"
      30             : 
      31             : 
      32             : typedef struct
      33             : {
      34             :     Index       varno;          /* RT index of Var */
      35             :     AttrNumber  varattno;       /* attr number of Var */
      36             :     AttrNumber  resno;          /* TLE position of Var */
      37             : } tlist_vinfo;
      38             : 
      39             : typedef struct
      40             : {
      41             :     List       *tlist;          /* underlying target list */
      42             :     int         num_vars;       /* number of plain Var tlist entries */
      43             :     bool        has_ph_vars;    /* are there PlaceHolderVar entries? */
      44             :     bool        has_non_vars;   /* are there other entries? */
      45             :     tlist_vinfo vars[FLEXIBLE_ARRAY_MEMBER];    /* has num_vars entries */
      46             : } indexed_tlist;
      47             : 
      48             : typedef struct
      49             : {
      50             :     PlannerInfo *root;
      51             :     int         rtoffset;
      52             : } fix_scan_expr_context;
      53             : 
      54             : typedef struct
      55             : {
      56             :     PlannerInfo *root;
      57             :     indexed_tlist *outer_itlist;
      58             :     indexed_tlist *inner_itlist;
      59             :     Index       acceptable_rel;
      60             :     int         rtoffset;
      61             : } fix_join_expr_context;
      62             : 
      63             : typedef struct
      64             : {
      65             :     PlannerInfo *root;
      66             :     indexed_tlist *subplan_itlist;
      67             :     Index       newvarno;
      68             :     int         rtoffset;
      69             : } fix_upper_expr_context;
      70             : 
      71             : /*
      72             :  * Check if a Const node is a regclass value.  We accept plain OID too,
      73             :  * since a regclass Const will get folded to that type if it's an argument
      74             :  * to oideq or similar operators.  (This might result in some extraneous
      75             :  * values in a plan's list of relation dependencies, but the worst result
      76             :  * would be occasional useless replans.)
      77             :  */
      78             : #define ISREGCLASSCONST(con) \
      79             :     (((con)->consttype == REGCLASSOID || (con)->consttype == OIDOID) && \
      80             :      !(con)->constisnull)
      81             : 
      82             : #define fix_scan_list(root, lst, rtoffset) \
      83             :     ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset))
      84             : 
      85             : static void add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing);
      86             : static void flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte);
      87             : static bool flatten_rtes_walker(Node *node, PlannerGlobal *glob);
      88             : static void add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte);
      89             : static Plan *set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset);
      90             : static Plan *set_indexonlyscan_references(PlannerInfo *root,
      91             :                                           IndexOnlyScan *plan,
      92             :                                           int rtoffset);
      93             : static Plan *set_subqueryscan_references(PlannerInfo *root,
      94             :                                          SubqueryScan *plan,
      95             :                                          int rtoffset);
      96             : static bool trivial_subqueryscan(SubqueryScan *plan);
      97             : static Plan *clean_up_removed_plan_level(Plan *parent, Plan *child);
      98             : static void set_foreignscan_references(PlannerInfo *root,
      99             :                                        ForeignScan *fscan,
     100             :                                        int rtoffset);
     101             : static void set_customscan_references(PlannerInfo *root,
     102             :                                       CustomScan *cscan,
     103             :                                       int rtoffset);
     104             : static Plan *set_append_references(PlannerInfo *root,
     105             :                                    Append *aplan,
     106             :                                    int rtoffset);
     107             : static Plan *set_mergeappend_references(PlannerInfo *root,
     108             :                                         MergeAppend *mplan,
     109             :                                         int rtoffset);
     110             : static void set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset);
     111             : static Relids offset_relid_set(Relids relids, int rtoffset);
     112             : static Node *fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset);
     113             : static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);
     114             : static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context);
     115             : static void set_join_references(PlannerInfo *root, Join *join, int rtoffset);
     116             : static void set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset);
     117             : static void set_param_references(PlannerInfo *root, Plan *plan);
     118             : static Node *convert_combining_aggrefs(Node *node, void *context);
     119             : static void set_dummy_tlist_references(Plan *plan, int rtoffset);
     120             : static indexed_tlist *build_tlist_index(List *tlist);
     121             : static Var *search_indexed_tlist_for_var(Var *var,
     122             :                                          indexed_tlist *itlist,
     123             :                                          Index newvarno,
     124             :                                          int rtoffset);
     125             : static Var *search_indexed_tlist_for_non_var(Expr *node,
     126             :                                              indexed_tlist *itlist,
     127             :                                              Index newvarno);
     128             : static Var *search_indexed_tlist_for_sortgroupref(Expr *node,
     129             :                                                   Index sortgroupref,
     130             :                                                   indexed_tlist *itlist,
     131             :                                                   Index newvarno);
     132             : static List *fix_join_expr(PlannerInfo *root,
     133             :                            List *clauses,
     134             :                            indexed_tlist *outer_itlist,
     135             :                            indexed_tlist *inner_itlist,
     136             :                            Index acceptable_rel, int rtoffset);
     137             : static Node *fix_join_expr_mutator(Node *node,
     138             :                                    fix_join_expr_context *context);
     139             : static Node *fix_upper_expr(PlannerInfo *root,
     140             :                             Node *node,
     141             :                             indexed_tlist *subplan_itlist,
     142             :                             Index newvarno,
     143             :                             int rtoffset);
     144             : static Node *fix_upper_expr_mutator(Node *node,
     145             :                                     fix_upper_expr_context *context);
     146             : static List *set_returning_clause_references(PlannerInfo *root,
     147             :                                              List *rlist,
     148             :                                              Plan *topplan,
     149             :                                              Index resultRelation,
     150             :                                              int rtoffset);
     151             : 
     152             : 
     153             : /*****************************************************************************
     154             :  *
     155             :  *      SUBPLAN REFERENCES
     156             :  *
     157             :  *****************************************************************************/
     158             : 
     159             : /*
     160             :  * set_plan_references
     161             :  *
     162             :  * This is the final processing pass of the planner/optimizer.  The plan
     163             :  * tree is complete; we just have to adjust some representational details
     164             :  * for the convenience of the executor:
     165             :  *
     166             :  * 1. We flatten the various subquery rangetables into a single list, and
     167             :  * zero out RangeTblEntry fields that are not useful to the executor.
     168             :  *
     169             :  * 2. We adjust Vars in scan nodes to be consistent with the flat rangetable.
     170             :  *
     171             :  * 3. We adjust Vars in upper plan nodes to refer to the outputs of their
     172             :  * subplans.
     173             :  *
     174             :  * 4. Aggrefs in Agg plan nodes need to be adjusted in some cases involving
     175             :  * partial aggregation or minmax aggregate optimization.
     176             :  *
     177             :  * 5. PARAM_MULTIEXPR Params are replaced by regular PARAM_EXEC Params,
     178             :  * now that we have finished planning all MULTIEXPR subplans.
     179             :  *
     180             :  * 6. We compute regproc OIDs for operators (ie, we look up the function
     181             :  * that implements each op).
     182             :  *
     183             :  * 7. We create lists of specific objects that the plan depends on.
     184             :  * This will be used by plancache.c to drive invalidation of cached plans.
     185             :  * Relation dependencies are represented by OIDs, and everything else by
     186             :  * PlanInvalItems (this distinction is motivated by the shared-inval APIs).
     187             :  * Currently, relations, user-defined functions, and domains are the only
     188             :  * types of objects that are explicitly tracked this way.
     189             :  *
     190             :  * 8. We assign every plan node in the tree a unique ID.
     191             :  *
     192             :  * We also perform one final optimization step, which is to delete
     193             :  * SubqueryScan, Append, and MergeAppend plan nodes that aren't doing
     194             :  * anything useful.  The reason for doing this last is that
     195             :  * it can't readily be done before set_plan_references, because it would
     196             :  * break set_upper_references: the Vars in the child plan's top tlist
     197             :  * wouldn't match up with the Vars in the outer plan tree.  A SubqueryScan
     198             :  * serves a necessary function as a buffer between outer query and subquery
     199             :  * variable numbering ... but after we've flattened the rangetable this is
     200             :  * no longer a problem, since then there's only one rtindex namespace.
     201             :  * Likewise, Append and MergeAppend buffer between the parent and child vars
     202             :  * of an appendrel, but we don't need to worry about that once we've done
     203             :  * set_plan_references.
     204             :  *
     205             :  * set_plan_references recursively traverses the whole plan tree.
     206             :  *
     207             :  * The return value is normally the same Plan node passed in, but can be
     208             :  * different when the passed-in Plan is a node we decide isn't needed.
     209             :  *
     210             :  * The flattened rangetable entries are appended to root->glob->finalrtable.
     211             :  * Also, rowmarks entries are appended to root->glob->finalrowmarks, and the
     212             :  * RT indexes of ModifyTable result relations to root->glob->resultRelations,
     213             :  * and flattened AppendRelInfos are appended to root->glob->appendRelations.
     214             :  * Plan dependencies are appended to root->glob->relationOids (for relations)
     215             :  * and root->glob->invalItems (for everything else).
     216             :  *
     217             :  * Notice that we modify Plan nodes in-place, but use expression_tree_mutator
     218             :  * to process targetlist and qual expressions.  We can assume that the Plan
     219             :  * nodes were just built by the planner and are not multiply referenced, but
     220             :  * it's not so safe to assume that for expression tree nodes.
     221             :  */
     222             : Plan *
     223      317938 : set_plan_references(PlannerInfo *root, Plan *plan)
     224             : {
     225      317938 :     PlannerGlobal *glob = root->glob;
     226      317938 :     int         rtoffset = list_length(glob->finalrtable);
     227             :     ListCell   *lc;
     228             : 
     229             :     /*
     230             :      * Add all the query's RTEs to the flattened rangetable.  The live ones
     231             :      * will have their rangetable indexes increased by rtoffset.  (Additional
     232             :      * RTEs, not referenced by the Plan tree, might get added after those.)
     233             :      */
     234      317938 :     add_rtes_to_flat_rtable(root, false);
     235             : 
     236             :     /*
     237             :      * Adjust RT indexes of PlanRowMarks and add to final rowmarks list
     238             :      */
     239      324992 :     foreach(lc, root->rowMarks)
     240             :     {
     241        7054 :         PlanRowMark *rc = lfirst_node(PlanRowMark, lc);
     242             :         PlanRowMark *newrc;
     243             : 
     244             :         /* flat copy is enough since all fields are scalars */
     245        7054 :         newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark));
     246        7054 :         memcpy(newrc, rc, sizeof(PlanRowMark));
     247             : 
     248             :         /* adjust indexes ... but *not* the rowmarkId */
     249        7054 :         newrc->rti += rtoffset;
     250        7054 :         newrc->prti += rtoffset;
     251             : 
     252        7054 :         glob->finalrowmarks = lappend(glob->finalrowmarks, newrc);
     253             :     }
     254             : 
     255             :     /*
     256             :      * Adjust RT indexes of AppendRelInfos and add to final appendrels list.
     257             :      * We assume the AppendRelInfos were built during planning and don't need
     258             :      * to be copied.
     259             :      */
     260      342102 :     foreach(lc, root->append_rel_list)
     261             :     {
     262       24164 :         AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
     263             : 
     264             :         /* adjust RT indexes */
     265       24164 :         appinfo->parent_relid += rtoffset;
     266       24164 :         appinfo->child_relid += rtoffset;
     267             : 
     268             :         /*
     269             :          * Rather than adjust the translated_vars entries, just drop 'em.
     270             :          * Neither the executor nor EXPLAIN currently need that data.
     271             :          */
     272       24164 :         appinfo->translated_vars = NIL;
     273             : 
     274       24164 :         glob->appendRelations = lappend(glob->appendRelations, appinfo);
     275             :     }
     276             : 
     277             :     /* Now fix the Plan tree */
     278      317938 :     return set_plan_refs(root, plan, rtoffset);
     279             : }
     280             : 
     281             : /*
     282             :  * Extract RangeTblEntries from the plan's rangetable, and add to flat rtable
     283             :  *
     284             :  * This can recurse into subquery plans; "recursing" is true if so.
     285             :  */
     286             : static void
     287      318042 : add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
     288             : {
     289      318042 :     PlannerGlobal *glob = root->glob;
     290             :     Index       rti;
     291             :     ListCell   *lc;
     292             : 
     293             :     /*
     294             :      * Add the query's own RTEs to the flattened rangetable.
     295             :      *
     296             :      * At top level, we must add all RTEs so that their indexes in the
     297             :      * flattened rangetable match up with their original indexes.  When
     298             :      * recursing, we only care about extracting relation RTEs.
     299             :      */
     300      925814 :     foreach(lc, root->parse->rtable)
     301             :     {
     302      607772 :         RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
     303             : 
     304      607772 :         if (!recursing || rte->rtekind == RTE_RELATION)
     305      607612 :             add_rte_to_flat_rtable(glob, rte);
     306             :     }
     307             : 
     308             :     /*
     309             :      * If there are any dead subqueries, they are not referenced in the Plan
     310             :      * tree, so we must add RTEs contained in them to the flattened rtable
     311             :      * separately.  (If we failed to do this, the executor would not perform
     312             :      * expected permission checks for tables mentioned in such subqueries.)
     313             :      *
     314             :      * Note: this pass over the rangetable can't be combined with the previous
     315             :      * one, because that would mess up the numbering of the live RTEs in the
     316             :      * flattened rangetable.
     317             :      */
     318      318042 :     rti = 1;
     319      925814 :     foreach(lc, root->parse->rtable)
     320             :     {
     321      607772 :         RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
     322             : 
     323             :         /*
     324             :          * We should ignore inheritance-parent RTEs: their contents have been
     325             :          * pulled up into our rangetable already.  Also ignore any subquery
     326             :          * RTEs without matching RelOptInfos, as they likewise have been
     327             :          * pulled up.
     328             :          */
     329      607772 :         if (rte->rtekind == RTE_SUBQUERY && !rte->inh &&
     330       48984 :             rti < root->simple_rel_array_size)
     331             :         {
     332       48984 :             RelOptInfo *rel = root->simple_rel_array[rti];
     333             : 
     334       48984 :             if (rel != NULL)
     335             :             {
     336             :                 Assert(rel->relid == rti);   /* sanity check on array */
     337             : 
     338             :                 /*
     339             :                  * The subquery might never have been planned at all, if it
     340             :                  * was excluded on the basis of self-contradictory constraints
     341             :                  * in our query level.  In this case apply
     342             :                  * flatten_unplanned_rtes.
     343             :                  *
     344             :                  * If it was planned but the result rel is dummy, we assume
     345             :                  * that it has been omitted from our plan tree (see
     346             :                  * set_subquery_pathlist), and recurse to pull up its RTEs.
     347             :                  *
     348             :                  * Otherwise, it should be represented by a SubqueryScan node
     349             :                  * somewhere in our plan tree, and we'll pull up its RTEs when
     350             :                  * we process that plan node.
     351             :                  *
     352             :                  * However, if we're recursing, then we should pull up RTEs
     353             :                  * whether the subquery is dummy or not, because we've found
     354             :                  * that some upper query level is treating this one as dummy,
     355             :                  * and so we won't scan this level's plan tree at all.
     356             :                  */
     357        9320 :                 if (rel->subroot == NULL)
     358          28 :                     flatten_unplanned_rtes(glob, rte);
     359       18552 :                 else if (recursing ||
     360        9260 :                          IS_DUMMY_REL(fetch_upper_rel(rel->subroot,
     361             :                                                       UPPERREL_FINAL, NULL)))
     362         104 :                     add_rtes_to_flat_rtable(rel->subroot, true);
     363             :             }
     364             :         }
     365      607772 :         rti++;
     366             :     }
     367      318042 : }
     368             : 
     369             : /*
     370             :  * Extract RangeTblEntries from a subquery that was never planned at all
     371             :  */
     372             : static void
     373          28 : flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte)
     374             : {
     375             :     /* Use query_tree_walker to find all RTEs in the parse tree */
     376          28 :     (void) query_tree_walker(rte->subquery,
     377             :                              flatten_rtes_walker,
     378             :                              (void *) glob,
     379             :                              QTW_EXAMINE_RTES_BEFORE);
     380          28 : }
     381             : 
     382             : static bool
     383         772 : flatten_rtes_walker(Node *node, PlannerGlobal *glob)
     384             : {
     385         772 :     if (node == NULL)
     386         400 :         return false;
     387         372 :     if (IsA(node, RangeTblEntry))
     388             :     {
     389          40 :         RangeTblEntry *rte = (RangeTblEntry *) node;
     390             : 
     391             :         /* As above, we need only save relation RTEs */
     392          40 :         if (rte->rtekind == RTE_RELATION)
     393          28 :             add_rte_to_flat_rtable(glob, rte);
     394          40 :         return false;
     395             :     }
     396         332 :     if (IsA(node, Query))
     397             :     {
     398             :         /* Recurse into subselects */
     399           8 :         return query_tree_walker((Query *) node,
     400             :                                  flatten_rtes_walker,
     401             :                                  (void *) glob,
     402             :                                  QTW_EXAMINE_RTES_BEFORE);
     403             :     }
     404         324 :     return expression_tree_walker(node, flatten_rtes_walker,
     405             :                                   (void *) glob);
     406             : }
     407             : 
     408             : /*
     409             :  * Add (a copy of) the given RTE to the final rangetable
     410             :  *
     411             :  * In the flat rangetable, we zero out substructure pointers that are not
     412             :  * needed by the executor; this reduces the storage space and copying cost
     413             :  * for cached plans.  We keep only the ctename, alias and eref Alias fields,
     414             :  * which are needed by EXPLAIN, and the selectedCols, insertedCols and
     415             :  * updatedCols bitmaps, which are needed for executor-startup permissions
     416             :  * checking and for trigger event checking.
     417             :  */
     418             : static void
     419      607640 : add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte)
     420             : {
     421             :     RangeTblEntry *newrte;
     422             : 
     423             :     /* flat copy to duplicate all the scalar fields */
     424      607640 :     newrte = (RangeTblEntry *) palloc(sizeof(RangeTblEntry));
     425      607640 :     memcpy(newrte, rte, sizeof(RangeTblEntry));
     426             : 
     427             :     /* zap unneeded sub-structure */
     428      607640 :     newrte->tablesample = NULL;
     429      607640 :     newrte->subquery = NULL;
     430      607640 :     newrte->joinaliasvars = NIL;
     431      607640 :     newrte->joinleftcols = NIL;
     432      607640 :     newrte->joinrightcols = NIL;
     433      607640 :     newrte->functions = NIL;
     434      607640 :     newrte->tablefunc = NULL;
     435      607640 :     newrte->values_lists = NIL;
     436      607640 :     newrte->coltypes = NIL;
     437      607640 :     newrte->coltypmods = NIL;
     438      607640 :     newrte->colcollations = NIL;
     439      607640 :     newrte->securityQuals = NIL;
     440             : 
     441      607640 :     glob->finalrtable = lappend(glob->finalrtable, newrte);
     442             : 
     443             :     /*
     444             :      * Check for RT index overflow; it's very unlikely, but if it did happen,
     445             :      * the executor would get confused by varnos that match the special varno
     446             :      * values.
     447             :      */
     448      607640 :     if (IS_SPECIAL_VARNO(list_length(glob->finalrtable)))
     449           0 :         ereport(ERROR,
     450             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     451             :                  errmsg("too many range table entries")));
     452             : 
     453             :     /*
     454             :      * If it's a plain relation RTE, add the table to relationOids.
     455             :      *
     456             :      * We do this even though the RTE might be unreferenced in the plan tree;
     457             :      * this would correspond to cases such as views that were expanded, child
     458             :      * tables that were eliminated by constraint exclusion, etc. Schema
     459             :      * invalidation on such a rel must still force rebuilding of the plan.
     460             :      *
     461             :      * Note we don't bother to avoid making duplicate list entries.  We could,
     462             :      * but it would probably cost more cycles than it would save.
     463             :      */
     464      607640 :     if (newrte->rtekind == RTE_RELATION)
     465      350840 :         glob->relationOids = lappend_oid(glob->relationOids, newrte->relid);
     466      607640 : }
     467             : 
     468             : /*
     469             :  * set_plan_refs: recurse through the Plan nodes of a single subquery level
     470             :  */
     471             : static Plan *
     472     1717090 : set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
     473             : {
     474             :     ListCell   *l;
     475             : 
     476     1717090 :     if (plan == NULL)
     477     1038370 :         return NULL;
     478             : 
     479             :     /* Assign this node a unique ID. */
     480      678720 :     plan->plan_node_id = root->glob->lastPlanNodeId++;
     481             : 
     482             :     /*
     483             :      * Plan-type-specific fixes
     484             :      */
     485      678720 :     switch (nodeTag(plan))
     486             :     {
     487      123356 :         case T_SeqScan:
     488             :             {
     489      123356 :                 SeqScan    *splan = (SeqScan *) plan;
     490             : 
     491      123356 :                 splan->scanrelid += rtoffset;
     492      123356 :                 splan->plan.targetlist =
     493      123356 :                     fix_scan_list(root, splan->plan.targetlist, rtoffset);
     494      123356 :                 splan->plan.qual =
     495      123356 :                     fix_scan_list(root, splan->plan.qual, rtoffset);
     496             :             }
     497      123356 :             break;
     498         180 :         case T_SampleScan:
     499             :             {
     500         180 :                 SampleScan *splan = (SampleScan *) plan;
     501             : 
     502         180 :                 splan->scan.scanrelid += rtoffset;
     503         180 :                 splan->scan.plan.targetlist =
     504         180 :                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
     505         180 :                 splan->scan.plan.qual =
     506         180 :                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
     507         180 :                 splan->tablesample = (TableSampleClause *)
     508         180 :                     fix_scan_expr(root, (Node *) splan->tablesample, rtoffset);
     509             :             }
     510         180 :             break;
     511       76462 :         case T_IndexScan:
     512             :             {
     513       76462 :                 IndexScan  *splan = (IndexScan *) plan;
     514             : 
     515       76462 :                 splan->scan.scanrelid += rtoffset;
     516       76462 :                 splan->scan.plan.targetlist =
     517       76462 :                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
     518       76462 :                 splan->scan.plan.qual =
     519       76462 :                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
     520       76462 :                 splan->indexqual =
     521       76462 :                     fix_scan_list(root, splan->indexqual, rtoffset);
     522       76462 :                 splan->indexqualorig =
     523       76462 :                     fix_scan_list(root, splan->indexqualorig, rtoffset);
     524       76462 :                 splan->indexorderby =
     525       76462 :                     fix_scan_list(root, splan->indexorderby, rtoffset);
     526       76462 :                 splan->indexorderbyorig =
     527       76462 :                     fix_scan_list(root, splan->indexorderbyorig, rtoffset);
     528             :             }
     529       76462 :             break;
     530        8198 :         case T_IndexOnlyScan:
     531             :             {
     532        8198 :                 IndexOnlyScan *splan = (IndexOnlyScan *) plan;
     533             : 
     534        8198 :                 return set_indexonlyscan_references(root, splan, rtoffset);
     535             :             }
     536             :             break;
     537       22344 :         case T_BitmapIndexScan:
     538             :             {
     539       22344 :                 BitmapIndexScan *splan = (BitmapIndexScan *) plan;
     540             : 
     541       22344 :                 splan->scan.scanrelid += rtoffset;
     542             :                 /* no need to fix targetlist and qual */
     543             :                 Assert(splan->scan.plan.targetlist == NIL);
     544             :                 Assert(splan->scan.plan.qual == NIL);
     545       22344 :                 splan->indexqual =
     546       22344 :                     fix_scan_list(root, splan->indexqual, rtoffset);
     547       22344 :                 splan->indexqualorig =
     548       22344 :                     fix_scan_list(root, splan->indexqualorig, rtoffset);
     549             :             }
     550       22344 :             break;
     551       22132 :         case T_BitmapHeapScan:
     552             :             {
     553       22132 :                 BitmapHeapScan *splan = (BitmapHeapScan *) plan;
     554             : 
     555       22132 :                 splan->scan.scanrelid += rtoffset;
     556       22132 :                 splan->scan.plan.targetlist =
     557       22132 :                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
     558       22132 :                 splan->scan.plan.qual =
     559       22132 :                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
     560       22132 :                 splan->bitmapqualorig =
     561       22132 :                     fix_scan_list(root, splan->bitmapqualorig, rtoffset);
     562             :             }
     563       22132 :             break;
     564         432 :         case T_TidScan:
     565             :             {
     566         432 :                 TidScan    *splan = (TidScan *) plan;
     567             : 
     568         432 :                 splan->scan.scanrelid += rtoffset;
     569         432 :                 splan->scan.plan.targetlist =
     570         432 :                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
     571         432 :                 splan->scan.plan.qual =
     572         432 :                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
     573         432 :                 splan->tidquals =
     574         432 :                     fix_scan_list(root, splan->tidquals, rtoffset);
     575             :             }
     576         432 :             break;
     577        9188 :         case T_SubqueryScan:
     578             :             /* Needs special treatment, see comments below */
     579        9188 :             return set_subqueryscan_references(root,
     580             :                                                (SubqueryScan *) plan,
     581             :                                                rtoffset);
     582       30530 :         case T_FunctionScan:
     583             :             {
     584       30530 :                 FunctionScan *splan = (FunctionScan *) plan;
     585             : 
     586       30530 :                 splan->scan.scanrelid += rtoffset;
     587       30530 :                 splan->scan.plan.targetlist =
     588       30530 :                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
     589       30530 :                 splan->scan.plan.qual =
     590       30530 :                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
     591       30530 :                 splan->functions =
     592       30530 :                     fix_scan_list(root, splan->functions, rtoffset);
     593             :             }
     594       30530 :             break;
     595         144 :         case T_TableFuncScan:
     596             :             {
     597         144 :                 TableFuncScan *splan = (TableFuncScan *) plan;
     598             : 
     599         144 :                 splan->scan.scanrelid += rtoffset;
     600         144 :                 splan->scan.plan.targetlist =
     601         144 :                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
     602         144 :                 splan->scan.plan.qual =
     603         144 :                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
     604         144 :                 splan->tablefunc = (TableFunc *)
     605         144 :                     fix_scan_expr(root, (Node *) splan->tablefunc, rtoffset);
     606             :             }
     607         144 :             break;
     608        3932 :         case T_ValuesScan:
     609             :             {
     610        3932 :                 ValuesScan *splan = (ValuesScan *) plan;
     611             : 
     612        3932 :                 splan->scan.scanrelid += rtoffset;
     613        3932 :                 splan->scan.plan.targetlist =
     614        3932 :                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
     615        3932 :                 splan->scan.plan.qual =
     616        3932 :                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
     617        3932 :                 splan->values_lists =
     618        3932 :                     fix_scan_list(root, splan->values_lists, rtoffset);
     619             :             }
     620        3932 :             break;
     621         892 :         case T_CteScan:
     622             :             {
     623         892 :                 CteScan    *splan = (CteScan *) plan;
     624             : 
     625         892 :                 splan->scan.scanrelid += rtoffset;
     626         892 :                 splan->scan.plan.targetlist =
     627         892 :                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
     628         892 :                 splan->scan.plan.qual =
     629         892 :                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
     630             :             }
     631         892 :             break;
     632         260 :         case T_NamedTuplestoreScan:
     633             :             {
     634         260 :                 NamedTuplestoreScan *splan = (NamedTuplestoreScan *) plan;
     635             : 
     636         260 :                 splan->scan.scanrelid += rtoffset;
     637         260 :                 splan->scan.plan.targetlist =
     638         260 :                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
     639         260 :                 splan->scan.plan.qual =
     640         260 :                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
     641             :             }
     642         260 :             break;
     643         332 :         case T_WorkTableScan:
     644             :             {
     645         332 :                 WorkTableScan *splan = (WorkTableScan *) plan;
     646             : 
     647         332 :                 splan->scan.scanrelid += rtoffset;
     648         332 :                 splan->scan.plan.targetlist =
     649         332 :                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
     650         332 :                 splan->scan.plan.qual =
     651         332 :                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
     652             :             }
     653         332 :             break;
     654        1398 :         case T_ForeignScan:
     655        1398 :             set_foreignscan_references(root, (ForeignScan *) plan, rtoffset);
     656        1398 :             break;
     657           0 :         case T_CustomScan:
     658           0 :             set_customscan_references(root, (CustomScan *) plan, rtoffset);
     659           0 :             break;
     660             : 
     661       64698 :         case T_NestLoop:
     662             :         case T_MergeJoin:
     663             :         case T_HashJoin:
     664       64698 :             set_join_references(root, (Join *) plan, rtoffset);
     665       64698 :             break;
     666             : 
     667         672 :         case T_Gather:
     668             :         case T_GatherMerge:
     669             :             {
     670         672 :                 set_upper_references(root, plan, rtoffset);
     671         672 :                 set_param_references(root, plan);
     672             :             }
     673         672 :             break;
     674             : 
     675       29024 :         case T_Hash:
     676       29024 :             set_hash_references(root, plan, rtoffset);
     677       29024 :             break;
     678             : 
     679       38276 :         case T_Material:
     680             :         case T_Sort:
     681             :         case T_IncrementalSort:
     682             :         case T_Unique:
     683             :         case T_SetOp:
     684             : 
     685             :             /*
     686             :              * These plan types don't actually bother to evaluate their
     687             :              * targetlists, because they just return their unmodified input
     688             :              * tuples.  Even though the targetlist won't be used by the
     689             :              * executor, we fix it up for possible use by EXPLAIN (not to
     690             :              * mention ease of debugging --- wrong varnos are very confusing).
     691             :              */
     692       38276 :             set_dummy_tlist_references(plan, rtoffset);
     693             : 
     694             :             /*
     695             :              * Since these plan types don't check quals either, we should not
     696             :              * find any qual expression attached to them.
     697             :              */
     698             :             Assert(plan->qual == NIL);
     699       38276 :             break;
     700        4886 :         case T_LockRows:
     701        4886 :             {
     702        4886 :                 LockRows   *splan = (LockRows *) plan;
     703             : 
     704             :                 /*
     705             :                  * Like the plan types above, LockRows doesn't evaluate its
     706             :                  * tlist or quals.  But we have to fix up the RT indexes in
     707             :                  * its rowmarks.
     708             :                  */
     709        4886 :                 set_dummy_tlist_references(plan, rtoffset);
     710             :                 Assert(splan->plan.qual == NIL);
     711             : 
     712       10914 :                 foreach(l, splan->rowMarks)
     713             :                 {
     714        6028 :                     PlanRowMark *rc = (PlanRowMark *) lfirst(l);
     715             : 
     716        6028 :                     rc->rti += rtoffset;
     717        6028 :                     rc->prti += rtoffset;
     718             :                 }
     719             :             }
     720        4886 :             break;
     721        3370 :         case T_Limit:
     722             :             {
     723        3370 :                 Limit      *splan = (Limit *) plan;
     724             : 
     725             :                 /*
     726             :                  * Like the plan types above, Limit doesn't evaluate its tlist
     727             :                  * or quals.  It does have live expressions for limit/offset,
     728             :                  * however; and those cannot contain subplan variable refs, so
     729             :                  * fix_scan_expr works for them.
     730             :                  */
     731        3370 :                 set_dummy_tlist_references(plan, rtoffset);
     732             :                 Assert(splan->plan.qual == NIL);
     733             : 
     734        3370 :                 splan->limitOffset =
     735        3370 :                     fix_scan_expr(root, splan->limitOffset, rtoffset);
     736        3370 :                 splan->limitCount =
     737        3370 :                     fix_scan_expr(root, splan->limitCount, rtoffset);
     738             :             }
     739        3370 :             break;
     740       26378 :         case T_Agg:
     741             :             {
     742       26378 :                 Agg        *agg = (Agg *) plan;
     743             : 
     744             :                 /*
     745             :                  * If this node is combining partial-aggregation results, we
     746             :                  * must convert its Aggrefs to contain references to the
     747             :                  * partial-aggregate subexpressions that will be available
     748             :                  * from the child plan node.
     749             :                  */
     750       26378 :                 if (DO_AGGSPLIT_COMBINE(agg->aggsplit))
     751             :                 {
     752         492 :                     plan->targetlist = (List *)
     753         492 :                         convert_combining_aggrefs((Node *) plan->targetlist,
     754             :                                                   NULL);
     755         492 :                     plan->qual = (List *)
     756         492 :                         convert_combining_aggrefs((Node *) plan->qual,
     757             :                                                   NULL);
     758             :                 }
     759             : 
     760       26378 :                 set_upper_references(root, plan, rtoffset);
     761             :             }
     762       26378 :             break;
     763         150 :         case T_Group:
     764         150 :             set_upper_references(root, plan, rtoffset);
     765         150 :             break;
     766        1160 :         case T_WindowAgg:
     767             :             {
     768        1160 :                 WindowAgg  *wplan = (WindowAgg *) plan;
     769             : 
     770        1160 :                 set_upper_references(root, plan, rtoffset);
     771             : 
     772             :                 /*
     773             :                  * Like Limit node limit/offset expressions, WindowAgg has
     774             :                  * frame offset expressions, which cannot contain subplan
     775             :                  * variable refs, so fix_scan_expr works for them.
     776             :                  */
     777        1160 :                 wplan->startOffset =
     778        1160 :                     fix_scan_expr(root, wplan->startOffset, rtoffset);
     779        1160 :                 wplan->endOffset =
     780        1160 :                     fix_scan_expr(root, wplan->endOffset, rtoffset);
     781             :             }
     782        1160 :             break;
     783      122626 :         case T_Result:
     784             :             {
     785      122626 :                 Result     *splan = (Result *) plan;
     786             : 
     787             :                 /*
     788             :                  * Result may or may not have a subplan; if not, it's more
     789             :                  * like a scan node than an upper node.
     790             :                  */
     791      122626 :                 if (splan->plan.lefttree != NULL)
     792        3668 :                     set_upper_references(root, plan, rtoffset);
     793             :                 else
     794             :                 {
     795      118958 :                     splan->plan.targetlist =
     796      118958 :                         fix_scan_list(root, splan->plan.targetlist, rtoffset);
     797      118958 :                     splan->plan.qual =
     798      118958 :                         fix_scan_list(root, splan->plan.qual, rtoffset);
     799             :                 }
     800             :                 /* resconstantqual can't contain any subplan variable refs */
     801      122626 :                 splan->resconstantqual =
     802      122626 :                     fix_scan_expr(root, splan->resconstantqual, rtoffset);
     803             :             }
     804      122626 :             break;
     805        3878 :         case T_ProjectSet:
     806        3878 :             set_upper_references(root, plan, rtoffset);
     807        3878 :             break;
     808       73000 :         case T_ModifyTable:
     809       70308 :             {
     810       73000 :                 ModifyTable *splan = (ModifyTable *) plan;
     811             : 
     812             :                 Assert(splan->plan.targetlist == NIL);
     813             :                 Assert(splan->plan.qual == NIL);
     814             : 
     815       73000 :                 splan->withCheckOptionLists =
     816       73000 :                     fix_scan_list(root, splan->withCheckOptionLists, rtoffset);
     817             : 
     818       73000 :                 if (splan->returningLists)
     819             :                 {
     820        1644 :                     List       *newRL = NIL;
     821             :                     ListCell   *lcrl,
     822             :                                *lcrr,
     823             :                                *lcp;
     824             : 
     825             :                     /*
     826             :                      * Pass each per-subplan returningList through
     827             :                      * set_returning_clause_references().
     828             :                      */
     829             :                     Assert(list_length(splan->returningLists) == list_length(splan->resultRelations));
     830             :                     Assert(list_length(splan->returningLists) == list_length(splan->plans));
     831        3462 :                     forthree(lcrl, splan->returningLists,
     832             :                              lcrr, splan->resultRelations,
     833             :                              lcp, splan->plans)
     834             :                     {
     835        1818 :                         List       *rlist = (List *) lfirst(lcrl);
     836        1818 :                         Index       resultrel = lfirst_int(lcrr);
     837        1818 :                         Plan       *subplan = (Plan *) lfirst(lcp);
     838             : 
     839        1818 :                         rlist = set_returning_clause_references(root,
     840             :                                                                 rlist,
     841             :                                                                 subplan,
     842             :                                                                 resultrel,
     843             :                                                                 rtoffset);
     844        1818 :                         newRL = lappend(newRL, rlist);
     845             :                     }
     846        1644 :                     splan->returningLists = newRL;
     847             : 
     848             :                     /*
     849             :                      * Set up the visible plan targetlist as being the same as
     850             :                      * the first RETURNING list. This is for the use of
     851             :                      * EXPLAIN; the executor won't pay any attention to the
     852             :                      * targetlist.  We postpone this step until here so that
     853             :                      * we don't have to do set_returning_clause_references()
     854             :                      * twice on identical targetlists.
     855             :                      */
     856        1644 :                     splan->plan.targetlist = copyObject(linitial(newRL));
     857             :                 }
     858             : 
     859             :                 /*
     860             :                  * We treat ModifyTable with ON CONFLICT as a form of 'pseudo
     861             :                  * join', where the inner side is the EXCLUDED tuple.
     862             :                  * Therefore use fix_join_expr to setup the relevant variables
     863             :                  * to INNER_VAR. We explicitly don't create any OUTER_VARs as
     864             :                  * those are already used by RETURNING and it seems better to
     865             :                  * be non-conflicting.
     866             :                  */
     867       73000 :                 if (splan->onConflictSet)
     868             :                 {
     869             :                     indexed_tlist *itlist;
     870             : 
     871         864 :                     itlist = build_tlist_index(splan->exclRelTlist);
     872             : 
     873         864 :                     splan->onConflictSet =
     874         864 :                         fix_join_expr(root, splan->onConflictSet,
     875             :                                       NULL, itlist,
     876         864 :                                       linitial_int(splan->resultRelations),
     877             :                                       rtoffset);
     878             : 
     879         864 :                     splan->onConflictWhere = (Node *)
     880         864 :                         fix_join_expr(root, (List *) splan->onConflictWhere,
     881             :                                       NULL, itlist,
     882         864 :                                       linitial_int(splan->resultRelations),
     883             :                                       rtoffset);
     884             : 
     885         864 :                     pfree(itlist);
     886             : 
     887         864 :                     splan->exclRelTlist =
     888         864 :                         fix_scan_list(root, splan->exclRelTlist, rtoffset);
     889             :                 }
     890             : 
     891       73000 :                 splan->nominalRelation += rtoffset;
     892       73000 :                 if (splan->rootRelation)
     893        2692 :                     splan->rootRelation += rtoffset;
     894       73000 :                 splan->exclRelRTI += rtoffset;
     895             : 
     896      147198 :                 foreach(l, splan->resultRelations)
     897             :                 {
     898       74198 :                     lfirst_int(l) += rtoffset;
     899             :                 }
     900       73986 :                 foreach(l, splan->rowMarks)
     901             :                 {
     902         986 :                     PlanRowMark *rc = (PlanRowMark *) lfirst(l);
     903             : 
     904         986 :                     rc->rti += rtoffset;
     905         986 :                     rc->prti += rtoffset;
     906             :                 }
     907      147198 :                 foreach(l, splan->plans)
     908             :                 {
     909       74198 :                     lfirst(l) = set_plan_refs(root,
     910       74198 :                                               (Plan *) lfirst(l),
     911             :                                               rtoffset);
     912             :                 }
     913             : 
     914             :                 /*
     915             :                  * Append this ModifyTable node's final result relation RT
     916             :                  * index(es) to the global list for the plan, and set its
     917             :                  * resultRelIndex to reflect their starting position in the
     918             :                  * global list.
     919             :                  */
     920       73000 :                 splan->resultRelIndex = list_length(root->glob->resultRelations);
     921      146000 :                 root->glob->resultRelations =
     922      146000 :                     list_concat(root->glob->resultRelations,
     923       73000 :                                 splan->resultRelations);
     924             : 
     925             :                 /*
     926             :                  * If the main target relation is a partitioned table, also
     927             :                  * add the partition root's RT index to rootResultRelations,
     928             :                  * and remember its index in that list in rootResultRelIndex.
     929             :                  */
     930       73000 :                 if (splan->rootRelation)
     931             :                 {
     932        2692 :                     splan->rootResultRelIndex =
     933        2692 :                         list_length(root->glob->rootResultRelations);
     934        2692 :                     root->glob->rootResultRelations =
     935        5384 :                         lappend_int(root->glob->rootResultRelations,
     936        2692 :                                     splan->rootRelation);
     937             :                 }
     938             :             }
     939       73000 :             break;
     940       10064 :         case T_Append:
     941             :             /* Needs special treatment, see comments below */
     942       10064 :             return set_append_references(root,
     943             :                                          (Append *) plan,
     944             :                                          rtoffset);
     945         250 :         case T_MergeAppend:
     946             :             /* Needs special treatment, see comments below */
     947         250 :             return set_mergeappend_references(root,
     948             :                                               (MergeAppend *) plan,
     949             :                                               rtoffset);
     950         332 :         case T_RecursiveUnion:
     951             :             /* This doesn't evaluate targetlist or check quals either */
     952         332 :             set_dummy_tlist_references(plan, rtoffset);
     953             :             Assert(plan->qual == NIL);
     954         332 :             break;
     955          40 :         case T_BitmapAnd:
     956          40 :             {
     957          40 :                 BitmapAnd  *splan = (BitmapAnd *) plan;
     958             : 
     959             :                 /* BitmapAnd works like Append, but has no tlist */
     960             :                 Assert(splan->plan.targetlist == NIL);
     961             :                 Assert(splan->plan.qual == NIL);
     962         120 :                 foreach(l, splan->bitmapplans)
     963             :                 {
     964          80 :                     lfirst(l) = set_plan_refs(root,
     965          80 :                                               (Plan *) lfirst(l),
     966             :                                               rtoffset);
     967             :                 }
     968             :             }
     969          40 :             break;
     970         136 :         case T_BitmapOr:
     971         136 :             {
     972         136 :                 BitmapOr   *splan = (BitmapOr *) plan;
     973             : 
     974             :                 /* BitmapOr works like Append, but has no tlist */
     975             :                 Assert(splan->plan.targetlist == NIL);
     976             :                 Assert(splan->plan.qual == NIL);
     977         444 :                 foreach(l, splan->bitmapplans)
     978             :                 {
     979         308 :                     lfirst(l) = set_plan_refs(root,
     980         308 :                                               (Plan *) lfirst(l),
     981             :                                               rtoffset);
     982             :                 }
     983             :             }
     984         136 :             break;
     985           0 :         default:
     986           0 :             elog(ERROR, "unrecognized node type: %d",
     987             :                  (int) nodeTag(plan));
     988             :             break;
     989             :     }
     990             : 
     991             :     /*
     992             :      * Now recurse into child plans, if any
     993             :      *
     994             :      * NOTE: it is essential that we recurse into child plans AFTER we set
     995             :      * subplan references in this plan's tlist and quals.  If we did the
     996             :      * reference-adjustments bottom-up, then we would fail to match this
     997             :      * plan's var nodes against the already-modified nodes of the children.
     998             :      */
     999      651020 :     plan->lefttree = set_plan_refs(root, plan->lefttree, rtoffset);
    1000      651020 :     plan->righttree = set_plan_refs(root, plan->righttree, rtoffset);
    1001             : 
    1002      651020 :     return plan;
    1003             : }
    1004             : 
    1005             : /*
    1006             :  * set_indexonlyscan_references
    1007             :  *      Do set_plan_references processing on an IndexOnlyScan
    1008             :  *
    1009             :  * This is unlike the handling of a plain IndexScan because we have to
    1010             :  * convert Vars referencing the heap into Vars referencing the index.
    1011             :  * We can use the fix_upper_expr machinery for that, by working from a
    1012             :  * targetlist describing the index columns.
    1013             :  */
    1014             : static Plan *
    1015        8198 : set_indexonlyscan_references(PlannerInfo *root,
    1016             :                              IndexOnlyScan *plan,
    1017             :                              int rtoffset)
    1018             : {
    1019             :     indexed_tlist *index_itlist;
    1020             : 
    1021        8198 :     index_itlist = build_tlist_index(plan->indextlist);
    1022             : 
    1023        8198 :     plan->scan.scanrelid += rtoffset;
    1024        8198 :     plan->scan.plan.targetlist = (List *)
    1025        8198 :         fix_upper_expr(root,
    1026        8198 :                        (Node *) plan->scan.plan.targetlist,
    1027             :                        index_itlist,
    1028             :                        INDEX_VAR,
    1029             :                        rtoffset);
    1030        8198 :     plan->scan.plan.qual = (List *)
    1031        8198 :         fix_upper_expr(root,
    1032        8198 :                        (Node *) plan->scan.plan.qual,
    1033             :                        index_itlist,
    1034             :                        INDEX_VAR,
    1035             :                        rtoffset);
    1036             :     /* indexqual is already transformed to reference index columns */
    1037        8198 :     plan->indexqual = fix_scan_list(root, plan->indexqual, rtoffset);
    1038             :     /* indexorderby is already transformed to reference index columns */
    1039        8198 :     plan->indexorderby = fix_scan_list(root, plan->indexorderby, rtoffset);
    1040             :     /* indextlist must NOT be transformed to reference index columns */
    1041        8198 :     plan->indextlist = fix_scan_list(root, plan->indextlist, rtoffset);
    1042             : 
    1043        8198 :     pfree(index_itlist);
    1044             : 
    1045        8198 :     return (Plan *) plan;
    1046             : }
    1047             : 
    1048             : /*
    1049             :  * set_subqueryscan_references
    1050             :  *      Do set_plan_references processing on a SubqueryScan
    1051             :  *
    1052             :  * We try to strip out the SubqueryScan entirely; if we can't, we have
    1053             :  * to do the normal processing on it.
    1054             :  */
    1055             : static Plan *
    1056        9188 : set_subqueryscan_references(PlannerInfo *root,
    1057             :                             SubqueryScan *plan,
    1058             :                             int rtoffset)
    1059             : {
    1060             :     RelOptInfo *rel;
    1061             :     Plan       *result;
    1062             : 
    1063             :     /* Need to look up the subquery's RelOptInfo, since we need its subroot */
    1064        9188 :     rel = find_base_rel(root, plan->scan.scanrelid);
    1065             : 
    1066             :     /* Recursively process the subplan */
    1067        9188 :     plan->subplan = set_plan_references(rel->subroot, plan->subplan);
    1068             : 
    1069        9188 :     if (trivial_subqueryscan(plan))
    1070             :     {
    1071             :         /*
    1072             :          * We can omit the SubqueryScan node and just pull up the subplan.
    1073             :          */
    1074        6834 :         result = clean_up_removed_plan_level((Plan *) plan, plan->subplan);
    1075             :     }
    1076             :     else
    1077             :     {
    1078             :         /*
    1079             :          * Keep the SubqueryScan node.  We have to do the processing that
    1080             :          * set_plan_references would otherwise have done on it.  Notice we do
    1081             :          * not do set_upper_references() here, because a SubqueryScan will
    1082             :          * always have been created with correct references to its subplan's
    1083             :          * outputs to begin with.
    1084             :          */
    1085        2354 :         plan->scan.scanrelid += rtoffset;
    1086        2354 :         plan->scan.plan.targetlist =
    1087        2354 :             fix_scan_list(root, plan->scan.plan.targetlist, rtoffset);
    1088        2354 :         plan->scan.plan.qual =
    1089        2354 :             fix_scan_list(root, plan->scan.plan.qual, rtoffset);
    1090             : 
    1091        2354 :         result = (Plan *) plan;
    1092             :     }
    1093             : 
    1094        9188 :     return result;
    1095             : }
    1096             : 
    1097             : /*
    1098             :  * trivial_subqueryscan
    1099             :  *      Detect whether a SubqueryScan can be deleted from the plan tree.
    1100             :  *
    1101             :  * We can delete it if it has no qual to check and the targetlist just
    1102             :  * regurgitates the output of the child plan.
    1103             :  */
    1104             : static bool
    1105        9188 : trivial_subqueryscan(SubqueryScan *plan)
    1106             : {
    1107             :     int         attrno;
    1108             :     ListCell   *lp,
    1109             :                *lc;
    1110             : 
    1111        9188 :     if (plan->scan.plan.qual != NIL)
    1112         334 :         return false;
    1113             : 
    1114       17708 :     if (list_length(plan->scan.plan.targetlist) !=
    1115        8854 :         list_length(plan->subplan->targetlist))
    1116        1400 :         return false;           /* tlists not same length */
    1117             : 
    1118        7454 :     attrno = 1;
    1119       18316 :     forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
    1120             :     {
    1121       11482 :         TargetEntry *ptle = (TargetEntry *) lfirst(lp);
    1122       11482 :         TargetEntry *ctle = (TargetEntry *) lfirst(lc);
    1123             : 
    1124       11482 :         if (ptle->resjunk != ctle->resjunk)
    1125         620 :             return false;       /* tlist doesn't match junk status */
    1126             : 
    1127             :         /*
    1128             :          * We accept either a Var referencing the corresponding element of the
    1129             :          * subplan tlist, or a Const equaling the subplan element. See
    1130             :          * generate_setop_tlist() for motivation.
    1131             :          */
    1132       11462 :         if (ptle->expr && IsA(ptle->expr, Var))
    1133        9916 :         {
    1134       10008 :             Var        *var = (Var *) ptle->expr;
    1135             : 
    1136             :             Assert(var->varno == plan->scan.scanrelid);
    1137             :             Assert(var->varlevelsup == 0);
    1138       10008 :             if (var->varattno != attrno)
    1139          92 :                 return false;   /* out of order */
    1140             :         }
    1141        1454 :         else if (ptle->expr && IsA(ptle->expr, Const))
    1142             :         {
    1143        1038 :             if (!equal(ptle->expr, ctle->expr))
    1144          92 :                 return false;
    1145             :         }
    1146             :         else
    1147         416 :             return false;
    1148             : 
    1149       10862 :         attrno++;
    1150             :     }
    1151             : 
    1152        6834 :     return true;
    1153             : }
    1154             : 
    1155             : /*
    1156             :  * clean_up_removed_plan_level
    1157             :  *      Do necessary cleanup when we strip out a SubqueryScan, Append, etc
    1158             :  *
    1159             :  * We are dropping the "parent" plan in favor of returning just its "child".
    1160             :  * A few small tweaks are needed.
    1161             :  */
    1162             : static Plan *
    1163       10368 : clean_up_removed_plan_level(Plan *parent, Plan *child)
    1164             : {
    1165             :     /* We have to be sure we don't lose any initplans */
    1166       20736 :     child->initPlan = list_concat(parent->initPlan,
    1167       10368 :                                   child->initPlan);
    1168             : 
    1169             :     /*
    1170             :      * We also have to transfer the parent's column labeling info into the
    1171             :      * child, else columns sent to client will be improperly labeled if this
    1172             :      * is the topmost plan level.  resjunk and so on may be important too.
    1173             :      */
    1174       10368 :     apply_tlist_labeling(child->targetlist, parent->targetlist);
    1175             : 
    1176       10368 :     return child;
    1177             : }
    1178             : 
    1179             : /*
    1180             :  * set_foreignscan_references
    1181             :  *     Do set_plan_references processing on a ForeignScan
    1182             :  */
    1183             : static void
    1184        1398 : set_foreignscan_references(PlannerInfo *root,
    1185             :                            ForeignScan *fscan,
    1186             :                            int rtoffset)
    1187             : {
    1188             :     /* Adjust scanrelid if it's valid */
    1189        1398 :     if (fscan->scan.scanrelid > 0)
    1190         958 :         fscan->scan.scanrelid += rtoffset;
    1191             : 
    1192        1398 :     if (fscan->fdw_scan_tlist != NIL || fscan->scan.scanrelid == 0)
    1193         440 :     {
    1194             :         /*
    1195             :          * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals to reference
    1196             :          * foreign scan tuple
    1197             :          */
    1198         440 :         indexed_tlist *itlist = build_tlist_index(fscan->fdw_scan_tlist);
    1199             : 
    1200         440 :         fscan->scan.plan.targetlist = (List *)
    1201         440 :             fix_upper_expr(root,
    1202         440 :                            (Node *) fscan->scan.plan.targetlist,
    1203             :                            itlist,
    1204             :                            INDEX_VAR,
    1205             :                            rtoffset);
    1206         440 :         fscan->scan.plan.qual = (List *)
    1207         440 :             fix_upper_expr(root,
    1208         440 :                            (Node *) fscan->scan.plan.qual,
    1209             :                            itlist,
    1210             :                            INDEX_VAR,
    1211             :                            rtoffset);
    1212         440 :         fscan->fdw_exprs = (List *)
    1213         440 :             fix_upper_expr(root,
    1214         440 :                            (Node *) fscan->fdw_exprs,
    1215             :                            itlist,
    1216             :                            INDEX_VAR,
    1217             :                            rtoffset);
    1218         440 :         fscan->fdw_recheck_quals = (List *)
    1219         440 :             fix_upper_expr(root,
    1220         440 :                            (Node *) fscan->fdw_recheck_quals,
    1221             :                            itlist,
    1222             :                            INDEX_VAR,
    1223             :                            rtoffset);
    1224         440 :         pfree(itlist);
    1225             :         /* fdw_scan_tlist itself just needs fix_scan_list() adjustments */
    1226         440 :         fscan->fdw_scan_tlist =
    1227         440 :             fix_scan_list(root, fscan->fdw_scan_tlist, rtoffset);
    1228             :     }
    1229             :     else
    1230             :     {
    1231             :         /*
    1232             :          * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals in the standard
    1233             :          * way
    1234             :          */
    1235         958 :         fscan->scan.plan.targetlist =
    1236         958 :             fix_scan_list(root, fscan->scan.plan.targetlist, rtoffset);
    1237         958 :         fscan->scan.plan.qual =
    1238         958 :             fix_scan_list(root, fscan->scan.plan.qual, rtoffset);
    1239         958 :         fscan->fdw_exprs =
    1240         958 :             fix_scan_list(root, fscan->fdw_exprs, rtoffset);
    1241         958 :         fscan->fdw_recheck_quals =
    1242         958 :             fix_scan_list(root, fscan->fdw_recheck_quals, rtoffset);
    1243             :     }
    1244             : 
    1245        1398 :     fscan->fs_relids = offset_relid_set(fscan->fs_relids, rtoffset);
    1246        1398 : }
    1247             : 
    1248             : /*
    1249             :  * set_customscan_references
    1250             :  *     Do set_plan_references processing on a CustomScan
    1251             :  */
    1252             : static void
    1253           0 : set_customscan_references(PlannerInfo *root,
    1254             :                           CustomScan *cscan,
    1255             :                           int rtoffset)
    1256             : {
    1257             :     ListCell   *lc;
    1258             : 
    1259             :     /* Adjust scanrelid if it's valid */
    1260           0 :     if (cscan->scan.scanrelid > 0)
    1261           0 :         cscan->scan.scanrelid += rtoffset;
    1262             : 
    1263           0 :     if (cscan->custom_scan_tlist != NIL || cscan->scan.scanrelid == 0)
    1264           0 :     {
    1265             :         /* Adjust tlist, qual, custom_exprs to reference custom scan tuple */
    1266           0 :         indexed_tlist *itlist = build_tlist_index(cscan->custom_scan_tlist);
    1267             : 
    1268           0 :         cscan->scan.plan.targetlist = (List *)
    1269           0 :             fix_upper_expr(root,
    1270           0 :                            (Node *) cscan->scan.plan.targetlist,
    1271             :                            itlist,
    1272             :                            INDEX_VAR,
    1273             :                            rtoffset);
    1274           0 :         cscan->scan.plan.qual = (List *)
    1275           0 :             fix_upper_expr(root,
    1276           0 :                            (Node *) cscan->scan.plan.qual,
    1277             :                            itlist,
    1278             :                            INDEX_VAR,
    1279             :                            rtoffset);
    1280           0 :         cscan->custom_exprs = (List *)
    1281           0 :             fix_upper_expr(root,
    1282           0 :                            (Node *) cscan->custom_exprs,
    1283             :                            itlist,
    1284             :                            INDEX_VAR,
    1285             :                            rtoffset);
    1286           0 :         pfree(itlist);
    1287             :         /* custom_scan_tlist itself just needs fix_scan_list() adjustments */
    1288           0 :         cscan->custom_scan_tlist =
    1289           0 :             fix_scan_list(root, cscan->custom_scan_tlist, rtoffset);
    1290             :     }
    1291             :     else
    1292             :     {
    1293             :         /* Adjust tlist, qual, custom_exprs in the standard way */
    1294           0 :         cscan->scan.plan.targetlist =
    1295           0 :             fix_scan_list(root, cscan->scan.plan.targetlist, rtoffset);
    1296           0 :         cscan->scan.plan.qual =
    1297           0 :             fix_scan_list(root, cscan->scan.plan.qual, rtoffset);
    1298           0 :         cscan->custom_exprs =
    1299           0 :             fix_scan_list(root, cscan->custom_exprs, rtoffset);
    1300             :     }
    1301             : 
    1302             :     /* Adjust child plan-nodes recursively, if needed */
    1303           0 :     foreach(lc, cscan->custom_plans)
    1304             :     {
    1305           0 :         lfirst(lc) = set_plan_refs(root, (Plan *) lfirst(lc), rtoffset);
    1306             :     }
    1307             : 
    1308           0 :     cscan->custom_relids = offset_relid_set(cscan->custom_relids, rtoffset);
    1309           0 : }
    1310             : 
    1311             : /*
    1312             :  * set_append_references
    1313             :  *      Do set_plan_references processing on an Append
    1314             :  *
    1315             :  * We try to strip out the Append entirely; if we can't, we have
    1316             :  * to do the normal processing on it.
    1317             :  */
    1318             : static Plan *
    1319       10064 : set_append_references(PlannerInfo *root,
    1320             :                       Append *aplan,
    1321             :                       int rtoffset)
    1322             : {
    1323             :     ListCell   *l;
    1324             : 
    1325             :     /*
    1326             :      * Append, like Sort et al, doesn't actually evaluate its targetlist or
    1327             :      * check quals.  If it's got exactly one child plan, then it's not doing
    1328             :      * anything useful at all, and we can strip it out.
    1329             :      */
    1330             :     Assert(aplan->plan.qual == NIL);
    1331             : 
    1332             :     /* First, we gotta recurse on the children */
    1333       31834 :     foreach(l, aplan->appendplans)
    1334             :     {
    1335       21770 :         lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset);
    1336             :     }
    1337             : 
    1338             :     /* Now, if there's just one, forget the Append and return that child */
    1339       10064 :     if (list_length(aplan->appendplans) == 1)
    1340        3526 :         return clean_up_removed_plan_level((Plan *) aplan,
    1341        3526 :                                            (Plan *) linitial(aplan->appendplans));
    1342             : 
    1343             :     /*
    1344             :      * Otherwise, clean up the Append as needed.  It's okay to do this after
    1345             :      * recursing to the children, because set_dummy_tlist_references doesn't
    1346             :      * look at those.
    1347             :      */
    1348        6538 :     set_dummy_tlist_references((Plan *) aplan, rtoffset);
    1349             : 
    1350        6538 :     aplan->apprelids = offset_relid_set(aplan->apprelids, rtoffset);
    1351             : 
    1352        6538 :     if (aplan->part_prune_info)
    1353             :     {
    1354         504 :         foreach(l, aplan->part_prune_info->prune_infos)
    1355             :         {
    1356         256 :             List       *prune_infos = lfirst(l);
    1357             :             ListCell   *l2;
    1358             : 
    1359         778 :             foreach(l2, prune_infos)
    1360             :             {
    1361         522 :                 PartitionedRelPruneInfo *pinfo = lfirst(l2);
    1362             : 
    1363         522 :                 pinfo->rtindex += rtoffset;
    1364             :             }
    1365             :         }
    1366             :     }
    1367             : 
    1368             :     /* We don't need to recurse to lefttree or righttree ... */
    1369             :     Assert(aplan->plan.lefttree == NULL);
    1370             :     Assert(aplan->plan.righttree == NULL);
    1371             : 
    1372        6538 :     return (Plan *) aplan;
    1373             : }
    1374             : 
    1375             : /*
    1376             :  * set_mergeappend_references
    1377             :  *      Do set_plan_references processing on a MergeAppend
    1378             :  *
    1379             :  * We try to strip out the MergeAppend entirely; if we can't, we have
    1380             :  * to do the normal processing on it.
    1381             :  */
    1382             : static Plan *
    1383         250 : set_mergeappend_references(PlannerInfo *root,
    1384             :                            MergeAppend *mplan,
    1385             :                            int rtoffset)
    1386             : {
    1387             :     ListCell   *l;
    1388             : 
    1389             :     /*
    1390             :      * MergeAppend, like Sort et al, doesn't actually evaluate its targetlist
    1391             :      * or check quals.  If it's got exactly one child plan, then it's not
    1392             :      * doing anything useful at all, and we can strip it out.
    1393             :      */
    1394             :     Assert(mplan->plan.qual == NIL);
    1395             : 
    1396             :     /* First, we gotta recurse on the children */
    1397        1006 :     foreach(l, mplan->mergeplans)
    1398             :     {
    1399         756 :         lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset);
    1400             :     }
    1401             : 
    1402             :     /* Now, if there's just one, forget the MergeAppend and return that child */
    1403         250 :     if (list_length(mplan->mergeplans) == 1)
    1404           8 :         return clean_up_removed_plan_level((Plan *) mplan,
    1405           8 :                                            (Plan *) linitial(mplan->mergeplans));
    1406             : 
    1407             :     /*
    1408             :      * Otherwise, clean up the MergeAppend as needed.  It's okay to do this
    1409             :      * after recursing to the children, because set_dummy_tlist_references
    1410             :      * doesn't look at those.
    1411             :      */
    1412         242 :     set_dummy_tlist_references((Plan *) mplan, rtoffset);
    1413             : 
    1414         242 :     mplan->apprelids = offset_relid_set(mplan->apprelids, rtoffset);
    1415             : 
    1416         242 :     if (mplan->part_prune_info)
    1417             :     {
    1418          24 :         foreach(l, mplan->part_prune_info->prune_infos)
    1419             :         {
    1420          12 :             List       *prune_infos = lfirst(l);
    1421             :             ListCell   *l2;
    1422             : 
    1423          24 :             foreach(l2, prune_infos)
    1424             :             {
    1425          12 :                 PartitionedRelPruneInfo *pinfo = lfirst(l2);
    1426             : 
    1427          12 :                 pinfo->rtindex += rtoffset;
    1428             :             }
    1429             :         }
    1430             :     }
    1431             : 
    1432             :     /* We don't need to recurse to lefttree or righttree ... */
    1433             :     Assert(mplan->plan.lefttree == NULL);
    1434             :     Assert(mplan->plan.righttree == NULL);
    1435             : 
    1436         242 :     return (Plan *) mplan;
    1437             : }
    1438             : 
    1439             : /*
    1440             :  * set_hash_references
    1441             :  *     Do set_plan_references processing on a Hash node
    1442             :  */
    1443             : static void
    1444       29024 : set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset)
    1445             : {
    1446       29024 :     Hash       *hplan = (Hash *) plan;
    1447       29024 :     Plan       *outer_plan = plan->lefttree;
    1448             :     indexed_tlist *outer_itlist;
    1449             : 
    1450             :     /*
    1451             :      * Hash's hashkeys are used when feeding tuples into the hashtable,
    1452             :      * therefore have them reference Hash's outer plan (which itself is the
    1453             :      * inner plan of the HashJoin).
    1454             :      */
    1455       29024 :     outer_itlist = build_tlist_index(outer_plan->targetlist);
    1456       29024 :     hplan->hashkeys = (List *)
    1457       29024 :         fix_upper_expr(root,
    1458       29024 :                        (Node *) hplan->hashkeys,
    1459             :                        outer_itlist,
    1460             :                        OUTER_VAR,
    1461             :                        rtoffset);
    1462             : 
    1463             :     /* Hash doesn't project */
    1464       29024 :     set_dummy_tlist_references(plan, rtoffset);
    1465             : 
    1466             :     /* Hash nodes don't have their own quals */
    1467             :     Assert(plan->qual == NIL);
    1468       29024 : }
    1469             : 
    1470             : /*
    1471             :  * offset_relid_set
    1472             :  *      Apply rtoffset to the members of a Relids set.
    1473             :  */
    1474             : static Relids
    1475        8178 : offset_relid_set(Relids relids, int rtoffset)
    1476             : {
    1477        8178 :     Relids      result = NULL;
    1478             :     int         rtindex;
    1479             : 
    1480             :     /* If there's no offset to apply, we needn't recompute the value */
    1481        8178 :     if (rtoffset == 0)
    1482        7286 :         return relids;
    1483         892 :     rtindex = -1;
    1484        2282 :     while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
    1485        1390 :         result = bms_add_member(result, rtindex + rtoffset);
    1486         892 :     return result;
    1487             : }
    1488             : 
    1489             : /*
    1490             :  * copyVar
    1491             :  *      Copy a Var node.
    1492             :  *
    1493             :  * fix_scan_expr and friends do this enough times that it's worth having
    1494             :  * a bespoke routine instead of using the generic copyObject() function.
    1495             :  */
    1496             : static inline Var *
    1497     1121944 : copyVar(Var *var)
    1498             : {
    1499     1121944 :     Var        *newvar = (Var *) palloc(sizeof(Var));
    1500             : 
    1501     1121944 :     *newvar = *var;
    1502     1121944 :     return newvar;
    1503             : }
    1504             : 
    1505             : /*
    1506             :  * fix_expr_common
    1507             :  *      Do generic set_plan_references processing on an expression node
    1508             :  *
    1509             :  * This is code that is common to all variants of expression-fixing.
    1510             :  * We must look up operator opcode info for OpExpr and related nodes,
    1511             :  * add OIDs from regclass Const nodes into root->glob->relationOids, and
    1512             :  * add PlanInvalItems for user-defined functions into root->glob->invalItems.
    1513             :  * We also fill in column index lists for GROUPING() expressions.
    1514             :  *
    1515             :  * We assume it's okay to update opcode info in-place.  So this could possibly
    1516             :  * scribble on the planner's input data structures, but it's OK.
    1517             :  */
    1518             : static void
    1519     8062416 : fix_expr_common(PlannerInfo *root, Node *node)
    1520             : {
    1521             :     /* We assume callers won't call us on a NULL pointer */
    1522     8062416 :     if (IsA(node, Aggref))
    1523             :     {
    1524       32142 :         record_plan_function_dependency(root,
    1525             :                                         ((Aggref *) node)->aggfnoid);
    1526             :     }
    1527     8030274 :     else if (IsA(node, WindowFunc))
    1528             :     {
    1529        1408 :         record_plan_function_dependency(root,
    1530             :                                         ((WindowFunc *) node)->winfnoid);
    1531             :     }
    1532     8028866 :     else if (IsA(node, FuncExpr))
    1533             :     {
    1534      218094 :         record_plan_function_dependency(root,
    1535             :                                         ((FuncExpr *) node)->funcid);
    1536             :     }
    1537     7810772 :     else if (IsA(node, OpExpr))
    1538             :     {
    1539      469830 :         set_opfuncid((OpExpr *) node);
    1540      469830 :         record_plan_function_dependency(root,
    1541             :                                         ((OpExpr *) node)->opfuncid);
    1542             :     }
    1543     7340942 :     else if (IsA(node, DistinctExpr))
    1544             :     {
    1545         466 :         set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
    1546         466 :         record_plan_function_dependency(root,
    1547             :                                         ((DistinctExpr *) node)->opfuncid);
    1548             :     }
    1549     7340476 :     else if (IsA(node, NullIfExpr))
    1550             :     {
    1551         156 :         set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
    1552         156 :         record_plan_function_dependency(root,
    1553             :                                         ((NullIfExpr *) node)->opfuncid);
    1554             :     }
    1555     7340320 :     else if (IsA(node, ScalarArrayOpExpr))
    1556             :     {
    1557       20850 :         set_sa_opfuncid((ScalarArrayOpExpr *) node);
    1558       20850 :         record_plan_function_dependency(root,
    1559             :                                         ((ScalarArrayOpExpr *) node)->opfuncid);
    1560             :     }
    1561     7319470 :     else if (IsA(node, Const))
    1562             :     {
    1563      777710 :         Const      *con = (Const *) node;
    1564             : 
    1565             :         /* Check for regclass reference */
    1566      777710 :         if (ISREGCLASSCONST(con))
    1567      167424 :             root->glob->relationOids =
    1568      334848 :                 lappend_oid(root->glob->relationOids,
    1569      167424 :                             DatumGetObjectId(con->constvalue));
    1570             :     }
    1571     6541760 :     else if (IsA(node, GroupingFunc))
    1572             :     {
    1573         168 :         GroupingFunc *g = (GroupingFunc *) node;
    1574         168 :         AttrNumber *grouping_map = root->grouping_map;
    1575             : 
    1576             :         /* If there are no grouping sets, we don't need this. */
    1577             : 
    1578             :         Assert(grouping_map || g->cols == NIL);
    1579             : 
    1580         168 :         if (grouping_map)
    1581             :         {
    1582             :             ListCell   *lc;
    1583         132 :             List       *cols = NIL;
    1584             : 
    1585         372 :             foreach(lc, g->refs)
    1586             :             {
    1587         240 :                 cols = lappend_int(cols, grouping_map[lfirst_int(lc)]);
    1588             :             }
    1589             : 
    1590             :             Assert(!g->cols || equal(cols, g->cols));
    1591             : 
    1592         132 :             if (!g->cols)
    1593         132 :                 g->cols = cols;
    1594             :         }
    1595             :     }
    1596     8062416 : }
    1597             : 
    1598             : /*
    1599             :  * fix_param_node
    1600             :  *      Do set_plan_references processing on a Param
    1601             :  *
    1602             :  * If it's a PARAM_MULTIEXPR, replace it with the appropriate Param from
    1603             :  * root->multiexpr_params; otherwise no change is needed.
    1604             :  * Just for paranoia's sake, we make a copy of the node in either case.
    1605             :  */
    1606             : static Node *
    1607       80932 : fix_param_node(PlannerInfo *root, Param *p)
    1608             : {
    1609       80932 :     if (p->paramkind == PARAM_MULTIEXPR)
    1610             :     {
    1611         114 :         int         subqueryid = p->paramid >> 16;
    1612         114 :         int         colno = p->paramid & 0xFFFF;
    1613             :         List       *params;
    1614             : 
    1615         228 :         if (subqueryid <= 0 ||
    1616         114 :             subqueryid > list_length(root->multiexpr_params))
    1617           0 :             elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
    1618         114 :         params = (List *) list_nth(root->multiexpr_params, subqueryid - 1);
    1619         114 :         if (colno <= 0 || colno > list_length(params))
    1620           0 :             elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
    1621         114 :         return copyObject(list_nth(params, colno - 1));
    1622             :     }
    1623       80818 :     return (Node *) copyObject(p);
    1624             : }
    1625             : 
    1626             : /*
    1627             :  * fix_scan_expr
    1628             :  *      Do set_plan_references processing on a scan-level expression
    1629             :  *
    1630             :  * This consists of incrementing all Vars' varnos by rtoffset,
    1631             :  * replacing PARAM_MULTIEXPR Params, expanding PlaceHolderVars,
    1632             :  * replacing Aggref nodes that should be replaced by initplan output Params,
    1633             :  * looking up operator opcode info for OpExpr and related nodes,
    1634             :  * and adding OIDs from regclass Const nodes into root->glob->relationOids.
    1635             :  */
    1636             : static Node *
    1637     1402230 : fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset)
    1638             : {
    1639             :     fix_scan_expr_context context;
    1640             : 
    1641     1402230 :     context.root = root;
    1642     1402230 :     context.rtoffset = rtoffset;
    1643             : 
    1644     1402230 :     if (rtoffset != 0 ||
    1645     1168496 :         root->multiexpr_params != NIL ||
    1646     1168266 :         root->glob->lastPHId != 0 ||
    1647     1164254 :         root->minmax_aggs != NIL)
    1648             :     {
    1649      238840 :         return fix_scan_expr_mutator(node, &context);
    1650             :     }
    1651             :     else
    1652             :     {
    1653             :         /*
    1654             :          * If rtoffset == 0, we don't need to change any Vars, and if there
    1655             :          * are no MULTIEXPR subqueries then we don't need to replace
    1656             :          * PARAM_MULTIEXPR Params, and if there are no placeholders anywhere
    1657             :          * we won't need to remove them, and if there are no minmax Aggrefs we
    1658             :          * won't need to replace them.  Then it's OK to just scribble on the
    1659             :          * input node tree instead of copying (since the only change, filling
    1660             :          * in any unset opfuncid fields, is harmless).  This saves just enough
    1661             :          * cycles to be noticeable on trivial queries.
    1662             :          */
    1663     1163390 :         (void) fix_scan_expr_walker(node, &context);
    1664     1163390 :         return node;
    1665             :     }
    1666             : }
    1667             : 
    1668             : static Node *
    1669     1481746 : fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
    1670             : {
    1671     1481746 :     if (node == NULL)
    1672       76148 :         return NULL;
    1673     1405598 :     if (IsA(node, Var))
    1674             :     {
    1675      405124 :         Var        *var = copyVar((Var *) node);
    1676             : 
    1677             :         Assert(var->varlevelsup == 0);
    1678             : 
    1679             :         /*
    1680             :          * We should not see any Vars marked INNER_VAR or OUTER_VAR.  But an
    1681             :          * indexqual expression could contain INDEX_VAR Vars.
    1682             :          */
    1683             :         Assert(var->varno != INNER_VAR);
    1684             :         Assert(var->varno != OUTER_VAR);
    1685      405124 :         if (!IS_SPECIAL_VARNO(var->varno))
    1686      385574 :             var->varno += context->rtoffset;
    1687      405124 :         if (var->varnosyn > 0)
    1688      405124 :             var->varnosyn += context->rtoffset;
    1689      405124 :         return (Node *) var;
    1690             :     }
    1691     1000474 :     if (IsA(node, Param))
    1692       77698 :         return fix_param_node(context->root, (Param *) node);
    1693      922776 :     if (IsA(node, Aggref))
    1694             :     {
    1695         394 :         Aggref     *aggref = (Aggref *) node;
    1696             : 
    1697             :         /* See if the Aggref should be replaced by a Param */
    1698         762 :         if (context->root->minmax_aggs != NIL &&
    1699         368 :             list_length(aggref->args) == 1)
    1700             :         {
    1701         368 :             TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
    1702             :             ListCell   *lc;
    1703             : 
    1704         392 :             foreach(lc, context->root->minmax_aggs)
    1705             :             {
    1706         392 :                 MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
    1707             : 
    1708         760 :                 if (mminfo->aggfnoid == aggref->aggfnoid &&
    1709         368 :                     equal(mminfo->target, curTarget->expr))
    1710         368 :                     return (Node *) copyObject(mminfo->param);
    1711             :             }
    1712             :         }
    1713             :         /* If no match, just fall through to process it normally */
    1714             :     }
    1715      922408 :     if (IsA(node, CurrentOfExpr))
    1716             :     {
    1717           0 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
    1718             : 
    1719             :         Assert(cexpr->cvarno != INNER_VAR);
    1720             :         Assert(cexpr->cvarno != OUTER_VAR);
    1721           0 :         if (!IS_SPECIAL_VARNO(cexpr->cvarno))
    1722           0 :             cexpr->cvarno += context->rtoffset;
    1723           0 :         return (Node *) cexpr;
    1724             :     }
    1725      922408 :     if (IsA(node, PlaceHolderVar))
    1726             :     {
    1727             :         /* At scan level, we should always just evaluate the contained expr */
    1728         604 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
    1729             : 
    1730         604 :         return fix_scan_expr_mutator((Node *) phv->phexpr, context);
    1731             :     }
    1732      921804 :     fix_expr_common(context->root, node);
    1733      921804 :     return expression_tree_mutator(node, fix_scan_expr_mutator,
    1734             :                                    (void *) context);
    1735             : }
    1736             : 
    1737             : static bool
    1738     6233558 : fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
    1739             : {
    1740     6233558 :     if (node == NULL)
    1741      619188 :         return false;
    1742             :     Assert(!IsA(node, PlaceHolderVar));
    1743     5614370 :     fix_expr_common(context->root, node);
    1744     5614370 :     return expression_tree_walker(node, fix_scan_expr_walker,
    1745             :                                   (void *) context);
    1746             : }
    1747             : 
    1748             : /*
    1749             :  * set_join_references
    1750             :  *    Modify the target list and quals of a join node to reference its
    1751             :  *    subplans, by setting the varnos to OUTER_VAR or INNER_VAR and setting
    1752             :  *    attno values to the result domain number of either the corresponding
    1753             :  *    outer or inner join tuple item.  Also perform opcode lookup for these
    1754             :  *    expressions, and add regclass OIDs to root->glob->relationOids.
    1755             :  */
    1756             : static void
    1757       64698 : set_join_references(PlannerInfo *root, Join *join, int rtoffset)
    1758             : {
    1759       64698 :     Plan       *outer_plan = join->plan.lefttree;
    1760       64698 :     Plan       *inner_plan = join->plan.righttree;
    1761             :     indexed_tlist *outer_itlist;
    1762             :     indexed_tlist *inner_itlist;
    1763             : 
    1764       64698 :     outer_itlist = build_tlist_index(outer_plan->targetlist);
    1765       64698 :     inner_itlist = build_tlist_index(inner_plan->targetlist);
    1766             : 
    1767             :     /*
    1768             :      * First process the joinquals (including merge or hash clauses).  These
    1769             :      * are logically below the join so they can always use all values
    1770             :      * available from the input tlists.  It's okay to also handle
    1771             :      * NestLoopParams now, because those couldn't refer to nullable
    1772             :      * subexpressions.
    1773             :      */
    1774       64698 :     join->joinqual = fix_join_expr(root,
    1775             :                                    join->joinqual,
    1776             :                                    outer_itlist,
    1777             :                                    inner_itlist,
    1778             :                                    (Index) 0,
    1779             :                                    rtoffset);
    1780             : 
    1781             :     /* Now do join-type-specific stuff */
    1782       64698 :     if (IsA(join, NestLoop))
    1783             :     {
    1784       33524 :         NestLoop   *nl = (NestLoop *) join;
    1785             :         ListCell   *lc;
    1786             : 
    1787       53504 :         foreach(lc, nl->nestParams)
    1788             :         {
    1789       19980 :             NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
    1790             : 
    1791       39960 :             nlp->paramval = (Var *) fix_upper_expr(root,
    1792       19980 :                                                    (Node *) nlp->paramval,
    1793             :                                                    outer_itlist,
    1794             :                                                    OUTER_VAR,
    1795             :                                                    rtoffset);
    1796             :             /* Check we replaced any PlaceHolderVar with simple Var */
    1797       19980 :             if (!(IsA(nlp->paramval, Var) &&
    1798       19980 :                   nlp->paramval->varno == OUTER_VAR))
    1799           0 :                 elog(ERROR, "NestLoopParam was not reduced to a simple Var");
    1800             :         }
    1801             :     }
    1802       31174 :     else if (IsA(join, MergeJoin))
    1803             :     {
    1804        2150 :         MergeJoin  *mj = (MergeJoin *) join;
    1805             : 
    1806        2150 :         mj->mergeclauses = fix_join_expr(root,
    1807             :                                          mj->mergeclauses,
    1808             :                                          outer_itlist,
    1809             :                                          inner_itlist,
    1810             :                                          (Index) 0,
    1811             :                                          rtoffset);
    1812             :     }
    1813       29024 :     else if (IsA(join, HashJoin))
    1814             :     {
    1815       29024 :         HashJoin   *hj = (HashJoin *) join;
    1816             : 
    1817       29024 :         hj->hashclauses = fix_join_expr(root,
    1818             :                                         hj->hashclauses,
    1819             :                                         outer_itlist,
    1820             :                                         inner_itlist,
    1821             :                                         (Index) 0,
    1822             :                                         rtoffset);
    1823             : 
    1824             :         /*
    1825             :          * HashJoin's hashkeys are used to look for matching tuples from its
    1826             :          * outer plan (not the Hash node!) in the hashtable.
    1827             :          */
    1828       29024 :         hj->hashkeys = (List *) fix_upper_expr(root,
    1829       29024 :                                                (Node *) hj->hashkeys,
    1830             :                                                outer_itlist,
    1831             :                                                OUTER_VAR,
    1832             :                                                rtoffset);
    1833             :     }
    1834             : 
    1835             :     /*
    1836             :      * Now we need to fix up the targetlist and qpqual, which are logically
    1837             :      * above the join.  This means they should not re-use any input expression
    1838             :      * that was computed in the nullable side of an outer join.  Vars and
    1839             :      * PlaceHolderVars are fine, so we can implement this restriction just by
    1840             :      * clearing has_non_vars in the indexed_tlist structs.
    1841             :      *
    1842             :      * XXX This is a grotty workaround for the fact that we don't clearly
    1843             :      * distinguish between a Var appearing below an outer join and the "same"
    1844             :      * Var appearing above it.  If we did, we'd not need to hack the matching
    1845             :      * rules this way.
    1846             :      */
    1847       64698 :     switch (join->jointype)
    1848             :     {
    1849       27140 :         case JOIN_LEFT:
    1850             :         case JOIN_SEMI:
    1851             :         case JOIN_ANTI:
    1852       27140 :             inner_itlist->has_non_vars = false;
    1853       27140 :             break;
    1854        5472 :         case JOIN_RIGHT:
    1855        5472 :             outer_itlist->has_non_vars = false;
    1856        5472 :             break;
    1857         782 :         case JOIN_FULL:
    1858         782 :             outer_itlist->has_non_vars = false;
    1859         782 :             inner_itlist->has_non_vars = false;
    1860         782 :             break;
    1861       31304 :         default:
    1862       31304 :             break;
    1863             :     }
    1864             : 
    1865       64698 :     join->plan.targetlist = fix_join_expr(root,
    1866             :                                           join->plan.targetlist,
    1867             :                                           outer_itlist,
    1868             :                                           inner_itlist,
    1869             :                                           (Index) 0,
    1870             :                                           rtoffset);
    1871       64698 :     join->plan.qual = fix_join_expr(root,
    1872             :                                     join->plan.qual,
    1873             :                                     outer_itlist,
    1874             :                                     inner_itlist,
    1875             :                                     (Index) 0,
    1876             :                                     rtoffset);
    1877             : 
    1878       64698 :     pfree(outer_itlist);
    1879       64698 :     pfree(inner_itlist);
    1880       64698 : }
    1881             : 
    1882             : /*
    1883             :  * set_upper_references
    1884             :  *    Update the targetlist and quals of an upper-level plan node
    1885             :  *    to refer to the tuples returned by its lefttree subplan.
    1886             :  *    Also perform opcode lookup for these expressions, and
    1887             :  *    add regclass OIDs to root->glob->relationOids.
    1888             :  *
    1889             :  * This is used for single-input plan types like Agg, Group, Result.
    1890             :  *
    1891             :  * In most cases, we have to match up individual Vars in the tlist and
    1892             :  * qual expressions with elements of the subplan's tlist (which was
    1893             :  * generated by flattening these selfsame expressions, so it should have all
    1894             :  * the required variables).  There is an important exception, however:
    1895             :  * depending on where we are in the plan tree, sort/group columns may have
    1896             :  * been pushed into the subplan tlist unflattened.  If these values are also
    1897             :  * needed in the output then we want to reference the subplan tlist element
    1898             :  * rather than recomputing the expression.
    1899             :  */
    1900             : static void
    1901       35906 : set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
    1902             : {
    1903       35906 :     Plan       *subplan = plan->lefttree;
    1904             :     indexed_tlist *subplan_itlist;
    1905             :     List       *output_targetlist;
    1906             :     ListCell   *l;
    1907             : 
    1908       35906 :     subplan_itlist = build_tlist_index(subplan->targetlist);
    1909             : 
    1910       35906 :     output_targetlist = NIL;
    1911       85344 :     foreach(l, plan->targetlist)
    1912             :     {
    1913       49438 :         TargetEntry *tle = (TargetEntry *) lfirst(l);
    1914             :         Node       *newexpr;
    1915             : 
    1916             :         /* If it's a sort/group item, first try to match by sortref */
    1917       49438 :         if (tle->ressortgroupref != 0)
    1918             :         {
    1919             :             newexpr = (Node *)
    1920        8258 :                 search_indexed_tlist_for_sortgroupref(tle->expr,
    1921             :                                                       tle->ressortgroupref,
    1922             :                                                       subplan_itlist,
    1923             :                                                       OUTER_VAR);
    1924        8258 :             if (!newexpr)
    1925        1544 :                 newexpr = fix_upper_expr(root,
    1926        1544 :                                          (Node *) tle->expr,
    1927             :                                          subplan_itlist,
    1928             :                                          OUTER_VAR,
    1929             :                                          rtoffset);
    1930             :         }
    1931             :         else
    1932       41180 :             newexpr = fix_upper_expr(root,
    1933       41180 :                                      (Node *) tle->expr,
    1934             :                                      subplan_itlist,
    1935             :                                      OUTER_VAR,
    1936             :                                      rtoffset);
    1937       49438 :         tle = flatCopyTargetEntry(tle);
    1938       49438 :         tle->expr = (Expr *) newexpr;
    1939       49438 :         output_targetlist = lappend(output_targetlist, tle);
    1940             :     }
    1941       35906 :     plan->targetlist = output_targetlist;
    1942             : 
    1943       35906 :     plan->qual = (List *)
    1944       35906 :         fix_upper_expr(root,
    1945       35906 :                        (Node *) plan->qual,
    1946             :                        subplan_itlist,
    1947             :                        OUTER_VAR,
    1948             :                        rtoffset);
    1949             : 
    1950       35906 :     pfree(subplan_itlist);
    1951       35906 : }
    1952             : 
    1953             : /*
    1954             :  * set_param_references
    1955             :  *    Initialize the initParam list in Gather or Gather merge node such that
    1956             :  *    it contains reference of all the params that needs to be evaluated
    1957             :  *    before execution of the node.  It contains the initplan params that are
    1958             :  *    being passed to the plan nodes below it.
    1959             :  */
    1960             : static void
    1961         672 : set_param_references(PlannerInfo *root, Plan *plan)
    1962             : {
    1963             :     Assert(IsA(plan, Gather) || IsA(plan, GatherMerge));
    1964             : 
    1965         672 :     if (plan->lefttree->extParam)
    1966             :     {
    1967             :         PlannerInfo *proot;
    1968         654 :         Bitmapset  *initSetParam = NULL;
    1969             :         ListCell   *l;
    1970             : 
    1971        1400 :         for (proot = root; proot != NULL; proot = proot->parent_root)
    1972             :         {
    1973         786 :             foreach(l, proot->init_plans)
    1974             :             {
    1975          40 :                 SubPlan    *initsubplan = (SubPlan *) lfirst(l);
    1976             :                 ListCell   *l2;
    1977             : 
    1978          80 :                 foreach(l2, initsubplan->setParam)
    1979             :                 {
    1980          40 :                     initSetParam = bms_add_member(initSetParam, lfirst_int(l2));
    1981             :                 }
    1982             :             }
    1983             :         }
    1984             : 
    1985             :         /*
    1986             :          * Remember the list of all external initplan params that are used by
    1987             :          * the children of Gather or Gather merge node.
    1988             :          */
    1989         654 :         if (IsA(plan, Gather))
    1990         502 :             ((Gather *) plan)->initParam =
    1991         502 :                 bms_intersect(plan->lefttree->extParam, initSetParam);
    1992             :         else
    1993         152 :             ((GatherMerge *) plan)->initParam =
    1994         152 :                 bms_intersect(plan->lefttree->extParam, initSetParam);
    1995             :     }
    1996         672 : }
    1997             : 
    1998             : /*
    1999             :  * Recursively scan an expression tree and convert Aggrefs to the proper
    2000             :  * intermediate form for combining aggregates.  This means (1) replacing each
    2001             :  * one's argument list with a single argument that is the original Aggref
    2002             :  * modified to show partial aggregation and (2) changing the upper Aggref to
    2003             :  * show combining aggregation.
    2004             :  *
    2005             :  * After this step, set_upper_references will replace the partial Aggrefs
    2006             :  * with Vars referencing the lower Agg plan node's outputs, so that the final
    2007             :  * form seen by the executor is a combining Aggref with a Var as input.
    2008             :  *
    2009             :  * It's rather messy to postpone this step until setrefs.c; ideally it'd be
    2010             :  * done in createplan.c.  The difficulty is that once we modify the Aggref
    2011             :  * expressions, they will no longer be equal() to their original form and
    2012             :  * so cross-plan-node-level matches will fail.  So this has to happen after
    2013             :  * the plan node above the Agg has resolved its subplan references.
    2014             :  */
    2015             : static Node *
    2016        3540 : convert_combining_aggrefs(Node *node, void *context)
    2017             : {
    2018        3540 :     if (node == NULL)
    2019         378 :         return NULL;
    2020        3162 :     if (IsA(node, Aggref))
    2021             :     {
    2022         814 :         Aggref     *orig_agg = (Aggref *) node;
    2023             :         Aggref     *child_agg;
    2024             :         Aggref     *parent_agg;
    2025             : 
    2026             :         /* Assert we've not chosen to partial-ize any unsupported cases */
    2027             :         Assert(orig_agg->aggorder == NIL);
    2028             :         Assert(orig_agg->aggdistinct == NIL);
    2029             : 
    2030             :         /*
    2031             :          * Since aggregate calls can't be nested, we needn't recurse into the
    2032             :          * arguments.  But for safety, flat-copy the Aggref node itself rather
    2033             :          * than modifying it in-place.
    2034             :          */
    2035         814 :         child_agg = makeNode(Aggref);
    2036         814 :         memcpy(child_agg, orig_agg, sizeof(Aggref));
    2037             : 
    2038             :         /*
    2039             :          * For the parent Aggref, we want to copy all the fields of the
    2040             :          * original aggregate *except* the args list, which we'll replace
    2041             :          * below, and the aggfilter expression, which should be applied only
    2042             :          * by the child not the parent.  Rather than explicitly knowing about
    2043             :          * all the other fields here, we can momentarily modify child_agg to
    2044             :          * provide a suitable source for copyObject.
    2045             :          */
    2046         814 :         child_agg->args = NIL;
    2047         814 :         child_agg->aggfilter = NULL;
    2048         814 :         parent_agg = copyObject(child_agg);
    2049         814 :         child_agg->args = orig_agg->args;
    2050         814 :         child_agg->aggfilter = orig_agg->aggfilter;
    2051             : 
    2052             :         /*
    2053             :          * Now, set up child_agg to represent the first phase of partial
    2054             :          * aggregation.  For now, assume serialization is required.
    2055             :          */
    2056         814 :         mark_partial_aggref(child_agg, AGGSPLIT_INITIAL_SERIAL);
    2057             : 
    2058             :         /*
    2059             :          * And set up parent_agg to represent the second phase.
    2060             :          */
    2061         814 :         parent_agg->args = list_make1(makeTargetEntry((Expr *) child_agg,
    2062             :                                                       1, NULL, false));
    2063         814 :         mark_partial_aggref(parent_agg, AGGSPLIT_FINAL_DESERIAL);
    2064             : 
    2065         814 :         return (Node *) parent_agg;
    2066             :     }
    2067        2348 :     return expression_tree_mutator(node, convert_combining_aggrefs,
    2068             :                                    (void *) context);
    2069             : }
    2070             : 
    2071             : /*
    2072             :  * set_dummy_tlist_references
    2073             :  *    Replace the targetlist of an upper-level plan node with a simple
    2074             :  *    list of OUTER_VAR references to its child.
    2075             :  *
    2076             :  * This is used for plan types like Sort and Append that don't evaluate
    2077             :  * their targetlists.  Although the executor doesn't care at all what's in
    2078             :  * the tlist, EXPLAIN needs it to be realistic.
    2079             :  *
    2080             :  * Note: we could almost use set_upper_references() here, but it fails for
    2081             :  * Append for lack of a lefttree subplan.  Single-purpose code is faster
    2082             :  * anyway.
    2083             :  */
    2084             : static void
    2085       82668 : set_dummy_tlist_references(Plan *plan, int rtoffset)
    2086             : {
    2087             :     List       *output_targetlist;
    2088             :     ListCell   *l;
    2089             : 
    2090       82668 :     output_targetlist = NIL;
    2091      394308 :     foreach(l, plan->targetlist)
    2092             :     {
    2093      311640 :         TargetEntry *tle = (TargetEntry *) lfirst(l);
    2094      311640 :         Var        *oldvar = (Var *) tle->expr;
    2095             :         Var        *newvar;
    2096             : 
    2097             :         /*
    2098             :          * As in search_indexed_tlist_for_non_var(), we prefer to keep Consts
    2099             :          * as Consts, not Vars referencing Consts.  Here, there's no speed
    2100             :          * advantage to be had, but it makes EXPLAIN output look cleaner, and
    2101             :          * again it avoids confusing the executor.
    2102             :          */
    2103      311640 :         if (IsA(oldvar, Const))
    2104             :         {
    2105             :             /* just reuse the existing TLE node */
    2106       10244 :             output_targetlist = lappend(output_targetlist, tle);
    2107       10244 :             continue;
    2108             :         }
    2109             : 
    2110      301396 :         newvar = makeVar(OUTER_VAR,
    2111      301396 :                          tle->resno,
    2112             :                          exprType((Node *) oldvar),
    2113             :                          exprTypmod((Node *) oldvar),
    2114             :                          exprCollation((Node *) oldvar),
    2115             :                          0);
    2116      301396 :         if (IsA(oldvar, Var) &&
    2117      247966 :             oldvar->varnosyn > 0)
    2118             :         {
    2119      242388 :             newvar->varnosyn = oldvar->varnosyn + rtoffset;
    2120      242388 :             newvar->varattnosyn = oldvar->varattnosyn;
    2121             :         }
    2122             :         else
    2123             :         {
    2124       59008 :             newvar->varnosyn = 0;    /* wasn't ever a plain Var */
    2125       59008 :             newvar->varattnosyn = 0;
    2126             :         }
    2127             : 
    2128      301396 :         tle = flatCopyTargetEntry(tle);
    2129      301396 :         tle->expr = (Expr *) newvar;
    2130      301396 :         output_targetlist = lappend(output_targetlist, tle);
    2131             :     }
    2132       82668 :     plan->targetlist = output_targetlist;
    2133             : 
    2134             :     /* We don't touch plan->qual here */
    2135       82668 : }
    2136             : 
    2137             : 
    2138             : /*
    2139             :  * build_tlist_index --- build an index data structure for a child tlist
    2140             :  *
    2141             :  * In most cases, subplan tlists will be "flat" tlists with only Vars,
    2142             :  * so we try to optimize that case by extracting information about Vars
    2143             :  * in advance.  Matching a parent tlist to a child is still an O(N^2)
    2144             :  * operation, but at least with a much smaller constant factor than plain
    2145             :  * tlist_member() searches.
    2146             :  *
    2147             :  * The result of this function is an indexed_tlist struct to pass to
    2148             :  * search_indexed_tlist_for_var() or search_indexed_tlist_for_non_var().
    2149             :  * When done, the indexed_tlist may be freed with a single pfree().
    2150             :  */
    2151             : static indexed_tlist *
    2152      203828 : build_tlist_index(List *tlist)
    2153             : {
    2154             :     indexed_tlist *itlist;
    2155             :     tlist_vinfo *vinfo;
    2156             :     ListCell   *l;
    2157             : 
    2158             :     /* Create data structure with enough slots for all tlist entries */
    2159             :     itlist = (indexed_tlist *)
    2160      203828 :         palloc(offsetof(indexed_tlist, vars) +
    2161      203828 :                list_length(tlist) * sizeof(tlist_vinfo));
    2162             : 
    2163      203828 :     itlist->tlist = tlist;
    2164      203828 :     itlist->has_ph_vars = false;
    2165      203828 :     itlist->has_non_vars = false;
    2166             : 
    2167             :     /* Find the Vars and fill in the index array */
    2168      203828 :     vinfo = itlist->vars;
    2169     1919750 :     foreach(l, tlist)
    2170             :     {
    2171     1715922 :         TargetEntry *tle = (TargetEntry *) lfirst(l);
    2172             : 
    2173     1715922 :         if (tle->expr && IsA(tle->expr, Var))
    2174     1711002 :         {
    2175     1711002 :             Var        *var = (Var *) tle->expr;
    2176             : 
    2177     1711002 :             vinfo->varno = var->varno;
    2178     1711002 :             vinfo->varattno = var->varattno;
    2179     1711002 :             vinfo->resno = tle->resno;
    2180     1711002 :             vinfo++;
    2181             :         }
    2182        4920 :         else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
    2183        1146 :             itlist->has_ph_vars = true;
    2184             :         else
    2185        3774 :             itlist->has_non_vars = true;
    2186             :     }
    2187             : 
    2188      203828 :     itlist->num_vars = (vinfo - itlist->vars);
    2189             : 
    2190      203828 :     return itlist;
    2191             : }
    2192             : 
    2193             : /*
    2194             :  * build_tlist_index_other_vars --- build a restricted tlist index
    2195             :  *
    2196             :  * This is like build_tlist_index, but we only index tlist entries that
    2197             :  * are Vars belonging to some rel other than the one specified.  We will set
    2198             :  * has_ph_vars (allowing PlaceHolderVars to be matched), but not has_non_vars
    2199             :  * (so nothing other than Vars and PlaceHolderVars can be matched).
    2200             :  */
    2201             : static indexed_tlist *
    2202        1818 : build_tlist_index_other_vars(List *tlist, Index ignore_rel)
    2203             : {
    2204             :     indexed_tlist *itlist;
    2205             :     tlist_vinfo *vinfo;
    2206             :     ListCell   *l;
    2207             : 
    2208             :     /* Create data structure with enough slots for all tlist entries */
    2209             :     itlist = (indexed_tlist *)
    2210        1818 :         palloc(offsetof(indexed_tlist, vars) +
    2211        1818 :                list_length(tlist) * sizeof(tlist_vinfo));
    2212             : 
    2213        1818 :     itlist->tlist = tlist;
    2214        1818 :     itlist->has_ph_vars = false;
    2215        1818 :     itlist->has_non_vars = false;
    2216             : 
    2217             :     /* Find the desired Vars and fill in the index array */
    2218        1818 :     vinfo = itlist->vars;
    2219        7802 :     foreach(l, tlist)
    2220             :     {
    2221        5984 :         TargetEntry *tle = (TargetEntry *) lfirst(l);
    2222             : 
    2223        5984 :         if (tle->expr && IsA(tle->expr, Var))
    2224        3468 :         {
    2225        3468 :             Var        *var = (Var *) tle->expr;
    2226             : 
    2227        3468 :             if (var->varno != ignore_rel)
    2228             :             {
    2229        1036 :                 vinfo->varno = var->varno;
    2230        1036 :                 vinfo->varattno = var->varattno;
    2231        1036 :                 vinfo->resno = tle->resno;
    2232        1036 :                 vinfo++;
    2233             :             }
    2234             :         }
    2235        2516 :         else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
    2236           0 :             itlist->has_ph_vars = true;
    2237             :     }
    2238             : 
    2239        1818 :     itlist->num_vars = (vinfo - itlist->vars);
    2240             : 
    2241        1818 :     return itlist;
    2242             : }
    2243             : 
    2244             : /*
    2245             :  * search_indexed_tlist_for_var --- find a Var in an indexed tlist
    2246             :  *
    2247             :  * If a match is found, return a copy of the given Var with suitably
    2248             :  * modified varno/varattno (to wit, newvarno and the resno of the TLE entry).
    2249             :  * Also ensure that varnosyn is incremented by rtoffset.
    2250             :  * If no match, return NULL.
    2251             :  */
    2252             : static Var *
    2253      918010 : search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist,
    2254             :                              Index newvarno, int rtoffset)
    2255             : {
    2256      918010 :     Index       varno = var->varno;
    2257      918010 :     AttrNumber  varattno = var->varattno;
    2258             :     tlist_vinfo *vinfo;
    2259             :     int         i;
    2260             : 
    2261      918010 :     vinfo = itlist->vars;
    2262      918010 :     i = itlist->num_vars;
    2263     7694124 :     while (i-- > 0)
    2264             :     {
    2265     7486982 :         if (vinfo->varno == varno && vinfo->varattno == varattno)
    2266             :         {
    2267             :             /* Found a match */
    2268      710868 :             Var        *newvar = copyVar(var);
    2269             : 
    2270      710868 :             newvar->varno = newvarno;
    2271      710868 :             newvar->varattno = vinfo->resno;
    2272      710868 :             if (newvar->varnosyn > 0)
    2273      710400 :                 newvar->varnosyn += rtoffset;
    2274      710868 :             return newvar;
    2275             :         }
    2276     6776114 :         vinfo++;
    2277             :     }
    2278      207142 :     return NULL;                /* no match */
    2279             : }
    2280             : 
    2281             : /*
    2282             :  * search_indexed_tlist_for_non_var --- find a non-Var in an indexed tlist
    2283             :  *
    2284             :  * If a match is found, return a Var constructed to reference the tlist item.
    2285             :  * If no match, return NULL.
    2286             :  *
    2287             :  * NOTE: it is a waste of time to call this unless itlist->has_ph_vars or
    2288             :  * itlist->has_non_vars.  Furthermore, set_join_references() relies on being
    2289             :  * able to prevent matching of non-Vars by clearing itlist->has_non_vars,
    2290             :  * so there's a correctness reason not to call it unless that's set.
    2291             :  */
    2292             : static Var *
    2293       15218 : search_indexed_tlist_for_non_var(Expr *node,
    2294             :                                  indexed_tlist *itlist, Index newvarno)
    2295             : {
    2296             :     TargetEntry *tle;
    2297             : 
    2298             :     /*
    2299             :      * If it's a simple Const, replacing it with a Var is silly, even if there
    2300             :      * happens to be an identical Const below; a Var is more expensive to
    2301             :      * execute than a Const.  What's more, replacing it could confuse some
    2302             :      * places in the executor that expect to see simple Consts for, eg,
    2303             :      * dropped columns.
    2304             :      */
    2305       15218 :     if (IsA(node, Const))
    2306        1346 :         return NULL;
    2307             : 
    2308       13872 :     tle = tlist_member(node, itlist->tlist);
    2309       13872 :     if (tle)
    2310             :     {
    2311             :         /* Found a matching subplan output expression */
    2312             :         Var        *newvar;
    2313             : 
    2314        4194 :         newvar = makeVarFromTargetEntry(newvarno, tle);
    2315        4194 :         newvar->varnosyn = 0;    /* wasn't ever a plain Var */
    2316        4194 :         newvar->varattnosyn = 0;
    2317        4194 :         return newvar;
    2318             :     }
    2319        9678 :     return NULL;                /* no match */
    2320             : }
    2321             : 
    2322             : /*
    2323             :  * search_indexed_tlist_for_sortgroupref --- find a sort/group expression
    2324             :  *
    2325             :  * If a match is found, return a Var constructed to reference the tlist item.
    2326             :  * If no match, return NULL.
    2327             :  *
    2328             :  * This is needed to ensure that we select the right subplan TLE in cases
    2329             :  * where there are multiple textually-equal()-but-volatile sort expressions.
    2330             :  * And it's also faster than search_indexed_tlist_for_non_var.
    2331             :  */
    2332             : static Var *
    2333        8258 : search_indexed_tlist_for_sortgroupref(Expr *node,
    2334             :                                       Index sortgroupref,
    2335             :                                       indexed_tlist *itlist,
    2336             :                                       Index newvarno)
    2337             : {
    2338             :     ListCell   *lc;
    2339             : 
    2340       16798 :     foreach(lc, itlist->tlist)
    2341             :     {
    2342       15254 :         TargetEntry *tle = (TargetEntry *) lfirst(lc);
    2343             : 
    2344             :         /* The equal() check should be redundant, but let's be paranoid */
    2345       21992 :         if (tle->ressortgroupref == sortgroupref &&
    2346        6738 :             equal(node, tle->expr))
    2347             :         {
    2348             :             /* Found a matching subplan output expression */
    2349             :             Var        *newvar;
    2350             : 
    2351        6714 :             newvar = makeVarFromTargetEntry(newvarno, tle);
    2352        6714 :             newvar->varnosyn = 0;    /* wasn't ever a plain Var */
    2353        6714 :             newvar->varattnosyn = 0;
    2354        6714 :             return newvar;
    2355             :         }
    2356             :     }
    2357        1544 :     return NULL;                /* no match */
    2358             : }
    2359             : 
    2360             : /*
    2361             :  * fix_join_expr
    2362             :  *     Create a new set of targetlist entries or join qual clauses by
    2363             :  *     changing the varno/varattno values of variables in the clauses
    2364             :  *     to reference target list values from the outer and inner join
    2365             :  *     relation target lists.  Also perform opcode lookup and add
    2366             :  *     regclass OIDs to root->glob->relationOids.
    2367             :  *
    2368             :  * This is used in three different scenarios:
    2369             :  * 1) a normal join clause, where all the Vars in the clause *must* be
    2370             :  *    replaced by OUTER_VAR or INNER_VAR references.  In this case
    2371             :  *    acceptable_rel should be zero so that any failure to match a Var will be
    2372             :  *    reported as an error.
    2373             :  * 2) RETURNING clauses, which may contain both Vars of the target relation
    2374             :  *    and Vars of other relations. In this case we want to replace the
    2375             :  *    other-relation Vars by OUTER_VAR references, while leaving target Vars
    2376             :  *    alone. Thus inner_itlist = NULL and acceptable_rel = the ID of the
    2377             :  *    target relation should be passed.
    2378             :  * 3) ON CONFLICT UPDATE SET/WHERE clauses.  Here references to EXCLUDED are
    2379             :  *    to be replaced with INNER_VAR references, while leaving target Vars (the
    2380             :  *    to-be-updated relation) alone. Correspondingly inner_itlist is to be
    2381             :  *    EXCLUDED elements, outer_itlist = NULL and acceptable_rel the target
    2382             :  *    relation.
    2383             :  *
    2384             :  * 'clauses' is the targetlist or list of join clauses
    2385             :  * 'outer_itlist' is the indexed target list of the outer join relation,
    2386             :  *      or NULL
    2387             :  * 'inner_itlist' is the indexed target list of the inner join relation,
    2388             :  *      or NULL
    2389             :  * 'acceptable_rel' is either zero or the rangetable index of a relation
    2390             :  *      whose Vars may appear in the clause without provoking an error
    2391             :  * 'rtoffset': how much to increment varnos by
    2392             :  *
    2393             :  * Returns the new expression tree.  The original clause structure is
    2394             :  * not modified.
    2395             :  */
    2396             : static List *
    2397      228814 : fix_join_expr(PlannerInfo *root,
    2398             :               List *clauses,
    2399             :               indexed_tlist *outer_itlist,
    2400             :               indexed_tlist *inner_itlist,
    2401             :               Index acceptable_rel,
    2402             :               int rtoffset)
    2403             : {
    2404             :     fix_join_expr_context context;
    2405             : 
    2406      228814 :     context.root = root;
    2407      228814 :     context.outer_itlist = outer_itlist;
    2408      228814 :     context.inner_itlist = inner_itlist;
    2409      228814 :     context.acceptable_rel = acceptable_rel;
    2410      228814 :     context.rtoffset = rtoffset;
    2411      228814 :     return (List *) fix_join_expr_mutator((Node *) clauses, &context);
    2412             : }
    2413             : 
    2414             : static Node *
    2415     1713812 : fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
    2416             : {
    2417             :     Var        *newvar;
    2418             : 
    2419     1713812 :     if (node == NULL)
    2420      154406 :         return NULL;
    2421     1559406 :     if (IsA(node, Var))
    2422             :     {
    2423      585412 :         Var        *var = (Var *) node;
    2424             : 
    2425             :         /* Look for the var in the input tlists, first in the outer */
    2426      585412 :         if (context->outer_itlist)
    2427             :         {
    2428      583106 :             newvar = search_indexed_tlist_for_var(var,
    2429             :                                                   context->outer_itlist,
    2430             :                                                   OUTER_VAR,
    2431             :                                                   context->rtoffset);
    2432      583106 :             if (newvar)
    2433      377622 :                 return (Node *) newvar;
    2434             :         }
    2435             : 
    2436             :         /* then in the inner. */
    2437      207790 :         if (context->inner_itlist)
    2438             :         {
    2439      203496 :             newvar = search_indexed_tlist_for_var(var,
    2440             :                                                   context->inner_itlist,
    2441             :                                                   INNER_VAR,
    2442             :                                                   context->rtoffset);
    2443      203496 :             if (newvar)
    2444      201838 :                 return (Node *) newvar;
    2445             :         }
    2446             : 
    2447             :         /* If it's for acceptable_rel, adjust and return it */
    2448        5952 :         if (var->varno == context->acceptable_rel)
    2449             :         {
    2450        5952 :             var = copyVar(var);
    2451        5952 :             var->varno += context->rtoffset;
    2452        5952 :             if (var->varnosyn > 0)
    2453        5860 :                 var->varnosyn += context->rtoffset;
    2454        5952 :             return (Node *) var;
    2455             :         }
    2456             : 
    2457             :         /* No referent found for Var */
    2458           0 :         elog(ERROR, "variable not found in subplan target lists");
    2459             :     }
    2460      973994 :     if (IsA(node, PlaceHolderVar))
    2461             :     {
    2462        1076 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
    2463             : 
    2464             :         /* See if the PlaceHolderVar has bubbled up from a lower plan node */
    2465        1076 :         if (context->outer_itlist && context->outer_itlist->has_ph_vars)
    2466             :         {
    2467         540 :             newvar = search_indexed_tlist_for_non_var((Expr *) phv,
    2468             :                                                       context->outer_itlist,
    2469             :                                                       OUTER_VAR);
    2470         540 :             if (newvar)
    2471         358 :                 return (Node *) newvar;
    2472             :         }
    2473         718 :         if (context->inner_itlist && context->inner_itlist->has_ph_vars)
    2474             :         {
    2475         586 :             newvar = search_indexed_tlist_for_non_var((Expr *) phv,
    2476             :                                                       context->inner_itlist,
    2477             :                                                       INNER_VAR);
    2478         586 :             if (newvar)
    2479         550 :                 return (Node *) newvar;
    2480             :         }
    2481             : 
    2482             :         /* If not supplied by input plans, evaluate the contained expr */
    2483         168 :         return fix_join_expr_mutator((Node *) phv->phexpr, context);
    2484             :     }
    2485             :     /* Try matching more complex expressions too, if tlists have any */
    2486      972918 :     if (context->outer_itlist && context->outer_itlist->has_non_vars)
    2487             :     {
    2488         404 :         newvar = search_indexed_tlist_for_non_var((Expr *) node,
    2489             :                                                   context->outer_itlist,
    2490             :                                                   OUTER_VAR);
    2491         404 :         if (newvar)
    2492          36 :             return (Node *) newvar;
    2493             :     }
    2494      972882 :     if (context->inner_itlist && context->inner_itlist->has_non_vars)
    2495             :     {
    2496         594 :         newvar = search_indexed_tlist_for_non_var((Expr *) node,
    2497             :                                                   context->inner_itlist,
    2498             :                                                   INNER_VAR);
    2499         594 :         if (newvar)
    2500          56 :             return (Node *) newvar;
    2501             :     }
    2502             :     /* Special cases (apply only AFTER failing to match to lower tlist) */
    2503      972826 :     if (IsA(node, Param))
    2504        2512 :         return fix_param_node(context->root, (Param *) node);
    2505      970314 :     fix_expr_common(context->root, node);
    2506      970314 :     return expression_tree_mutator(node,
    2507             :                                    fix_join_expr_mutator,
    2508             :                                    (void *) context);
    2509             : }
    2510             : 
    2511             : /*
    2512             :  * fix_upper_expr
    2513             :  *      Modifies an expression tree so that all Var nodes reference outputs
    2514             :  *      of a subplan.  Also looks for Aggref nodes that should be replaced
    2515             :  *      by initplan output Params.  Also performs opcode lookup, and adds
    2516             :  *      regclass OIDs to root->glob->relationOids.
    2517             :  *
    2518             :  * This is used to fix up target and qual expressions of non-join upper-level
    2519             :  * plan nodes, as well as index-only scan nodes.
    2520             :  *
    2521             :  * An error is raised if no matching var can be found in the subplan tlist
    2522             :  * --- so this routine should only be applied to nodes whose subplans'
    2523             :  * targetlists were generated by flattening the expressions used in the
    2524             :  * parent node.
    2525             :  *
    2526             :  * If itlist->has_non_vars is true, then we try to match whole subexpressions
    2527             :  * against elements of the subplan tlist, so that we can avoid recomputing
    2528             :  * expressions that were already computed by the subplan.  (This is relatively
    2529             :  * expensive, so we don't want to try it in the common case where the
    2530             :  * subplan tlist is just a flattened list of Vars.)
    2531             :  *
    2532             :  * 'node': the tree to be fixed (a target item or qual)
    2533             :  * 'subplan_itlist': indexed target list for subplan (or index)
    2534             :  * 'newvarno': varno to use for Vars referencing tlist elements
    2535             :  * 'rtoffset': how much to increment varnos by
    2536             :  *
    2537             :  * The resulting tree is a copy of the original in which all Var nodes have
    2538             :  * varno = newvarno, varattno = resno of corresponding targetlist element.
    2539             :  * The original tree is not modified.
    2540             :  */
    2541             : static Node *
    2542      174814 : fix_upper_expr(PlannerInfo *root,
    2543             :                Node *node,
    2544             :                indexed_tlist *subplan_itlist,
    2545             :                Index newvarno,
    2546             :                int rtoffset)
    2547             : {
    2548             :     fix_upper_expr_context context;
    2549             : 
    2550      174814 :     context.root = root;
    2551      174814 :     context.subplan_itlist = subplan_itlist;
    2552      174814 :     context.newvarno = newvarno;
    2553      174814 :     context.rtoffset = rtoffset;
    2554      174814 :     return fix_upper_expr_mutator(node, &context);
    2555             : }
    2556             : 
    2557             : static Node *
    2558      533862 : fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
    2559             : {
    2560             :     Var        *newvar;
    2561             : 
    2562      533862 :     if (node == NULL)
    2563      158988 :         return NULL;
    2564      374874 :     if (IsA(node, Var))
    2565             :     {
    2566      131408 :         Var        *var = (Var *) node;
    2567             : 
    2568      131408 :         newvar = search_indexed_tlist_for_var(var,
    2569             :                                               context->subplan_itlist,
    2570             :                                               context->newvarno,
    2571             :                                               context->rtoffset);
    2572      131408 :         if (!newvar)
    2573           0 :             elog(ERROR, "variable not found in subplan target list");
    2574      131408 :         return (Node *) newvar;
    2575             :     }
    2576      243466 :     if (IsA(node, PlaceHolderVar))
    2577             :     {
    2578         216 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
    2579             : 
    2580             :         /* See if the PlaceHolderVar has bubbled up from a lower plan node */
    2581         216 :         if (context->subplan_itlist->has_ph_vars)
    2582             :         {
    2583         184 :             newvar = search_indexed_tlist_for_non_var((Expr *) phv,
    2584             :                                                       context->subplan_itlist,
    2585             :                                                       context->newvarno);
    2586         184 :             if (newvar)
    2587         184 :                 return (Node *) newvar;
    2588             :         }
    2589             :         /* If not supplied by input plan, evaluate the contained expr */
    2590          32 :         return fix_upper_expr_mutator((Node *) phv->phexpr, context);
    2591             :     }
    2592             :     /* Try matching more complex expressions too, if tlist has any */
    2593      243250 :     if (context->subplan_itlist->has_non_vars)
    2594             :     {
    2595       12910 :         newvar = search_indexed_tlist_for_non_var((Expr *) node,
    2596             :                                                   context->subplan_itlist,
    2597             :                                                   context->newvarno);
    2598       12910 :         if (newvar)
    2599        3010 :             return (Node *) newvar;
    2600             :     }
    2601             :     /* Special cases (apply only AFTER failing to match to lower tlist) */
    2602      240240 :     if (IsA(node, Param))
    2603         722 :         return fix_param_node(context->root, (Param *) node);
    2604      239518 :     if (IsA(node, Aggref))
    2605             :     {
    2606       28650 :         Aggref     *aggref = (Aggref *) node;
    2607             : 
    2608             :         /* See if the Aggref should be replaced by a Param */
    2609       28650 :         if (context->root->minmax_aggs != NIL &&
    2610           0 :             list_length(aggref->args) == 1)
    2611             :         {
    2612           0 :             TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
    2613             :             ListCell   *lc;
    2614             : 
    2615           0 :             foreach(lc, context->root->minmax_aggs)
    2616             :             {
    2617           0 :                 MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
    2618             : 
    2619           0 :                 if (mminfo->aggfnoid == aggref->aggfnoid &&
    2620           0 :                     equal(mminfo->target, curTarget->expr))
    2621           0 :                     return (Node *) copyObject(mminfo->param);
    2622             :             }
    2623             :         }
    2624             :         /* If no match, just fall through to process it normally */
    2625             :     }
    2626      239518 :     fix_expr_common(context->root, node);
    2627      239518 :     return expression_tree_mutator(node,
    2628             :                                    fix_upper_expr_mutator,
    2629             :                                    (void *) context);
    2630             : }
    2631             : 
    2632             : /*
    2633             :  * set_returning_clause_references
    2634             :  *      Perform setrefs.c's work on a RETURNING targetlist
    2635             :  *
    2636             :  * If the query involves more than just the result table, we have to
    2637             :  * adjust any Vars that refer to other tables to reference junk tlist
    2638             :  * entries in the top subplan's targetlist.  Vars referencing the result
    2639             :  * table should be left alone, however (the executor will evaluate them
    2640             :  * using the actual heap tuple, after firing triggers if any).  In the
    2641             :  * adjusted RETURNING list, result-table Vars will have their original
    2642             :  * varno (plus rtoffset), but Vars for other rels will have varno OUTER_VAR.
    2643             :  *
    2644             :  * We also must perform opcode lookup and add regclass OIDs to
    2645             :  * root->glob->relationOids.
    2646             :  *
    2647             :  * 'rlist': the RETURNING targetlist to be fixed
    2648             :  * 'topplan': the top subplan node that will be just below the ModifyTable
    2649             :  *      node (note it's not yet passed through set_plan_refs)
    2650             :  * 'resultRelation': RT index of the associated result relation
    2651             :  * 'rtoffset': how much to increment varnos by
    2652             :  *
    2653             :  * Note: the given 'root' is for the parent query level, not the 'topplan'.
    2654             :  * This does not matter currently since we only access the dependency-item
    2655             :  * lists in root->glob, but it would need some hacking if we wanted a root
    2656             :  * that actually matches the subplan.
    2657             :  *
    2658             :  * Note: resultRelation is not yet adjusted by rtoffset.
    2659             :  */
    2660             : static List *
    2661        1818 : set_returning_clause_references(PlannerInfo *root,
    2662             :                                 List *rlist,
    2663             :                                 Plan *topplan,
    2664             :                                 Index resultRelation,
    2665             :                                 int rtoffset)
    2666             : {
    2667             :     indexed_tlist *itlist;
    2668             : 
    2669             :     /*
    2670             :      * We can perform the desired Var fixup by abusing the fix_join_expr
    2671             :      * machinery that formerly handled inner indexscan fixup.  We search the
    2672             :      * top plan's targetlist for Vars of non-result relations, and use
    2673             :      * fix_join_expr to convert RETURNING Vars into references to those tlist
    2674             :      * entries, while leaving result-rel Vars as-is.
    2675             :      *
    2676             :      * PlaceHolderVars will also be sought in the targetlist, but no
    2677             :      * more-complex expressions will be.  Note that it is not possible for a
    2678             :      * PlaceHolderVar to refer to the result relation, since the result is
    2679             :      * never below an outer join.  If that case could happen, we'd have to be
    2680             :      * prepared to pick apart the PlaceHolderVar and evaluate its contained
    2681             :      * expression instead.
    2682             :      */
    2683        1818 :     itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
    2684             : 
    2685        1818 :     rlist = fix_join_expr(root,
    2686             :                           rlist,
    2687             :                           itlist,
    2688             :                           NULL,
    2689             :                           resultRelation,
    2690             :                           rtoffset);
    2691             : 
    2692        1818 :     pfree(itlist);
    2693             : 
    2694        1818 :     return rlist;
    2695             : }
    2696             : 
    2697             : 
    2698             : /*****************************************************************************
    2699             :  *                  QUERY DEPENDENCY MANAGEMENT
    2700             :  *****************************************************************************/
    2701             : 
    2702             : /*
    2703             :  * record_plan_function_dependency
    2704             :  *      Mark the current plan as depending on a particular function.
    2705             :  *
    2706             :  * This is exported so that the function-inlining code can record a
    2707             :  * dependency on a function that it's removed from the plan tree.
    2708             :  */
    2709             : void
    2710      750336 : record_plan_function_dependency(PlannerInfo *root, Oid funcid)
    2711             : {
    2712             :     /*
    2713             :      * For performance reasons, we don't bother to track built-in functions;
    2714             :      * we just assume they'll never change (or at least not in ways that'd
    2715             :      * invalidate plans using them).  For this purpose we can consider a
    2716             :      * built-in function to be one with OID less than FirstBootstrapObjectId.
    2717             :      * Note that the OID generator guarantees never to generate such an OID
    2718             :      * after startup, even at OID wraparound.
    2719             :      */
    2720      750336 :     if (funcid >= (Oid) FirstBootstrapObjectId)
    2721             :     {
    2722       26902 :         PlanInvalItem *inval_item = makeNode(PlanInvalItem);
    2723             : 
    2724             :         /*
    2725             :          * It would work to use any syscache on pg_proc, but the easiest is
    2726             :          * PROCOID since we already have the function's OID at hand.  Note
    2727             :          * that plancache.c knows we use PROCOID.
    2728             :          */
    2729       26902 :         inval_item->cacheId = PROCOID;
    2730       26902 :         inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
    2731             :                                                       ObjectIdGetDatum(funcid));
    2732             : 
    2733       26902 :         root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
    2734             :     }
    2735      750336 : }
    2736             : 
    2737             : /*
    2738             :  * record_plan_type_dependency
    2739             :  *      Mark the current plan as depending on a particular type.
    2740             :  *
    2741             :  * This is exported so that eval_const_expressions can record a
    2742             :  * dependency on a domain that it's removed a CoerceToDomain node for.
    2743             :  *
    2744             :  * We don't currently need to record dependencies on domains that the
    2745             :  * plan contains CoerceToDomain nodes for, though that might change in
    2746             :  * future.  Hence, this isn't actually called in this module, though
    2747             :  * someday fix_expr_common might call it.
    2748             :  */
    2749             : void
    2750       51538 : record_plan_type_dependency(PlannerInfo *root, Oid typid)
    2751             : {
    2752             :     /*
    2753             :      * As in record_plan_function_dependency, ignore the possibility that
    2754             :      * someone would change a built-in domain.
    2755             :      */
    2756       51538 :     if (typid >= (Oid) FirstBootstrapObjectId)
    2757             :     {
    2758       51538 :         PlanInvalItem *inval_item = makeNode(PlanInvalItem);
    2759             : 
    2760             :         /*
    2761             :          * It would work to use any syscache on pg_type, but the easiest is
    2762             :          * TYPEOID since we already have the type's OID at hand.  Note that
    2763             :          * plancache.c knows we use TYPEOID.
    2764             :          */
    2765       51538 :         inval_item->cacheId = TYPEOID;
    2766       51538 :         inval_item->hashValue = GetSysCacheHashValue1(TYPEOID,
    2767             :                                                       ObjectIdGetDatum(typid));
    2768             : 
    2769       51538 :         root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
    2770             :     }
    2771       51538 : }
    2772             : 
    2773             : /*
    2774             :  * extract_query_dependencies
    2775             :  *      Given a rewritten, but not yet planned, query or queries
    2776             :  *      (i.e. a Query node or list of Query nodes), extract dependencies
    2777             :  *      just as set_plan_references would do.  Also detect whether any
    2778             :  *      rewrite steps were affected by RLS.
    2779             :  *
    2780             :  * This is needed by plancache.c to handle invalidation of cached unplanned
    2781             :  * queries.
    2782             :  *
    2783             :  * Note: this does not go through eval_const_expressions, and hence doesn't
    2784             :  * reflect its additions of inlined functions and elided CoerceToDomain nodes
    2785             :  * to the invalItems list.  This is obviously OK for functions, since we'll
    2786             :  * see them in the original query tree anyway.  For domains, it's OK because
    2787             :  * we don't care about domains unless they get elided.  That is, a plan might
    2788             :  * have domain dependencies that the query tree doesn't.
    2789             :  */
    2790             : void
    2791       33410 : extract_query_dependencies(Node *query,
    2792             :                            List **relationOids,
    2793             :                            List **invalItems,
    2794             :                            bool *hasRowSecurity)
    2795             : {
    2796             :     PlannerGlobal glob;
    2797             :     PlannerInfo root;
    2798             : 
    2799             :     /* Make up dummy planner state so we can use this module's machinery */
    2800      601380 :     MemSet(&glob, 0, sizeof(glob));
    2801       33410 :     glob.type = T_PlannerGlobal;
    2802       33410 :     glob.relationOids = NIL;
    2803       33410 :     glob.invalItems = NIL;
    2804             :     /* Hack: we use glob.dependsOnRole to collect hasRowSecurity flags */
    2805       33410 :     glob.dependsOnRole = false;
    2806             : 
    2807     2271880 :     MemSet(&root, 0, sizeof(root));
    2808       33410 :     root.type = T_PlannerInfo;
    2809       33410 :     root.glob = &glob;
    2810             : 
    2811       33410 :     (void) extract_query_dependencies_walker(query, &root);
    2812             : 
    2813       33410 :     *relationOids = glob.relationOids;
    2814       33410 :     *invalItems = glob.invalItems;
    2815       33410 :     *hasRowSecurity = glob.dependsOnRole;
    2816       33410 : }
    2817             : 
    2818             : /*
    2819             :  * Tree walker for extract_query_dependencies.
    2820             :  *
    2821             :  * This is exported so that expression_planner_with_deps can call it on
    2822             :  * simple expressions (post-planning, not before planning, in that case).
    2823             :  * In that usage, glob.dependsOnRole isn't meaningful, but the relationOids
    2824             :  * and invalItems lists are added to as needed.
    2825             :  */
    2826             : bool
    2827      708170 : extract_query_dependencies_walker(Node *node, PlannerInfo *context)
    2828             : {
    2829      708170 :     if (node == NULL)
    2830      357698 :         return false;
    2831             :     Assert(!IsA(node, PlaceHolderVar));
    2832      350472 :     if (IsA(node, Query))
    2833             :     {
    2834       34062 :         Query      *query = (Query *) node;
    2835             :         ListCell   *lc;
    2836             : 
    2837       34062 :         if (query->commandType == CMD_UTILITY)
    2838             :         {
    2839             :             /*
    2840             :              * Ignore utility statements, except those (such as EXPLAIN) that
    2841             :              * contain a parsed-but-not-planned query.
    2842             :              */
    2843        4474 :             query = UtilityContainsQuery(query->utilityStmt);
    2844        4474 :             if (query == NULL)
    2845         274 :                 return false;
    2846             :         }
    2847             : 
    2848             :         /* Remember if any Query has RLS quals applied by rewriter */
    2849       33788 :         if (query->hasRowSecurity)
    2850         112 :             context->glob->dependsOnRole = true;
    2851             : 
    2852             :         /* Collect relation OIDs in this Query's rtable */
    2853       52320 :         foreach(lc, query->rtable)
    2854             :         {
    2855       18532 :             RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
    2856             : 
    2857       18532 :             if (rte->rtekind == RTE_RELATION)
    2858       16530 :                 context->glob->relationOids =
    2859       16530 :                     lappend_oid(context->glob->relationOids, rte->relid);
    2860        2002 :             else if (rte->rtekind == RTE_NAMEDTUPLESTORE &&
    2861         252 :                      OidIsValid(rte->relid))
    2862         252 :                 context->glob->relationOids =
    2863         252 :                     lappend_oid(context->glob->relationOids,
    2864             :                                 rte->relid);
    2865             :         }
    2866             : 
    2867             :         /* And recurse into the query's subexpressions */
    2868       33788 :         return query_tree_walker(query, extract_query_dependencies_walker,
    2869             :                                  (void *) context, 0);
    2870             :     }
    2871             :     /* Extract function dependencies and check for regclass Consts */
    2872      316410 :     fix_expr_common(context, node);
    2873      316410 :     return expression_tree_walker(node, extract_query_dependencies_walker,
    2874             :                                   (void *) context);
    2875             : }

Generated by: LCOV version 1.13