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

Generated by: LCOV version 1.11