LCOV - code coverage report
Current view: top level - src/backend/optimizer/plan - setrefs.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 95.7 % 1156 1106
Test Date: 2026-02-17 17:20:33 Functions: 98.0 % 49 48
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-2026, 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/subselect.h"
      27              : #include "optimizer/tlist.h"
      28              : #include "parser/parse_relation.h"
      29              : #include "rewrite/rewriteManip.h"
      30              : #include "tcop/utility.h"
      31              : #include "utils/syscache.h"
      32              : 
      33              : 
      34              : typedef enum
      35              : {
      36              :     NRM_EQUAL,                  /* expect exact match of nullingrels */
      37              :     NRM_SUBSET,                 /* actual Var may have a subset of input */
      38              :     NRM_SUPERSET,               /* actual Var may have a superset of input */
      39              : } NullingRelsMatch;
      40              : 
      41              : typedef struct
      42              : {
      43              :     int         varno;          /* RT index of Var */
      44              :     AttrNumber  varattno;       /* attr number of Var */
      45              :     AttrNumber  resno;          /* TLE position of Var */
      46              :     Bitmapset  *varnullingrels; /* Var's varnullingrels */
      47              : } tlist_vinfo;
      48              : 
      49              : typedef struct
      50              : {
      51              :     List       *tlist;          /* underlying target list */
      52              :     int         num_vars;       /* number of plain Var tlist entries */
      53              :     bool        has_ph_vars;    /* are there PlaceHolderVar entries? */
      54              :     bool        has_non_vars;   /* are there other entries? */
      55              :     tlist_vinfo vars[FLEXIBLE_ARRAY_MEMBER];    /* has num_vars entries */
      56              : } indexed_tlist;
      57              : 
      58              : typedef struct
      59              : {
      60              :     PlannerInfo *root;
      61              :     int         rtoffset;
      62              :     double      num_exec;
      63              : } fix_scan_expr_context;
      64              : 
      65              : typedef struct
      66              : {
      67              :     PlannerInfo *root;
      68              :     indexed_tlist *outer_itlist;
      69              :     indexed_tlist *inner_itlist;
      70              :     Index       acceptable_rel;
      71              :     int         rtoffset;
      72              :     NullingRelsMatch nrm_match;
      73              :     double      num_exec;
      74              : } fix_join_expr_context;
      75              : 
      76              : typedef struct
      77              : {
      78              :     PlannerInfo *root;
      79              :     indexed_tlist *subplan_itlist;
      80              :     int         newvarno;
      81              :     int         rtoffset;
      82              :     NullingRelsMatch nrm_match;
      83              :     double      num_exec;
      84              : } fix_upper_expr_context;
      85              : 
      86              : typedef struct
      87              : {
      88              :     PlannerInfo *root;
      89              :     indexed_tlist *subplan_itlist;
      90              :     int         newvarno;
      91              : } fix_windowagg_cond_context;
      92              : 
      93              : /* Context info for flatten_rtes_walker() */
      94              : typedef struct
      95              : {
      96              :     PlannerGlobal *glob;
      97              :     Query      *query;
      98              : } flatten_rtes_walker_context;
      99              : 
     100              : /*
     101              :  * Selecting the best alternative in an AlternativeSubPlan expression requires
     102              :  * estimating how many times that expression will be evaluated.  For an
     103              :  * expression in a plan node's targetlist, the plan's estimated number of
     104              :  * output rows is clearly what to use, but for an expression in a qual it's
     105              :  * far less clear.  Since AlternativeSubPlans aren't heavily used, we don't
     106              :  * want to expend a lot of cycles making such estimates.  What we use is twice
     107              :  * the number of output rows.  That's not entirely unfounded: we know that
     108              :  * clause_selectivity() would fall back to a default selectivity estimate
     109              :  * of 0.5 for any SubPlan, so if the qual containing the SubPlan is the last
     110              :  * to be applied (which it likely would be, thanks to order_qual_clauses()),
     111              :  * this matches what we could have estimated in a far more laborious fashion.
     112              :  * Obviously there are many other scenarios, but it's probably not worth the
     113              :  * trouble to try to improve on this estimate, especially not when we don't
     114              :  * have a better estimate for the selectivity of the SubPlan qual itself.
     115              :  */
     116              : #define NUM_EXEC_TLIST(parentplan)  ((parentplan)->plan_rows)
     117              : #define NUM_EXEC_QUAL(parentplan)   ((parentplan)->plan_rows * 2.0)
     118              : 
     119              : /*
     120              :  * Check if a Const node is a regclass value.  We accept plain OID too,
     121              :  * since a regclass Const will get folded to that type if it's an argument
     122              :  * to oideq or similar operators.  (This might result in some extraneous
     123              :  * values in a plan's list of relation dependencies, but the worst result
     124              :  * would be occasional useless replans.)
     125              :  */
     126              : #define ISREGCLASSCONST(con) \
     127              :     (((con)->consttype == REGCLASSOID || (con)->consttype == OIDOID) && \
     128              :      !(con)->constisnull)
     129              : 
     130              : #define fix_scan_list(root, lst, rtoffset, num_exec) \
     131              :     ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset, num_exec))
     132              : 
     133              : static void add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing);
     134              : static void flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte);
     135              : static bool flatten_rtes_walker(Node *node, flatten_rtes_walker_context *cxt);
     136              : static void add_rte_to_flat_rtable(PlannerGlobal *glob, List *rteperminfos,
     137              :                                    RangeTblEntry *rte);
     138              : static Plan *set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset);
     139              : static Plan *set_indexonlyscan_references(PlannerInfo *root,
     140              :                                           IndexOnlyScan *plan,
     141              :                                           int rtoffset);
     142              : static Plan *set_subqueryscan_references(PlannerInfo *root,
     143              :                                          SubqueryScan *plan,
     144              :                                          int rtoffset);
     145              : static Plan *clean_up_removed_plan_level(Plan *parent, Plan *child);
     146              : static void set_foreignscan_references(PlannerInfo *root,
     147              :                                        ForeignScan *fscan,
     148              :                                        int rtoffset);
     149              : static void set_customscan_references(PlannerInfo *root,
     150              :                                       CustomScan *cscan,
     151              :                                       int rtoffset);
     152              : static Plan *set_append_references(PlannerInfo *root,
     153              :                                    Append *aplan,
     154              :                                    int rtoffset);
     155              : static Plan *set_mergeappend_references(PlannerInfo *root,
     156              :                                         MergeAppend *mplan,
     157              :                                         int rtoffset);
     158              : static void set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset);
     159              : static Relids offset_relid_set(Relids relids, int rtoffset);
     160              : static Node *fix_scan_expr(PlannerInfo *root, Node *node,
     161              :                            int rtoffset, double num_exec);
     162              : static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);
     163              : static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context);
     164              : static void set_join_references(PlannerInfo *root, Join *join, int rtoffset);
     165              : static void set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset);
     166              : static void set_param_references(PlannerInfo *root, Plan *plan);
     167              : static Node *convert_combining_aggrefs(Node *node, void *context);
     168              : static void set_dummy_tlist_references(Plan *plan, int rtoffset);
     169              : static indexed_tlist *build_tlist_index(List *tlist);
     170              : static Var *search_indexed_tlist_for_var(Var *var,
     171              :                                          indexed_tlist *itlist,
     172              :                                          int newvarno,
     173              :                                          int rtoffset,
     174              :                                          NullingRelsMatch nrm_match);
     175              : static Var *search_indexed_tlist_for_phv(PlaceHolderVar *phv,
     176              :                                          indexed_tlist *itlist,
     177              :                                          int newvarno,
     178              :                                          NullingRelsMatch nrm_match);
     179              : static Var *search_indexed_tlist_for_non_var(Expr *node,
     180              :                                              indexed_tlist *itlist,
     181              :                                              int newvarno);
     182              : static Var *search_indexed_tlist_for_sortgroupref(Expr *node,
     183              :                                                   Index sortgroupref,
     184              :                                                   indexed_tlist *itlist,
     185              :                                                   int newvarno);
     186              : static List *fix_join_expr(PlannerInfo *root,
     187              :                            List *clauses,
     188              :                            indexed_tlist *outer_itlist,
     189              :                            indexed_tlist *inner_itlist,
     190              :                            Index acceptable_rel,
     191              :                            int rtoffset,
     192              :                            NullingRelsMatch nrm_match,
     193              :                            double num_exec);
     194              : static Node *fix_join_expr_mutator(Node *node,
     195              :                                    fix_join_expr_context *context);
     196              : static Node *fix_upper_expr(PlannerInfo *root,
     197              :                             Node *node,
     198              :                             indexed_tlist *subplan_itlist,
     199              :                             int newvarno,
     200              :                             int rtoffset,
     201              :                             NullingRelsMatch nrm_match,
     202              :                             double num_exec);
     203              : static Node *fix_upper_expr_mutator(Node *node,
     204              :                                     fix_upper_expr_context *context);
     205              : static List *set_returning_clause_references(PlannerInfo *root,
     206              :                                              List *rlist,
     207              :                                              Plan *topplan,
     208              :                                              Index resultRelation,
     209              :                                              int rtoffset);
     210              : static List *set_windowagg_runcondition_references(PlannerInfo *root,
     211              :                                                    List *runcondition,
     212              :                                                    Plan *plan);
     213              : 
     214              : static void record_elided_node(PlannerGlobal *glob, int plan_node_id,
     215              :                                NodeTag elided_type, Bitmapset *relids);
     216              : 
     217              : 
     218              : /*****************************************************************************
     219              :  *
     220              :  *      SUBPLAN REFERENCES
     221              :  *
     222              :  *****************************************************************************/
     223              : 
     224              : /*
     225              :  * set_plan_references
     226              :  *
     227              :  * This is the final processing pass of the planner/optimizer.  The plan
     228              :  * tree is complete; we just have to adjust some representational details
     229              :  * for the convenience of the executor:
     230              :  *
     231              :  * 1. We flatten the various subquery rangetables into a single list, and
     232              :  * zero out RangeTblEntry fields that are not useful to the executor.
     233              :  *
     234              :  * 2. We adjust Vars in scan nodes to be consistent with the flat rangetable.
     235              :  *
     236              :  * 3. We adjust Vars in upper plan nodes to refer to the outputs of their
     237              :  * subplans.
     238              :  *
     239              :  * 4. Aggrefs in Agg plan nodes need to be adjusted in some cases involving
     240              :  * partial aggregation or minmax aggregate optimization.
     241              :  *
     242              :  * 5. PARAM_MULTIEXPR Params are replaced by regular PARAM_EXEC Params,
     243              :  * now that we have finished planning all MULTIEXPR subplans.
     244              :  *
     245              :  * 6. AlternativeSubPlan expressions are replaced by just one of their
     246              :  * alternatives, using an estimate of how many times they'll be executed.
     247              :  *
     248              :  * 7. We compute regproc OIDs for operators (ie, we look up the function
     249              :  * that implements each op).
     250              :  *
     251              :  * 8. We create lists of specific objects that the plan depends on.
     252              :  * This will be used by plancache.c to drive invalidation of cached plans.
     253              :  * Relation dependencies are represented by OIDs, and everything else by
     254              :  * PlanInvalItems (this distinction is motivated by the shared-inval APIs).
     255              :  * Currently, relations, user-defined functions, and domains are the only
     256              :  * types of objects that are explicitly tracked this way.
     257              :  *
     258              :  * 9. We assign every plan node in the tree a unique ID.
     259              :  *
     260              :  * We also perform one final optimization step, which is to delete
     261              :  * SubqueryScan, Append, and MergeAppend plan nodes that aren't doing
     262              :  * anything useful.  The reason for doing this last is that
     263              :  * it can't readily be done before set_plan_references, because it would
     264              :  * break set_upper_references: the Vars in the child plan's top tlist
     265              :  * wouldn't match up with the Vars in the outer plan tree.  A SubqueryScan
     266              :  * serves a necessary function as a buffer between outer query and subquery
     267              :  * variable numbering ... but after we've flattened the rangetable this is
     268              :  * no longer a problem, since then there's only one rtindex namespace.
     269              :  * Likewise, Append and MergeAppend buffer between the parent and child vars
     270              :  * of an appendrel, but we don't need to worry about that once we've done
     271              :  * set_plan_references.
     272              :  *
     273              :  * set_plan_references recursively traverses the whole plan tree.
     274              :  *
     275              :  * The return value is normally the same Plan node passed in, but can be
     276              :  * different when the passed-in Plan is a node we decide isn't needed.
     277              :  *
     278              :  * The flattened rangetable entries are appended to root->glob->finalrtable.
     279              :  * Also, rowmarks entries are appended to root->glob->finalrowmarks, and the
     280              :  * RT indexes of ModifyTable result relations to root->glob->resultRelations,
     281              :  * and flattened AppendRelInfos are appended to root->glob->appendRelations.
     282              :  * Plan dependencies are appended to root->glob->relationOids (for relations)
     283              :  * and root->glob->invalItems (for everything else).
     284              :  *
     285              :  * Notice that we modify Plan nodes in-place, but use expression_tree_mutator
     286              :  * to process targetlist and qual expressions.  We can assume that the Plan
     287              :  * nodes were just built by the planner and are not multiply referenced, but
     288              :  * it's not so safe to assume that for expression tree nodes.
     289              :  */
     290              : Plan *
     291       274585 : set_plan_references(PlannerInfo *root, Plan *plan)
     292              : {
     293              :     Plan       *result;
     294       274585 :     PlannerGlobal *glob = root->glob;
     295       274585 :     int         rtoffset = list_length(glob->finalrtable);
     296              :     ListCell   *lc;
     297              : 
     298              :     /*
     299              :      * Add all the query's RTEs to the flattened rangetable.  The live ones
     300              :      * will have their rangetable indexes increased by rtoffset.  (Additional
     301              :      * RTEs, not referenced by the Plan tree, might get added after those.)
     302              :      */
     303       274585 :     add_rtes_to_flat_rtable(root, false);
     304              : 
     305              :     /*
     306              :      * Adjust RT indexes of PlanRowMarks and add to final rowmarks list
     307              :      */
     308       284087 :     foreach(lc, root->rowMarks)
     309              :     {
     310         9502 :         PlanRowMark *rc = lfirst_node(PlanRowMark, lc);
     311              :         PlanRowMark *newrc;
     312              : 
     313              :         /* sanity check on existing row marks */
     314              :         Assert(root->simple_rel_array[rc->rti] != NULL &&
     315              :                root->simple_rte_array[rc->rti] != NULL);
     316              : 
     317              :         /* flat copy is enough since all fields are scalars */
     318         9502 :         newrc = palloc_object(PlanRowMark);
     319         9502 :         memcpy(newrc, rc, sizeof(PlanRowMark));
     320              : 
     321              :         /* adjust indexes ... but *not* the rowmarkId */
     322         9502 :         newrc->rti += rtoffset;
     323         9502 :         newrc->prti += rtoffset;
     324              : 
     325         9502 :         glob->finalrowmarks = lappend(glob->finalrowmarks, newrc);
     326              :     }
     327              : 
     328              :     /*
     329              :      * Adjust RT indexes of AppendRelInfos and add to final appendrels list.
     330              :      * We assume the AppendRelInfos were built during planning and don't need
     331              :      * to be copied.
     332              :      */
     333       304206 :     foreach(lc, root->append_rel_list)
     334              :     {
     335        29621 :         AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
     336              : 
     337              :         /* adjust RT indexes */
     338        29621 :         appinfo->parent_relid += rtoffset;
     339        29621 :         appinfo->child_relid += rtoffset;
     340              : 
     341              :         /*
     342              :          * Rather than adjust the translated_vars entries, just drop 'em.
     343              :          * Neither the executor nor EXPLAIN currently need that data.
     344              :          */
     345        29621 :         appinfo->translated_vars = NIL;
     346              : 
     347        29621 :         glob->appendRelations = lappend(glob->appendRelations, appinfo);
     348              :     }
     349              : 
     350              :     /* If needed, create workspace for processing AlternativeSubPlans */
     351       274585 :     if (root->hasAlternativeSubPlans)
     352              :     {
     353          551 :         root->isAltSubplan = (bool *)
     354          551 :             palloc0(list_length(glob->subplans) * sizeof(bool));
     355          551 :         root->isUsedSubplan = (bool *)
     356          551 :             palloc0(list_length(glob->subplans) * sizeof(bool));
     357              :     }
     358              : 
     359              :     /* Now fix the Plan tree */
     360       274585 :     result = set_plan_refs(root, plan, rtoffset);
     361              : 
     362              :     /*
     363              :      * If we have AlternativeSubPlans, it is likely that we now have some
     364              :      * unreferenced subplans in glob->subplans.  To avoid expending cycles on
     365              :      * those subplans later, get rid of them by setting those list entries to
     366              :      * NULL.  (Note: we can't do this immediately upon processing an
     367              :      * AlternativeSubPlan, because there may be multiple copies of the
     368              :      * AlternativeSubPlan, and they can get resolved differently.)
     369              :      */
     370       274585 :     if (root->hasAlternativeSubPlans)
     371              :     {
     372         2673 :         foreach(lc, glob->subplans)
     373              :         {
     374         2122 :             int         ndx = foreach_current_index(lc);
     375              : 
     376              :             /*
     377              :              * If it was used by some AlternativeSubPlan in this query level,
     378              :              * but wasn't selected as best by any AlternativeSubPlan, then we
     379              :              * don't need it.  Do not touch subplans that aren't parts of
     380              :              * AlternativeSubPlans.
     381              :              */
     382         2122 :             if (root->isAltSubplan[ndx] && !root->isUsedSubplan[ndx])
     383          846 :                 lfirst(lc) = NULL;
     384              :         }
     385              :     }
     386              : 
     387       274585 :     return result;
     388              : }
     389              : 
     390              : /*
     391              :  * Extract RangeTblEntries from the plan's rangetable, and add to flat rtable
     392              :  *
     393              :  * This can recurse into subquery plans; "recursing" is true if so.
     394              :  *
     395              :  * This also seems like a good place to add the query's RTEPermissionInfos to
     396              :  * the flat rteperminfos.
     397              :  */
     398              : static void
     399       274716 : add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
     400              : {
     401       274716 :     PlannerGlobal *glob = root->glob;
     402              :     Index       rti;
     403              :     ListCell   *lc;
     404              : 
     405              :     /*
     406              :      * Record enough information to make it possible for code that looks at
     407              :      * the final range table to understand how it was constructed. (If
     408              :      * finalrtable is still NIL, then this is the very topmost PlannerInfo,
     409              :      * which will always have plan_name == NULL and rtoffset == 0; we omit the
     410              :      * degenerate list entry.)
     411              :      */
     412       274716 :     if (root->glob->finalrtable != NIL)
     413              :     {
     414        42412 :         SubPlanRTInfo *rtinfo = makeNode(SubPlanRTInfo);
     415              : 
     416        42412 :         rtinfo->plan_name = root->plan_name;
     417        42412 :         rtinfo->rtoffset = list_length(root->glob->finalrtable);
     418              : 
     419              :         /* When recursing = true, it's an unplanned or dummy subquery. */
     420        42412 :         rtinfo->dummy = recursing;
     421              : 
     422        42412 :         root->glob->subrtinfos = lappend(root->glob->subrtinfos, rtinfo);
     423              :     }
     424              : 
     425              :     /*
     426              :      * Add the query's own RTEs to the flattened rangetable.
     427              :      *
     428              :      * At top level, we must add all RTEs so that their indexes in the
     429              :      * flattened rangetable match up with their original indexes.  When
     430              :      * recursing, we only care about extracting relation RTEs (and subquery
     431              :      * RTEs that were once relation RTEs).
     432              :      */
     433       772516 :     foreach(lc, root->parse->rtable)
     434              :     {
     435       497800 :         RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
     436              : 
     437       497800 :         if (!recursing || rte->rtekind == RTE_RELATION ||
     438          123 :             (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)))
     439       497677 :             add_rte_to_flat_rtable(glob, root->parse->rteperminfos, rte);
     440              :     }
     441              : 
     442              :     /*
     443              :      * If there are any dead subqueries, they are not referenced in the Plan
     444              :      * tree, so we must add RTEs contained in them to the flattened rtable
     445              :      * separately.  (If we failed to do this, the executor would not perform
     446              :      * expected permission checks for tables mentioned in such subqueries.)
     447              :      *
     448              :      * Note: this pass over the rangetable can't be combined with the previous
     449              :      * one, because that would mess up the numbering of the live RTEs in the
     450              :      * flattened rangetable.
     451              :      */
     452       274716 :     rti = 1;
     453       772516 :     foreach(lc, root->parse->rtable)
     454              :     {
     455       497800 :         RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
     456              : 
     457              :         /*
     458              :          * We should ignore inheritance-parent RTEs: their contents have been
     459              :          * pulled up into our rangetable already.  Also ignore any subquery
     460              :          * RTEs without matching RelOptInfos, as they likewise have been
     461              :          * pulled up.
     462              :          */
     463       497800 :         if (rte->rtekind == RTE_SUBQUERY && !rte->inh &&
     464        38928 :             rti < root->simple_rel_array_size)
     465              :         {
     466        38928 :             RelOptInfo *rel = root->simple_rel_array[rti];
     467              : 
     468        38928 :             if (rel != NULL)
     469              :             {
     470              :                 Assert(rel->relid == rti);   /* sanity check on array */
     471              : 
     472              :                 /*
     473              :                  * The subquery might never have been planned at all, if it
     474              :                  * was excluded on the basis of self-contradictory constraints
     475              :                  * in our query level.  In this case apply
     476              :                  * flatten_unplanned_rtes.
     477              :                  *
     478              :                  * If it was planned but the result rel is dummy, we assume
     479              :                  * that it has been omitted from our plan tree (see
     480              :                  * set_subquery_pathlist), and recurse to pull up its RTEs.
     481              :                  *
     482              :                  * Otherwise, it should be represented by a SubqueryScan node
     483              :                  * somewhere in our plan tree, and we'll pull up its RTEs when
     484              :                  * we process that plan node.
     485              :                  *
     486              :                  * However, if we're recursing, then we should pull up RTEs
     487              :                  * whether the subquery is dummy or not, because we've found
     488              :                  * that some upper query level is treating this one as dummy,
     489              :                  * and so we won't scan this level's plan tree at all.
     490              :                  */
     491        20225 :                 if (rel->subroot == NULL)
     492           12 :                     flatten_unplanned_rtes(glob, rte);
     493        40402 :                 else if (recursing ||
     494        20189 :                          IS_DUMMY_REL(fetch_upper_rel(rel->subroot,
     495              :                                                       UPPERREL_FINAL, NULL)))
     496          131 :                     add_rtes_to_flat_rtable(rel->subroot, true);
     497              :             }
     498              :         }
     499       497800 :         rti++;
     500              :     }
     501       274716 : }
     502              : 
     503              : /*
     504              :  * Extract RangeTblEntries from a subquery that was never planned at all
     505              :  */
     506              : 
     507              : static void
     508           12 : flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte)
     509              : {
     510           12 :     flatten_rtes_walker_context cxt = {glob, rte->subquery};
     511              : 
     512              :     /* Use query_tree_walker to find all RTEs in the parse tree */
     513           12 :     (void) query_tree_walker(rte->subquery,
     514              :                              flatten_rtes_walker,
     515              :                              &cxt,
     516              :                              QTW_EXAMINE_RTES_BEFORE);
     517           12 : }
     518              : 
     519              : static bool
     520          300 : flatten_rtes_walker(Node *node, flatten_rtes_walker_context *cxt)
     521              : {
     522          300 :     if (node == NULL)
     523          174 :         return false;
     524          126 :     if (IsA(node, RangeTblEntry))
     525              :     {
     526            9 :         RangeTblEntry *rte = (RangeTblEntry *) node;
     527              : 
     528              :         /* As above, we need only save relation RTEs and former relations */
     529            9 :         if (rte->rtekind == RTE_RELATION ||
     530            0 :             (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)))
     531            9 :             add_rte_to_flat_rtable(cxt->glob, cxt->query->rteperminfos, rte);
     532            9 :         return false;
     533              :     }
     534          117 :     if (IsA(node, Query))
     535              :     {
     536              :         /*
     537              :          * Recurse into subselects.  Must update cxt->query to this query so
     538              :          * that the rtable and rteperminfos correspond with each other.
     539              :          */
     540            3 :         Query      *save_query = cxt->query;
     541              :         bool        result;
     542              : 
     543            3 :         cxt->query = (Query *) node;
     544            3 :         result = query_tree_walker((Query *) node,
     545              :                                    flatten_rtes_walker,
     546              :                                    cxt,
     547              :                                    QTW_EXAMINE_RTES_BEFORE);
     548            3 :         cxt->query = save_query;
     549            3 :         return result;
     550              :     }
     551          114 :     return expression_tree_walker(node, flatten_rtes_walker, cxt);
     552              : }
     553              : 
     554              : /*
     555              :  * Add (a copy of) the given RTE to the final rangetable and also the
     556              :  * corresponding RTEPermissionInfo, if any, to final rteperminfos.
     557              :  *
     558              :  * In the flat rangetable, we zero out substructure pointers that are not
     559              :  * needed by the executor; this reduces the storage space and copying cost
     560              :  * for cached plans.  We keep only the ctename, alias, eref Alias fields,
     561              :  * which are needed by EXPLAIN, and perminfoindex which is needed by the
     562              :  * executor to fetch the RTE's RTEPermissionInfo.
     563              :  */
     564              : static void
     565       497686 : add_rte_to_flat_rtable(PlannerGlobal *glob, List *rteperminfos,
     566              :                        RangeTblEntry *rte)
     567              : {
     568              :     RangeTblEntry *newrte;
     569              : 
     570              :     /* flat copy to duplicate all the scalar fields */
     571       497686 :     newrte = palloc_object(RangeTblEntry);
     572       497686 :     memcpy(newrte, rte, sizeof(RangeTblEntry));
     573              : 
     574              :     /* zap unneeded sub-structure */
     575       497686 :     newrte->tablesample = NULL;
     576       497686 :     newrte->subquery = NULL;
     577       497686 :     newrte->joinaliasvars = NIL;
     578       497686 :     newrte->joinleftcols = NIL;
     579       497686 :     newrte->joinrightcols = NIL;
     580       497686 :     newrte->join_using_alias = NULL;
     581       497686 :     newrte->functions = NIL;
     582       497686 :     newrte->tablefunc = NULL;
     583       497686 :     newrte->values_lists = NIL;
     584       497686 :     newrte->coltypes = NIL;
     585       497686 :     newrte->coltypmods = NIL;
     586       497686 :     newrte->colcollations = NIL;
     587       497686 :     newrte->groupexprs = NIL;
     588       497686 :     newrte->securityQuals = NIL;
     589              : 
     590       497686 :     glob->finalrtable = lappend(glob->finalrtable, newrte);
     591              : 
     592              :     /*
     593              :      * If it's a plain relation RTE (or a subquery that was once a view
     594              :      * reference), add the relation OID to relationOids.  Also add its new RT
     595              :      * index to the set of relations to be potentially accessed during
     596              :      * execution.
     597              :      *
     598              :      * We do this even though the RTE might be unreferenced in the plan tree;
     599              :      * this would correspond to cases such as views that were expanded, child
     600              :      * tables that were eliminated by constraint exclusion, etc. Schema
     601              :      * invalidation on such a rel must still force rebuilding of the plan.
     602              :      *
     603              :      * Note we don't bother to avoid making duplicate list entries.  We could,
     604              :      * but it would probably cost more cycles than it would save.
     605              :      */
     606       497686 :     if (newrte->rtekind == RTE_RELATION ||
     607       229017 :         (newrte->rtekind == RTE_SUBQUERY && OidIsValid(newrte->relid)))
     608              :     {
     609       277054 :         glob->relationOids = lappend_oid(glob->relationOids, newrte->relid);
     610       277054 :         glob->allRelids = bms_add_member(glob->allRelids,
     611       277054 :                                          list_length(glob->finalrtable));
     612              :     }
     613              : 
     614              :     /*
     615              :      * Add a copy of the RTEPermissionInfo, if any, corresponding to this RTE
     616              :      * to the flattened global list.
     617              :      */
     618       497686 :     if (rte->perminfoindex > 0)
     619              :     {
     620              :         RTEPermissionInfo *perminfo;
     621              :         RTEPermissionInfo *newperminfo;
     622              : 
     623              :         /* Get the existing one from this query's rteperminfos. */
     624       255316 :         perminfo = getRTEPermissionInfo(rteperminfos, newrte);
     625              : 
     626              :         /*
     627              :          * Add a new one to finalrteperminfos and copy the contents of the
     628              :          * existing one into it.  Note that addRTEPermissionInfo() also
     629              :          * updates newrte->perminfoindex to point to newperminfo in
     630              :          * finalrteperminfos.
     631              :          */
     632       255316 :         newrte->perminfoindex = 0;   /* expected by addRTEPermissionInfo() */
     633       255316 :         newperminfo = addRTEPermissionInfo(&glob->finalrteperminfos, newrte);
     634       255316 :         memcpy(newperminfo, perminfo, sizeof(RTEPermissionInfo));
     635              :     }
     636       497686 : }
     637              : 
     638              : /*
     639              :  * set_plan_refs: recurse through the Plan nodes of a single subquery level
     640              :  */
     641              : static Plan *
     642      1474619 : set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
     643              : {
     644              :     ListCell   *l;
     645              : 
     646      1474619 :     if (plan == NULL)
     647       848662 :         return NULL;
     648              : 
     649              :     /* Assign this node a unique ID. */
     650       625957 :     plan->plan_node_id = root->glob->lastPlanNodeId++;
     651              : 
     652              :     /*
     653              :      * Plan-type-specific fixes
     654              :      */
     655       625957 :     switch (nodeTag(plan))
     656              :     {
     657       111544 :         case T_SeqScan:
     658              :             {
     659       111544 :                 SeqScan    *splan = (SeqScan *) plan;
     660              : 
     661       111544 :                 splan->scan.scanrelid += rtoffset;
     662       111544 :                 splan->scan.plan.targetlist =
     663       111544 :                     fix_scan_list(root, splan->scan.plan.targetlist,
     664              :                                   rtoffset, NUM_EXEC_TLIST(plan));
     665       111544 :                 splan->scan.plan.qual =
     666       111544 :                     fix_scan_list(root, splan->scan.plan.qual,
     667              :                                   rtoffset, NUM_EXEC_QUAL(plan));
     668              :             }
     669       111544 :             break;
     670          153 :         case T_SampleScan:
     671              :             {
     672          153 :                 SampleScan *splan = (SampleScan *) plan;
     673              : 
     674          153 :                 splan->scan.scanrelid += rtoffset;
     675          153 :                 splan->scan.plan.targetlist =
     676          153 :                     fix_scan_list(root, splan->scan.plan.targetlist,
     677              :                                   rtoffset, NUM_EXEC_TLIST(plan));
     678          153 :                 splan->scan.plan.qual =
     679          153 :                     fix_scan_list(root, splan->scan.plan.qual,
     680              :                                   rtoffset, NUM_EXEC_QUAL(plan));
     681          153 :                 splan->tablesample = (TableSampleClause *)
     682          153 :                     fix_scan_expr(root, (Node *) splan->tablesample,
     683              :                                   rtoffset, 1);
     684              :             }
     685          153 :             break;
     686        72619 :         case T_IndexScan:
     687              :             {
     688        72619 :                 IndexScan  *splan = (IndexScan *) plan;
     689              : 
     690        72619 :                 splan->scan.scanrelid += rtoffset;
     691        72619 :                 splan->scan.plan.targetlist =
     692        72619 :                     fix_scan_list(root, splan->scan.plan.targetlist,
     693              :                                   rtoffset, NUM_EXEC_TLIST(plan));
     694        72619 :                 splan->scan.plan.qual =
     695        72619 :                     fix_scan_list(root, splan->scan.plan.qual,
     696              :                                   rtoffset, NUM_EXEC_QUAL(plan));
     697        72619 :                 splan->indexqual =
     698        72619 :                     fix_scan_list(root, splan->indexqual,
     699              :                                   rtoffset, 1);
     700        72619 :                 splan->indexqualorig =
     701        72619 :                     fix_scan_list(root, splan->indexqualorig,
     702              :                                   rtoffset, NUM_EXEC_QUAL(plan));
     703        72619 :                 splan->indexorderby =
     704        72619 :                     fix_scan_list(root, splan->indexorderby,
     705              :                                   rtoffset, 1);
     706        72619 :                 splan->indexorderbyorig =
     707        72619 :                     fix_scan_list(root, splan->indexorderbyorig,
     708              :                                   rtoffset, NUM_EXEC_QUAL(plan));
     709              :             }
     710        72619 :             break;
     711         9260 :         case T_IndexOnlyScan:
     712              :             {
     713         9260 :                 IndexOnlyScan *splan = (IndexOnlyScan *) plan;
     714              : 
     715         9260 :                 return set_indexonlyscan_references(root, splan, rtoffset);
     716              :             }
     717              :             break;
     718        13651 :         case T_BitmapIndexScan:
     719              :             {
     720        13651 :                 BitmapIndexScan *splan = (BitmapIndexScan *) plan;
     721              : 
     722        13651 :                 splan->scan.scanrelid += rtoffset;
     723              :                 /* no need to fix targetlist and qual */
     724              :                 Assert(splan->scan.plan.targetlist == NIL);
     725              :                 Assert(splan->scan.plan.qual == NIL);
     726        13651 :                 splan->indexqual =
     727        13651 :                     fix_scan_list(root, splan->indexqual, rtoffset, 1);
     728        13651 :                 splan->indexqualorig =
     729        13651 :                     fix_scan_list(root, splan->indexqualorig,
     730              :                                   rtoffset, NUM_EXEC_QUAL(plan));
     731              :             }
     732        13651 :             break;
     733        13304 :         case T_BitmapHeapScan:
     734              :             {
     735        13304 :                 BitmapHeapScan *splan = (BitmapHeapScan *) plan;
     736              : 
     737        13304 :                 splan->scan.scanrelid += rtoffset;
     738        13304 :                 splan->scan.plan.targetlist =
     739        13304 :                     fix_scan_list(root, splan->scan.plan.targetlist,
     740              :                                   rtoffset, NUM_EXEC_TLIST(plan));
     741        13304 :                 splan->scan.plan.qual =
     742        13304 :                     fix_scan_list(root, splan->scan.plan.qual,
     743              :                                   rtoffset, NUM_EXEC_QUAL(plan));
     744        13304 :                 splan->bitmapqualorig =
     745        13304 :                     fix_scan_list(root, splan->bitmapqualorig,
     746              :                                   rtoffset, NUM_EXEC_QUAL(plan));
     747              :             }
     748        13304 :             break;
     749          376 :         case T_TidScan:
     750              :             {
     751          376 :                 TidScan    *splan = (TidScan *) plan;
     752              : 
     753          376 :                 splan->scan.scanrelid += rtoffset;
     754          376 :                 splan->scan.plan.targetlist =
     755          376 :                     fix_scan_list(root, splan->scan.plan.targetlist,
     756              :                                   rtoffset, NUM_EXEC_TLIST(plan));
     757          376 :                 splan->scan.plan.qual =
     758          376 :                     fix_scan_list(root, splan->scan.plan.qual,
     759              :                                   rtoffset, NUM_EXEC_QUAL(plan));
     760          376 :                 splan->tidquals =
     761          376 :                     fix_scan_list(root, splan->tidquals,
     762              :                                   rtoffset, 1);
     763              :             }
     764          376 :             break;
     765         1002 :         case T_TidRangeScan:
     766              :             {
     767         1002 :                 TidRangeScan *splan = (TidRangeScan *) plan;
     768              : 
     769         1002 :                 splan->scan.scanrelid += rtoffset;
     770         1002 :                 splan->scan.plan.targetlist =
     771         1002 :                     fix_scan_list(root, splan->scan.plan.targetlist,
     772              :                                   rtoffset, NUM_EXEC_TLIST(plan));
     773         1002 :                 splan->scan.plan.qual =
     774         1002 :                     fix_scan_list(root, splan->scan.plan.qual,
     775              :                                   rtoffset, NUM_EXEC_QUAL(plan));
     776         1002 :                 splan->tidrangequals =
     777         1002 :                     fix_scan_list(root, splan->tidrangequals,
     778              :                                   rtoffset, 1);
     779              :             }
     780         1002 :             break;
     781        20064 :         case T_SubqueryScan:
     782              :             /* Needs special treatment, see comments below */
     783        20064 :             return set_subqueryscan_references(root,
     784              :                                                (SubqueryScan *) plan,
     785              :                                                rtoffset);
     786        26432 :         case T_FunctionScan:
     787              :             {
     788        26432 :                 FunctionScan *splan = (FunctionScan *) plan;
     789              : 
     790        26432 :                 splan->scan.scanrelid += rtoffset;
     791        26432 :                 splan->scan.plan.targetlist =
     792        26432 :                     fix_scan_list(root, splan->scan.plan.targetlist,
     793              :                                   rtoffset, NUM_EXEC_TLIST(plan));
     794        26432 :                 splan->scan.plan.qual =
     795        26432 :                     fix_scan_list(root, splan->scan.plan.qual,
     796              :                                   rtoffset, NUM_EXEC_QUAL(plan));
     797        26432 :                 splan->functions =
     798        26432 :                     fix_scan_list(root, splan->functions, rtoffset, 1);
     799              :             }
     800        26432 :             break;
     801          313 :         case T_TableFuncScan:
     802              :             {
     803          313 :                 TableFuncScan *splan = (TableFuncScan *) plan;
     804              : 
     805          313 :                 splan->scan.scanrelid += rtoffset;
     806          313 :                 splan->scan.plan.targetlist =
     807          313 :                     fix_scan_list(root, splan->scan.plan.targetlist,
     808              :                                   rtoffset, NUM_EXEC_TLIST(plan));
     809          313 :                 splan->scan.plan.qual =
     810          313 :                     fix_scan_list(root, splan->scan.plan.qual,
     811              :                                   rtoffset, NUM_EXEC_QUAL(plan));
     812          313 :                 splan->tablefunc = (TableFunc *)
     813          313 :                     fix_scan_expr(root, (Node *) splan->tablefunc,
     814              :                                   rtoffset, 1);
     815              :             }
     816          313 :             break;
     817         4292 :         case T_ValuesScan:
     818              :             {
     819         4292 :                 ValuesScan *splan = (ValuesScan *) plan;
     820              : 
     821         4292 :                 splan->scan.scanrelid += rtoffset;
     822         4292 :                 splan->scan.plan.targetlist =
     823         4292 :                     fix_scan_list(root, splan->scan.plan.targetlist,
     824              :                                   rtoffset, NUM_EXEC_TLIST(plan));
     825         4292 :                 splan->scan.plan.qual =
     826         4292 :                     fix_scan_list(root, splan->scan.plan.qual,
     827              :                                   rtoffset, NUM_EXEC_QUAL(plan));
     828         4292 :                 splan->values_lists =
     829         4292 :                     fix_scan_list(root, splan->values_lists,
     830              :                                   rtoffset, 1);
     831              :             }
     832         4292 :             break;
     833         2224 :         case T_CteScan:
     834              :             {
     835         2224 :                 CteScan    *splan = (CteScan *) plan;
     836              : 
     837         2224 :                 splan->scan.scanrelid += rtoffset;
     838         2224 :                 splan->scan.plan.targetlist =
     839         2224 :                     fix_scan_list(root, splan->scan.plan.targetlist,
     840              :                                   rtoffset, NUM_EXEC_TLIST(plan));
     841         2224 :                 splan->scan.plan.qual =
     842         2224 :                     fix_scan_list(root, splan->scan.plan.qual,
     843              :                                   rtoffset, NUM_EXEC_QUAL(plan));
     844              :             }
     845         2224 :             break;
     846          237 :         case T_NamedTuplestoreScan:
     847              :             {
     848          237 :                 NamedTuplestoreScan *splan = (NamedTuplestoreScan *) plan;
     849              : 
     850          237 :                 splan->scan.scanrelid += rtoffset;
     851          237 :                 splan->scan.plan.targetlist =
     852          237 :                     fix_scan_list(root, splan->scan.plan.targetlist,
     853              :                                   rtoffset, NUM_EXEC_TLIST(plan));
     854          237 :                 splan->scan.plan.qual =
     855          237 :                     fix_scan_list(root, splan->scan.plan.qual,
     856              :                                   rtoffset, NUM_EXEC_QUAL(plan));
     857              :             }
     858          237 :             break;
     859          468 :         case T_WorkTableScan:
     860              :             {
     861          468 :                 WorkTableScan *splan = (WorkTableScan *) plan;
     862              : 
     863          468 :                 splan->scan.scanrelid += rtoffset;
     864          468 :                 splan->scan.plan.targetlist =
     865          468 :                     fix_scan_list(root, splan->scan.plan.targetlist,
     866              :                                   rtoffset, NUM_EXEC_TLIST(plan));
     867          468 :                 splan->scan.plan.qual =
     868          468 :                     fix_scan_list(root, splan->scan.plan.qual,
     869              :                                   rtoffset, NUM_EXEC_QUAL(plan));
     870              :             }
     871          468 :             break;
     872         1024 :         case T_ForeignScan:
     873         1024 :             set_foreignscan_references(root, (ForeignScan *) plan, rtoffset);
     874         1024 :             break;
     875            0 :         case T_CustomScan:
     876            0 :             set_customscan_references(root, (CustomScan *) plan, rtoffset);
     877            0 :             break;
     878              : 
     879        72378 :         case T_NestLoop:
     880              :         case T_MergeJoin:
     881              :         case T_HashJoin:
     882        72378 :             set_join_references(root, (Join *) plan, rtoffset);
     883        72378 :             break;
     884              : 
     885          753 :         case T_Gather:
     886              :         case T_GatherMerge:
     887              :             {
     888          753 :                 set_upper_references(root, plan, rtoffset);
     889          753 :                 set_param_references(root, plan);
     890              :             }
     891          753 :             break;
     892              : 
     893        17804 :         case T_Hash:
     894        17804 :             set_hash_references(root, plan, rtoffset);
     895        17804 :             break;
     896              : 
     897          992 :         case T_Memoize:
     898              :             {
     899          992 :                 Memoize    *mplan = (Memoize *) plan;
     900              : 
     901              :                 /*
     902              :                  * Memoize does not evaluate its targetlist.  It just uses the
     903              :                  * same targetlist from its outer subnode.
     904              :                  */
     905          992 :                 set_dummy_tlist_references(plan, rtoffset);
     906              : 
     907          992 :                 mplan->param_exprs = fix_scan_list(root, mplan->param_exprs,
     908              :                                                    rtoffset,
     909              :                                                    NUM_EXEC_TLIST(plan));
     910          992 :                 break;
     911              :             }
     912              : 
     913        46570 :         case T_Material:
     914              :         case T_Sort:
     915              :         case T_IncrementalSort:
     916              :         case T_Unique:
     917              :         case T_SetOp:
     918              : 
     919              :             /*
     920              :              * These plan types don't actually bother to evaluate their
     921              :              * targetlists, because they just return their unmodified input
     922              :              * tuples.  Even though the targetlist won't be used by the
     923              :              * executor, we fix it up for possible use by EXPLAIN (not to
     924              :              * mention ease of debugging --- wrong varnos are very confusing).
     925              :              */
     926        46570 :             set_dummy_tlist_references(plan, rtoffset);
     927              : 
     928              :             /*
     929              :              * Since these plan types don't check quals either, we should not
     930              :              * find any qual expression attached to them.
     931              :              */
     932              :             Assert(plan->qual == NIL);
     933        46570 :             break;
     934         6774 :         case T_LockRows:
     935              :             {
     936         6774 :                 LockRows   *splan = (LockRows *) plan;
     937              : 
     938              :                 /*
     939              :                  * Like the plan types above, LockRows doesn't evaluate its
     940              :                  * tlist or quals.  But we have to fix up the RT indexes in
     941              :                  * its rowmarks.
     942              :                  */
     943         6774 :                 set_dummy_tlist_references(plan, rtoffset);
     944              :                 Assert(splan->plan.qual == NIL);
     945              : 
     946        14779 :                 foreach(l, splan->rowMarks)
     947              :                 {
     948         8005 :                     PlanRowMark *rc = (PlanRowMark *) lfirst(l);
     949              : 
     950         8005 :                     rc->rti += rtoffset;
     951         8005 :                     rc->prti += rtoffset;
     952              :                 }
     953              :             }
     954         6774 :             break;
     955         2543 :         case T_Limit:
     956              :             {
     957         2543 :                 Limit      *splan = (Limit *) plan;
     958              : 
     959              :                 /*
     960              :                  * Like the plan types above, Limit doesn't evaluate its tlist
     961              :                  * or quals.  It does have live expressions for limit/offset,
     962              :                  * however; and those cannot contain subplan variable refs, so
     963              :                  * fix_scan_expr works for them.
     964              :                  */
     965         2543 :                 set_dummy_tlist_references(plan, rtoffset);
     966              :                 Assert(splan->plan.qual == NIL);
     967              : 
     968         2543 :                 splan->limitOffset =
     969         2543 :                     fix_scan_expr(root, splan->limitOffset, rtoffset, 1);
     970         2543 :                 splan->limitCount =
     971         2543 :                     fix_scan_expr(root, splan->limitCount, rtoffset, 1);
     972              :             }
     973         2543 :             break;
     974        24812 :         case T_Agg:
     975              :             {
     976        24812 :                 Agg        *agg = (Agg *) plan;
     977              : 
     978              :                 /*
     979              :                  * If this node is combining partial-aggregation results, we
     980              :                  * must convert its Aggrefs to contain references to the
     981              :                  * partial-aggregate subexpressions that will be available
     982              :                  * from the child plan node.
     983              :                  */
     984        24812 :                 if (DO_AGGSPLIT_COMBINE(agg->aggsplit))
     985              :                 {
     986          703 :                     plan->targetlist = (List *)
     987          703 :                         convert_combining_aggrefs((Node *) plan->targetlist,
     988              :                                                   NULL);
     989          703 :                     plan->qual = (List *)
     990          703 :                         convert_combining_aggrefs((Node *) plan->qual,
     991              :                                                   NULL);
     992              :                 }
     993              : 
     994        24812 :                 set_upper_references(root, plan, rtoffset);
     995              :             }
     996        24812 :             break;
     997          123 :         case T_Group:
     998          123 :             set_upper_references(root, plan, rtoffset);
     999          123 :             break;
    1000         1431 :         case T_WindowAgg:
    1001              :             {
    1002         1431 :                 WindowAgg  *wplan = (WindowAgg *) plan;
    1003              : 
    1004              :                 /*
    1005              :                  * Adjust the WindowAgg's run conditions by swapping the
    1006              :                  * WindowFuncs references out to instead reference the Var in
    1007              :                  * the scan slot so that when the executor evaluates the
    1008              :                  * runCondition, it receives the WindowFunc's value from the
    1009              :                  * slot that the result has just been stored into rather than
    1010              :                  * evaluating the WindowFunc all over again.
    1011              :                  */
    1012         1431 :                 wplan->runCondition = set_windowagg_runcondition_references(root,
    1013              :                                                                             wplan->runCondition,
    1014              :                                                                             (Plan *) wplan);
    1015              : 
    1016         1431 :                 set_upper_references(root, plan, rtoffset);
    1017              : 
    1018              :                 /*
    1019              :                  * Like Limit node limit/offset expressions, WindowAgg has
    1020              :                  * frame offset expressions, which cannot contain subplan
    1021              :                  * variable refs, so fix_scan_expr works for them.
    1022              :                  */
    1023         1431 :                 wplan->startOffset =
    1024         1431 :                     fix_scan_expr(root, wplan->startOffset, rtoffset, 1);
    1025         1431 :                 wplan->endOffset =
    1026         1431 :                     fix_scan_expr(root, wplan->endOffset, rtoffset, 1);
    1027         1431 :                 wplan->runCondition = fix_scan_list(root,
    1028              :                                                     wplan->runCondition,
    1029              :                                                     rtoffset,
    1030              :                                                     NUM_EXEC_TLIST(plan));
    1031         1431 :                 wplan->runConditionOrig = fix_scan_list(root,
    1032              :                                                         wplan->runConditionOrig,
    1033              :                                                         rtoffset,
    1034              :                                                         NUM_EXEC_TLIST(plan));
    1035              :             }
    1036         1431 :             break;
    1037       108483 :         case T_Result:
    1038              :             {
    1039       108483 :                 Result     *splan = (Result *) plan;
    1040              : 
    1041              :                 /*
    1042              :                  * Result may or may not have a subplan; if not, it's more
    1043              :                  * like a scan node than an upper node.
    1044              :                  */
    1045       108483 :                 if (splan->plan.lefttree != NULL)
    1046         6035 :                     set_upper_references(root, plan, rtoffset);
    1047              :                 else
    1048              :                 {
    1049              :                     /*
    1050              :                      * The tlist of a childless Result could contain
    1051              :                      * unresolved ROWID_VAR Vars, in case it's representing a
    1052              :                      * target relation which is completely empty because of
    1053              :                      * constraint exclusion.  Replace any such Vars by null
    1054              :                      * constants, as though they'd been resolved for a leaf
    1055              :                      * scan node that doesn't support them.  We could have
    1056              :                      * fix_scan_expr do this, but since the case is only
    1057              :                      * expected to occur here, it seems safer to special-case
    1058              :                      * it here and keep the assertions that ROWID_VARs
    1059              :                      * shouldn't be seen by fix_scan_expr.
    1060              :                      *
    1061              :                      * We also must handle the case where set operations have
    1062              :                      * been short-circuited resulting in a dummy Result node.
    1063              :                      * prepunion.c uses varno==0 for the set op targetlist.
    1064              :                      * See generate_setop_tlist() and generate_setop_tlist().
    1065              :                      * Here we rewrite these to use varno==1, which is the
    1066              :                      * varno of the first set-op child.  Without this, EXPLAIN
    1067              :                      * will have trouble displaying targetlists of dummy set
    1068              :                      * operations.
    1069              :                      */
    1070       238641 :                     foreach(l, splan->plan.targetlist)
    1071              :                     {
    1072       136193 :                         TargetEntry *tle = (TargetEntry *) lfirst(l);
    1073       136193 :                         Var        *var = (Var *) tle->expr;
    1074              : 
    1075       136193 :                         if (var && IsA(var, Var))
    1076              :                         {
    1077          932 :                             if (var->varno == ROWID_VAR)
    1078           40 :                                 tle->expr = (Expr *) makeNullConst(var->vartype,
    1079              :                                                                    var->vartypmod,
    1080              :                                                                    var->varcollid);
    1081          892 :                             else if (var->varno == 0)
    1082           15 :                                 tle->expr = (Expr *) makeVar(1,
    1083           15 :                                                              var->varattno,
    1084              :                                                              var->vartype,
    1085              :                                                              var->vartypmod,
    1086              :                                                              var->varcollid,
    1087              :                                                              var->varlevelsup);
    1088              :                         }
    1089              :                     }
    1090              : 
    1091       102448 :                     splan->plan.targetlist =
    1092       102448 :                         fix_scan_list(root, splan->plan.targetlist,
    1093              :                                       rtoffset, NUM_EXEC_TLIST(plan));
    1094       102448 :                     splan->plan.qual =
    1095       102448 :                         fix_scan_list(root, splan->plan.qual,
    1096              :                                       rtoffset, NUM_EXEC_QUAL(plan));
    1097              :                 }
    1098              :                 /* resconstantqual can't contain any subplan variable refs */
    1099       108483 :                 splan->resconstantqual =
    1100       108483 :                     fix_scan_expr(root, splan->resconstantqual, rtoffset, 1);
    1101              :                 /* adjust the relids set */
    1102       108483 :                 splan->relids = offset_relid_set(splan->relids, rtoffset);
    1103              :             }
    1104       108483 :             break;
    1105         6041 :         case T_ProjectSet:
    1106         6041 :             set_upper_references(root, plan, rtoffset);
    1107         6041 :             break;
    1108        46738 :         case T_ModifyTable:
    1109              :             {
    1110        46738 :                 ModifyTable *splan = (ModifyTable *) plan;
    1111        46738 :                 Plan       *subplan = outerPlan(splan);
    1112              : 
    1113              :                 Assert(splan->plan.targetlist == NIL);
    1114              :                 Assert(splan->plan.qual == NIL);
    1115              : 
    1116        46738 :                 splan->withCheckOptionLists =
    1117        46738 :                     fix_scan_list(root, splan->withCheckOptionLists,
    1118              :                                   rtoffset, 1);
    1119              : 
    1120        46738 :                 if (splan->returningLists)
    1121              :                 {
    1122         1700 :                     List       *newRL = NIL;
    1123              :                     ListCell   *lcrl,
    1124              :                                *lcrr;
    1125              : 
    1126              :                     /*
    1127              :                      * Pass each per-resultrel returningList through
    1128              :                      * set_returning_clause_references().
    1129              :                      */
    1130              :                     Assert(list_length(splan->returningLists) == list_length(splan->resultRelations));
    1131         3596 :                     forboth(lcrl, splan->returningLists,
    1132              :                             lcrr, splan->resultRelations)
    1133              :                     {
    1134         1896 :                         List       *rlist = (List *) lfirst(lcrl);
    1135         1896 :                         Index       resultrel = lfirst_int(lcrr);
    1136              : 
    1137         1896 :                         rlist = set_returning_clause_references(root,
    1138              :                                                                 rlist,
    1139              :                                                                 subplan,
    1140              :                                                                 resultrel,
    1141              :                                                                 rtoffset);
    1142         1896 :                         newRL = lappend(newRL, rlist);
    1143              :                     }
    1144         1700 :                     splan->returningLists = newRL;
    1145              : 
    1146              :                     /*
    1147              :                      * Set up the visible plan targetlist as being the same as
    1148              :                      * the first RETURNING list.  This is mostly for the use
    1149              :                      * of EXPLAIN; the executor won't execute that targetlist,
    1150              :                      * although it does use it to prepare the node's result
    1151              :                      * tuple slot.  We postpone this step until here so that
    1152              :                      * we don't have to do set_returning_clause_references()
    1153              :                      * twice on identical targetlists.
    1154              :                      */
    1155         1700 :                     splan->plan.targetlist = copyObject(linitial(newRL));
    1156              :                 }
    1157              : 
    1158              :                 /*
    1159              :                  * We treat ModifyTable with ON CONFLICT as a form of 'pseudo
    1160              :                  * join', where the inner side is the EXCLUDED tuple.
    1161              :                  * Therefore use fix_join_expr to setup the relevant variables
    1162              :                  * to INNER_VAR. We explicitly don't create any OUTER_VARs as
    1163              :                  * those are already used by RETURNING and it seems better to
    1164              :                  * be non-conflicting.
    1165              :                  */
    1166        46738 :                 if (splan->onConflictAction == ONCONFLICT_UPDATE ||
    1167        46212 :                     splan->onConflictAction == ONCONFLICT_SELECT)
    1168              :                 {
    1169              :                     indexed_tlist *itlist;
    1170              : 
    1171          703 :                     itlist = build_tlist_index(splan->exclRelTlist);
    1172              : 
    1173          703 :                     splan->onConflictSet =
    1174         1406 :                         fix_join_expr(root, splan->onConflictSet,
    1175              :                                       NULL, itlist,
    1176          703 :                                       linitial_int(splan->resultRelations),
    1177          703 :                                       rtoffset, NRM_EQUAL, NUM_EXEC_QUAL(plan));
    1178              : 
    1179          703 :                     splan->onConflictWhere = (Node *)
    1180         1406 :                         fix_join_expr(root, (List *) splan->onConflictWhere,
    1181              :                                       NULL, itlist,
    1182          703 :                                       linitial_int(splan->resultRelations),
    1183          703 :                                       rtoffset, NRM_EQUAL, NUM_EXEC_QUAL(plan));
    1184              : 
    1185          703 :                     pfree(itlist);
    1186              : 
    1187          703 :                     splan->exclRelTlist =
    1188          703 :                         fix_scan_list(root, splan->exclRelTlist, rtoffset, 1);
    1189              :                 }
    1190              : 
    1191              :                 /*
    1192              :                  * The MERGE statement produces the target rows by performing
    1193              :                  * a right join between the target relation and the source
    1194              :                  * relation (which could be a plain relation or a subquery).
    1195              :                  * The INSERT and UPDATE actions of the MERGE statement
    1196              :                  * require access to the columns from the source relation. We
    1197              :                  * arrange things so that the source relation attributes are
    1198              :                  * available as INNER_VAR and the target relation attributes
    1199              :                  * are available from the scan tuple.
    1200              :                  */
    1201        46738 :                 if (splan->mergeActionLists != NIL)
    1202              :                 {
    1203          926 :                     List       *newMJC = NIL;
    1204              :                     ListCell   *lca,
    1205              :                                *lcj,
    1206              :                                *lcr;
    1207              : 
    1208              :                     /*
    1209              :                      * Fix the targetList of individual action nodes so that
    1210              :                      * the so-called "source relation" Vars are referenced as
    1211              :                      * INNER_VAR.  Note that for this to work correctly during
    1212              :                      * execution, the ecxt_innertuple must be set to the tuple
    1213              :                      * obtained by executing the subplan, which is what
    1214              :                      * constitutes the "source relation".
    1215              :                      *
    1216              :                      * We leave the Vars from the result relation (i.e. the
    1217              :                      * target relation) unchanged i.e. those Vars would be
    1218              :                      * picked from the scan slot. So during execution, we must
    1219              :                      * ensure that ecxt_scantuple is setup correctly to refer
    1220              :                      * to the tuple from the target relation.
    1221              :                      */
    1222              :                     indexed_tlist *itlist;
    1223              : 
    1224          926 :                     itlist = build_tlist_index(subplan->targetlist);
    1225              : 
    1226         1997 :                     forthree(lca, splan->mergeActionLists,
    1227              :                              lcj, splan->mergeJoinConditions,
    1228              :                              lcr, splan->resultRelations)
    1229              :                     {
    1230         1071 :                         List       *mergeActionList = lfirst(lca);
    1231         1071 :                         Node       *mergeJoinCondition = lfirst(lcj);
    1232         1071 :                         Index       resultrel = lfirst_int(lcr);
    1233              : 
    1234         2860 :                         foreach(l, mergeActionList)
    1235              :                         {
    1236         1789 :                             MergeAction *action = (MergeAction *) lfirst(l);
    1237              : 
    1238              :                             /* Fix targetList of each action. */
    1239         1789 :                             action->targetList = fix_join_expr(root,
    1240              :                                                                action->targetList,
    1241              :                                                                NULL, itlist,
    1242              :                                                                resultrel,
    1243              :                                                                rtoffset,
    1244              :                                                                NRM_EQUAL,
    1245              :                                                                NUM_EXEC_TLIST(plan));
    1246              : 
    1247              :                             /* Fix quals too. */
    1248         1789 :                             action->qual = (Node *) fix_join_expr(root,
    1249         1789 :                                                                   (List *) action->qual,
    1250              :                                                                   NULL, itlist,
    1251              :                                                                   resultrel,
    1252              :                                                                   rtoffset,
    1253              :                                                                   NRM_EQUAL,
    1254         1789 :                                                                   NUM_EXEC_QUAL(plan));
    1255              :                         }
    1256              : 
    1257              :                         /* Fix join condition too. */
    1258              :                         mergeJoinCondition = (Node *)
    1259         1071 :                             fix_join_expr(root,
    1260              :                                           (List *) mergeJoinCondition,
    1261              :                                           NULL, itlist,
    1262              :                                           resultrel,
    1263              :                                           rtoffset,
    1264              :                                           NRM_EQUAL,
    1265         1071 :                                           NUM_EXEC_QUAL(plan));
    1266         1071 :                         newMJC = lappend(newMJC, mergeJoinCondition);
    1267              :                     }
    1268          926 :                     splan->mergeJoinConditions = newMJC;
    1269              :                 }
    1270              : 
    1271        46738 :                 splan->nominalRelation += rtoffset;
    1272        46738 :                 if (splan->rootRelation)
    1273         1457 :                     splan->rootRelation += rtoffset;
    1274        46738 :                 splan->exclRelRTI += rtoffset;
    1275              : 
    1276        94724 :                 foreach(l, splan->resultRelations)
    1277              :                 {
    1278        47986 :                     lfirst_int(l) += rtoffset;
    1279              :                 }
    1280        48215 :                 foreach(l, splan->rowMarks)
    1281              :                 {
    1282         1477 :                     PlanRowMark *rc = (PlanRowMark *) lfirst(l);
    1283              : 
    1284         1477 :                     rc->rti += rtoffset;
    1285         1477 :                     rc->prti += rtoffset;
    1286              :                 }
    1287              : 
    1288              :                 /*
    1289              :                  * Append this ModifyTable node's final result relation RT
    1290              :                  * index(es) to the global list for the plan.
    1291              :                  */
    1292        93476 :                 root->glob->resultRelations =
    1293        46738 :                     list_concat(root->glob->resultRelations,
    1294        46738 :                                 splan->resultRelations);
    1295        46738 :                 if (splan->rootRelation)
    1296              :                 {
    1297         1457 :                     root->glob->resultRelations =
    1298         1457 :                         lappend_int(root->glob->resultRelations,
    1299         1457 :                                     splan->rootRelation);
    1300              :                 }
    1301              :             }
    1302        46738 :             break;
    1303        12451 :         case T_Append:
    1304              :             /* Needs special treatment, see comments below */
    1305        12451 :             return set_append_references(root,
    1306              :                                          (Append *) plan,
    1307              :                                          rtoffset);
    1308          289 :         case T_MergeAppend:
    1309              :             /* Needs special treatment, see comments below */
    1310          289 :             return set_mergeappend_references(root,
    1311              :                                               (MergeAppend *) plan,
    1312              :                                               rtoffset);
    1313          468 :         case T_RecursiveUnion:
    1314              :             /* This doesn't evaluate targetlist or check quals either */
    1315          468 :             set_dummy_tlist_references(plan, rtoffset);
    1316              :             Assert(plan->qual == NIL);
    1317          468 :             break;
    1318          127 :         case T_BitmapAnd:
    1319              :             {
    1320          127 :                 BitmapAnd  *splan = (BitmapAnd *) plan;
    1321              : 
    1322              :                 /* BitmapAnd works like Append, but has no tlist */
    1323              :                 Assert(splan->plan.targetlist == NIL);
    1324              :                 Assert(splan->plan.qual == NIL);
    1325          381 :                 foreach(l, splan->bitmapplans)
    1326              :                 {
    1327          254 :                     lfirst(l) = set_plan_refs(root,
    1328          254 :                                               (Plan *) lfirst(l),
    1329              :                                               rtoffset);
    1330              :                 }
    1331              :             }
    1332          127 :             break;
    1333          217 :         case T_BitmapOr:
    1334              :             {
    1335          217 :                 BitmapOr   *splan = (BitmapOr *) plan;
    1336              : 
    1337              :                 /* BitmapOr works like Append, but has no tlist */
    1338              :                 Assert(splan->plan.targetlist == NIL);
    1339              :                 Assert(splan->plan.qual == NIL);
    1340          654 :                 foreach(l, splan->bitmapplans)
    1341              :                 {
    1342          437 :                     lfirst(l) = set_plan_refs(root,
    1343          437 :                                               (Plan *) lfirst(l),
    1344              :                                               rtoffset);
    1345              :                 }
    1346              :             }
    1347          217 :             break;
    1348            0 :         default:
    1349            0 :             elog(ERROR, "unrecognized node type: %d",
    1350              :                  (int) nodeTag(plan));
    1351              :             break;
    1352              :     }
    1353              : 
    1354              :     /*
    1355              :      * Now recurse into child plans, if any
    1356              :      *
    1357              :      * NOTE: it is essential that we recurse into child plans AFTER we set
    1358              :      * subplan references in this plan's tlist and quals.  If we did the
    1359              :      * reference-adjustments bottom-up, then we would fail to match this
    1360              :      * plan's var nodes against the already-modified nodes of the children.
    1361              :      */
    1362       583893 :     plan->lefttree = set_plan_refs(root, plan->lefttree, rtoffset);
    1363       583893 :     plan->righttree = set_plan_refs(root, plan->righttree, rtoffset);
    1364              : 
    1365       583893 :     return plan;
    1366              : }
    1367              : 
    1368              : /*
    1369              :  * set_indexonlyscan_references
    1370              :  *      Do set_plan_references processing on an IndexOnlyScan
    1371              :  *
    1372              :  * This is unlike the handling of a plain IndexScan because we have to
    1373              :  * convert Vars referencing the heap into Vars referencing the index.
    1374              :  * We can use the fix_upper_expr machinery for that, by working from a
    1375              :  * targetlist describing the index columns.
    1376              :  */
    1377              : static Plan *
    1378         9260 : set_indexonlyscan_references(PlannerInfo *root,
    1379              :                              IndexOnlyScan *plan,
    1380              :                              int rtoffset)
    1381              : {
    1382              :     indexed_tlist *index_itlist;
    1383              :     List       *stripped_indextlist;
    1384              :     ListCell   *lc;
    1385              : 
    1386              :     /*
    1387              :      * Vars in the plan node's targetlist, qual, and recheckqual must only
    1388              :      * reference columns that the index AM can actually return.  To ensure
    1389              :      * this, remove non-returnable columns (which are marked as resjunk) from
    1390              :      * the indexed tlist.  We can just drop them because the indexed_tlist
    1391              :      * machinery pays attention to TLE resnos, not physical list position.
    1392              :      */
    1393         9260 :     stripped_indextlist = NIL;
    1394        21695 :     foreach(lc, plan->indextlist)
    1395              :     {
    1396        12435 :         TargetEntry *indextle = (TargetEntry *) lfirst(lc);
    1397              : 
    1398        12435 :         if (!indextle->resjunk)
    1399        12409 :             stripped_indextlist = lappend(stripped_indextlist, indextle);
    1400              :     }
    1401              : 
    1402         9260 :     index_itlist = build_tlist_index(stripped_indextlist);
    1403              : 
    1404         9260 :     plan->scan.scanrelid += rtoffset;
    1405         9260 :     plan->scan.plan.targetlist = (List *)
    1406         9260 :         fix_upper_expr(root,
    1407         9260 :                        (Node *) plan->scan.plan.targetlist,
    1408              :                        index_itlist,
    1409              :                        INDEX_VAR,
    1410              :                        rtoffset,
    1411              :                        NRM_EQUAL,
    1412              :                        NUM_EXEC_TLIST((Plan *) plan));
    1413         9260 :     plan->scan.plan.qual = (List *)
    1414         9260 :         fix_upper_expr(root,
    1415         9260 :                        (Node *) plan->scan.plan.qual,
    1416              :                        index_itlist,
    1417              :                        INDEX_VAR,
    1418              :                        rtoffset,
    1419              :                        NRM_EQUAL,
    1420         9260 :                        NUM_EXEC_QUAL((Plan *) plan));
    1421         9260 :     plan->recheckqual = (List *)
    1422         9260 :         fix_upper_expr(root,
    1423         9260 :                        (Node *) plan->recheckqual,
    1424              :                        index_itlist,
    1425              :                        INDEX_VAR,
    1426              :                        rtoffset,
    1427              :                        NRM_EQUAL,
    1428         9260 :                        NUM_EXEC_QUAL((Plan *) plan));
    1429              :     /* indexqual is already transformed to reference index columns */
    1430         9260 :     plan->indexqual = fix_scan_list(root, plan->indexqual,
    1431              :                                     rtoffset, 1);
    1432              :     /* indexorderby is already transformed to reference index columns */
    1433         9260 :     plan->indexorderby = fix_scan_list(root, plan->indexorderby,
    1434              :                                        rtoffset, 1);
    1435              :     /* indextlist must NOT be transformed to reference index columns */
    1436         9260 :     plan->indextlist = fix_scan_list(root, plan->indextlist,
    1437              :                                      rtoffset, NUM_EXEC_TLIST((Plan *) plan));
    1438              : 
    1439         9260 :     pfree(index_itlist);
    1440              : 
    1441         9260 :     return (Plan *) plan;
    1442              : }
    1443              : 
    1444              : /*
    1445              :  * set_subqueryscan_references
    1446              :  *      Do set_plan_references processing on a SubqueryScan
    1447              :  *
    1448              :  * We try to strip out the SubqueryScan entirely; if we can't, we have
    1449              :  * to do the normal processing on it.
    1450              :  */
    1451              : static Plan *
    1452        20064 : set_subqueryscan_references(PlannerInfo *root,
    1453              :                             SubqueryScan *plan,
    1454              :                             int rtoffset)
    1455              : {
    1456              :     RelOptInfo *rel;
    1457              :     Plan       *result;
    1458              : 
    1459              :     /* Need to look up the subquery's RelOptInfo, since we need its subroot */
    1460        20064 :     rel = find_base_rel(root, plan->scan.scanrelid);
    1461              : 
    1462              :     /* Recursively process the subplan */
    1463        20064 :     plan->subplan = set_plan_references(rel->subroot, plan->subplan);
    1464              : 
    1465        20064 :     if (trivial_subqueryscan(plan))
    1466              :     {
    1467              :         Index       scanrelid;
    1468              : 
    1469              :         /*
    1470              :          * We can omit the SubqueryScan node and just pull up the subplan.
    1471              :          */
    1472         9152 :         result = clean_up_removed_plan_level((Plan *) plan, plan->subplan);
    1473              : 
    1474              :         /* Remember that we removed a SubqueryScan */
    1475         9152 :         scanrelid = plan->scan.scanrelid + rtoffset;
    1476         9152 :         record_elided_node(root->glob, plan->subplan->plan_node_id,
    1477              :                            T_SubqueryScan, bms_make_singleton(scanrelid));
    1478              :     }
    1479              :     else
    1480              :     {
    1481              :         /*
    1482              :          * Keep the SubqueryScan node.  We have to do the processing that
    1483              :          * set_plan_references would otherwise have done on it.  Notice we do
    1484              :          * not do set_upper_references() here, because a SubqueryScan will
    1485              :          * always have been created with correct references to its subplan's
    1486              :          * outputs to begin with.
    1487              :          */
    1488        10912 :         plan->scan.scanrelid += rtoffset;
    1489        10912 :         plan->scan.plan.targetlist =
    1490        10912 :             fix_scan_list(root, plan->scan.plan.targetlist,
    1491              :                           rtoffset, NUM_EXEC_TLIST((Plan *) plan));
    1492        10912 :         plan->scan.plan.qual =
    1493        10912 :             fix_scan_list(root, plan->scan.plan.qual,
    1494              :                           rtoffset, NUM_EXEC_QUAL((Plan *) plan));
    1495              : 
    1496        10912 :         result = (Plan *) plan;
    1497              :     }
    1498              : 
    1499        20064 :     return result;
    1500              : }
    1501              : 
    1502              : /*
    1503              :  * trivial_subqueryscan
    1504              :  *      Detect whether a SubqueryScan can be deleted from the plan tree.
    1505              :  *
    1506              :  * We can delete it if it has no qual to check and the targetlist just
    1507              :  * regurgitates the output of the child plan.
    1508              :  *
    1509              :  * This can be called from mark_async_capable_plan(), a helper function for
    1510              :  * create_append_plan(), before set_subqueryscan_references(), to determine
    1511              :  * triviality of a SubqueryScan that is a child of an Append node.  So we
    1512              :  * cache the result in the SubqueryScan node to avoid repeated computation.
    1513              :  *
    1514              :  * Note: when called from mark_async_capable_plan(), we determine the result
    1515              :  * before running finalize_plan() on the SubqueryScan node (if needed) and
    1516              :  * set_plan_references() on the subplan tree, but this would be safe, because
    1517              :  * 1) finalize_plan() doesn't modify the tlist or quals for the SubqueryScan
    1518              :  *    node (or that for any plan node in the subplan tree), and
    1519              :  * 2) set_plan_references() modifies the tlist for every plan node in the
    1520              :  *    subplan tree, but keeps const/resjunk columns as const/resjunk ones and
    1521              :  *    preserves the length and order of the tlist, and
    1522              :  * 3) set_plan_references() might delete the topmost plan node like an Append
    1523              :  *    or MergeAppend from the subplan tree and pull up the child plan node,
    1524              :  *    but in that case, the tlist for the child plan node exactly matches the
    1525              :  *    parent.
    1526              :  */
    1527              : bool
    1528        25744 : trivial_subqueryscan(SubqueryScan *plan)
    1529              : {
    1530              :     int         attrno;
    1531              :     ListCell   *lp,
    1532              :                *lc;
    1533              : 
    1534              :     /* We might have detected this already; in which case reuse the result */
    1535        25744 :     if (plan->scanstatus == SUBQUERY_SCAN_TRIVIAL)
    1536         2310 :         return true;
    1537        23434 :     if (plan->scanstatus == SUBQUERY_SCAN_NONTRIVIAL)
    1538         3370 :         return false;
    1539              :     Assert(plan->scanstatus == SUBQUERY_SCAN_UNKNOWN);
    1540              :     /* Initially, mark the SubqueryScan as non-deletable from the plan tree */
    1541        20064 :     plan->scanstatus = SUBQUERY_SCAN_NONTRIVIAL;
    1542              : 
    1543        20064 :     if (plan->scan.plan.qual != NIL)
    1544          365 :         return false;
    1545              : 
    1546        39398 :     if (list_length(plan->scan.plan.targetlist) !=
    1547        19699 :         list_length(plan->subplan->targetlist))
    1548         6425 :         return false;           /* tlists not same length */
    1549              : 
    1550        13274 :     attrno = 1;
    1551        41104 :     forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
    1552              :     {
    1553        31952 :         TargetEntry *ptle = (TargetEntry *) lfirst(lp);
    1554        31952 :         TargetEntry *ctle = (TargetEntry *) lfirst(lc);
    1555              : 
    1556        31952 :         if (ptle->resjunk != ctle->resjunk)
    1557         4122 :             return false;       /* tlist doesn't match junk status */
    1558              : 
    1559              :         /*
    1560              :          * We accept either a Var referencing the corresponding element of the
    1561              :          * subplan tlist, or a Const equaling the subplan element. See
    1562              :          * generate_setop_tlist() for motivation.
    1563              :          */
    1564        31940 :         if (ptle->expr && IsA(ptle->expr, Var))
    1565        26624 :         {
    1566        26720 :             Var        *var = (Var *) ptle->expr;
    1567              : 
    1568              :             Assert(var->varno == plan->scan.scanrelid);
    1569              :             Assert(var->varlevelsup == 0);
    1570        26720 :             if (var->varattno != attrno)
    1571           96 :                 return false;   /* out of order */
    1572              :         }
    1573         5220 :         else if (ptle->expr && IsA(ptle->expr, Const))
    1574              :         {
    1575         4492 :             if (!equal(ptle->expr, ctle->expr))
    1576         3286 :                 return false;
    1577              :         }
    1578              :         else
    1579          728 :             return false;
    1580              : 
    1581        27830 :         attrno++;
    1582              :     }
    1583              : 
    1584              :     /* Re-mark the SubqueryScan as deletable from the plan tree */
    1585         9152 :     plan->scanstatus = SUBQUERY_SCAN_TRIVIAL;
    1586              : 
    1587         9152 :     return true;
    1588              : }
    1589              : 
    1590              : /*
    1591              :  * clean_up_removed_plan_level
    1592              :  *      Do necessary cleanup when we strip out a SubqueryScan, Append, etc
    1593              :  *
    1594              :  * We are dropping the "parent" plan in favor of returning just its "child".
    1595              :  * A few small tweaks are needed.
    1596              :  */
    1597              : static Plan *
    1598        12518 : clean_up_removed_plan_level(Plan *parent, Plan *child)
    1599              : {
    1600              :     /*
    1601              :      * We have to be sure we don't lose any initplans, so move any that were
    1602              :      * attached to the parent plan to the child.  If any are parallel-unsafe,
    1603              :      * the child is no longer parallel-safe.  As a cosmetic matter, also add
    1604              :      * the initplans' run costs to the child's costs.
    1605              :      */
    1606        12518 :     if (parent->initPlan)
    1607              :     {
    1608              :         Cost        initplan_cost;
    1609              :         bool        unsafe_initplans;
    1610              : 
    1611           21 :         SS_compute_initplan_cost(parent->initPlan,
    1612              :                                  &initplan_cost, &unsafe_initplans);
    1613           21 :         child->startup_cost += initplan_cost;
    1614           21 :         child->total_cost += initplan_cost;
    1615           21 :         if (unsafe_initplans)
    1616            9 :             child->parallel_safe = false;
    1617              : 
    1618              :         /*
    1619              :          * Attach plans this way so that parent's initplans are processed
    1620              :          * before any pre-existing initplans of the child.  Probably doesn't
    1621              :          * matter, but let's preserve the ordering just in case.
    1622              :          */
    1623           21 :         child->initPlan = list_concat(parent->initPlan,
    1624           21 :                                       child->initPlan);
    1625              :     }
    1626              : 
    1627              :     /*
    1628              :      * We also have to transfer the parent's column labeling info into the
    1629              :      * child, else columns sent to client will be improperly labeled if this
    1630              :      * is the topmost plan level.  resjunk and so on may be important too.
    1631              :      */
    1632        12518 :     apply_tlist_labeling(child->targetlist, parent->targetlist);
    1633              : 
    1634        12518 :     return child;
    1635              : }
    1636              : 
    1637              : /*
    1638              :  * set_foreignscan_references
    1639              :  *     Do set_plan_references processing on a ForeignScan
    1640              :  */
    1641              : static void
    1642         1024 : set_foreignscan_references(PlannerInfo *root,
    1643              :                            ForeignScan *fscan,
    1644              :                            int rtoffset)
    1645              : {
    1646              :     /* Adjust scanrelid if it's valid */
    1647         1024 :     if (fscan->scan.scanrelid > 0)
    1648          738 :         fscan->scan.scanrelid += rtoffset;
    1649              : 
    1650         1024 :     if (fscan->fdw_scan_tlist != NIL || fscan->scan.scanrelid == 0)
    1651          286 :     {
    1652              :         /*
    1653              :          * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals to reference
    1654              :          * foreign scan tuple
    1655              :          */
    1656          286 :         indexed_tlist *itlist = build_tlist_index(fscan->fdw_scan_tlist);
    1657              : 
    1658          286 :         fscan->scan.plan.targetlist = (List *)
    1659          286 :             fix_upper_expr(root,
    1660          286 :                            (Node *) fscan->scan.plan.targetlist,
    1661              :                            itlist,
    1662              :                            INDEX_VAR,
    1663              :                            rtoffset,
    1664              :                            NRM_EQUAL,
    1665              :                            NUM_EXEC_TLIST((Plan *) fscan));
    1666          286 :         fscan->scan.plan.qual = (List *)
    1667          286 :             fix_upper_expr(root,
    1668          286 :                            (Node *) fscan->scan.plan.qual,
    1669              :                            itlist,
    1670              :                            INDEX_VAR,
    1671              :                            rtoffset,
    1672              :                            NRM_EQUAL,
    1673          286 :                            NUM_EXEC_QUAL((Plan *) fscan));
    1674          286 :         fscan->fdw_exprs = (List *)
    1675          286 :             fix_upper_expr(root,
    1676          286 :                            (Node *) fscan->fdw_exprs,
    1677              :                            itlist,
    1678              :                            INDEX_VAR,
    1679              :                            rtoffset,
    1680              :                            NRM_EQUAL,
    1681          286 :                            NUM_EXEC_QUAL((Plan *) fscan));
    1682          286 :         fscan->fdw_recheck_quals = (List *)
    1683          286 :             fix_upper_expr(root,
    1684          286 :                            (Node *) fscan->fdw_recheck_quals,
    1685              :                            itlist,
    1686              :                            INDEX_VAR,
    1687              :                            rtoffset,
    1688              :                            NRM_EQUAL,
    1689          286 :                            NUM_EXEC_QUAL((Plan *) fscan));
    1690          286 :         pfree(itlist);
    1691              :         /* fdw_scan_tlist itself just needs fix_scan_list() adjustments */
    1692          286 :         fscan->fdw_scan_tlist =
    1693          286 :             fix_scan_list(root, fscan->fdw_scan_tlist,
    1694              :                           rtoffset, NUM_EXEC_TLIST((Plan *) fscan));
    1695              :     }
    1696              :     else
    1697              :     {
    1698              :         /*
    1699              :          * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals in the standard
    1700              :          * way
    1701              :          */
    1702          738 :         fscan->scan.plan.targetlist =
    1703          738 :             fix_scan_list(root, fscan->scan.plan.targetlist,
    1704              :                           rtoffset, NUM_EXEC_TLIST((Plan *) fscan));
    1705          738 :         fscan->scan.plan.qual =
    1706          738 :             fix_scan_list(root, fscan->scan.plan.qual,
    1707              :                           rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
    1708          738 :         fscan->fdw_exprs =
    1709          738 :             fix_scan_list(root, fscan->fdw_exprs,
    1710              :                           rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
    1711          738 :         fscan->fdw_recheck_quals =
    1712          738 :             fix_scan_list(root, fscan->fdw_recheck_quals,
    1713              :                           rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
    1714              :     }
    1715              : 
    1716         1024 :     fscan->fs_relids = offset_relid_set(fscan->fs_relids, rtoffset);
    1717         1024 :     fscan->fs_base_relids = offset_relid_set(fscan->fs_base_relids, rtoffset);
    1718              : 
    1719              :     /* Adjust resultRelation if it's valid */
    1720         1024 :     if (fscan->resultRelation > 0)
    1721          104 :         fscan->resultRelation += rtoffset;
    1722         1024 : }
    1723              : 
    1724              : /*
    1725              :  * set_customscan_references
    1726              :  *     Do set_plan_references processing on a CustomScan
    1727              :  */
    1728              : static void
    1729            0 : set_customscan_references(PlannerInfo *root,
    1730              :                           CustomScan *cscan,
    1731              :                           int rtoffset)
    1732              : {
    1733              :     ListCell   *lc;
    1734              : 
    1735              :     /* Adjust scanrelid if it's valid */
    1736            0 :     if (cscan->scan.scanrelid > 0)
    1737            0 :         cscan->scan.scanrelid += rtoffset;
    1738              : 
    1739            0 :     if (cscan->custom_scan_tlist != NIL || cscan->scan.scanrelid == 0)
    1740            0 :     {
    1741              :         /* Adjust tlist, qual, custom_exprs to reference custom scan tuple */
    1742            0 :         indexed_tlist *itlist = build_tlist_index(cscan->custom_scan_tlist);
    1743              : 
    1744            0 :         cscan->scan.plan.targetlist = (List *)
    1745            0 :             fix_upper_expr(root,
    1746            0 :                            (Node *) cscan->scan.plan.targetlist,
    1747              :                            itlist,
    1748              :                            INDEX_VAR,
    1749              :                            rtoffset,
    1750              :                            NRM_EQUAL,
    1751              :                            NUM_EXEC_TLIST((Plan *) cscan));
    1752            0 :         cscan->scan.plan.qual = (List *)
    1753            0 :             fix_upper_expr(root,
    1754            0 :                            (Node *) cscan->scan.plan.qual,
    1755              :                            itlist,
    1756              :                            INDEX_VAR,
    1757              :                            rtoffset,
    1758              :                            NRM_EQUAL,
    1759            0 :                            NUM_EXEC_QUAL((Plan *) cscan));
    1760            0 :         cscan->custom_exprs = (List *)
    1761            0 :             fix_upper_expr(root,
    1762            0 :                            (Node *) cscan->custom_exprs,
    1763              :                            itlist,
    1764              :                            INDEX_VAR,
    1765              :                            rtoffset,
    1766              :                            NRM_EQUAL,
    1767            0 :                            NUM_EXEC_QUAL((Plan *) cscan));
    1768            0 :         pfree(itlist);
    1769              :         /* custom_scan_tlist itself just needs fix_scan_list() adjustments */
    1770            0 :         cscan->custom_scan_tlist =
    1771            0 :             fix_scan_list(root, cscan->custom_scan_tlist,
    1772              :                           rtoffset, NUM_EXEC_TLIST((Plan *) cscan));
    1773              :     }
    1774              :     else
    1775              :     {
    1776              :         /* Adjust tlist, qual, custom_exprs in the standard way */
    1777            0 :         cscan->scan.plan.targetlist =
    1778            0 :             fix_scan_list(root, cscan->scan.plan.targetlist,
    1779              :                           rtoffset, NUM_EXEC_TLIST((Plan *) cscan));
    1780            0 :         cscan->scan.plan.qual =
    1781            0 :             fix_scan_list(root, cscan->scan.plan.qual,
    1782              :                           rtoffset, NUM_EXEC_QUAL((Plan *) cscan));
    1783            0 :         cscan->custom_exprs =
    1784            0 :             fix_scan_list(root, cscan->custom_exprs,
    1785              :                           rtoffset, NUM_EXEC_QUAL((Plan *) cscan));
    1786              :     }
    1787              : 
    1788              :     /* Adjust child plan-nodes recursively, if needed */
    1789            0 :     foreach(lc, cscan->custom_plans)
    1790              :     {
    1791            0 :         lfirst(lc) = set_plan_refs(root, (Plan *) lfirst(lc), rtoffset);
    1792              :     }
    1793              : 
    1794            0 :     cscan->custom_relids = offset_relid_set(cscan->custom_relids, rtoffset);
    1795            0 : }
    1796              : 
    1797              : /*
    1798              :  * register_partpruneinfo
    1799              :  *      Subroutine for set_append_references and set_mergeappend_references
    1800              :  *
    1801              :  * Add the PartitionPruneInfo from root->partPruneInfos at the given index
    1802              :  * into PlannerGlobal->partPruneInfos and return its index there.
    1803              :  *
    1804              :  * Also update the RT indexes present in PartitionedRelPruneInfos to add the
    1805              :  * offset.
    1806              :  *
    1807              :  * Finally, if there are initial pruning steps, add the RT indexes of the
    1808              :  * leaf partitions to the set of relations that are prunable at execution
    1809              :  * startup time.
    1810              :  */
    1811              : static int
    1812          283 : register_partpruneinfo(PlannerInfo *root, int part_prune_index, int rtoffset)
    1813              : {
    1814          283 :     PlannerGlobal *glob = root->glob;
    1815              :     PartitionPruneInfo *pinfo;
    1816              :     ListCell   *l;
    1817              : 
    1818              :     Assert(part_prune_index >= 0 &&
    1819              :            part_prune_index < list_length(root->partPruneInfos));
    1820          283 :     pinfo = list_nth_node(PartitionPruneInfo, root->partPruneInfos,
    1821              :                           part_prune_index);
    1822              : 
    1823          283 :     pinfo->relids = offset_relid_set(pinfo->relids, rtoffset);
    1824          572 :     foreach(l, pinfo->prune_infos)
    1825              :     {
    1826          289 :         List       *prune_infos = lfirst(l);
    1827              :         ListCell   *l2;
    1828              : 
    1829          785 :         foreach(l2, prune_infos)
    1830              :         {
    1831          496 :             PartitionedRelPruneInfo *prelinfo = lfirst(l2);
    1832              :             int         i;
    1833              : 
    1834          496 :             prelinfo->rtindex += rtoffset;
    1835          496 :             prelinfo->initial_pruning_steps =
    1836          496 :                 fix_scan_list(root, prelinfo->initial_pruning_steps,
    1837              :                               rtoffset, 1);
    1838          496 :             prelinfo->exec_pruning_steps =
    1839          496 :                 fix_scan_list(root, prelinfo->exec_pruning_steps,
    1840              :                               rtoffset, 1);
    1841              : 
    1842         1961 :             for (i = 0; i < prelinfo->nparts; i++)
    1843              :             {
    1844              :                 /*
    1845              :                  * Non-leaf partitions and partitions that do not have a
    1846              :                  * subplan are not included in this map as mentioned in
    1847              :                  * make_partitionedrel_pruneinfo().
    1848              :                  */
    1849         1465 :                 if (prelinfo->leafpart_rti_map[i])
    1850              :                 {
    1851         1187 :                     prelinfo->leafpart_rti_map[i] += rtoffset;
    1852         1187 :                     if (prelinfo->initial_pruning_steps)
    1853          374 :                         glob->prunableRelids = bms_add_member(glob->prunableRelids,
    1854          374 :                                                               prelinfo->leafpart_rti_map[i]);
    1855              :                 }
    1856              :             }
    1857              :         }
    1858              :     }
    1859              : 
    1860          283 :     glob->partPruneInfos = lappend(glob->partPruneInfos, pinfo);
    1861              : 
    1862          283 :     return list_length(glob->partPruneInfos) - 1;
    1863              : }
    1864              : 
    1865              : /*
    1866              :  * set_append_references
    1867              :  *      Do set_plan_references processing on an Append
    1868              :  *
    1869              :  * We try to strip out the Append entirely; if we can't, we have
    1870              :  * to do the normal processing on it.
    1871              :  */
    1872              : static Plan *
    1873        12451 : set_append_references(PlannerInfo *root,
    1874              :                       Append *aplan,
    1875              :                       int rtoffset)
    1876              : {
    1877              :     ListCell   *l;
    1878              : 
    1879              :     /*
    1880              :      * Append, like Sort et al, doesn't actually evaluate its targetlist or
    1881              :      * check quals.  If it's got exactly one child plan, then it's not doing
    1882              :      * anything useful at all, and we can strip it out.
    1883              :      */
    1884              :     Assert(aplan->plan.qual == NIL);
    1885              : 
    1886              :     /* First, we gotta recurse on the children */
    1887        43197 :     foreach(l, aplan->appendplans)
    1888              :     {
    1889        30746 :         lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset);
    1890              :     }
    1891              : 
    1892              :     /*
    1893              :      * See if it's safe to get rid of the Append entirely.  For this to be
    1894              :      * safe, there must be only one child plan and that child plan's parallel
    1895              :      * awareness must match the Append's.  The reason for the latter is that
    1896              :      * if the Append is parallel aware and the child is not, then the calling
    1897              :      * plan may execute the non-parallel aware child multiple times.  (If you
    1898              :      * change these rules, update create_append_path to match.)
    1899              :      */
    1900        12451 :     if (list_length(aplan->appendplans) == 1)
    1901              :     {
    1902         3364 :         Plan       *p = (Plan *) linitial(aplan->appendplans);
    1903              : 
    1904         3364 :         if (p->parallel_aware == aplan->plan.parallel_aware)
    1905              :         {
    1906              :             Plan       *result;
    1907              : 
    1908         3364 :             result = clean_up_removed_plan_level((Plan *) aplan, p);
    1909              : 
    1910              :             /* Remember that we removed an Append */
    1911         3364 :             record_elided_node(root->glob, p->plan_node_id, T_Append,
    1912              :                                offset_relid_set(aplan->apprelids, rtoffset));
    1913              : 
    1914         3364 :             return result;
    1915              :         }
    1916              :     }
    1917              : 
    1918              :     /*
    1919              :      * Otherwise, clean up the Append as needed.  It's okay to do this after
    1920              :      * recursing to the children, because set_dummy_tlist_references doesn't
    1921              :      * look at those.
    1922              :      */
    1923         9087 :     set_dummy_tlist_references((Plan *) aplan, rtoffset);
    1924              : 
    1925         9087 :     aplan->apprelids = offset_relid_set(aplan->apprelids, rtoffset);
    1926              : 
    1927              :     /*
    1928              :      * Add PartitionPruneInfo, if any, to PlannerGlobal and update the index.
    1929              :      * Also update the RT indexes present in it to add the offset.
    1930              :      */
    1931         9087 :     if (aplan->part_prune_index >= 0)
    1932          265 :         aplan->part_prune_index =
    1933          265 :             register_partpruneinfo(root, aplan->part_prune_index, rtoffset);
    1934              : 
    1935              :     /* We don't need to recurse to lefttree or righttree ... */
    1936              :     Assert(aplan->plan.lefttree == NULL);
    1937              :     Assert(aplan->plan.righttree == NULL);
    1938              : 
    1939         9087 :     return (Plan *) aplan;
    1940              : }
    1941              : 
    1942              : /*
    1943              :  * set_mergeappend_references
    1944              :  *      Do set_plan_references processing on a MergeAppend
    1945              :  *
    1946              :  * We try to strip out the MergeAppend entirely; if we can't, we have
    1947              :  * to do the normal processing on it.
    1948              :  */
    1949              : static Plan *
    1950          289 : set_mergeappend_references(PlannerInfo *root,
    1951              :                            MergeAppend *mplan,
    1952              :                            int rtoffset)
    1953              : {
    1954              :     ListCell   *l;
    1955              : 
    1956              :     /*
    1957              :      * MergeAppend, like Sort et al, doesn't actually evaluate its targetlist
    1958              :      * or check quals.  If it's got exactly one child plan, then it's not
    1959              :      * doing anything useful at all, and we can strip it out.
    1960              :      */
    1961              :     Assert(mplan->plan.qual == NIL);
    1962              : 
    1963              :     /* First, we gotta recurse on the children */
    1964         1100 :     foreach(l, mplan->mergeplans)
    1965              :     {
    1966          811 :         lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset);
    1967              :     }
    1968              : 
    1969              :     /*
    1970              :      * See if it's safe to get rid of the MergeAppend entirely.  For this to
    1971              :      * be safe, there must be only one child plan and that child plan's
    1972              :      * parallel awareness must match the MergeAppend's.  The reason for the
    1973              :      * latter is that if the MergeAppend is parallel aware and the child is
    1974              :      * not, then the calling plan may execute the non-parallel aware child
    1975              :      * multiple times.  (If you change these rules, update
    1976              :      * create_merge_append_path to match.)
    1977              :      */
    1978          289 :     if (list_length(mplan->mergeplans) == 1)
    1979              :     {
    1980            2 :         Plan       *p = (Plan *) linitial(mplan->mergeplans);
    1981              : 
    1982            2 :         if (p->parallel_aware == mplan->plan.parallel_aware)
    1983              :         {
    1984              :             Plan       *result;
    1985              : 
    1986            2 :             result = clean_up_removed_plan_level((Plan *) mplan, p);
    1987              : 
    1988              :             /* Remember that we removed a MergeAppend */
    1989            2 :             record_elided_node(root->glob, p->plan_node_id, T_MergeAppend,
    1990              :                                offset_relid_set(mplan->apprelids, rtoffset));
    1991              : 
    1992            2 :             return result;
    1993              :         }
    1994              :     }
    1995              : 
    1996              :     /*
    1997              :      * Otherwise, clean up the MergeAppend as needed.  It's okay to do this
    1998              :      * after recursing to the children, because set_dummy_tlist_references
    1999              :      * doesn't look at those.
    2000              :      */
    2001          287 :     set_dummy_tlist_references((Plan *) mplan, rtoffset);
    2002              : 
    2003          287 :     mplan->apprelids = offset_relid_set(mplan->apprelids, rtoffset);
    2004              : 
    2005              :     /*
    2006              :      * Add PartitionPruneInfo, if any, to PlannerGlobal and update the index.
    2007              :      * Also update the RT indexes present in it to add the offset.
    2008              :      */
    2009          287 :     if (mplan->part_prune_index >= 0)
    2010           18 :         mplan->part_prune_index =
    2011           18 :             register_partpruneinfo(root, mplan->part_prune_index, rtoffset);
    2012              : 
    2013              :     /* We don't need to recurse to lefttree or righttree ... */
    2014              :     Assert(mplan->plan.lefttree == NULL);
    2015              :     Assert(mplan->plan.righttree == NULL);
    2016              : 
    2017          287 :     return (Plan *) mplan;
    2018              : }
    2019              : 
    2020              : /*
    2021              :  * set_hash_references
    2022              :  *     Do set_plan_references processing on a Hash node
    2023              :  */
    2024              : static void
    2025        17804 : set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset)
    2026              : {
    2027        17804 :     Hash       *hplan = (Hash *) plan;
    2028        17804 :     Plan       *outer_plan = plan->lefttree;
    2029              :     indexed_tlist *outer_itlist;
    2030              : 
    2031              :     /*
    2032              :      * Hash's hashkeys are used when feeding tuples into the hashtable,
    2033              :      * therefore have them reference Hash's outer plan (which itself is the
    2034              :      * inner plan of the HashJoin).
    2035              :      */
    2036        17804 :     outer_itlist = build_tlist_index(outer_plan->targetlist);
    2037        17804 :     hplan->hashkeys = (List *)
    2038        17804 :         fix_upper_expr(root,
    2039        17804 :                        (Node *) hplan->hashkeys,
    2040              :                        outer_itlist,
    2041              :                        OUTER_VAR,
    2042              :                        rtoffset,
    2043              :                        NRM_EQUAL,
    2044        17804 :                        NUM_EXEC_QUAL(plan));
    2045              : 
    2046              :     /* Hash doesn't project */
    2047        17804 :     set_dummy_tlist_references(plan, rtoffset);
    2048              : 
    2049              :     /* Hash nodes don't have their own quals */
    2050              :     Assert(plan->qual == NIL);
    2051        17804 : }
    2052              : 
    2053              : /*
    2054              :  * offset_relid_set
    2055              :  *      Apply rtoffset to the members of a Relids set.
    2056              :  */
    2057              : static Relids
    2058       123554 : offset_relid_set(Relids relids, int rtoffset)
    2059              : {
    2060       123554 :     Relids      result = NULL;
    2061              :     int         rtindex;
    2062              : 
    2063              :     /* If there's no offset to apply, we needn't recompute the value */
    2064       123554 :     if (rtoffset == 0)
    2065       113103 :         return relids;
    2066        10451 :     rtindex = -1;
    2067        15909 :     while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
    2068         5458 :         result = bms_add_member(result, rtindex + rtoffset);
    2069        10451 :     return result;
    2070              : }
    2071              : 
    2072              : /*
    2073              :  * copyVar
    2074              :  *      Copy a Var node.
    2075              :  *
    2076              :  * fix_scan_expr and friends do this enough times that it's worth having
    2077              :  * a bespoke routine instead of using the generic copyObject() function.
    2078              :  */
    2079              : static inline Var *
    2080      1095107 : copyVar(Var *var)
    2081              : {
    2082      1095107 :     Var        *newvar = palloc_object(Var);
    2083              : 
    2084      1095107 :     *newvar = *var;
    2085      1095107 :     return newvar;
    2086              : }
    2087              : 
    2088              : /*
    2089              :  * fix_expr_common
    2090              :  *      Do generic set_plan_references processing on an expression node
    2091              :  *
    2092              :  * This is code that is common to all variants of expression-fixing.
    2093              :  * We must look up operator opcode info for OpExpr and related nodes,
    2094              :  * add OIDs from regclass Const nodes into root->glob->relationOids, and
    2095              :  * add PlanInvalItems for user-defined functions into root->glob->invalItems.
    2096              :  * We also fill in column index lists for GROUPING() expressions.
    2097              :  *
    2098              :  * We assume it's okay to update opcode info in-place.  So this could possibly
    2099              :  * scribble on the planner's input data structures, but it's OK.
    2100              :  */
    2101              : static void
    2102      7360081 : fix_expr_common(PlannerInfo *root, Node *node)
    2103              : {
    2104              :     /* We assume callers won't call us on a NULL pointer */
    2105      7360081 :     if (IsA(node, Aggref))
    2106              :     {
    2107        31792 :         record_plan_function_dependency(root,
    2108              :                                         ((Aggref *) node)->aggfnoid);
    2109              :     }
    2110      7328289 :     else if (IsA(node, WindowFunc))
    2111              :     {
    2112         1998 :         record_plan_function_dependency(root,
    2113              :                                         ((WindowFunc *) node)->winfnoid);
    2114              :     }
    2115      7326291 :     else if (IsA(node, FuncExpr))
    2116              :     {
    2117       155642 :         record_plan_function_dependency(root,
    2118              :                                         ((FuncExpr *) node)->funcid);
    2119              :     }
    2120      7170649 :     else if (IsA(node, OpExpr))
    2121              :     {
    2122       445645 :         set_opfuncid((OpExpr *) node);
    2123       445645 :         record_plan_function_dependency(root,
    2124              :                                         ((OpExpr *) node)->opfuncid);
    2125              :     }
    2126      6725004 :     else if (IsA(node, DistinctExpr))
    2127              :     {
    2128          552 :         set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
    2129          552 :         record_plan_function_dependency(root,
    2130              :                                         ((DistinctExpr *) node)->opfuncid);
    2131              :     }
    2132      6724452 :     else if (IsA(node, NullIfExpr))
    2133              :     {
    2134           65 :         set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
    2135           65 :         record_plan_function_dependency(root,
    2136              :                                         ((NullIfExpr *) node)->opfuncid);
    2137              :     }
    2138      6724387 :     else if (IsA(node, ScalarArrayOpExpr))
    2139              :     {
    2140        19634 :         ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) node;
    2141              : 
    2142        19634 :         set_sa_opfuncid(saop);
    2143        19634 :         record_plan_function_dependency(root, saop->opfuncid);
    2144              : 
    2145        19634 :         if (OidIsValid(saop->hashfuncid))
    2146          325 :             record_plan_function_dependency(root, saop->hashfuncid);
    2147              : 
    2148        19634 :         if (OidIsValid(saop->negfuncid))
    2149           35 :             record_plan_function_dependency(root, saop->negfuncid);
    2150              :     }
    2151      6704753 :     else if (IsA(node, Const))
    2152              :     {
    2153       734401 :         Const      *con = (Const *) node;
    2154              : 
    2155              :         /* Check for regclass reference */
    2156       734401 :         if (ISREGCLASSCONST(con))
    2157       133716 :             root->glob->relationOids =
    2158       133716 :                 lappend_oid(root->glob->relationOids,
    2159              :                             DatumGetObjectId(con->constvalue));
    2160              :     }
    2161      5970352 :     else if (IsA(node, GroupingFunc))
    2162              :     {
    2163          179 :         GroupingFunc *g = (GroupingFunc *) node;
    2164          179 :         AttrNumber *grouping_map = root->grouping_map;
    2165              : 
    2166              :         /* If there are no grouping sets, we don't need this. */
    2167              : 
    2168              :         Assert(grouping_map || g->cols == NIL);
    2169              : 
    2170          179 :         if (grouping_map)
    2171              :         {
    2172              :             ListCell   *lc;
    2173          130 :             List       *cols = NIL;
    2174              : 
    2175          342 :             foreach(lc, g->refs)
    2176              :             {
    2177          212 :                 cols = lappend_int(cols, grouping_map[lfirst_int(lc)]);
    2178              :             }
    2179              : 
    2180              :             Assert(!g->cols || equal(cols, g->cols));
    2181              : 
    2182          130 :             if (!g->cols)
    2183          130 :                 g->cols = cols;
    2184              :         }
    2185              :     }
    2186      7360081 : }
    2187              : 
    2188              : /*
    2189              :  * fix_param_node
    2190              :  *      Do set_plan_references processing on a Param
    2191              :  *
    2192              :  * If it's a PARAM_MULTIEXPR, replace it with the appropriate Param from
    2193              :  * root->multiexpr_params; otherwise no change is needed.
    2194              :  * Just for paranoia's sake, we make a copy of the node in either case.
    2195              :  */
    2196              : static Node *
    2197        55752 : fix_param_node(PlannerInfo *root, Param *p)
    2198              : {
    2199        55752 :     if (p->paramkind == PARAM_MULTIEXPR)
    2200              :     {
    2201          143 :         int         subqueryid = p->paramid >> 16;
    2202          143 :         int         colno = p->paramid & 0xFFFF;
    2203              :         List       *params;
    2204              : 
    2205          286 :         if (subqueryid <= 0 ||
    2206          143 :             subqueryid > list_length(root->multiexpr_params))
    2207            0 :             elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
    2208          143 :         params = (List *) list_nth(root->multiexpr_params, subqueryid - 1);
    2209          143 :         if (colno <= 0 || colno > list_length(params))
    2210            0 :             elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
    2211          143 :         return copyObject(list_nth(params, colno - 1));
    2212              :     }
    2213        55609 :     return (Node *) copyObject(p);
    2214              : }
    2215              : 
    2216              : /*
    2217              :  * fix_alternative_subplan
    2218              :  *      Do set_plan_references processing on an AlternativeSubPlan
    2219              :  *
    2220              :  * Choose one of the alternative implementations and return just that one,
    2221              :  * discarding the rest of the AlternativeSubPlan structure.
    2222              :  * Note: caller must still recurse into the result!
    2223              :  *
    2224              :  * We don't make any attempt to fix up cost estimates in the parent plan
    2225              :  * node or higher-level nodes.
    2226              :  */
    2227              : static Node *
    2228          918 : fix_alternative_subplan(PlannerInfo *root, AlternativeSubPlan *asplan,
    2229              :                         double num_exec)
    2230              : {
    2231          918 :     SubPlan    *bestplan = NULL;
    2232          918 :     Cost        bestcost = 0;
    2233              :     ListCell   *lc;
    2234              : 
    2235              :     /*
    2236              :      * Compute the estimated cost of each subplan assuming num_exec
    2237              :      * executions, and keep the cheapest one.  In event of exact equality of
    2238              :      * estimates, we prefer the later plan; this is a bit arbitrary, but in
    2239              :      * current usage it biases us to break ties against fast-start subplans.
    2240              :      */
    2241              :     Assert(asplan->subplans != NIL);
    2242              : 
    2243         2754 :     foreach(lc, asplan->subplans)
    2244              :     {
    2245         1836 :         SubPlan    *curplan = (SubPlan *) lfirst(lc);
    2246              :         Cost        curcost;
    2247              : 
    2248         1836 :         curcost = curplan->startup_cost + num_exec * curplan->per_call_cost;
    2249         1836 :         if (bestplan == NULL || curcost <= bestcost)
    2250              :         {
    2251         1293 :             bestplan = curplan;
    2252         1293 :             bestcost = curcost;
    2253              :         }
    2254              : 
    2255              :         /* Also mark all subplans that are in AlternativeSubPlans */
    2256         1836 :         root->isAltSubplan[curplan->plan_id - 1] = true;
    2257              :     }
    2258              : 
    2259              :     /* Mark the subplan we selected */
    2260          918 :     root->isUsedSubplan[bestplan->plan_id - 1] = true;
    2261              : 
    2262          918 :     return (Node *) bestplan;
    2263              : }
    2264              : 
    2265              : /*
    2266              :  * fix_scan_expr
    2267              :  *      Do set_plan_references processing on a scan-level expression
    2268              :  *
    2269              :  * This consists of incrementing all Vars' varnos by rtoffset,
    2270              :  * replacing PARAM_MULTIEXPR Params, expanding PlaceHolderVars,
    2271              :  * replacing Aggref nodes that should be replaced by initplan output Params,
    2272              :  * choosing the best implementation for AlternativeSubPlans,
    2273              :  * looking up operator opcode info for OpExpr and related nodes,
    2274              :  * and adding OIDs from regclass Const nodes into root->glob->relationOids.
    2275              :  *
    2276              :  * 'node': the expression to be modified
    2277              :  * 'rtoffset': how much to increment varnos by
    2278              :  * 'num_exec': estimated number of executions of expression
    2279              :  *
    2280              :  * The expression tree is either copied-and-modified, or modified in-place
    2281              :  * if that seems safe.
    2282              :  */
    2283              : static Node *
    2284      1256034 : fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset, double num_exec)
    2285              : {
    2286              :     fix_scan_expr_context context;
    2287              : 
    2288      1256034 :     context.root = root;
    2289      1256034 :     context.rtoffset = rtoffset;
    2290      1256034 :     context.num_exec = num_exec;
    2291              : 
    2292      1256034 :     if (rtoffset != 0 ||
    2293      1036038 :         root->multiexpr_params != NIL ||
    2294      1035747 :         root->glob->lastPHId != 0 ||
    2295      1030173 :         root->minmax_aggs != NIL ||
    2296      1029768 :         root->hasAlternativeSubPlans)
    2297              :     {
    2298       232972 :         return fix_scan_expr_mutator(node, &context);
    2299              :     }
    2300              :     else
    2301              :     {
    2302              :         /*
    2303              :          * If rtoffset == 0, we don't need to change any Vars, and if there
    2304              :          * are no MULTIEXPR subqueries then we don't need to replace
    2305              :          * PARAM_MULTIEXPR Params, and if there are no placeholders anywhere
    2306              :          * we won't need to remove them, and if there are no minmax Aggrefs we
    2307              :          * won't need to replace them, and if there are no AlternativeSubPlans
    2308              :          * we won't need to remove them.  Then it's OK to just scribble on the
    2309              :          * input node tree instead of copying (since the only change, filling
    2310              :          * in any unset opfuncid fields, is harmless).  This saves just enough
    2311              :          * cycles to be noticeable on trivial queries.
    2312              :          */
    2313      1023062 :         (void) fix_scan_expr_walker(node, &context);
    2314      1023062 :         return node;
    2315              :     }
    2316              : }
    2317              : 
    2318              : static Node *
    2319      1450083 : fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
    2320              : {
    2321      1450083 :     if (node == NULL)
    2322        88823 :         return NULL;
    2323      1361260 :     if (IsA(node, Var))
    2324              :     {
    2325       468632 :         Var        *var = copyVar((Var *) node);
    2326              : 
    2327              :         Assert(var->varlevelsup == 0);
    2328              : 
    2329              :         /*
    2330              :          * We should not see Vars marked INNER_VAR, OUTER_VAR, or ROWID_VAR.
    2331              :          * But an indexqual expression could contain INDEX_VAR Vars.
    2332              :          */
    2333              :         Assert(var->varno != INNER_VAR);
    2334              :         Assert(var->varno != OUTER_VAR);
    2335              :         Assert(var->varno != ROWID_VAR);
    2336       468632 :         if (!IS_SPECIAL_VARNO(var->varno))
    2337       441239 :             var->varno += context->rtoffset;
    2338       468632 :         if (var->varnosyn > 0)
    2339       468158 :             var->varnosyn += context->rtoffset;
    2340       468632 :         return (Node *) var;
    2341              :     }
    2342       892628 :     if (IsA(node, Param))
    2343        47916 :         return fix_param_node(context->root, (Param *) node);
    2344       844712 :     if (IsA(node, Aggref))
    2345              :     {
    2346          227 :         Aggref     *aggref = (Aggref *) node;
    2347              :         Param      *aggparam;
    2348              : 
    2349              :         /* See if the Aggref should be replaced by a Param */
    2350          227 :         aggparam = find_minmax_agg_replacement_param(context->root, aggref);
    2351          227 :         if (aggparam != NULL)
    2352              :         {
    2353              :             /* Make a copy of the Param for paranoia's sake */
    2354          212 :             return (Node *) copyObject(aggparam);
    2355              :         }
    2356              :         /* If no match, just fall through to process it normally */
    2357              :     }
    2358       844500 :     if (IsA(node, CurrentOfExpr))
    2359              :     {
    2360            0 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
    2361              : 
    2362              :         Assert(!IS_SPECIAL_VARNO(cexpr->cvarno));
    2363            0 :         cexpr->cvarno += context->rtoffset;
    2364            0 :         return (Node *) cexpr;
    2365              :     }
    2366       844500 :     if (IsA(node, PlaceHolderVar))
    2367              :     {
    2368              :         /* At scan level, we should always just evaluate the contained expr */
    2369         1337 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
    2370              : 
    2371              :         /* XXX can we assert something about phnullingrels? */
    2372         1337 :         return fix_scan_expr_mutator((Node *) phv->phexpr, context);
    2373              :     }
    2374       843163 :     if (IsA(node, AlternativeSubPlan))
    2375          147 :         return fix_scan_expr_mutator(fix_alternative_subplan(context->root,
    2376              :                                                              (AlternativeSubPlan *) node,
    2377              :                                                              context->num_exec),
    2378              :                                      context);
    2379       843016 :     fix_expr_common(context->root, node);
    2380       843016 :     return expression_tree_mutator(node, fix_scan_expr_mutator, context);
    2381              : }
    2382              : 
    2383              : static bool
    2384      5492560 : fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
    2385              : {
    2386      5492560 :     if (node == NULL)
    2387       521622 :         return false;
    2388              :     Assert(!(IsA(node, Var) && ((Var *) node)->varno == ROWID_VAR));
    2389              :     Assert(!IsA(node, PlaceHolderVar));
    2390              :     Assert(!IsA(node, AlternativeSubPlan));
    2391      4970938 :     fix_expr_common(context->root, node);
    2392      4970938 :     return expression_tree_walker(node, fix_scan_expr_walker, context);
    2393              : }
    2394              : 
    2395              : /*
    2396              :  * set_join_references
    2397              :  *    Modify the target list and quals of a join node to reference its
    2398              :  *    subplans, by setting the varnos to OUTER_VAR or INNER_VAR and setting
    2399              :  *    attno values to the result domain number of either the corresponding
    2400              :  *    outer or inner join tuple item.  Also perform opcode lookup for these
    2401              :  *    expressions, and add regclass OIDs to root->glob->relationOids.
    2402              :  */
    2403              : static void
    2404        72378 : set_join_references(PlannerInfo *root, Join *join, int rtoffset)
    2405              : {
    2406        72378 :     Plan       *outer_plan = join->plan.lefttree;
    2407        72378 :     Plan       *inner_plan = join->plan.righttree;
    2408              :     indexed_tlist *outer_itlist;
    2409              :     indexed_tlist *inner_itlist;
    2410              : 
    2411        72378 :     outer_itlist = build_tlist_index(outer_plan->targetlist);
    2412        72378 :     inner_itlist = build_tlist_index(inner_plan->targetlist);
    2413              : 
    2414              :     /*
    2415              :      * First process the joinquals (including merge or hash clauses).  These
    2416              :      * are logically below the join so they can always use all values
    2417              :      * available from the input tlists.  It's okay to also handle
    2418              :      * NestLoopParams now, because those couldn't refer to nullable
    2419              :      * subexpressions.
    2420              :      */
    2421       144756 :     join->joinqual = fix_join_expr(root,
    2422              :                                    join->joinqual,
    2423              :                                    outer_itlist,
    2424              :                                    inner_itlist,
    2425              :                                    (Index) 0,
    2426              :                                    rtoffset,
    2427              :                                    NRM_EQUAL,
    2428        72378 :                                    NUM_EXEC_QUAL((Plan *) join));
    2429              : 
    2430              :     /* Now do join-type-specific stuff */
    2431        72378 :     if (IsA(join, NestLoop))
    2432              :     {
    2433        50718 :         NestLoop   *nl = (NestLoop *) join;
    2434              :         ListCell   *lc;
    2435              : 
    2436        79673 :         foreach(lc, nl->nestParams)
    2437              :         {
    2438        28955 :             NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
    2439              : 
    2440              :             /*
    2441              :              * Because we don't reparameterize parameterized paths to match
    2442              :              * the outer-join level at which they are used, Vars seen in the
    2443              :              * NestLoopParam expression may have nullingrels that are just a
    2444              :              * subset of those in the Vars actually available from the outer
    2445              :              * side.  (Lateral references can also cause this, as explained in
    2446              :              * the comments for identify_current_nestloop_params.)  Not
    2447              :              * checking this exactly is a bit grotty, but the work needed to
    2448              :              * make things match up perfectly seems well out of proportion to
    2449              :              * the value.
    2450              :              */
    2451        57910 :             nlp->paramval = (Var *) fix_upper_expr(root,
    2452        28955 :                                                    (Node *) nlp->paramval,
    2453              :                                                    outer_itlist,
    2454              :                                                    OUTER_VAR,
    2455              :                                                    rtoffset,
    2456              :                                                    NRM_SUBSET,
    2457              :                                                    NUM_EXEC_TLIST(outer_plan));
    2458              :             /* Check we replaced any PlaceHolderVar with simple Var */
    2459        28955 :             if (!(IsA(nlp->paramval, Var) &&
    2460        28955 :                   nlp->paramval->varno == OUTER_VAR))
    2461            0 :                 elog(ERROR, "NestLoopParam was not reduced to a simple Var");
    2462              :         }
    2463              :     }
    2464        21660 :     else if (IsA(join, MergeJoin))
    2465              :     {
    2466         3856 :         MergeJoin  *mj = (MergeJoin *) join;
    2467              : 
    2468         3856 :         mj->mergeclauses = fix_join_expr(root,
    2469              :                                          mj->mergeclauses,
    2470              :                                          outer_itlist,
    2471              :                                          inner_itlist,
    2472              :                                          (Index) 0,
    2473              :                                          rtoffset,
    2474              :                                          NRM_EQUAL,
    2475         3856 :                                          NUM_EXEC_QUAL((Plan *) join));
    2476              :     }
    2477        17804 :     else if (IsA(join, HashJoin))
    2478              :     {
    2479        17804 :         HashJoin   *hj = (HashJoin *) join;
    2480              : 
    2481        35608 :         hj->hashclauses = fix_join_expr(root,
    2482              :                                         hj->hashclauses,
    2483              :                                         outer_itlist,
    2484              :                                         inner_itlist,
    2485              :                                         (Index) 0,
    2486              :                                         rtoffset,
    2487              :                                         NRM_EQUAL,
    2488        17804 :                                         NUM_EXEC_QUAL((Plan *) join));
    2489              : 
    2490              :         /*
    2491              :          * HashJoin's hashkeys are used to look for matching tuples from its
    2492              :          * outer plan (not the Hash node!) in the hashtable.
    2493              :          */
    2494        17804 :         hj->hashkeys = (List *) fix_upper_expr(root,
    2495        17804 :                                                (Node *) hj->hashkeys,
    2496              :                                                outer_itlist,
    2497              :                                                OUTER_VAR,
    2498              :                                                rtoffset,
    2499              :                                                NRM_EQUAL,
    2500        17804 :                                                NUM_EXEC_QUAL((Plan *) join));
    2501              :     }
    2502              : 
    2503              :     /*
    2504              :      * Now we need to fix up the targetlist and qpqual, which are logically
    2505              :      * above the join.  This means that, if it's not an inner join, any Vars
    2506              :      * and PHVs appearing here should have nullingrels that include the
    2507              :      * effects of the outer join, ie they will have nullingrels equal to the
    2508              :      * input Vars' nullingrels plus the bit added by the outer join.  We don't
    2509              :      * currently have enough info available here to identify what that should
    2510              :      * be, so we just tell fix_join_expr to accept superset nullingrels
    2511              :      * matches instead of exact ones.
    2512              :      */
    2513        72378 :     join->plan.targetlist = fix_join_expr(root,
    2514              :                                           join->plan.targetlist,
    2515              :                                           outer_itlist,
    2516              :                                           inner_itlist,
    2517              :                                           (Index) 0,
    2518              :                                           rtoffset,
    2519        72378 :                                           (join->jointype == JOIN_INNER ? NRM_EQUAL : NRM_SUPERSET),
    2520              :                                           NUM_EXEC_TLIST((Plan *) join));
    2521        72378 :     join->plan.qual = fix_join_expr(root,
    2522              :                                     join->plan.qual,
    2523              :                                     outer_itlist,
    2524              :                                     inner_itlist,
    2525              :                                     (Index) 0,
    2526              :                                     rtoffset,
    2527        72378 :                                     (join->jointype == JOIN_INNER ? NRM_EQUAL : NRM_SUPERSET),
    2528        72378 :                                     NUM_EXEC_QUAL((Plan *) join));
    2529              : 
    2530        72378 :     pfree(outer_itlist);
    2531        72378 :     pfree(inner_itlist);
    2532        72378 : }
    2533              : 
    2534              : /*
    2535              :  * set_upper_references
    2536              :  *    Update the targetlist and quals of an upper-level plan node
    2537              :  *    to refer to the tuples returned by its lefttree subplan.
    2538              :  *    Also perform opcode lookup for these expressions, and
    2539              :  *    add regclass OIDs to root->glob->relationOids.
    2540              :  *
    2541              :  * This is used for single-input plan types like Agg, Group, Result.
    2542              :  *
    2543              :  * In most cases, we have to match up individual Vars in the tlist and
    2544              :  * qual expressions with elements of the subplan's tlist (which was
    2545              :  * generated by flattening these selfsame expressions, so it should have all
    2546              :  * the required variables).  There is an important exception, however:
    2547              :  * depending on where we are in the plan tree, sort/group columns may have
    2548              :  * been pushed into the subplan tlist unflattened.  If these values are also
    2549              :  * needed in the output then we want to reference the subplan tlist element
    2550              :  * rather than recomputing the expression.
    2551              :  */
    2552              : static void
    2553        39195 : set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
    2554              : {
    2555        39195 :     Plan       *subplan = plan->lefttree;
    2556              :     indexed_tlist *subplan_itlist;
    2557              :     List       *output_targetlist;
    2558              :     ListCell   *l;
    2559              : 
    2560        39195 :     subplan_itlist = build_tlist_index(subplan->targetlist);
    2561              : 
    2562              :     /*
    2563              :      * If it's a grouping node with grouping sets, any Vars and PHVs appearing
    2564              :      * in the targetlist and quals should have nullingrels that include the
    2565              :      * effects of the grouping step, ie they will have nullingrels equal to
    2566              :      * the input Vars/PHVs' nullingrels plus the RT index of the grouping
    2567              :      * step.  In order to perform exact nullingrels matches, we remove the RT
    2568              :      * index of the grouping step first.
    2569              :      */
    2570        39195 :     if (IsA(plan, Agg) &&
    2571        24812 :         root->group_rtindex > 0 &&
    2572         3436 :         ((Agg *) plan)->groupingSets)
    2573              :     {
    2574          465 :         plan->targetlist = (List *)
    2575          465 :             remove_nulling_relids((Node *) plan->targetlist,
    2576          465 :                                   bms_make_singleton(root->group_rtindex),
    2577              :                                   NULL);
    2578          465 :         plan->qual = (List *)
    2579          465 :             remove_nulling_relids((Node *) plan->qual,
    2580          465 :                                   bms_make_singleton(root->group_rtindex),
    2581              :                                   NULL);
    2582              :     }
    2583              : 
    2584        39195 :     output_targetlist = NIL;
    2585       105592 :     foreach(l, plan->targetlist)
    2586              :     {
    2587        66397 :         TargetEntry *tle = (TargetEntry *) lfirst(l);
    2588              :         Node       *newexpr;
    2589              : 
    2590              :         /* If it's a sort/group item, first try to match by sortref */
    2591        66397 :         if (tle->ressortgroupref != 0)
    2592              :         {
    2593              :             newexpr = (Node *)
    2594        20087 :                 search_indexed_tlist_for_sortgroupref(tle->expr,
    2595              :                                                       tle->ressortgroupref,
    2596              :                                                       subplan_itlist,
    2597              :                                                       OUTER_VAR);
    2598        20087 :             if (!newexpr)
    2599        11169 :                 newexpr = fix_upper_expr(root,
    2600        11169 :                                          (Node *) tle->expr,
    2601              :                                          subplan_itlist,
    2602              :                                          OUTER_VAR,
    2603              :                                          rtoffset,
    2604              :                                          NRM_EQUAL,
    2605              :                                          NUM_EXEC_TLIST(plan));
    2606              :         }
    2607              :         else
    2608        46310 :             newexpr = fix_upper_expr(root,
    2609        46310 :                                      (Node *) tle->expr,
    2610              :                                      subplan_itlist,
    2611              :                                      OUTER_VAR,
    2612              :                                      rtoffset,
    2613              :                                      NRM_EQUAL,
    2614              :                                      NUM_EXEC_TLIST(plan));
    2615        66397 :         tle = flatCopyTargetEntry(tle);
    2616        66397 :         tle->expr = (Expr *) newexpr;
    2617        66397 :         output_targetlist = lappend(output_targetlist, tle);
    2618              :     }
    2619        39195 :     plan->targetlist = output_targetlist;
    2620              : 
    2621        39195 :     plan->qual = (List *)
    2622        39195 :         fix_upper_expr(root,
    2623        39195 :                        (Node *) plan->qual,
    2624              :                        subplan_itlist,
    2625              :                        OUTER_VAR,
    2626              :                        rtoffset,
    2627              :                        NRM_EQUAL,
    2628        39195 :                        NUM_EXEC_QUAL(plan));
    2629              : 
    2630        39195 :     pfree(subplan_itlist);
    2631        39195 : }
    2632              : 
    2633              : /*
    2634              :  * set_param_references
    2635              :  *    Initialize the initParam list in Gather or Gather merge node such that
    2636              :  *    it contains reference of all the params that needs to be evaluated
    2637              :  *    before execution of the node.  It contains the initplan params that are
    2638              :  *    being passed to the plan nodes below it.
    2639              :  */
    2640              : static void
    2641          753 : set_param_references(PlannerInfo *root, Plan *plan)
    2642              : {
    2643              :     Assert(IsA(plan, Gather) || IsA(plan, GatherMerge));
    2644              : 
    2645          753 :     if (plan->lefttree->extParam)
    2646              :     {
    2647              :         PlannerInfo *proot;
    2648          689 :         Bitmapset  *initSetParam = NULL;
    2649              :         ListCell   *l;
    2650              : 
    2651         1468 :         for (proot = root; proot != NULL; proot = proot->parent_root)
    2652              :         {
    2653          818 :             foreach(l, proot->init_plans)
    2654              :             {
    2655           39 :                 SubPlan    *initsubplan = (SubPlan *) lfirst(l);
    2656              :                 ListCell   *l2;
    2657              : 
    2658           78 :                 foreach(l2, initsubplan->setParam)
    2659              :                 {
    2660           39 :                     initSetParam = bms_add_member(initSetParam, lfirst_int(l2));
    2661              :                 }
    2662              :             }
    2663              :         }
    2664              : 
    2665              :         /*
    2666              :          * Remember the list of all external initplan params that are used by
    2667              :          * the children of Gather or Gather merge node.
    2668              :          */
    2669          689 :         if (IsA(plan, Gather))
    2670          509 :             ((Gather *) plan)->initParam =
    2671          509 :                 bms_intersect(plan->lefttree->extParam, initSetParam);
    2672              :         else
    2673          180 :             ((GatherMerge *) plan)->initParam =
    2674          180 :                 bms_intersect(plan->lefttree->extParam, initSetParam);
    2675              :     }
    2676          753 : }
    2677              : 
    2678              : /*
    2679              :  * Recursively scan an expression tree and convert Aggrefs to the proper
    2680              :  * intermediate form for combining aggregates.  This means (1) replacing each
    2681              :  * one's argument list with a single argument that is the original Aggref
    2682              :  * modified to show partial aggregation and (2) changing the upper Aggref to
    2683              :  * show combining aggregation.
    2684              :  *
    2685              :  * After this step, set_upper_references will replace the partial Aggrefs
    2686              :  * with Vars referencing the lower Agg plan node's outputs, so that the final
    2687              :  * form seen by the executor is a combining Aggref with a Var as input.
    2688              :  *
    2689              :  * It's rather messy to postpone this step until setrefs.c; ideally it'd be
    2690              :  * done in createplan.c.  The difficulty is that once we modify the Aggref
    2691              :  * expressions, they will no longer be equal() to their original form and
    2692              :  * so cross-plan-node-level matches will fail.  So this has to happen after
    2693              :  * the plan node above the Agg has resolved its subplan references.
    2694              :  */
    2695              : static Node *
    2696         5103 : convert_combining_aggrefs(Node *node, void *context)
    2697              : {
    2698         5103 :     if (node == NULL)
    2699          609 :         return NULL;
    2700         4494 :     if (IsA(node, Aggref))
    2701              :     {
    2702         1153 :         Aggref     *orig_agg = (Aggref *) node;
    2703              :         Aggref     *child_agg;
    2704              :         Aggref     *parent_agg;
    2705              : 
    2706              :         /* Assert we've not chosen to partial-ize any unsupported cases */
    2707              :         Assert(orig_agg->aggorder == NIL);
    2708              :         Assert(orig_agg->aggdistinct == NIL);
    2709              : 
    2710              :         /*
    2711              :          * Since aggregate calls can't be nested, we needn't recurse into the
    2712              :          * arguments.  But for safety, flat-copy the Aggref node itself rather
    2713              :          * than modifying it in-place.
    2714              :          */
    2715         1153 :         child_agg = makeNode(Aggref);
    2716         1153 :         memcpy(child_agg, orig_agg, sizeof(Aggref));
    2717              : 
    2718              :         /*
    2719              :          * For the parent Aggref, we want to copy all the fields of the
    2720              :          * original aggregate *except* the args list, which we'll replace
    2721              :          * below, and the aggfilter expression, which should be applied only
    2722              :          * by the child not the parent.  Rather than explicitly knowing about
    2723              :          * all the other fields here, we can momentarily modify child_agg to
    2724              :          * provide a suitable source for copyObject.
    2725              :          */
    2726         1153 :         child_agg->args = NIL;
    2727         1153 :         child_agg->aggfilter = NULL;
    2728         1153 :         parent_agg = copyObject(child_agg);
    2729         1153 :         child_agg->args = orig_agg->args;
    2730         1153 :         child_agg->aggfilter = orig_agg->aggfilter;
    2731              : 
    2732              :         /*
    2733              :          * Now, set up child_agg to represent the first phase of partial
    2734              :          * aggregation.  For now, assume serialization is required.
    2735              :          */
    2736         1153 :         mark_partial_aggref(child_agg, AGGSPLIT_INITIAL_SERIAL);
    2737              : 
    2738              :         /*
    2739              :          * And set up parent_agg to represent the second phase.
    2740              :          */
    2741         1153 :         parent_agg->args = list_make1(makeTargetEntry((Expr *) child_agg,
    2742              :                                                       1, NULL, false));
    2743         1153 :         mark_partial_aggref(parent_agg, AGGSPLIT_FINAL_DESERIAL);
    2744              : 
    2745         1153 :         return (Node *) parent_agg;
    2746              :     }
    2747         3341 :     return expression_tree_mutator(node, convert_combining_aggrefs, context);
    2748              : }
    2749              : 
    2750              : /*
    2751              :  * set_dummy_tlist_references
    2752              :  *    Replace the targetlist of an upper-level plan node with a simple
    2753              :  *    list of OUTER_VAR references to its child.
    2754              :  *
    2755              :  * This is used for plan types like Sort and Append that don't evaluate
    2756              :  * their targetlists.  Although the executor doesn't care at all what's in
    2757              :  * the tlist, EXPLAIN needs it to be realistic.
    2758              :  *
    2759              :  * Note: we could almost use set_upper_references() here, but it fails for
    2760              :  * Append for lack of a lefttree subplan.  Single-purpose code is faster
    2761              :  * anyway.
    2762              :  */
    2763              : static void
    2764        84525 : set_dummy_tlist_references(Plan *plan, int rtoffset)
    2765              : {
    2766              :     List       *output_targetlist;
    2767              :     ListCell   *l;
    2768              : 
    2769        84525 :     output_targetlist = NIL;
    2770       374804 :     foreach(l, plan->targetlist)
    2771              :     {
    2772       290279 :         TargetEntry *tle = (TargetEntry *) lfirst(l);
    2773       290279 :         Var        *oldvar = (Var *) tle->expr;
    2774              :         Var        *newvar;
    2775              : 
    2776              :         /*
    2777              :          * As in search_indexed_tlist_for_non_var(), we prefer to keep Consts
    2778              :          * as Consts, not Vars referencing Consts.  Here, there's no speed
    2779              :          * advantage to be had, but it makes EXPLAIN output look cleaner, and
    2780              :          * again it avoids confusing the executor.
    2781              :          */
    2782       290279 :         if (IsA(oldvar, Const))
    2783              :         {
    2784              :             /* just reuse the existing TLE node */
    2785        11201 :             output_targetlist = lappend(output_targetlist, tle);
    2786        11201 :             continue;
    2787              :         }
    2788              : 
    2789       279078 :         newvar = makeVar(OUTER_VAR,
    2790       279078 :                          tle->resno,
    2791              :                          exprType((Node *) oldvar),
    2792              :                          exprTypmod((Node *) oldvar),
    2793              :                          exprCollation((Node *) oldvar),
    2794              :                          0);
    2795       279078 :         if (IsA(oldvar, Var) &&
    2796       221668 :             oldvar->varnosyn > 0)
    2797              :         {
    2798       201269 :             newvar->varnosyn = oldvar->varnosyn + rtoffset;
    2799       201269 :             newvar->varattnosyn = oldvar->varattnosyn;
    2800              :         }
    2801              :         else
    2802              :         {
    2803        77809 :             newvar->varnosyn = 0;    /* wasn't ever a plain Var */
    2804        77809 :             newvar->varattnosyn = 0;
    2805              :         }
    2806              : 
    2807       279078 :         tle = flatCopyTargetEntry(tle);
    2808       279078 :         tle->expr = (Expr *) newvar;
    2809       279078 :         output_targetlist = lappend(output_targetlist, tle);
    2810              :     }
    2811        84525 :     plan->targetlist = output_targetlist;
    2812              : 
    2813              :     /* We don't touch plan->qual here */
    2814        84525 : }
    2815              : 
    2816              : 
    2817              : /*
    2818              :  * build_tlist_index --- build an index data structure for a child tlist
    2819              :  *
    2820              :  * In most cases, subplan tlists will be "flat" tlists with only Vars,
    2821              :  * so we try to optimize that case by extracting information about Vars
    2822              :  * in advance.  Matching a parent tlist to a child is still an O(N^2)
    2823              :  * operation, but at least with a much smaller constant factor than plain
    2824              :  * tlist_member() searches.
    2825              :  *
    2826              :  * The result of this function is an indexed_tlist struct to pass to
    2827              :  * search_indexed_tlist_for_var() and siblings.
    2828              :  * When done, the indexed_tlist may be freed with a single pfree().
    2829              :  */
    2830              : static indexed_tlist *
    2831       214361 : build_tlist_index(List *tlist)
    2832              : {
    2833              :     indexed_tlist *itlist;
    2834              :     tlist_vinfo *vinfo;
    2835              :     ListCell   *l;
    2836              : 
    2837              :     /* Create data structure with enough slots for all tlist entries */
    2838              :     itlist = (indexed_tlist *)
    2839       214361 :         palloc(offsetof(indexed_tlist, vars) +
    2840       214361 :                list_length(tlist) * sizeof(tlist_vinfo));
    2841              : 
    2842       214361 :     itlist->tlist = tlist;
    2843       214361 :     itlist->has_ph_vars = false;
    2844       214361 :     itlist->has_non_vars = false;
    2845              : 
    2846              :     /* Find the Vars and fill in the index array */
    2847       214361 :     vinfo = itlist->vars;
    2848      2003342 :     foreach(l, tlist)
    2849              :     {
    2850      1788981 :         TargetEntry *tle = (TargetEntry *) lfirst(l);
    2851              : 
    2852      1788981 :         if (tle->expr && IsA(tle->expr, Var))
    2853      1778789 :         {
    2854      1778789 :             Var        *var = (Var *) tle->expr;
    2855              : 
    2856      1778789 :             vinfo->varno = var->varno;
    2857      1778789 :             vinfo->varattno = var->varattno;
    2858      1778789 :             vinfo->resno = tle->resno;
    2859      1778789 :             vinfo->varnullingrels = var->varnullingrels;
    2860      1778789 :             vinfo++;
    2861              :         }
    2862        10192 :         else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
    2863         1771 :             itlist->has_ph_vars = true;
    2864              :         else
    2865         8421 :             itlist->has_non_vars = true;
    2866              :     }
    2867              : 
    2868       214361 :     itlist->num_vars = (vinfo - itlist->vars);
    2869              : 
    2870       214361 :     return itlist;
    2871              : }
    2872              : 
    2873              : /*
    2874              :  * build_tlist_index_other_vars --- build a restricted tlist index
    2875              :  *
    2876              :  * This is like build_tlist_index, but we only index tlist entries that
    2877              :  * are Vars belonging to some rel other than the one specified.  We will set
    2878              :  * has_ph_vars (allowing PlaceHolderVars to be matched), but not has_non_vars
    2879              :  * (so nothing other than Vars and PlaceHolderVars can be matched).
    2880              :  */
    2881              : static indexed_tlist *
    2882         1896 : build_tlist_index_other_vars(List *tlist, int ignore_rel)
    2883              : {
    2884              :     indexed_tlist *itlist;
    2885              :     tlist_vinfo *vinfo;
    2886              :     ListCell   *l;
    2887              : 
    2888              :     /* Create data structure with enough slots for all tlist entries */
    2889              :     itlist = (indexed_tlist *)
    2890         1896 :         palloc(offsetof(indexed_tlist, vars) +
    2891         1896 :                list_length(tlist) * sizeof(tlist_vinfo));
    2892              : 
    2893         1896 :     itlist->tlist = tlist;
    2894         1896 :     itlist->has_ph_vars = false;
    2895         1896 :     itlist->has_non_vars = false;
    2896              : 
    2897              :     /* Find the desired Vars and fill in the index array */
    2898         1896 :     vinfo = itlist->vars;
    2899         7246 :     foreach(l, tlist)
    2900              :     {
    2901         5350 :         TargetEntry *tle = (TargetEntry *) lfirst(l);
    2902              : 
    2903         5350 :         if (tle->expr && IsA(tle->expr, Var))
    2904         2824 :         {
    2905         2824 :             Var        *var = (Var *) tle->expr;
    2906              : 
    2907         2824 :             if (var->varno != ignore_rel)
    2908              :             {
    2909         2153 :                 vinfo->varno = var->varno;
    2910         2153 :                 vinfo->varattno = var->varattno;
    2911         2153 :                 vinfo->resno = tle->resno;
    2912         2153 :                 vinfo->varnullingrels = var->varnullingrels;
    2913         2153 :                 vinfo++;
    2914              :             }
    2915              :         }
    2916         2526 :         else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
    2917           60 :             itlist->has_ph_vars = true;
    2918              :     }
    2919              : 
    2920         1896 :     itlist->num_vars = (vinfo - itlist->vars);
    2921              : 
    2922         1896 :     return itlist;
    2923              : }
    2924              : 
    2925              : /*
    2926              :  * search_indexed_tlist_for_var --- find a Var in an indexed tlist
    2927              :  *
    2928              :  * If a match is found, return a copy of the given Var with suitably
    2929              :  * modified varno/varattno (to wit, newvarno and the resno of the TLE entry).
    2930              :  * Also ensure that varnosyn is incremented by rtoffset.
    2931              :  * If no match, return NULL.
    2932              :  *
    2933              :  * We cross-check the varnullingrels of the subplan output Var based on
    2934              :  * nrm_match.  Most call sites should pass NRM_EQUAL indicating we expect
    2935              :  * an exact match.  However, there are places where we haven't cleaned
    2936              :  * things up completely, and we have to settle for allowing subset or
    2937              :  * superset matches.
    2938              :  */
    2939              : static Var *
    2940       803173 : search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist,
    2941              :                              int newvarno, int rtoffset,
    2942              :                              NullingRelsMatch nrm_match)
    2943              : {
    2944       803173 :     int         varno = var->varno;
    2945       803173 :     AttrNumber  varattno = var->varattno;
    2946              :     tlist_vinfo *vinfo;
    2947              :     int         i;
    2948              : 
    2949       803173 :     vinfo = itlist->vars;
    2950       803173 :     i = itlist->num_vars;
    2951      5735467 :     while (i-- > 0)
    2952              :     {
    2953      5551184 :         if (vinfo->varno == varno && vinfo->varattno == varattno)
    2954              :         {
    2955              :             /* Found a match */
    2956       618890 :             Var        *newvar = copyVar(var);
    2957              : 
    2958              :             /*
    2959              :              * Verify that we kept all the nullingrels machinations straight.
    2960              :              *
    2961              :              * XXX we skip the check for system columns and whole-row Vars.
    2962              :              * That's because such Vars might be row identity Vars, which are
    2963              :              * generated without any varnullingrels.  It'd be hard to do
    2964              :              * otherwise, since they're normally made very early in planning,
    2965              :              * when we haven't looked at the jointree yet and don't know which
    2966              :              * joins might null such Vars.  Doesn't seem worth the expense to
    2967              :              * make them fully valid.  (While it's slightly annoying that we
    2968              :              * thereby lose checking for user-written references to such
    2969              :              * columns, it seems unlikely that a bug in nullingrels logic
    2970              :              * would affect only system columns.)
    2971              :              */
    2972      1220642 :             if (!(varattno <= 0 ||
    2973              :                   (nrm_match == NRM_SUBSET ?
    2974        28519 :                    bms_is_subset(var->varnullingrels, vinfo->varnullingrels) :
    2975              :                    nrm_match == NRM_SUPERSET ?
    2976       184390 :                    bms_is_subset(vinfo->varnullingrels, var->varnullingrels) :
    2977       388843 :                    bms_equal(vinfo->varnullingrels, var->varnullingrels))))
    2978            0 :                 elog(ERROR, "wrong varnullingrels %s (expected %s) for Var %d/%d",
    2979              :                      bmsToString(var->varnullingrels),
    2980              :                      bmsToString(vinfo->varnullingrels),
    2981              :                      varno, varattno);
    2982              : 
    2983       618890 :             newvar->varno = newvarno;
    2984       618890 :             newvar->varattno = vinfo->resno;
    2985       618890 :             if (newvar->varnosyn > 0)
    2986       618587 :                 newvar->varnosyn += rtoffset;
    2987       618890 :             return newvar;
    2988              :         }
    2989      4932294 :         vinfo++;
    2990              :     }
    2991       184283 :     return NULL;                /* no match */
    2992              : }
    2993              : 
    2994              : /*
    2995              :  * search_indexed_tlist_for_phv --- find a PlaceHolderVar in an indexed tlist
    2996              :  *
    2997              :  * If a match is found, return a Var constructed to reference the tlist item.
    2998              :  * If no match, return NULL.
    2999              :  *
    3000              :  * Cross-check phnullingrels as in search_indexed_tlist_for_var.
    3001              :  *
    3002              :  * NOTE: it is a waste of time to call this unless itlist->has_ph_vars.
    3003              :  */
    3004              : static Var *
    3005         1749 : search_indexed_tlist_for_phv(PlaceHolderVar *phv,
    3006              :                              indexed_tlist *itlist, int newvarno,
    3007              :                              NullingRelsMatch nrm_match)
    3008              : {
    3009              :     ListCell   *lc;
    3010              : 
    3011         4309 :     foreach(lc, itlist->tlist)
    3012              :     {
    3013         4145 :         TargetEntry *tle = (TargetEntry *) lfirst(lc);
    3014              : 
    3015         4145 :         if (tle->expr && IsA(tle->expr, PlaceHolderVar))
    3016              :         {
    3017         2280 :             PlaceHolderVar *subphv = (PlaceHolderVar *) tle->expr;
    3018              :             Var        *newvar;
    3019              : 
    3020              :             /*
    3021              :              * Analogously to search_indexed_tlist_for_var, we match on phid
    3022              :              * only.  We don't use equal(), partially for speed but mostly
    3023              :              * because phnullingrels might not be exactly equal.
    3024              :              */
    3025         2280 :             if (phv->phid != subphv->phid)
    3026          695 :                 continue;
    3027              : 
    3028              :             /* Verify that we kept all the nullingrels machinations straight */
    3029         3170 :             if (!(nrm_match == NRM_SUBSET ?
    3030          126 :                   bms_is_subset(phv->phnullingrels, subphv->phnullingrels) :
    3031              :                   nrm_match == NRM_SUPERSET ?
    3032          774 :                   bms_is_subset(subphv->phnullingrels, phv->phnullingrels) :
    3033          685 :                   bms_equal(subphv->phnullingrels, phv->phnullingrels)))
    3034            0 :                 elog(ERROR, "wrong phnullingrels %s (expected %s) for PlaceHolderVar %d",
    3035              :                      bmsToString(phv->phnullingrels),
    3036              :                      bmsToString(subphv->phnullingrels),
    3037              :                      phv->phid);
    3038              : 
    3039              :             /* Found a matching subplan output expression */
    3040         1585 :             newvar = makeVarFromTargetEntry(newvarno, tle);
    3041         1585 :             newvar->varnosyn = 0;    /* wasn't ever a plain Var */
    3042         1585 :             newvar->varattnosyn = 0;
    3043         1585 :             return newvar;
    3044              :         }
    3045              :     }
    3046          164 :     return NULL;                /* no match */
    3047              : }
    3048              : 
    3049              : /*
    3050              :  * search_indexed_tlist_for_non_var --- find a non-Var/PHV in an indexed tlist
    3051              :  *
    3052              :  * If a match is found, return a Var constructed to reference the tlist item.
    3053              :  * If no match, return NULL.
    3054              :  *
    3055              :  * NOTE: it is a waste of time to call this unless itlist->has_non_vars.
    3056              :  */
    3057              : static Var *
    3058        19218 : search_indexed_tlist_for_non_var(Expr *node,
    3059              :                                  indexed_tlist *itlist, int newvarno)
    3060              : {
    3061              :     TargetEntry *tle;
    3062              : 
    3063              :     /*
    3064              :      * If it's a simple Const, replacing it with a Var is silly, even if there
    3065              :      * happens to be an identical Const below; a Var is more expensive to
    3066              :      * execute than a Const.  What's more, replacing it could confuse some
    3067              :      * places in the executor that expect to see simple Consts for, eg,
    3068              :      * dropped columns.
    3069              :      */
    3070        19218 :     if (IsA(node, Const))
    3071         1008 :         return NULL;
    3072              : 
    3073        18210 :     tle = tlist_member(node, itlist->tlist);
    3074        18210 :     if (tle)
    3075              :     {
    3076              :         /* Found a matching subplan output expression */
    3077              :         Var        *newvar;
    3078              : 
    3079         4696 :         newvar = makeVarFromTargetEntry(newvarno, tle);
    3080         4696 :         newvar->varnosyn = 0;    /* wasn't ever a plain Var */
    3081         4696 :         newvar->varattnosyn = 0;
    3082         4696 :         return newvar;
    3083              :     }
    3084        13514 :     return NULL;                /* no match */
    3085              : }
    3086              : 
    3087              : /*
    3088              :  * search_indexed_tlist_for_sortgroupref --- find a sort/group expression
    3089              :  *
    3090              :  * If a match is found, return a Var constructed to reference the tlist item.
    3091              :  * If no match, return NULL.
    3092              :  *
    3093              :  * This is needed to ensure that we select the right subplan TLE in cases
    3094              :  * where there are multiple textually-equal()-but-volatile sort expressions.
    3095              :  * And it's also faster than search_indexed_tlist_for_non_var.
    3096              :  */
    3097              : static Var *
    3098        20087 : search_indexed_tlist_for_sortgroupref(Expr *node,
    3099              :                                       Index sortgroupref,
    3100              :                                       indexed_tlist *itlist,
    3101              :                                       int newvarno)
    3102              : {
    3103              :     ListCell   *lc;
    3104              : 
    3105        90221 :     foreach(lc, itlist->tlist)
    3106              :     {
    3107        79052 :         TargetEntry *tle = (TargetEntry *) lfirst(lc);
    3108              : 
    3109              :         /*
    3110              :          * Usually the equal() check is redundant, but in setop plans it may
    3111              :          * not be, since prepunion.c assigns ressortgroupref equal to the
    3112              :          * column resno without regard to whether that matches the topmost
    3113              :          * level's sortgrouprefs and without regard to whether any implicit
    3114              :          * coercions are added in the setop tree.  We might have to clean that
    3115              :          * up someday; but for now, just ignore any false matches.
    3116              :          */
    3117        88036 :         if (tle->ressortgroupref == sortgroupref &&
    3118         8984 :             equal(node, tle->expr))
    3119              :         {
    3120              :             /* Found a matching subplan output expression */
    3121              :             Var        *newvar;
    3122              : 
    3123         8918 :             newvar = makeVarFromTargetEntry(newvarno, tle);
    3124         8918 :             newvar->varnosyn = 0;    /* wasn't ever a plain Var */
    3125         8918 :             newvar->varattnosyn = 0;
    3126         8918 :             return newvar;
    3127              :         }
    3128              :     }
    3129        11169 :     return NULL;                /* no match */
    3130              : }
    3131              : 
    3132              : /*
    3133              :  * fix_join_expr
    3134              :  *     Create a new set of targetlist entries or join qual clauses by
    3135              :  *     changing the varno/varattno values of variables in the clauses
    3136              :  *     to reference target list values from the outer and inner join
    3137              :  *     relation target lists.  Also perform opcode lookup and add
    3138              :  *     regclass OIDs to root->glob->relationOids.
    3139              :  *
    3140              :  * This is used in four different scenarios:
    3141              :  * 1) a normal join clause, where all the Vars in the clause *must* be
    3142              :  *    replaced by OUTER_VAR or INNER_VAR references.  In this case
    3143              :  *    acceptable_rel should be zero so that any failure to match a Var will be
    3144              :  *    reported as an error.
    3145              :  * 2) RETURNING clauses, which may contain both Vars of the target relation
    3146              :  *    and Vars of other relations. In this case we want to replace the
    3147              :  *    other-relation Vars by OUTER_VAR references, while leaving target Vars
    3148              :  *    alone. Thus inner_itlist = NULL and acceptable_rel = the ID of the
    3149              :  *    target relation should be passed.
    3150              :  * 3) ON CONFLICT SET and WHERE clauses.  Here references to EXCLUDED are
    3151              :  *    to be replaced with INNER_VAR references, while leaving target Vars (the
    3152              :  *    to-be-updated relation) alone. Correspondingly inner_itlist is to be
    3153              :  *    EXCLUDED elements, outer_itlist = NULL and acceptable_rel the target
    3154              :  *    relation.
    3155              :  * 4) MERGE.  In this case, references to the source relation are to be
    3156              :  *    replaced with INNER_VAR references, leaving Vars of the target
    3157              :  *    relation (the to-be-modified relation) alone.  So inner_itlist is to be
    3158              :  *    the source relation elements, outer_itlist = NULL and acceptable_rel
    3159              :  *    the target relation.
    3160              :  *
    3161              :  * 'clauses' is the targetlist or list of join clauses
    3162              :  * 'outer_itlist' is the indexed target list of the outer join relation,
    3163              :  *      or NULL
    3164              :  * 'inner_itlist' is the indexed target list of the inner join relation,
    3165              :  *      or NULL
    3166              :  * 'acceptable_rel' is either zero or the rangetable index of a relation
    3167              :  *      whose Vars may appear in the clause without provoking an error
    3168              :  * 'rtoffset': how much to increment varnos by
    3169              :  * 'nrm_match': as for search_indexed_tlist_for_var()
    3170              :  * 'num_exec': estimated number of executions of expression
    3171              :  *
    3172              :  * Returns the new expression tree.  The original clause structure is
    3173              :  * not modified.
    3174              :  */
    3175              : static List *
    3176       246745 : fix_join_expr(PlannerInfo *root,
    3177              :               List *clauses,
    3178              :               indexed_tlist *outer_itlist,
    3179              :               indexed_tlist *inner_itlist,
    3180              :               Index acceptable_rel,
    3181              :               int rtoffset,
    3182              :               NullingRelsMatch nrm_match,
    3183              :               double num_exec)
    3184              : {
    3185              :     fix_join_expr_context context;
    3186              : 
    3187       246745 :     context.root = root;
    3188       246745 :     context.outer_itlist = outer_itlist;
    3189       246745 :     context.inner_itlist = inner_itlist;
    3190       246745 :     context.acceptable_rel = acceptable_rel;
    3191       246745 :     context.rtoffset = rtoffset;
    3192       246745 :     context.nrm_match = nrm_match;
    3193       246745 :     context.num_exec = num_exec;
    3194       246745 :     return (List *) fix_join_expr_mutator((Node *) clauses, &context);
    3195              : }
    3196              : 
    3197              : static Node *
    3198      1553297 : fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
    3199              : {
    3200              :     Var        *newvar;
    3201              : 
    3202      1553297 :     if (node == NULL)
    3203       154155 :         return NULL;
    3204      1399142 :     if (IsA(node, Var))
    3205              :     {
    3206       506819 :         Var        *var = (Var *) node;
    3207              : 
    3208              :         /*
    3209              :          * Verify that Vars with non-default varreturningtype only appear in
    3210              :          * the RETURNING list, and refer to the target relation.
    3211              :          */
    3212       506819 :         if (var->varreturningtype != VAR_RETURNING_DEFAULT)
    3213              :         {
    3214         1401 :             if (context->inner_itlist != NULL ||
    3215         1401 :                 context->outer_itlist == NULL ||
    3216         1401 :                 context->acceptable_rel == 0)
    3217            0 :                 elog(ERROR, "variable returning old/new found outside RETURNING list");
    3218         1401 :             if (var->varno != context->acceptable_rel)
    3219            0 :                 elog(ERROR, "wrong varno %d (expected %d) for variable returning old/new",
    3220              :                      var->varno, context->acceptable_rel);
    3221              :         }
    3222              : 
    3223              :         /* Look for the var in the input tlists, first in the outer */
    3224       506819 :         if (context->outer_itlist)
    3225              :         {
    3226       503100 :             newvar = search_indexed_tlist_for_var(var,
    3227              :                                                   context->outer_itlist,
    3228              :                                                   OUTER_VAR,
    3229              :                                                   context->rtoffset,
    3230              :                                                   context->nrm_match);
    3231       503100 :             if (newvar)
    3232       320548 :                 return (Node *) newvar;
    3233              :         }
    3234              : 
    3235              :         /* then in the inner. */
    3236       186271 :         if (context->inner_itlist)
    3237              :         {
    3238       180417 :             newvar = search_indexed_tlist_for_var(var,
    3239              :                                                   context->inner_itlist,
    3240              :                                                   INNER_VAR,
    3241              :                                                   context->rtoffset,
    3242              :                                                   context->nrm_match);
    3243       180417 :             if (newvar)
    3244       178686 :                 return (Node *) newvar;
    3245              :         }
    3246              : 
    3247              :         /* If it's for acceptable_rel, adjust and return it */
    3248         7585 :         if (var->varno == context->acceptable_rel)
    3249              :         {
    3250         7585 :             var = copyVar(var);
    3251         7585 :             var->varno += context->rtoffset;
    3252         7585 :             if (var->varnosyn > 0)
    3253         7248 :                 var->varnosyn += context->rtoffset;
    3254         7585 :             return (Node *) var;
    3255              :         }
    3256              : 
    3257              :         /* No referent found for Var */
    3258            0 :         elog(ERROR, "variable not found in subplan target lists");
    3259              :     }
    3260       892323 :     if (IsA(node, PlaceHolderVar))
    3261              :     {
    3262         1322 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
    3263              : 
    3264              :         /* See if the PlaceHolderVar has bubbled up from a lower plan node */
    3265         1322 :         if (context->outer_itlist && context->outer_itlist->has_ph_vars)
    3266              :         {
    3267          468 :             newvar = search_indexed_tlist_for_phv(phv,
    3268              :                                                   context->outer_itlist,
    3269              :                                                   OUTER_VAR,
    3270              :                                                   context->nrm_match);
    3271          468 :             if (newvar)
    3272          334 :                 return (Node *) newvar;
    3273              :         }
    3274          988 :         if (context->inner_itlist && context->inner_itlist->has_ph_vars)
    3275              :         {
    3276          790 :             newvar = search_indexed_tlist_for_phv(phv,
    3277              :                                                   context->inner_itlist,
    3278              :                                                   INNER_VAR,
    3279              :                                                   context->nrm_match);
    3280          790 :             if (newvar)
    3281          760 :                 return (Node *) newvar;
    3282              :         }
    3283              : 
    3284              :         /* If not supplied by input plans, evaluate the contained expr */
    3285              :         /* XXX can we assert something about phnullingrels? */
    3286          228 :         return fix_join_expr_mutator((Node *) phv->phexpr, context);
    3287              :     }
    3288              :     /* Try matching more complex expressions too, if tlists have any */
    3289       891001 :     if (context->outer_itlist && context->outer_itlist->has_non_vars)
    3290              :     {
    3291          840 :         newvar = search_indexed_tlist_for_non_var((Expr *) node,
    3292              :                                                   context->outer_itlist,
    3293              :                                                   OUTER_VAR);
    3294          840 :         if (newvar)
    3295           65 :             return (Node *) newvar;
    3296              :     }
    3297       890936 :     if (context->inner_itlist && context->inner_itlist->has_non_vars)
    3298              :     {
    3299         3277 :         newvar = search_indexed_tlist_for_non_var((Expr *) node,
    3300              :                                                   context->inner_itlist,
    3301              :                                                   INNER_VAR);
    3302         3277 :         if (newvar)
    3303          590 :             return (Node *) newvar;
    3304              :     }
    3305              :     /* Special cases (apply only AFTER failing to match to lower tlist) */
    3306       890346 :     if (IsA(node, Param))
    3307         2985 :         return fix_param_node(context->root, (Param *) node);
    3308       887361 :     if (IsA(node, AlternativeSubPlan))
    3309          753 :         return fix_join_expr_mutator(fix_alternative_subplan(context->root,
    3310              :                                                              (AlternativeSubPlan *) node,
    3311              :                                                              context->num_exec),
    3312              :                                      context);
    3313       886608 :     fix_expr_common(context->root, node);
    3314       886608 :     return expression_tree_mutator(node, fix_join_expr_mutator, context);
    3315              : }
    3316              : 
    3317              : /*
    3318              :  * fix_upper_expr
    3319              :  *      Modifies an expression tree so that all Var nodes reference outputs
    3320              :  *      of a subplan.  Also looks for Aggref nodes that should be replaced
    3321              :  *      by initplan output Params.  Also performs opcode lookup, and adds
    3322              :  *      regclass OIDs to root->glob->relationOids.
    3323              :  *
    3324              :  * This is used to fix up target and qual expressions of non-join upper-level
    3325              :  * plan nodes, as well as index-only scan nodes.
    3326              :  *
    3327              :  * An error is raised if no matching var can be found in the subplan tlist
    3328              :  * --- so this routine should only be applied to nodes whose subplans'
    3329              :  * targetlists were generated by flattening the expressions used in the
    3330              :  * parent node.
    3331              :  *
    3332              :  * If itlist->has_non_vars is true, then we try to match whole subexpressions
    3333              :  * against elements of the subplan tlist, so that we can avoid recomputing
    3334              :  * expressions that were already computed by the subplan.  (This is relatively
    3335              :  * expensive, so we don't want to try it in the common case where the
    3336              :  * subplan tlist is just a flattened list of Vars.)
    3337              :  *
    3338              :  * 'node': the tree to be fixed (a target item or qual)
    3339              :  * 'subplan_itlist': indexed target list for subplan (or index)
    3340              :  * 'newvarno': varno to use for Vars referencing tlist elements
    3341              :  * 'rtoffset': how much to increment varnos by
    3342              :  * 'nrm_match': as for search_indexed_tlist_for_var()
    3343              :  * 'num_exec': estimated number of executions of expression
    3344              :  *
    3345              :  * The resulting tree is a copy of the original in which all Var nodes have
    3346              :  * varno = newvarno, varattno = resno of corresponding targetlist element.
    3347              :  * The original tree is not modified.
    3348              :  */
    3349              : static Node *
    3350       190161 : fix_upper_expr(PlannerInfo *root,
    3351              :                Node *node,
    3352              :                indexed_tlist *subplan_itlist,
    3353              :                int newvarno,
    3354              :                int rtoffset,
    3355              :                NullingRelsMatch nrm_match,
    3356              :                double num_exec)
    3357              : {
    3358              :     fix_upper_expr_context context;
    3359              : 
    3360       190161 :     context.root = root;
    3361       190161 :     context.subplan_itlist = subplan_itlist;
    3362       190161 :     context.newvarno = newvarno;
    3363       190161 :     context.rtoffset = rtoffset;
    3364       190161 :     context.nrm_match = nrm_match;
    3365       190161 :     context.num_exec = num_exec;
    3366       190161 :     return fix_upper_expr_mutator(node, &context);
    3367              : }
    3368              : 
    3369              : static Node *
    3370       542904 : fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
    3371              : {
    3372              :     Var        *newvar;
    3373              : 
    3374       542904 :     if (node == NULL)
    3375       176464 :         return NULL;
    3376       366440 :     if (IsA(node, Var))
    3377              :     {
    3378       119656 :         Var        *var = (Var *) node;
    3379              : 
    3380       119656 :         newvar = search_indexed_tlist_for_var(var,
    3381              :                                               context->subplan_itlist,
    3382              :                                               context->newvarno,
    3383              :                                               context->rtoffset,
    3384              :                                               context->nrm_match);
    3385       119656 :         if (!newvar)
    3386            0 :             elog(ERROR, "variable not found in subplan target list");
    3387       119656 :         return (Node *) newvar;
    3388              :     }
    3389       246784 :     if (IsA(node, PlaceHolderVar))
    3390              :     {
    3391          560 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
    3392              : 
    3393              :         /* See if the PlaceHolderVar has bubbled up from a lower plan node */
    3394          560 :         if (context->subplan_itlist->has_ph_vars)
    3395              :         {
    3396          491 :             newvar = search_indexed_tlist_for_phv(phv,
    3397              :                                                   context->subplan_itlist,
    3398              :                                                   context->newvarno,
    3399              :                                                   context->nrm_match);
    3400          491 :             if (newvar)
    3401          491 :                 return (Node *) newvar;
    3402              :         }
    3403              :         /* If not supplied by input plan, evaluate the contained expr */
    3404              :         /* XXX can we assert something about phnullingrels? */
    3405           69 :         return fix_upper_expr_mutator((Node *) phv->phexpr, context);
    3406              :     }
    3407              :     /* Try matching more complex expressions too, if tlist has any */
    3408       246224 :     if (context->subplan_itlist->has_non_vars)
    3409              :     {
    3410        15011 :         newvar = search_indexed_tlist_for_non_var((Expr *) node,
    3411              :                                                   context->subplan_itlist,
    3412              :                                                   context->newvarno);
    3413        15011 :         if (newvar)
    3414         3951 :             return (Node *) newvar;
    3415              :     }
    3416              :     /* Special cases (apply only AFTER failing to match to lower tlist) */
    3417       242273 :     if (IsA(node, Param))
    3418         4851 :         return fix_param_node(context->root, (Param *) node);
    3419       237422 :     if (IsA(node, Aggref))
    3420              :     {
    3421        27635 :         Aggref     *aggref = (Aggref *) node;
    3422              :         Param      *aggparam;
    3423              : 
    3424              :         /* See if the Aggref should be replaced by a Param */
    3425        27635 :         aggparam = find_minmax_agg_replacement_param(context->root, aggref);
    3426        27635 :         if (aggparam != NULL)
    3427              :         {
    3428              :             /* Make a copy of the Param for paranoia's sake */
    3429            0 :             return (Node *) copyObject(aggparam);
    3430              :         }
    3431              :         /* If no match, just fall through to process it normally */
    3432              :     }
    3433       237422 :     if (IsA(node, AlternativeSubPlan))
    3434           18 :         return fix_upper_expr_mutator(fix_alternative_subplan(context->root,
    3435              :                                                               (AlternativeSubPlan *) node,
    3436              :                                                               context->num_exec),
    3437              :                                       context);
    3438       237404 :     fix_expr_common(context->root, node);
    3439       237404 :     return expression_tree_mutator(node, fix_upper_expr_mutator, context);
    3440              : }
    3441              : 
    3442              : /*
    3443              :  * set_returning_clause_references
    3444              :  *      Perform setrefs.c's work on a RETURNING targetlist
    3445              :  *
    3446              :  * If the query involves more than just the result table, we have to
    3447              :  * adjust any Vars that refer to other tables to reference junk tlist
    3448              :  * entries in the top subplan's targetlist.  Vars referencing the result
    3449              :  * table should be left alone, however (the executor will evaluate them
    3450              :  * using the actual heap tuple, after firing triggers if any).  In the
    3451              :  * adjusted RETURNING list, result-table Vars will have their original
    3452              :  * varno (plus rtoffset), but Vars for other rels will have varno OUTER_VAR.
    3453              :  *
    3454              :  * We also must perform opcode lookup and add regclass OIDs to
    3455              :  * root->glob->relationOids.
    3456              :  *
    3457              :  * 'rlist': the RETURNING targetlist to be fixed
    3458              :  * 'topplan': the top subplan node that will be just below the ModifyTable
    3459              :  *      node (note it's not yet passed through set_plan_refs)
    3460              :  * 'resultRelation': RT index of the associated result relation
    3461              :  * 'rtoffset': how much to increment varnos by
    3462              :  *
    3463              :  * Note: the given 'root' is for the parent query level, not the 'topplan'.
    3464              :  * This does not matter currently since we only access the dependency-item
    3465              :  * lists in root->glob, but it would need some hacking if we wanted a root
    3466              :  * that actually matches the subplan.
    3467              :  *
    3468              :  * Note: resultRelation is not yet adjusted by rtoffset.
    3469              :  */
    3470              : static List *
    3471         1896 : set_returning_clause_references(PlannerInfo *root,
    3472              :                                 List *rlist,
    3473              :                                 Plan *topplan,
    3474              :                                 Index resultRelation,
    3475              :                                 int rtoffset)
    3476              : {
    3477              :     indexed_tlist *itlist;
    3478              : 
    3479              :     /*
    3480              :      * We can perform the desired Var fixup by abusing the fix_join_expr
    3481              :      * machinery that formerly handled inner indexscan fixup.  We search the
    3482              :      * top plan's targetlist for Vars of non-result relations, and use
    3483              :      * fix_join_expr to convert RETURNING Vars into references to those tlist
    3484              :      * entries, while leaving result-rel Vars as-is.
    3485              :      *
    3486              :      * PlaceHolderVars will also be sought in the targetlist, but no
    3487              :      * more-complex expressions will be.  Note that it is not possible for a
    3488              :      * PlaceHolderVar to refer to the result relation, since the result is
    3489              :      * never below an outer join.  If that case could happen, we'd have to be
    3490              :      * prepared to pick apart the PlaceHolderVar and evaluate its contained
    3491              :      * expression instead.
    3492              :      */
    3493         1896 :     itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
    3494              : 
    3495         1896 :     rlist = fix_join_expr(root,
    3496              :                           rlist,
    3497              :                           itlist,
    3498              :                           NULL,
    3499              :                           resultRelation,
    3500              :                           rtoffset,
    3501              :                           NRM_EQUAL,
    3502              :                           NUM_EXEC_TLIST(topplan));
    3503              : 
    3504         1896 :     pfree(itlist);
    3505              : 
    3506         1896 :     return rlist;
    3507              : }
    3508              : 
    3509              : /*
    3510              :  * fix_windowagg_condition_expr_mutator
    3511              :  *      Mutator function for replacing WindowFuncs with the corresponding Var
    3512              :  *      in the targetlist which references that WindowFunc.
    3513              :  */
    3514              : static Node *
    3515         1791 : fix_windowagg_condition_expr_mutator(Node *node,
    3516              :                                      fix_windowagg_cond_context *context)
    3517              : {
    3518         1791 :     if (node == NULL)
    3519         1347 :         return NULL;
    3520              : 
    3521          444 :     if (IsA(node, WindowFunc))
    3522              :     {
    3523              :         Var        *newvar;
    3524              : 
    3525           90 :         newvar = search_indexed_tlist_for_non_var((Expr *) node,
    3526              :                                                   context->subplan_itlist,
    3527              :                                                   context->newvarno);
    3528           90 :         if (newvar)
    3529           90 :             return (Node *) newvar;
    3530            0 :         elog(ERROR, "WindowFunc not found in subplan target lists");
    3531              :     }
    3532              : 
    3533          354 :     return expression_tree_mutator(node,
    3534              :                                    fix_windowagg_condition_expr_mutator,
    3535              :                                    context);
    3536              : }
    3537              : 
    3538              : /*
    3539              :  * fix_windowagg_condition_expr
    3540              :  *      Converts references in 'runcondition' so that any WindowFunc
    3541              :  *      references are swapped out for a Var which references the matching
    3542              :  *      WindowFunc in 'subplan_itlist'.
    3543              :  */
    3544              : static List *
    3545         1431 : fix_windowagg_condition_expr(PlannerInfo *root,
    3546              :                              List *runcondition,
    3547              :                              indexed_tlist *subplan_itlist)
    3548              : {
    3549              :     fix_windowagg_cond_context context;
    3550              : 
    3551         1431 :     context.root = root;
    3552         1431 :     context.subplan_itlist = subplan_itlist;
    3553         1431 :     context.newvarno = 0;
    3554              : 
    3555         1431 :     return (List *) fix_windowagg_condition_expr_mutator((Node *) runcondition,
    3556              :                                                          &context);
    3557              : }
    3558              : 
    3559              : /*
    3560              :  * set_windowagg_runcondition_references
    3561              :  *      Converts references in 'runcondition' so that any WindowFunc
    3562              :  *      references are swapped out for a Var which references the matching
    3563              :  *      WindowFunc in 'plan' targetlist.
    3564              :  */
    3565              : static List *
    3566         1431 : set_windowagg_runcondition_references(PlannerInfo *root,
    3567              :                                       List *runcondition,
    3568              :                                       Plan *plan)
    3569              : {
    3570              :     List       *newlist;
    3571              :     indexed_tlist *itlist;
    3572              : 
    3573         1431 :     itlist = build_tlist_index(plan->targetlist);
    3574              : 
    3575         1431 :     newlist = fix_windowagg_condition_expr(root, runcondition, itlist);
    3576              : 
    3577         1431 :     pfree(itlist);
    3578              : 
    3579         1431 :     return newlist;
    3580              : }
    3581              : 
    3582              : /*
    3583              :  * find_minmax_agg_replacement_param
    3584              :  *      If the given Aggref is one that we are optimizing into a subquery
    3585              :  *      (cf. planagg.c), then return the Param that should replace it.
    3586              :  *      Else return NULL.
    3587              :  *
    3588              :  * This is exported so that SS_finalize_plan can use it before setrefs.c runs.
    3589              :  * Note that it will not find anything until we have built a Plan from a
    3590              :  * MinMaxAggPath, as root->minmax_aggs will never be filled otherwise.
    3591              :  */
    3592              : Param *
    3593        39098 : find_minmax_agg_replacement_param(PlannerInfo *root, Aggref *aggref)
    3594              : {
    3595        39594 :     if (root->minmax_aggs != NIL &&
    3596          496 :         list_length(aggref->args) == 1)
    3597              :     {
    3598          496 :         TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
    3599              :         ListCell   *lc;
    3600              : 
    3601          544 :         foreach(lc, root->minmax_aggs)
    3602              :         {
    3603          544 :             MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
    3604              : 
    3605         1040 :             if (mminfo->aggfnoid == aggref->aggfnoid &&
    3606          496 :                 equal(mminfo->target, curTarget->expr))
    3607          496 :                 return mminfo->param;
    3608              :         }
    3609              :     }
    3610        38602 :     return NULL;
    3611              : }
    3612              : 
    3613              : 
    3614              : /*****************************************************************************
    3615              :  *                  QUERY DEPENDENCY MANAGEMENT
    3616              :  *****************************************************************************/
    3617              : 
    3618              : /*
    3619              :  * record_plan_function_dependency
    3620              :  *      Mark the current plan as depending on a particular function.
    3621              :  *
    3622              :  * This is exported so that the function-inlining code can record a
    3623              :  * dependency on a function that it's removed from the plan tree.
    3624              :  */
    3625              : void
    3626       657341 : record_plan_function_dependency(PlannerInfo *root, Oid funcid)
    3627              : {
    3628              :     /*
    3629              :      * For performance reasons, we don't bother to track built-in functions;
    3630              :      * we just assume they'll never change (or at least not in ways that'd
    3631              :      * invalidate plans using them).  For this purpose we can consider a
    3632              :      * built-in function to be one with OID less than FirstUnpinnedObjectId.
    3633              :      * Note that the OID generator guarantees never to generate such an OID
    3634              :      * after startup, even at OID wraparound.
    3635              :      */
    3636       657341 :     if (funcid >= (Oid) FirstUnpinnedObjectId)
    3637              :     {
    3638        21865 :         PlanInvalItem *inval_item = makeNode(PlanInvalItem);
    3639              : 
    3640              :         /*
    3641              :          * It would work to use any syscache on pg_proc, but the easiest is
    3642              :          * PROCOID since we already have the function's OID at hand.  Note
    3643              :          * that plancache.c knows we use PROCOID.
    3644              :          */
    3645        21865 :         inval_item->cacheId = PROCOID;
    3646        21865 :         inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
    3647              :                                                       ObjectIdGetDatum(funcid));
    3648              : 
    3649        21865 :         root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
    3650              :     }
    3651       657341 : }
    3652              : 
    3653              : /*
    3654              :  * record_plan_type_dependency
    3655              :  *      Mark the current plan as depending on a particular type.
    3656              :  *
    3657              :  * This is exported so that eval_const_expressions can record a
    3658              :  * dependency on a domain that it's removed a CoerceToDomain node for.
    3659              :  *
    3660              :  * We don't currently need to record dependencies on domains that the
    3661              :  * plan contains CoerceToDomain nodes for, though that might change in
    3662              :  * future.  Hence, this isn't actually called in this module, though
    3663              :  * someday fix_expr_common might call it.
    3664              :  */
    3665              : void
    3666         9269 : record_plan_type_dependency(PlannerInfo *root, Oid typid)
    3667              : {
    3668              :     /*
    3669              :      * As in record_plan_function_dependency, ignore the possibility that
    3670              :      * someone would change a built-in domain.
    3671              :      */
    3672         9269 :     if (typid >= (Oid) FirstUnpinnedObjectId)
    3673              :     {
    3674         9269 :         PlanInvalItem *inval_item = makeNode(PlanInvalItem);
    3675              : 
    3676              :         /*
    3677              :          * It would work to use any syscache on pg_type, but the easiest is
    3678              :          * TYPEOID since we already have the type's OID at hand.  Note that
    3679              :          * plancache.c knows we use TYPEOID.
    3680              :          */
    3681         9269 :         inval_item->cacheId = TYPEOID;
    3682         9269 :         inval_item->hashValue = GetSysCacheHashValue1(TYPEOID,
    3683              :                                                       ObjectIdGetDatum(typid));
    3684              : 
    3685         9269 :         root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
    3686              :     }
    3687         9269 : }
    3688              : 
    3689              : /*
    3690              :  * extract_query_dependencies
    3691              :  *      Given a rewritten, but not yet planned, query or queries
    3692              :  *      (i.e. a Query node or list of Query nodes), extract dependencies
    3693              :  *      just as set_plan_references would do.  Also detect whether any
    3694              :  *      rewrite steps were affected by RLS.
    3695              :  *
    3696              :  * This is needed by plancache.c to handle invalidation of cached unplanned
    3697              :  * queries.
    3698              :  *
    3699              :  * Note: this does not go through eval_const_expressions, and hence doesn't
    3700              :  * reflect its additions of inlined functions and elided CoerceToDomain nodes
    3701              :  * to the invalItems list.  This is obviously OK for functions, since we'll
    3702              :  * see them in the original query tree anyway.  For domains, it's OK because
    3703              :  * we don't care about domains unless they get elided.  That is, a plan might
    3704              :  * have domain dependencies that the query tree doesn't.
    3705              :  */
    3706              : void
    3707        31777 : extract_query_dependencies(Node *query,
    3708              :                            List **relationOids,
    3709              :                            List **invalItems,
    3710              :                            bool *hasRowSecurity)
    3711              : {
    3712              :     PlannerGlobal glob;
    3713              :     PlannerInfo root;
    3714              : 
    3715              :     /* Make up dummy planner state so we can use this module's machinery */
    3716       921533 :     MemSet(&glob, 0, sizeof(glob));
    3717        31777 :     glob.type = T_PlannerGlobal;
    3718        31777 :     glob.relationOids = NIL;
    3719        31777 :     glob.invalItems = NIL;
    3720              :     /* Hack: we use glob.dependsOnRole to collect hasRowSecurity flags */
    3721        31777 :     glob.dependsOnRole = false;
    3722              : 
    3723      2955261 :     MemSet(&root, 0, sizeof(root));
    3724        31777 :     root.type = T_PlannerInfo;
    3725        31777 :     root.glob = &glob;
    3726              : 
    3727        31777 :     (void) extract_query_dependencies_walker(query, &root);
    3728              : 
    3729        31777 :     *relationOids = glob.relationOids;
    3730        31777 :     *invalItems = glob.invalItems;
    3731        31777 :     *hasRowSecurity = glob.dependsOnRole;
    3732        31777 : }
    3733              : 
    3734              : /*
    3735              :  * Tree walker for extract_query_dependencies.
    3736              :  *
    3737              :  * This is exported so that expression_planner_with_deps can call it on
    3738              :  * simple expressions (post-planning, not before planning, in that case).
    3739              :  * In that usage, glob.dependsOnRole isn't meaningful, but the relationOids
    3740              :  * and invalItems lists are added to as needed.
    3741              :  */
    3742              : bool
    3743       863684 : extract_query_dependencies_walker(Node *node, PlannerInfo *context)
    3744              : {
    3745       863684 :     if (node == NULL)
    3746       407599 :         return false;
    3747              :     Assert(!IsA(node, PlaceHolderVar));
    3748       456085 :     if (IsA(node, Query))
    3749              :     {
    3750        33970 :         Query      *query = (Query *) node;
    3751              :         ListCell   *lc;
    3752              : 
    3753        33970 :         if (query->commandType == CMD_UTILITY)
    3754              :         {
    3755              :             /*
    3756              :              * This logic must handle any utility command for which parse
    3757              :              * analysis was nontrivial (cf. stmt_requires_parse_analysis).
    3758              :              *
    3759              :              * Notably, CALL requires its own processing.
    3760              :              */
    3761         4985 :             if (IsA(query->utilityStmt, CallStmt))
    3762              :             {
    3763           58 :                 CallStmt   *callstmt = (CallStmt *) query->utilityStmt;
    3764              : 
    3765              :                 /* We need not examine funccall, just the transformed exprs */
    3766           58 :                 (void) extract_query_dependencies_walker((Node *) callstmt->funcexpr,
    3767              :                                                          context);
    3768           58 :                 (void) extract_query_dependencies_walker((Node *) callstmt->outargs,
    3769              :                                                          context);
    3770           58 :                 return false;
    3771              :             }
    3772              : 
    3773              :             /*
    3774              :              * Ignore other utility statements, except those (such as EXPLAIN)
    3775              :              * that contain a parsed-but-not-planned query.  For those, we
    3776              :              * just need to transfer our attention to the contained query.
    3777              :              */
    3778         4927 :             query = UtilityContainsQuery(query->utilityStmt);
    3779         4927 :             if (query == NULL)
    3780           18 :                 return false;
    3781              :         }
    3782              : 
    3783              :         /* Remember if any Query has RLS quals applied by rewriter */
    3784        33894 :         if (query->hasRowSecurity)
    3785          114 :             context->glob->dependsOnRole = true;
    3786              : 
    3787              :         /* Collect relation OIDs in this Query's rtable */
    3788        54922 :         foreach(lc, query->rtable)
    3789              :         {
    3790        21028 :             RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
    3791              : 
    3792        21028 :             if (rte->rtekind == RTE_RELATION ||
    3793         3813 :                 (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)) ||
    3794         3579 :                 (rte->rtekind == RTE_NAMEDTUPLESTORE && OidIsValid(rte->relid)))
    3795        17682 :                 context->glob->relationOids =
    3796        17682 :                     lappend_oid(context->glob->relationOids, rte->relid);
    3797              :         }
    3798              : 
    3799              :         /* And recurse into the query's subexpressions */
    3800        33894 :         return query_tree_walker(query, extract_query_dependencies_walker,
    3801              :                                  context, 0);
    3802              :     }
    3803              :     /* Extract function dependencies and check for regclass Consts */
    3804       422115 :     fix_expr_common(context, node);
    3805       422115 :     return expression_tree_walker(node, extract_query_dependencies_walker,
    3806              :                                   context);
    3807              : }
    3808              : 
    3809              : /*
    3810              :  * Record some details about a node removed from the plan during setrefs
    3811              :  * processing, for the benefit of code trying to reconstruct planner decisions
    3812              :  * from examination of the final plan tree.
    3813              :  */
    3814              : static void
    3815        12518 : record_elided_node(PlannerGlobal *glob, int plan_node_id,
    3816              :                    NodeTag elided_type, Bitmapset *relids)
    3817              : {
    3818        12518 :     ElidedNode *n = makeNode(ElidedNode);
    3819              : 
    3820        12518 :     n->plan_node_id = plan_node_id;
    3821        12518 :     n->elided_type = elided_type;
    3822        12518 :     n->relids = relids;
    3823              : 
    3824        12518 :     glob->elidedNodes = lappend(glob->elidedNodes, n);
    3825        12518 : }
        

Generated by: LCOV version 2.0-1