LCOV - code coverage report
Current view: top level - src/backend/optimizer/plan - setrefs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 826 880 93.9 %
Date: 2019-07-19 13:07:20 Functions: 38 39 97.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13