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

Generated by: LCOV version 1.13