LCOV - code coverage report
Current view: top level - src/backend/optimizer/plan - setrefs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 14devel Lines: 951 1004 94.7 %
Date: 2021-05-13 08:06:46 Functions: 41 42 97.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13