PostgreSQL Source Code  git master
setrefs.c File Reference
#include "postgres.h"
#include "access/transam.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "optimizer/pathnode.h"
#include "optimizer/planmain.h"
#include "optimizer/planner.h"
#include "optimizer/tlist.h"
#include "tcop/utility.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
Include dependency graph for setrefs.c:

Go to the source code of this file.

Data Structures

struct  tlist_vinfo
 
struct  indexed_tlist
 
struct  fix_scan_expr_context
 
struct  fix_join_expr_context
 
struct  fix_upper_expr_context
 
struct  fix_windowagg_cond_context
 

Macros

#define NUM_EXEC_TLIST(parentplan)   ((parentplan)->plan_rows)
 
#define NUM_EXEC_QUAL(parentplan)   ((parentplan)->plan_rows * 2.0)
 
#define ISREGCLASSCONST(con)
 
#define fix_scan_list(root, lst, rtoffset, num_exec)    ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset, num_exec))
 

Functions

static void add_rtes_to_flat_rtable (PlannerInfo *root, bool recursing)
 
static void flatten_unplanned_rtes (PlannerGlobal *glob, RangeTblEntry *rte)
 
static bool flatten_rtes_walker (Node *node, PlannerGlobal *glob)
 
static void add_rte_to_flat_rtable (PlannerGlobal *glob, RangeTblEntry *rte)
 
static Planset_plan_refs (PlannerInfo *root, Plan *plan, int rtoffset)
 
static Planset_indexonlyscan_references (PlannerInfo *root, IndexOnlyScan *plan, int rtoffset)
 
static Planset_subqueryscan_references (PlannerInfo *root, SubqueryScan *plan, int rtoffset)
 
static Planclean_up_removed_plan_level (Plan *parent, Plan *child)
 
static void set_foreignscan_references (PlannerInfo *root, ForeignScan *fscan, int rtoffset)
 
static void set_customscan_references (PlannerInfo *root, CustomScan *cscan, int rtoffset)
 
static Planset_append_references (PlannerInfo *root, Append *aplan, int rtoffset)
 
static Planset_mergeappend_references (PlannerInfo *root, MergeAppend *mplan, int rtoffset)
 
static void set_hash_references (PlannerInfo *root, Plan *plan, int rtoffset)
 
static Relids offset_relid_set (Relids relids, int rtoffset)
 
static Nodefix_scan_expr (PlannerInfo *root, Node *node, int rtoffset, double num_exec)
 
static Nodefix_scan_expr_mutator (Node *node, fix_scan_expr_context *context)
 
static bool fix_scan_expr_walker (Node *node, fix_scan_expr_context *context)
 
static void set_join_references (PlannerInfo *root, Join *join, int rtoffset)
 
static void set_upper_references (PlannerInfo *root, Plan *plan, int rtoffset)
 
static void set_param_references (PlannerInfo *root, Plan *plan)
 
static Nodeconvert_combining_aggrefs (Node *node, void *context)
 
static void set_dummy_tlist_references (Plan *plan, int rtoffset)
 
static indexed_tlistbuild_tlist_index (List *tlist)
 
static Varsearch_indexed_tlist_for_var (Var *var, indexed_tlist *itlist, int newvarno, int rtoffset)
 
static Varsearch_indexed_tlist_for_non_var (Expr *node, indexed_tlist *itlist, int newvarno)
 
static Varsearch_indexed_tlist_for_sortgroupref (Expr *node, Index sortgroupref, indexed_tlist *itlist, int newvarno)
 
static Listfix_join_expr (PlannerInfo *root, List *clauses, indexed_tlist *outer_itlist, indexed_tlist *inner_itlist, Index acceptable_rel, int rtoffset, double num_exec)
 
static Nodefix_join_expr_mutator (Node *node, fix_join_expr_context *context)
 
static Nodefix_upper_expr (PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, int newvarno, int rtoffset, double num_exec)
 
static Nodefix_upper_expr_mutator (Node *node, fix_upper_expr_context *context)
 
static Listset_returning_clause_references (PlannerInfo *root, List *rlist, Plan *topplan, Index resultRelation, int rtoffset)
 
static Listset_windowagg_runcondition_references (PlannerInfo *root, List *runcondition, Plan *plan)
 
Planset_plan_references (PlannerInfo *root, Plan *plan)
 
bool trivial_subqueryscan (SubqueryScan *plan)
 
static VarcopyVar (Var *var)
 
static void fix_expr_common (PlannerInfo *root, Node *node)
 
static Nodefix_param_node (PlannerInfo *root, Param *p)
 
static Nodefix_alternative_subplan (PlannerInfo *root, AlternativeSubPlan *asplan, double num_exec)
 
static indexed_tlistbuild_tlist_index_other_vars (List *tlist, int ignore_rel)
 
static Nodefix_windowagg_condition_expr_mutator (Node *node, fix_windowagg_cond_context *context)
 
static Listfix_windowagg_condition_expr (PlannerInfo *root, List *runcondition, indexed_tlist *subplan_itlist)
 
void record_plan_function_dependency (PlannerInfo *root, Oid funcid)
 
void record_plan_type_dependency (PlannerInfo *root, Oid typid)
 
void extract_query_dependencies (Node *query, List **relationOids, List **invalItems, bool *hasRowSecurity)
 
bool extract_query_dependencies_walker (Node *node, PlannerInfo *context)
 

Macro Definition Documentation

◆ fix_scan_list

#define fix_scan_list (   root,
  lst,
  rtoffset,
  num_exec 
)     ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset, num_exec))

Definition at line 111 of file setrefs.c.

◆ ISREGCLASSCONST

#define ISREGCLASSCONST (   con)
Value:
(((con)->consttype == REGCLASSOID || (con)->consttype == OIDOID) && \
!(con)->constisnull)

Definition at line 107 of file setrefs.c.

◆ NUM_EXEC_QUAL

#define NUM_EXEC_QUAL (   parentplan)    ((parentplan)->plan_rows * 2.0)

Definition at line 98 of file setrefs.c.

◆ NUM_EXEC_TLIST

#define NUM_EXEC_TLIST (   parentplan)    ((parentplan)->plan_rows)

Definition at line 97 of file setrefs.c.

Function Documentation

◆ add_rte_to_flat_rtable()

static void add_rte_to_flat_rtable ( PlannerGlobal glob,
RangeTblEntry rte 
)
static

Definition at line 492 of file setrefs.c.

493 {
494  RangeTblEntry *newrte;
495 
496  /* flat copy to duplicate all the scalar fields */
497  newrte = (RangeTblEntry *) palloc(sizeof(RangeTblEntry));
498  memcpy(newrte, rte, sizeof(RangeTblEntry));
499 
500  /* zap unneeded sub-structure */
501  newrte->tablesample = NULL;
502  newrte->subquery = NULL;
503  newrte->joinaliasvars = NIL;
504  newrte->joinleftcols = NIL;
505  newrte->joinrightcols = NIL;
506  newrte->join_using_alias = NULL;
507  newrte->functions = NIL;
508  newrte->tablefunc = NULL;
509  newrte->values_lists = NIL;
510  newrte->coltypes = NIL;
511  newrte->coltypmods = NIL;
512  newrte->colcollations = NIL;
513  newrte->securityQuals = NIL;
514 
515  glob->finalrtable = lappend(glob->finalrtable, newrte);
516 
517  /*
518  * If it's a plain relation RTE, add the table to relationOids.
519  *
520  * We do this even though the RTE might be unreferenced in the plan tree;
521  * this would correspond to cases such as views that were expanded, child
522  * tables that were eliminated by constraint exclusion, etc. Schema
523  * invalidation on such a rel must still force rebuilding of the plan.
524  *
525  * Note we don't bother to avoid making duplicate list entries. We could,
526  * but it would probably cost more cycles than it would save.
527  */
528  if (newrte->rtekind == RTE_RELATION)
529  glob->relationOids = lappend_oid(glob->relationOids, newrte->relid);
530 }
List * lappend(List *list, void *datum)
Definition: list.c:338
List * lappend_oid(List *list, Oid datum)
Definition: list.c:374
void * palloc(Size size)
Definition: mcxt.c:1068
@ RTE_RELATION
Definition: parsenodes.h:999
#define NIL
Definition: pg_list.h:66
List * relationOids
Definition: pathnodes.h:110
List * finalrtable
Definition: pathnodes.h:102
List * colcollations
Definition: parsenodes.h:1150
TableFunc * tablefunc
Definition: parsenodes.h:1116
Alias * join_using_alias
Definition: parsenodes.h:1100
struct TableSampleClause * tablesample
Definition: parsenodes.h:1046
List * securityQuals
Definition: parsenodes.h:1172
Query * subquery
Definition: parsenodes.h:1051
List * coltypes
Definition: parsenodes.h:1148
List * joinrightcols
Definition: parsenodes.h:1093
List * values_lists
Definition: parsenodes.h:1121
List * joinaliasvars
Definition: parsenodes.h:1091
List * coltypmods
Definition: parsenodes.h:1149
List * functions
Definition: parsenodes.h:1110
List * joinleftcols
Definition: parsenodes.h:1092
RTEKind rtekind
Definition: parsenodes.h:1016

References RangeTblEntry::colcollations, RangeTblEntry::coltypes, RangeTblEntry::coltypmods, PlannerGlobal::finalrtable, RangeTblEntry::functions, RangeTblEntry::join_using_alias, RangeTblEntry::joinaliasvars, RangeTblEntry::joinleftcols, RangeTblEntry::joinrightcols, lappend(), lappend_oid(), NIL, palloc(), PlannerGlobal::relationOids, RangeTblEntry::relid, RTE_RELATION, RangeTblEntry::rtekind, RangeTblEntry::securityQuals, RangeTblEntry::subquery, RangeTblEntry::tablefunc, RangeTblEntry::tablesample, and RangeTblEntry::values_lists.

Referenced by add_rtes_to_flat_rtable(), and flatten_rtes_walker().

◆ add_rtes_to_flat_rtable()

static void add_rtes_to_flat_rtable ( PlannerInfo root,
bool  recursing 
)
static

Definition at line 360 of file setrefs.c.

361 {
362  PlannerGlobal *glob = root->glob;
363  Index rti;
364  ListCell *lc;
365 
366  /*
367  * Add the query's own RTEs to the flattened rangetable.
368  *
369  * At top level, we must add all RTEs so that their indexes in the
370  * flattened rangetable match up with their original indexes. When
371  * recursing, we only care about extracting relation RTEs.
372  */
373  foreach(lc, root->parse->rtable)
374  {
375  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
376 
377  if (!recursing || rte->rtekind == RTE_RELATION)
378  add_rte_to_flat_rtable(glob, rte);
379  }
380 
381  /*
382  * If there are any dead subqueries, they are not referenced in the Plan
383  * tree, so we must add RTEs contained in them to the flattened rtable
384  * separately. (If we failed to do this, the executor would not perform
385  * expected permission checks for tables mentioned in such subqueries.)
386  *
387  * Note: this pass over the rangetable can't be combined with the previous
388  * one, because that would mess up the numbering of the live RTEs in the
389  * flattened rangetable.
390  */
391  rti = 1;
392  foreach(lc, root->parse->rtable)
393  {
394  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
395 
396  /*
397  * We should ignore inheritance-parent RTEs: their contents have been
398  * pulled up into our rangetable already. Also ignore any subquery
399  * RTEs without matching RelOptInfos, as they likewise have been
400  * pulled up.
401  */
402  if (rte->rtekind == RTE_SUBQUERY && !rte->inh &&
403  rti < root->simple_rel_array_size)
404  {
405  RelOptInfo *rel = root->simple_rel_array[rti];
406 
407  if (rel != NULL)
408  {
409  Assert(rel->relid == rti); /* sanity check on array */
410 
411  /*
412  * The subquery might never have been planned at all, if it
413  * was excluded on the basis of self-contradictory constraints
414  * in our query level. In this case apply
415  * flatten_unplanned_rtes.
416  *
417  * If it was planned but the result rel is dummy, we assume
418  * that it has been omitted from our plan tree (see
419  * set_subquery_pathlist), and recurse to pull up its RTEs.
420  *
421  * Otherwise, it should be represented by a SubqueryScan node
422  * somewhere in our plan tree, and we'll pull up its RTEs when
423  * we process that plan node.
424  *
425  * However, if we're recursing, then we should pull up RTEs
426  * whether the subquery is dummy or not, because we've found
427  * that some upper query level is treating this one as dummy,
428  * and so we won't scan this level's plan tree at all.
429  */
430  if (rel->subroot == NULL)
431  flatten_unplanned_rtes(glob, rte);
432  else if (recursing ||
434  UPPERREL_FINAL, NULL)))
435  add_rtes_to_flat_rtable(rel->subroot, true);
436  }
437  }
438  rti++;
439  }
440 }
unsigned int Index
Definition: c.h:560
Assert(fmt[strlen(fmt) - 1] !='\n')
@ RTE_SUBQUERY
Definition: parsenodes.h:1000
#define IS_DUMMY_REL(r)
Definition: pathnodes.h:1636
@ UPPERREL_FINAL
Definition: pathnodes.h:77
#define lfirst(lc)
Definition: pg_list.h:170
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1210
static void add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
Definition: setrefs.c:360
static void add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte)
Definition: setrefs.c:492
static void flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte)
Definition: setrefs.c:446
PlannerGlobal * glob
Definition: pathnodes.h:164
struct RelOptInfo ** simple_rel_array
Definition: pathnodes.h:186
Query * parse
Definition: pathnodes.h:162
List * rtable
Definition: parsenodes.h:149
Index relid
Definition: pathnodes.h:740
PlannerInfo * subroot
Definition: pathnodes.h:770

References add_rte_to_flat_rtable(), Assert(), fetch_upper_rel(), flatten_unplanned_rtes(), PlannerInfo::glob, RangeTblEntry::inh, IS_DUMMY_REL, lfirst, PlannerInfo::parse, RelOptInfo::relid, Query::rtable, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, PlannerInfo::simple_rel_array, RelOptInfo::subroot, and UPPERREL_FINAL.

Referenced by set_plan_references().

◆ build_tlist_index()

static indexed_tlist * build_tlist_index ( List tlist)
static

Definition at line 2550 of file setrefs.c.

2551 {
2552  indexed_tlist *itlist;
2553  tlist_vinfo *vinfo;
2554  ListCell *l;
2555 
2556  /* Create data structure with enough slots for all tlist entries */
2557  itlist = (indexed_tlist *)
2559  list_length(tlist) * sizeof(tlist_vinfo));
2560 
2561  itlist->tlist = tlist;
2562  itlist->has_ph_vars = false;
2563  itlist->has_non_vars = false;
2564 
2565  /* Find the Vars and fill in the index array */
2566  vinfo = itlist->vars;
2567  foreach(l, tlist)
2568  {
2569  TargetEntry *tle = (TargetEntry *) lfirst(l);
2570 
2571  if (tle->expr && IsA(tle->expr, Var))
2572  {
2573  Var *var = (Var *) tle->expr;
2574 
2575  vinfo->varno = var->varno;
2576  vinfo->varattno = var->varattno;
2577  vinfo->resno = tle->resno;
2578  vinfo++;
2579  }
2580  else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2581  itlist->has_ph_vars = true;
2582  else
2583  itlist->has_non_vars = true;
2584  }
2585 
2586  itlist->num_vars = (vinfo - itlist->vars);
2587 
2588  return itlist;
2589 }
#define offsetof(type, field)
Definition: c.h:738
#define IsA(nodeptr, _type_)
Definition: nodes.h:625
static int list_length(const List *l)
Definition: pg_list.h:150
Expr * expr
Definition: primnodes.h:1828
AttrNumber resno
Definition: primnodes.h:1829
Definition: primnodes.h:209
AttrNumber varattno
Definition: primnodes.h:221
int varno
Definition: primnodes.h:216
tlist_vinfo vars[FLEXIBLE_ARRAY_MEMBER]
Definition: setrefs.c:45
bool has_ph_vars
Definition: setrefs.c:43
bool has_non_vars
Definition: setrefs.c:44
int num_vars
Definition: setrefs.c:42
List * tlist
Definition: setrefs.c:41
AttrNumber resno
Definition: setrefs.c:36
int varno
Definition: setrefs.c:34
AttrNumber varattno
Definition: setrefs.c:35
Definition: regcomp.c:238

References TargetEntry::expr, indexed_tlist::has_non_vars, indexed_tlist::has_ph_vars, IsA, lfirst, list_length(), indexed_tlist::num_vars, offsetof, palloc(), tlist_vinfo::resno, TargetEntry::resno, indexed_tlist::tlist, tlist_vinfo::varattno, Var::varattno, tlist_vinfo::varno, Var::varno, and indexed_tlist::vars.

Referenced by set_customscan_references(), set_foreignscan_references(), set_hash_references(), set_indexonlyscan_references(), set_join_references(), set_plan_refs(), set_upper_references(), and set_windowagg_runcondition_references().

◆ build_tlist_index_other_vars()

static indexed_tlist* build_tlist_index_other_vars ( List tlist,
int  ignore_rel 
)
static

Definition at line 2600 of file setrefs.c.

2601 {
2602  indexed_tlist *itlist;
2603  tlist_vinfo *vinfo;
2604  ListCell *l;
2605 
2606  /* Create data structure with enough slots for all tlist entries */
2607  itlist = (indexed_tlist *)
2609  list_length(tlist) * sizeof(tlist_vinfo));
2610 
2611  itlist->tlist = tlist;
2612  itlist->has_ph_vars = false;
2613  itlist->has_non_vars = false;
2614 
2615  /* Find the desired Vars and fill in the index array */
2616  vinfo = itlist->vars;
2617  foreach(l, tlist)
2618  {
2619  TargetEntry *tle = (TargetEntry *) lfirst(l);
2620 
2621  if (tle->expr && IsA(tle->expr, Var))
2622  {
2623  Var *var = (Var *) tle->expr;
2624 
2625  if (var->varno != ignore_rel)
2626  {
2627  vinfo->varno = var->varno;
2628  vinfo->varattno = var->varattno;
2629  vinfo->resno = tle->resno;
2630  vinfo++;
2631  }
2632  }
2633  else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2634  itlist->has_ph_vars = true;
2635  }
2636 
2637  itlist->num_vars = (vinfo - itlist->vars);
2638 
2639  return itlist;
2640 }
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77

References TargetEntry::expr, indexed_tlist::has_non_vars, indexed_tlist::has_ph_vars, if(), IsA, lfirst, list_length(), indexed_tlist::num_vars, offsetof, palloc(), tlist_vinfo::resno, TargetEntry::resno, indexed_tlist::tlist, tlist_vinfo::varattno, Var::varattno, tlist_vinfo::varno, Var::varno, and indexed_tlist::vars.

Referenced by set_returning_clause_references().

◆ clean_up_removed_plan_level()

static Plan * clean_up_removed_plan_level ( Plan parent,
Plan child 
)
static

Definition at line 1441 of file setrefs.c.

1442 {
1443  /* We have to be sure we don't lose any initplans */
1444  child->initPlan = list_concat(parent->initPlan,
1445  child->initPlan);
1446 
1447  /*
1448  * We also have to transfer the parent's column labeling info into the
1449  * child, else columns sent to client will be improperly labeled if this
1450  * is the topmost plan level. resjunk and so on may be important too.
1451  */
1452  apply_tlist_labeling(child->targetlist, parent->targetlist);
1453 
1454  return child;
1455 }
List * list_concat(List *list1, const List *list2)
Definition: list.c:560
List * targetlist
Definition: plannodes.h:142
List * initPlan
Definition: plannodes.h:146
void apply_tlist_labeling(List *dest_tlist, List *src_tlist)
Definition: tlist.c:307

References apply_tlist_labeling(), Plan::initPlan, list_concat(), and Plan::targetlist.

Referenced by set_append_references(), set_mergeappend_references(), and set_subqueryscan_references().

◆ convert_combining_aggrefs()

static Node * convert_combining_aggrefs ( Node node,
void *  context 
)
static

Definition at line 2414 of file setrefs.c.

2415 {
2416  if (node == NULL)
2417  return NULL;
2418  if (IsA(node, Aggref))
2419  {
2420  Aggref *orig_agg = (Aggref *) node;
2421  Aggref *child_agg;
2422  Aggref *parent_agg;
2423 
2424  /* Assert we've not chosen to partial-ize any unsupported cases */
2425  Assert(orig_agg->aggorder == NIL);
2426  Assert(orig_agg->aggdistinct == NIL);
2427 
2428  /*
2429  * Since aggregate calls can't be nested, we needn't recurse into the
2430  * arguments. But for safety, flat-copy the Aggref node itself rather
2431  * than modifying it in-place.
2432  */
2433  child_agg = makeNode(Aggref);
2434  memcpy(child_agg, orig_agg, sizeof(Aggref));
2435 
2436  /*
2437  * For the parent Aggref, we want to copy all the fields of the
2438  * original aggregate *except* the args list, which we'll replace
2439  * below, and the aggfilter expression, which should be applied only
2440  * by the child not the parent. Rather than explicitly knowing about
2441  * all the other fields here, we can momentarily modify child_agg to
2442  * provide a suitable source for copyObject.
2443  */
2444  child_agg->args = NIL;
2445  child_agg->aggfilter = NULL;
2446  parent_agg = copyObject(child_agg);
2447  child_agg->args = orig_agg->args;
2448  child_agg->aggfilter = orig_agg->aggfilter;
2449 
2450  /*
2451  * Now, set up child_agg to represent the first phase of partial
2452  * aggregation. For now, assume serialization is required.
2453  */
2455 
2456  /*
2457  * And set up parent_agg to represent the second phase.
2458  */
2459  parent_agg->args = list_make1(makeTargetEntry((Expr *) child_agg,
2460  1, NULL, false));
2462 
2463  return (Node *) parent_agg;
2464  }
2466  (void *) context);
2467 }
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:239
Node * expression_tree_mutator(Node *node, Node *(*mutator)(), void *context)
Definition: nodeFuncs.c:2815
#define copyObject(obj)
Definition: nodes.h:690
@ AGGSPLIT_FINAL_DESERIAL
Definition: nodes.h:835
@ AGGSPLIT_INITIAL_SERIAL
Definition: nodes.h:833
#define makeNode(_type_)
Definition: nodes.h:622
#define list_make1(x1)
Definition: pg_list.h:210
void mark_partial_aggref(Aggref *agg, AggSplit aggsplit)
Definition: planner.c:5120
static Node * convert_combining_aggrefs(Node *node, void *context)
Definition: setrefs.c:2414
List * aggdistinct
Definition: primnodes.h:393
List * args
Definition: primnodes.h:387
Expr * aggfilter
Definition: primnodes.h:396
List * aggorder
Definition: primnodes.h:390
Definition: nodes.h:575

References Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggorder, AGGSPLIT_FINAL_DESERIAL, AGGSPLIT_INITIAL_SERIAL, Aggref::args, Assert(), copyObject, expression_tree_mutator(), IsA, list_make1, makeNode, makeTargetEntry(), mark_partial_aggref(), and NIL.

Referenced by set_plan_refs().

◆ copyVar()

static Var* copyVar ( Var var)
inlinestatic

Definition at line 1812 of file setrefs.c.

1813 {
1814  Var *newvar = (Var *) palloc(sizeof(Var));
1815 
1816  *newvar = *var;
1817  return newvar;
1818 }

References palloc().

Referenced by fix_join_expr_mutator(), fix_scan_expr_mutator(), and search_indexed_tlist_for_var().

◆ extract_query_dependencies()

void extract_query_dependencies ( Node query,
List **  relationOids,
List **  invalItems,
bool hasRowSecurity 
)

Definition at line 3283 of file setrefs.c.

3287 {
3288  PlannerGlobal glob;
3289  PlannerInfo root;
3290 
3291  /* Make up dummy planner state so we can use this module's machinery */
3292  MemSet(&glob, 0, sizeof(glob));
3293  glob.type = T_PlannerGlobal;
3294  glob.relationOids = NIL;
3295  glob.invalItems = NIL;
3296  /* Hack: we use glob.dependsOnRole to collect hasRowSecurity flags */
3297  glob.dependsOnRole = false;
3298 
3299  MemSet(&root, 0, sizeof(root));
3300  root.type = T_PlannerInfo;
3301  root.glob = &glob;
3302 
3303  (void) extract_query_dependencies_walker(query, &root);
3304 
3305  *relationOids = glob.relationOids;
3306  *invalItems = glob.invalItems;
3307  *hasRowSecurity = glob.dependsOnRole;
3308 }
#define MemSet(start, val, len)
Definition: c.h:1019
@ T_PlannerInfo
Definition: nodes.h:236
@ T_PlannerGlobal
Definition: nodes.h:237
bool extract_query_dependencies_walker(Node *node, PlannerInfo *context)
Definition: setrefs.c:3319
NodeTag type
Definition: pathnodes.h:92
bool dependsOnRole
Definition: pathnodes.h:124
List * invalItems
Definition: pathnodes.h:112
NodeTag type
Definition: pathnodes.h:160

References PlannerGlobal::dependsOnRole, extract_query_dependencies_walker(), PlannerInfo::glob, PlannerGlobal::invalItems, MemSet, NIL, PlannerGlobal::relationOids, T_PlannerGlobal, T_PlannerInfo, PlannerGlobal::type, and PlannerInfo::type.

Referenced by CompleteCachedPlan(), and RevalidateCachedQuery().

◆ extract_query_dependencies_walker()

bool extract_query_dependencies_walker ( Node node,
PlannerInfo context 
)

Definition at line 3319 of file setrefs.c.

3320 {
3321  if (node == NULL)
3322  return false;
3323  Assert(!IsA(node, PlaceHolderVar));
3324  if (IsA(node, Query))
3325  {
3326  Query *query = (Query *) node;
3327  ListCell *lc;
3328 
3329  if (query->commandType == CMD_UTILITY)
3330  {
3331  /*
3332  * Ignore utility statements, except those (such as EXPLAIN) that
3333  * contain a parsed-but-not-planned query.
3334  */
3335  query = UtilityContainsQuery(query->utilityStmt);
3336  if (query == NULL)
3337  return false;
3338  }
3339 
3340  /* Remember if any Query has RLS quals applied by rewriter */
3341  if (query->hasRowSecurity)
3342  context->glob->dependsOnRole = true;
3343 
3344  /* Collect relation OIDs in this Query's rtable */
3345  foreach(lc, query->rtable)
3346  {
3347  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3348 
3349  if (rte->rtekind == RTE_RELATION)
3350  context->glob->relationOids =
3351  lappend_oid(context->glob->relationOids, rte->relid);
3352  else if (rte->rtekind == RTE_NAMEDTUPLESTORE &&
3353  OidIsValid(rte->relid))
3354  context->glob->relationOids =
3355  lappend_oid(context->glob->relationOids,
3356  rte->relid);
3357  }
3358 
3359  /* And recurse into the query's subexpressions */
3361  (void *) context, 0);
3362  }
3363  /* Extract function dependencies and check for regclass Consts */
3364  fix_expr_common(context, node);
3366  (void *) context);
3367 }
#define OidIsValid(objectId)
Definition: c.h:721
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2570
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:2015
@ CMD_UTILITY
Definition: nodes.h:727
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1006
static void fix_expr_common(PlannerInfo *root, Node *node)
Definition: setrefs.c:1834
bool hasRowSecurity
Definition: parsenodes.h:143
CmdType commandType
Definition: parsenodes.h:121
Node * utilityStmt
Definition: parsenodes.h:130
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2170

References Assert(), CMD_UTILITY, Query::commandType, PlannerGlobal::dependsOnRole, expression_tree_walker(), fix_expr_common(), PlannerInfo::glob, Query::hasRowSecurity, IsA, lappend_oid(), lfirst, OidIsValid, query_tree_walker(), PlannerGlobal::relationOids, RangeTblEntry::relid, Query::rtable, RTE_NAMEDTUPLESTORE, RTE_RELATION, RangeTblEntry::rtekind, UtilityContainsQuery(), and Query::utilityStmt.

Referenced by expression_planner_with_deps(), and extract_query_dependencies().

◆ fix_alternative_subplan()

static Node* fix_alternative_subplan ( PlannerInfo root,
AlternativeSubPlan asplan,
double  num_exec 
)
static

Definition at line 1960 of file setrefs.c.

1962 {
1963  SubPlan *bestplan = NULL;
1964  Cost bestcost = 0;
1965  ListCell *lc;
1966 
1967  /*
1968  * Compute the estimated cost of each subplan assuming num_exec
1969  * executions, and keep the cheapest one. In event of exact equality of
1970  * estimates, we prefer the later plan; this is a bit arbitrary, but in
1971  * current usage it biases us to break ties against fast-start subplans.
1972  */
1973  Assert(asplan->subplans != NIL);
1974 
1975  foreach(lc, asplan->subplans)
1976  {
1977  SubPlan *curplan = (SubPlan *) lfirst(lc);
1978  Cost curcost;
1979 
1980  curcost = curplan->startup_cost + num_exec * curplan->per_call_cost;
1981  if (bestplan == NULL || curcost <= bestcost)
1982  {
1983  bestplan = curplan;
1984  bestcost = curcost;
1985  }
1986 
1987  /* Also mark all subplans that are in AlternativeSubPlans */
1988  root->isAltSubplan[curplan->plan_id - 1] = true;
1989  }
1990 
1991  /* Mark the subplan we selected */
1992  root->isUsedSubplan[bestplan->plan_id - 1] = true;
1993 
1994  return (Node *) bestplan;
1995 }
double Cost
Definition: nodes.h:708
bool * isAltSubplan
Definition: pathnodes.h:381
bool * isUsedSubplan
Definition: pathnodes.h:382
int plan_id
Definition: primnodes.h:873
Cost startup_cost
Definition: primnodes.h:896
Cost per_call_cost
Definition: primnodes.h:897

References Assert(), PlannerInfo::isAltSubplan, PlannerInfo::isUsedSubplan, lfirst, NIL, SubPlan::per_call_cost, SubPlan::plan_id, SubPlan::startup_cost, and AlternativeSubPlan::subplans.

Referenced by fix_join_expr_mutator(), fix_scan_expr_mutator(), and fix_upper_expr_mutator().

◆ fix_expr_common()

static void fix_expr_common ( PlannerInfo root,
Node node 
)
static

Definition at line 1834 of file setrefs.c.

1835 {
1836  /* We assume callers won't call us on a NULL pointer */
1837  if (IsA(node, Aggref))
1838  {
1840  ((Aggref *) node)->aggfnoid);
1841  }
1842  else if (IsA(node, WindowFunc))
1843  {
1845  ((WindowFunc *) node)->winfnoid);
1846  }
1847  else if (IsA(node, FuncExpr))
1848  {
1850  ((FuncExpr *) node)->funcid);
1851  }
1852  else if (IsA(node, OpExpr))
1853  {
1854  set_opfuncid((OpExpr *) node);
1856  ((OpExpr *) node)->opfuncid);
1857  }
1858  else if (IsA(node, DistinctExpr))
1859  {
1860  set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1862  ((DistinctExpr *) node)->opfuncid);
1863  }
1864  else if (IsA(node, NullIfExpr))
1865  {
1866  set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1868  ((NullIfExpr *) node)->opfuncid);
1869  }
1870  else if (IsA(node, ScalarArrayOpExpr))
1871  {
1872  ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) node;
1873 
1874  set_sa_opfuncid(saop);
1876 
1877  if (!OidIsValid(saop->hashfuncid))
1879 
1880  if (!OidIsValid(saop->negfuncid))
1882  }
1883  else if (IsA(node, Const))
1884  {
1885  Const *con = (Const *) node;
1886 
1887  /* Check for regclass reference */
1888  if (ISREGCLASSCONST(con))
1889  root->glob->relationOids =
1890  lappend_oid(root->glob->relationOids,
1892  }
1893  else if (IsA(node, GroupingFunc))
1894  {
1895  GroupingFunc *g = (GroupingFunc *) node;
1896  AttrNumber *grouping_map = root->grouping_map;
1897 
1898  /* If there are no grouping sets, we don't need this. */
1899 
1900  Assert(grouping_map || g->cols == NIL);
1901 
1902  if (grouping_map)
1903  {
1904  ListCell *lc;
1905  List *cols = NIL;
1906 
1907  foreach(lc, g->refs)
1908  {
1909  cols = lappend_int(cols, grouping_map[lfirst_int(lc)]);
1910  }
1911 
1912  Assert(!g->cols || equal(cols, g->cols));
1913 
1914  if (!g->cols)
1915  g->cols = cols;
1916  }
1917  }
1918 }
int16 AttrNumber
Definition: attnum.h:21
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3580
List * lappend_int(List *list, int datum)
Definition: list.c:356
void set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
Definition: nodeFuncs.c:1805
void set_opfuncid(OpExpr *opexpr)
Definition: nodeFuncs.c:1794
#define lfirst_int(lc)
Definition: pg_list.h:171
#define DatumGetObjectId(X)
Definition: postgres.h:544
void record_plan_function_dependency(PlannerInfo *root, Oid funcid)
Definition: setrefs.c:3202
#define ISREGCLASSCONST(con)
Definition: setrefs.c:107
Datum constvalue
Definition: primnodes.h:260
List * refs
Definition: primnodes.h:458
List * cols
Definition: primnodes.h:461
Definition: pg_list.h:52
AttrNumber * grouping_map
Definition: pathnodes.h:336

References Assert(), GroupingFunc::cols, Const::constvalue, DatumGetObjectId, equal(), PlannerInfo::glob, PlannerInfo::grouping_map, ScalarArrayOpExpr::hashfuncid, IsA, ISREGCLASSCONST, lappend_int(), lappend_oid(), lfirst_int, ScalarArrayOpExpr::negfuncid, NIL, OidIsValid, ScalarArrayOpExpr::opfuncid, record_plan_function_dependency(), GroupingFunc::refs, PlannerGlobal::relationOids, set_opfuncid(), and set_sa_opfuncid().

Referenced by extract_query_dependencies_walker(), fix_join_expr_mutator(), fix_scan_expr_mutator(), fix_scan_expr_walker(), and fix_upper_expr_mutator().

◆ fix_join_expr()

static List * fix_join_expr ( PlannerInfo root,
List clauses,
indexed_tlist outer_itlist,
indexed_tlist inner_itlist,
Index  acceptable_rel,
int  rtoffset,
double  num_exec 
)
static

Definition at line 2801 of file setrefs.c.

2808 {
2809  fix_join_expr_context context;
2810 
2811  context.root = root;
2812  context.outer_itlist = outer_itlist;
2813  context.inner_itlist = inner_itlist;
2814  context.acceptable_rel = acceptable_rel;
2815  context.rtoffset = rtoffset;
2816  context.num_exec = num_exec;
2817  return (List *) fix_join_expr_mutator((Node *) clauses, &context);
2818 }
static Node * fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
Definition: setrefs.c:2821
indexed_tlist * outer_itlist
Definition: setrefs.c:58
PlannerInfo * root
Definition: setrefs.c:57
indexed_tlist * inner_itlist
Definition: setrefs.c:59

References fix_join_expr_context::acceptable_rel, fix_join_expr_mutator(), fix_join_expr_context::inner_itlist, fix_join_expr_context::num_exec, fix_join_expr_context::outer_itlist, fix_join_expr_context::root, and fix_join_expr_context::rtoffset.

Referenced by set_join_references(), set_plan_refs(), and set_returning_clause_references().

◆ fix_join_expr_mutator()

static Node * fix_join_expr_mutator ( Node node,
fix_join_expr_context context 
)
static

Definition at line 2821 of file setrefs.c.

2822 {
2823  Var *newvar;
2824 
2825  if (node == NULL)
2826  return NULL;
2827  if (IsA(node, Var))
2828  {
2829  Var *var = (Var *) node;
2830 
2831  /* Look for the var in the input tlists, first in the outer */
2832  if (context->outer_itlist)
2833  {
2834  newvar = search_indexed_tlist_for_var(var,
2835  context->outer_itlist,
2836  OUTER_VAR,
2837  context->rtoffset);
2838  if (newvar)
2839  return (Node *) newvar;
2840  }
2841 
2842  /* then in the inner. */
2843  if (context->inner_itlist)
2844  {
2845  newvar = search_indexed_tlist_for_var(var,
2846  context->inner_itlist,
2847  INNER_VAR,
2848  context->rtoffset);
2849  if (newvar)
2850  return (Node *) newvar;
2851  }
2852 
2853  /* If it's for acceptable_rel, adjust and return it */
2854  if (var->varno == context->acceptable_rel)
2855  {
2856  var = copyVar(var);
2857  var->varno += context->rtoffset;
2858  if (var->varnosyn > 0)
2859  var->varnosyn += context->rtoffset;
2860  return (Node *) var;
2861  }
2862 
2863  /* No referent found for Var */
2864  elog(ERROR, "variable not found in subplan target lists");
2865  }
2866  if (IsA(node, PlaceHolderVar))
2867  {
2868  PlaceHolderVar *phv = (PlaceHolderVar *) node;
2869 
2870  /* See if the PlaceHolderVar has bubbled up from a lower plan node */
2871  if (context->outer_itlist && context->outer_itlist->has_ph_vars)
2872  {
2873  newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2874  context->outer_itlist,
2875  OUTER_VAR);
2876  if (newvar)
2877  return (Node *) newvar;
2878  }
2879  if (context->inner_itlist && context->inner_itlist->has_ph_vars)
2880  {
2881  newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2882  context->inner_itlist,
2883  INNER_VAR);
2884  if (newvar)
2885  return (Node *) newvar;
2886  }
2887 
2888  /* If not supplied by input plans, evaluate the contained expr */
2889  return fix_join_expr_mutator((Node *) phv->phexpr, context);
2890  }
2891  /* Try matching more complex expressions too, if tlists have any */
2892  if (context->outer_itlist && context->outer_itlist->has_non_vars)
2893  {
2894  newvar = search_indexed_tlist_for_non_var((Expr *) node,
2895  context->outer_itlist,
2896  OUTER_VAR);
2897  if (newvar)
2898  return (Node *) newvar;
2899  }
2900  if (context->inner_itlist && context->inner_itlist->has_non_vars)
2901  {
2902  newvar = search_indexed_tlist_for_non_var((Expr *) node,
2903  context->inner_itlist,
2904  INNER_VAR);
2905  if (newvar)
2906  return (Node *) newvar;
2907  }
2908  /* Special cases (apply only AFTER failing to match to lower tlist) */
2909  if (IsA(node, Param))
2910  return fix_param_node(context->root, (Param *) node);
2911  if (IsA(node, AlternativeSubPlan))
2913  (AlternativeSubPlan *) node,
2914  context->num_exec),
2915  context);
2916  fix_expr_common(context->root, node);
2917  return expression_tree_mutator(node,
2919  (void *) context);
2920 }
#define ERROR
Definition: elog.h:33
#define OUTER_VAR
Definition: primnodes.h:198
#define INNER_VAR
Definition: primnodes.h:197
static Node * fix_param_node(PlannerInfo *root, Param *p)
Definition: setrefs.c:1929
static Var * search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist, int newvarno, int rtoffset)
Definition: setrefs.c:2651
static Node * fix_alternative_subplan(PlannerInfo *root, AlternativeSubPlan *asplan, double num_exec)
Definition: setrefs.c:1960
static Var * search_indexed_tlist_for_non_var(Expr *node, indexed_tlist *itlist, int newvarno)
Definition: setrefs.c:2691
static Var * copyVar(Var *var)
Definition: setrefs.c:1812
Index varnosyn
Definition: primnodes.h:237

References fix_join_expr_context::acceptable_rel, copyVar(), elog(), ERROR, expression_tree_mutator(), fix_alternative_subplan(), fix_expr_common(), fix_param_node(), indexed_tlist::has_non_vars, indexed_tlist::has_ph_vars, fix_join_expr_context::inner_itlist, INNER_VAR, IsA, fix_join_expr_context::num_exec, fix_join_expr_context::outer_itlist, OUTER_VAR, PlaceHolderVar::phexpr, fix_join_expr_context::root, fix_join_expr_context::rtoffset, search_indexed_tlist_for_non_var(), search_indexed_tlist_for_var(), Var::varno, and Var::varnosyn.

Referenced by fix_join_expr().

◆ fix_param_node()

static Node* fix_param_node ( PlannerInfo root,
Param p 
)
static

Definition at line 1929 of file setrefs.c.

1930 {
1931  if (p->paramkind == PARAM_MULTIEXPR)
1932  {
1933  int subqueryid = p->paramid >> 16;
1934  int colno = p->paramid & 0xFFFF;
1935  List *params;
1936 
1937  if (subqueryid <= 0 ||
1938  subqueryid > list_length(root->multiexpr_params))
1939  elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
1940  params = (List *) list_nth(root->multiexpr_params, subqueryid - 1);
1941  if (colno <= 0 || colno > list_length(params))
1942  elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
1943  return copyObject(list_nth(params, colno - 1));
1944  }
1945  return (Node *) copyObject(p);
1946 }
static void * list_nth(const List *list, int n)
Definition: pg_list.h:297
@ PARAM_MULTIEXPR
Definition: primnodes.h:302
int paramid
Definition: primnodes.h:309
ParamKind paramkind
Definition: primnodes.h:308
List * multiexpr_params
Definition: pathnodes.h:247

References copyObject, elog(), ERROR, list_length(), list_nth(), PlannerInfo::multiexpr_params, PARAM_MULTIEXPR, Param::paramid, and Param::paramkind.

Referenced by fix_join_expr_mutator(), fix_scan_expr_mutator(), and fix_upper_expr_mutator().

◆ fix_scan_expr()

static Node * fix_scan_expr ( PlannerInfo root,
Node node,
int  rtoffset,
double  num_exec 
)
static

Definition at line 2016 of file setrefs.c.

2017 {
2018  fix_scan_expr_context context;
2019 
2020  context.root = root;
2021  context.rtoffset = rtoffset;
2022  context.num_exec = num_exec;
2023 
2024  if (rtoffset != 0 ||
2025  root->multiexpr_params != NIL ||
2026  root->glob->lastPHId != 0 ||
2027  root->minmax_aggs != NIL ||
2028  root->hasAlternativeSubPlans)
2029  {
2030  return fix_scan_expr_mutator(node, &context);
2031  }
2032  else
2033  {
2034  /*
2035  * If rtoffset == 0, we don't need to change any Vars, and if there
2036  * are no MULTIEXPR subqueries then we don't need to replace
2037  * PARAM_MULTIEXPR Params, and if there are no placeholders anywhere
2038  * we won't need to remove them, and if there are no minmax Aggrefs we
2039  * won't need to replace them, and if there are no AlternativeSubPlans
2040  * we won't need to remove them. Then it's OK to just scribble on the
2041  * input node tree instead of copying (since the only change, filling
2042  * in any unset opfuncid fields, is harmless). This saves just enough
2043  * cycles to be noticeable on trivial queries.
2044  */
2045  (void) fix_scan_expr_walker(node, &context);
2046  return node;
2047  }
2048 }
static Node * fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
Definition: setrefs.c:2051
static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
Definition: setrefs.c:2124
Index lastPHId
Definition: pathnodes.h:116
List * minmax_aggs
Definition: pathnodes.h:338
bool hasAlternativeSubPlans
Definition: pathnodes.h:357
PlannerInfo * root
Definition: setrefs.c:50

References fix_scan_expr_mutator(), fix_scan_expr_walker(), PlannerInfo::glob, PlannerInfo::hasAlternativeSubPlans, PlannerGlobal::lastPHId, PlannerInfo::minmax_aggs, PlannerInfo::multiexpr_params, NIL, fix_scan_expr_context::num_exec, fix_scan_expr_context::root, and fix_scan_expr_context::rtoffset.

Referenced by set_plan_refs().

◆ fix_scan_expr_mutator()

static Node * fix_scan_expr_mutator ( Node node,
fix_scan_expr_context context 
)
static

Definition at line 2051 of file setrefs.c.

2052 {
2053  if (node == NULL)
2054  return NULL;
2055  if (IsA(node, Var))
2056  {
2057  Var *var = copyVar((Var *) node);
2058 
2059  Assert(var->varlevelsup == 0);
2060 
2061  /*
2062  * We should not see Vars marked INNER_VAR, OUTER_VAR, or ROWID_VAR.
2063  * But an indexqual expression could contain INDEX_VAR Vars.
2064  */
2065  Assert(var->varno != INNER_VAR);
2066  Assert(var->varno != OUTER_VAR);
2067  Assert(var->varno != ROWID_VAR);
2068  if (!IS_SPECIAL_VARNO(var->varno))
2069  var->varno += context->rtoffset;
2070  if (var->varnosyn > 0)
2071  var->varnosyn += context->rtoffset;
2072  return (Node *) var;
2073  }
2074  if (IsA(node, Param))
2075  return fix_param_node(context->root, (Param *) node);
2076  if (IsA(node, Aggref))
2077  {
2078  Aggref *aggref = (Aggref *) node;
2079 
2080  /* See if the Aggref should be replaced by a Param */
2081  if (context->root->minmax_aggs != NIL &&
2082  list_length(aggref->args) == 1)
2083  {
2084  TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
2085  ListCell *lc;
2086 
2087  foreach(lc, context->root->minmax_aggs)
2088  {
2089  MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
2090 
2091  if (mminfo->aggfnoid == aggref->aggfnoid &&
2092  equal(mminfo->target, curTarget->expr))
2093  return (Node *) copyObject(mminfo->param);
2094  }
2095  }
2096  /* If no match, just fall through to process it normally */
2097  }
2098  if (IsA(node, CurrentOfExpr))
2099  {
2100  CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
2101 
2102  Assert(!IS_SPECIAL_VARNO(cexpr->cvarno));
2103  cexpr->cvarno += context->rtoffset;
2104  return (Node *) cexpr;
2105  }
2106  if (IsA(node, PlaceHolderVar))
2107  {
2108  /* At scan level, we should always just evaluate the contained expr */
2109  PlaceHolderVar *phv = (PlaceHolderVar *) node;
2110 
2111  return fix_scan_expr_mutator((Node *) phv->phexpr, context);
2112  }
2113  if (IsA(node, AlternativeSubPlan))
2115  (AlternativeSubPlan *) node,
2116  context->num_exec),
2117  context);
2118  fix_expr_common(context->root, node);
2120  (void *) context);
2121 }
#define linitial(l)
Definition: pg_list.h:176
#define ROWID_VAR
Definition: primnodes.h:200
#define IS_SPECIAL_VARNO(varno)
Definition: primnodes.h:202
Oid aggfnoid
Definition: primnodes.h:366
Param * param
Definition: pathnodes.h:2690
Expr * target
Definition: pathnodes.h:2678
Index varlevelsup
Definition: primnodes.h:234

References MinMaxAggInfo::aggfnoid, Aggref::aggfnoid, Aggref::args, Assert(), copyObject, copyVar(), CurrentOfExpr::cvarno, equal(), TargetEntry::expr, expression_tree_mutator(), fix_alternative_subplan(), fix_expr_common(), fix_param_node(), INNER_VAR, IS_SPECIAL_VARNO, IsA, lfirst, linitial, list_length(), PlannerInfo::minmax_aggs, NIL, fix_scan_expr_context::num_exec, OUTER_VAR, MinMaxAggInfo::param, PlaceHolderVar::phexpr, fix_scan_expr_context::root, ROWID_VAR, fix_scan_expr_context::rtoffset, MinMaxAggInfo::target, Var::varlevelsup, Var::varno, and Var::varnosyn.

Referenced by fix_scan_expr().

◆ fix_scan_expr_walker()

static bool fix_scan_expr_walker ( Node node,
fix_scan_expr_context context 
)
static

Definition at line 2124 of file setrefs.c.

2125 {
2126  if (node == NULL)
2127  return false;
2128  Assert(!(IsA(node, Var) && ((Var *) node)->varno == ROWID_VAR));
2129  Assert(!IsA(node, PlaceHolderVar));
2130  Assert(!IsA(node, AlternativeSubPlan));
2131  fix_expr_common(context->root, node);
2133  (void *) context);
2134 }

References Assert(), expression_tree_walker(), fix_expr_common(), IsA, fix_scan_expr_context::root, and ROWID_VAR.

Referenced by fix_scan_expr().

◆ fix_upper_expr()

static Node * fix_upper_expr ( PlannerInfo root,
Node node,
indexed_tlist subplan_itlist,
int  newvarno,
int  rtoffset,
double  num_exec 
)
static

Definition at line 2954 of file setrefs.c.

2960 {
2961  fix_upper_expr_context context;
2962 
2963  context.root = root;
2964  context.subplan_itlist = subplan_itlist;
2965  context.newvarno = newvarno;
2966  context.rtoffset = rtoffset;
2967  context.num_exec = num_exec;
2968  return fix_upper_expr_mutator(node, &context);
2969 }
static Node * fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
Definition: setrefs.c:2972
indexed_tlist * subplan_itlist
Definition: setrefs.c:68
PlannerInfo * root
Definition: setrefs.c:67

References fix_upper_expr_mutator(), fix_upper_expr_context::newvarno, fix_upper_expr_context::num_exec, fix_upper_expr_context::root, fix_upper_expr_context::rtoffset, and fix_upper_expr_context::subplan_itlist.

Referenced by set_customscan_references(), set_foreignscan_references(), set_hash_references(), set_indexonlyscan_references(), set_join_references(), and set_upper_references().

◆ fix_upper_expr_mutator()

static Node * fix_upper_expr_mutator ( Node node,
fix_upper_expr_context context 
)
static

Definition at line 2972 of file setrefs.c.

2973 {
2974  Var *newvar;
2975 
2976  if (node == NULL)
2977  return NULL;
2978  if (IsA(node, Var))
2979  {
2980  Var *var = (Var *) node;
2981 
2982  newvar = search_indexed_tlist_for_var(var,
2983  context->subplan_itlist,
2984  context->newvarno,
2985  context->rtoffset);
2986  if (!newvar)
2987  elog(ERROR, "variable not found in subplan target list");
2988  return (Node *) newvar;
2989  }
2990  if (IsA(node, PlaceHolderVar))
2991  {
2992  PlaceHolderVar *phv = (PlaceHolderVar *) node;
2993 
2994  /* See if the PlaceHolderVar has bubbled up from a lower plan node */
2995  if (context->subplan_itlist->has_ph_vars)
2996  {
2997  newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2998  context->subplan_itlist,
2999  context->newvarno);
3000  if (newvar)
3001  return (Node *) newvar;
3002  }
3003  /* If not supplied by input plan, evaluate the contained expr */
3004  return fix_upper_expr_mutator((Node *) phv->phexpr, context);
3005  }
3006  /* Try matching more complex expressions too, if tlist has any */
3007  if (context->subplan_itlist->has_non_vars)
3008  {
3009  newvar = search_indexed_tlist_for_non_var((Expr *) node,
3010  context->subplan_itlist,
3011  context->newvarno);
3012  if (newvar)
3013  return (Node *) newvar;
3014  }
3015  /* Special cases (apply only AFTER failing to match to lower tlist) */
3016  if (IsA(node, Param))
3017  return fix_param_node(context->root, (Param *) node);
3018  if (IsA(node, Aggref))
3019  {
3020  Aggref *aggref = (Aggref *) node;
3021 
3022  /* See if the Aggref should be replaced by a Param */
3023  if (context->root->minmax_aggs != NIL &&
3024  list_length(aggref->args) == 1)
3025  {
3026  TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
3027  ListCell *lc;
3028 
3029  foreach(lc, context->root->minmax_aggs)
3030  {
3031  MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
3032 
3033  if (mminfo->aggfnoid == aggref->aggfnoid &&
3034  equal(mminfo->target, curTarget->expr))
3035  return (Node *) copyObject(mminfo->param);
3036  }
3037  }
3038  /* If no match, just fall through to process it normally */
3039  }
3040  if (IsA(node, AlternativeSubPlan))
3042  (AlternativeSubPlan *) node,
3043  context->num_exec),
3044  context);
3045  fix_expr_common(context->root, node);
3046  return expression_tree_mutator(node,
3048  (void *) context);
3049 }

References MinMaxAggInfo::aggfnoid, Aggref::aggfnoid, Aggref::args, copyObject, elog(), equal(), ERROR, TargetEntry::expr, expression_tree_mutator(), fix_alternative_subplan(), fix_expr_common(), fix_param_node(), indexed_tlist::has_non_vars, indexed_tlist::has_ph_vars, IsA, lfirst, linitial, list_length(), PlannerInfo::minmax_aggs, fix_upper_expr_context::newvarno, NIL, fix_upper_expr_context::num_exec, MinMaxAggInfo::param, PlaceHolderVar::phexpr, fix_upper_expr_context::root, fix_upper_expr_context::rtoffset, search_indexed_tlist_for_non_var(), search_indexed_tlist_for_var(), fix_upper_expr_context::subplan_itlist, and MinMaxAggInfo::target.

Referenced by fix_upper_expr().

◆ fix_windowagg_condition_expr()

static List* fix_windowagg_condition_expr ( PlannerInfo root,
List runcondition,
indexed_tlist subplan_itlist 
)
static

Definition at line 3153 of file setrefs.c.

3156 {
3158 
3159  context.root = root;
3160  context.subplan_itlist = subplan_itlist;
3161  context.newvarno = 0;
3162 
3163  return (List *) fix_windowagg_condition_expr_mutator((Node *) runcondition,
3164  &context);
3165 }
static Node * fix_windowagg_condition_expr_mutator(Node *node, fix_windowagg_cond_context *context)
Definition: setrefs.c:3123
indexed_tlist * subplan_itlist
Definition: setrefs.c:77
PlannerInfo * root
Definition: setrefs.c:76

References fix_windowagg_condition_expr_mutator(), fix_windowagg_cond_context::newvarno, fix_windowagg_cond_context::root, and fix_windowagg_cond_context::subplan_itlist.

Referenced by set_windowagg_runcondition_references().

◆ fix_windowagg_condition_expr_mutator()

static Node* fix_windowagg_condition_expr_mutator ( Node node,
fix_windowagg_cond_context context 
)
static

Definition at line 3123 of file setrefs.c.

3125 {
3126  if (node == NULL)
3127  return NULL;
3128 
3129  if (IsA(node, WindowFunc))
3130  {
3131  Var *newvar;
3132 
3133  newvar = search_indexed_tlist_for_non_var((Expr *) node,
3134  context->subplan_itlist,
3135  context->newvarno);
3136  if (newvar)
3137  return (Node *) newvar;
3138  elog(ERROR, "WindowFunc not found in subplan target lists");
3139  }
3140 
3141  return expression_tree_mutator(node,
3143  (void *) context);
3144 }

References elog(), ERROR, expression_tree_mutator(), IsA, fix_windowagg_cond_context::newvarno, search_indexed_tlist_for_non_var(), and fix_windowagg_cond_context::subplan_itlist.

Referenced by fix_windowagg_condition_expr().

◆ flatten_rtes_walker()

static bool flatten_rtes_walker ( Node node,
PlannerGlobal glob 
)
static

Definition at line 456 of file setrefs.c.

457 {
458  if (node == NULL)
459  return false;
460  if (IsA(node, RangeTblEntry))
461  {
462  RangeTblEntry *rte = (RangeTblEntry *) node;
463 
464  /* As above, we need only save relation RTEs */
465  if (rte->rtekind == RTE_RELATION)
466  add_rte_to_flat_rtable(glob, rte);
467  return false;
468  }
469  if (IsA(node, Query))
470  {
471  /* Recurse into subselects */
472  return query_tree_walker((Query *) node,
474  (void *) glob,
476  }
478  (void *) glob);
479 }
#define QTW_EXAMINE_RTES_BEFORE
Definition: nodeFuncs.h:25
static bool flatten_rtes_walker(Node *node, PlannerGlobal *glob)
Definition: setrefs.c:456

References add_rte_to_flat_rtable(), expression_tree_walker(), IsA, QTW_EXAMINE_RTES_BEFORE, query_tree_walker(), RTE_RELATION, and RangeTblEntry::rtekind.

Referenced by flatten_unplanned_rtes().

◆ flatten_unplanned_rtes()

static void flatten_unplanned_rtes ( PlannerGlobal glob,
RangeTblEntry rte 
)
static

Definition at line 446 of file setrefs.c.

447 {
448  /* Use query_tree_walker to find all RTEs in the parse tree */
449  (void) query_tree_walker(rte->subquery,
451  (void *) glob,
453 }

References flatten_rtes_walker(), QTW_EXAMINE_RTES_BEFORE, query_tree_walker(), and RangeTblEntry::subquery.

Referenced by add_rtes_to_flat_rtable().

◆ offset_relid_set()

static Relids offset_relid_set ( Relids  relids,
int  rtoffset 
)
static

Definition at line 1790 of file setrefs.c.

1791 {
1792  Relids result = NULL;
1793  int rtindex;
1794 
1795  /* If there's no offset to apply, we needn't recompute the value */
1796  if (rtoffset == 0)
1797  return relids;
1798  rtindex = -1;
1799  while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
1800  result = bms_add_member(result, rtindex + rtoffset);
1801  return result;
1802 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1045
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:738

References bms_add_member(), and bms_next_member().

Referenced by set_append_references(), set_customscan_references(), set_foreignscan_references(), and set_mergeappend_references().

◆ record_plan_function_dependency()

void record_plan_function_dependency ( PlannerInfo root,
Oid  funcid 
)

Definition at line 3202 of file setrefs.c.

3203 {
3204  /*
3205  * For performance reasons, we don't bother to track built-in functions;
3206  * we just assume they'll never change (or at least not in ways that'd
3207  * invalidate plans using them). For this purpose we can consider a
3208  * built-in function to be one with OID less than FirstUnpinnedObjectId.
3209  * Note that the OID generator guarantees never to generate such an OID
3210  * after startup, even at OID wraparound.
3211  */
3212  if (funcid >= (Oid) FirstUnpinnedObjectId)
3213  {
3214  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3215 
3216  /*
3217  * It would work to use any syscache on pg_proc, but the easiest is
3218  * PROCOID since we already have the function's OID at hand. Note
3219  * that plancache.c knows we use PROCOID.
3220  */
3221  inval_item->cacheId = PROCOID;
3222  inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
3223  ObjectIdGetDatum(funcid));
3224 
3225  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3226  }
3227 }
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
unsigned int Oid
Definition: postgres_ext.h:31
uint32 hashValue
Definition: plannodes.h:1532
@ PROCOID
Definition: syscache.h:79
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:206
#define FirstUnpinnedObjectId
Definition: transam.h:196

References PlanInvalItem::cacheId, FirstUnpinnedObjectId, GetSysCacheHashValue1, PlannerInfo::glob, PlanInvalItem::hashValue, PlannerGlobal::invalItems, lappend(), makeNode, ObjectIdGetDatum, and PROCOID.

Referenced by fix_expr_common(), inline_function(), and inline_set_returning_function().

◆ record_plan_type_dependency()

void record_plan_type_dependency ( PlannerInfo root,
Oid  typid 
)

Definition at line 3242 of file setrefs.c.

3243 {
3244  /*
3245  * As in record_plan_function_dependency, ignore the possibility that
3246  * someone would change a built-in domain.
3247  */
3248  if (typid >= (Oid) FirstUnpinnedObjectId)
3249  {
3250  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3251 
3252  /*
3253  * It would work to use any syscache on pg_type, but the easiest is
3254  * TYPEOID since we already have the type's OID at hand. Note that
3255  * plancache.c knows we use TYPEOID.
3256  */
3257  inval_item->cacheId = TYPEOID;
3258  inval_item->hashValue = GetSysCacheHashValue1(TYPEOID,
3259  ObjectIdGetDatum(typid));
3260 
3261  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3262  }
3263 }
@ TYPEOID
Definition: syscache.h:114

References PlanInvalItem::cacheId, FirstUnpinnedObjectId, GetSysCacheHashValue1, PlannerInfo::glob, PlanInvalItem::hashValue, PlannerGlobal::invalItems, lappend(), makeNode, ObjectIdGetDatum, and TYPEOID.

Referenced by eval_const_expressions_mutator().

◆ search_indexed_tlist_for_non_var()

static Var * search_indexed_tlist_for_non_var ( Expr node,
indexed_tlist itlist,
int  newvarno 
)
static

Definition at line 2691 of file setrefs.c.

2693 {
2694  TargetEntry *tle;
2695 
2696  /*
2697  * If it's a simple Const, replacing it with a Var is silly, even if there
2698  * happens to be an identical Const below; a Var is more expensive to
2699  * execute than a Const. What's more, replacing it could confuse some
2700  * places in the executor that expect to see simple Consts for, eg,
2701  * dropped columns.
2702  */
2703  if (IsA(node, Const))
2704  return NULL;
2705 
2706  tle = tlist_member(node, itlist->tlist);
2707  if (tle)
2708  {
2709  /* Found a matching subplan output expression */
2710  Var *newvar;
2711 
2712  newvar = makeVarFromTargetEntry(newvarno, tle);
2713  newvar->varnosyn = 0; /* wasn't ever a plain Var */
2714  newvar->varattnosyn = 0;
2715  return newvar;
2716  }
2717  return NULL; /* no match */
2718 }
Var * makeVarFromTargetEntry(int varno, TargetEntry *tle)
Definition: makefuncs.c:104
AttrNumber varattnosyn
Definition: primnodes.h:239
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:68

References IsA, makeVarFromTargetEntry(), indexed_tlist::tlist, tlist_member(), Var::varattnosyn, and Var::varnosyn.

Referenced by fix_join_expr_mutator(), fix_upper_expr_mutator(), and fix_windowagg_condition_expr_mutator().

◆ search_indexed_tlist_for_sortgroupref()

static Var * search_indexed_tlist_for_sortgroupref ( Expr node,
Index  sortgroupref,
indexed_tlist itlist,
int  newvarno 
)
static

Definition at line 2731 of file setrefs.c.

2735 {
2736  ListCell *lc;
2737 
2738  foreach(lc, itlist->tlist)
2739  {
2740  TargetEntry *tle = (TargetEntry *) lfirst(lc);
2741 
2742  /* The equal() check should be redundant, but let's be paranoid */
2743  if (tle->ressortgroupref == sortgroupref &&
2744  equal(node, tle->expr))
2745  {
2746  /* Found a matching subplan output expression */
2747  Var *newvar;
2748 
2749  newvar = makeVarFromTargetEntry(newvarno, tle);
2750  newvar->varnosyn = 0; /* wasn't ever a plain Var */
2751  newvar->varattnosyn = 0;
2752  return newvar;
2753  }
2754  }
2755  return NULL; /* no match */
2756 }
Index ressortgroupref
Definition: primnodes.h:1831

References equal(), TargetEntry::expr, lfirst, makeVarFromTargetEntry(), TargetEntry::ressortgroupref, indexed_tlist::tlist, Var::varattnosyn, and Var::varnosyn.

Referenced by set_upper_references().

◆ search_indexed_tlist_for_var()

static Var * search_indexed_tlist_for_var ( Var var,
indexed_tlist itlist,
int  newvarno,
int  rtoffset 
)
static

Definition at line 2651 of file setrefs.c.

2653 {
2654  int varno = var->varno;
2655  AttrNumber varattno = var->varattno;
2656  tlist_vinfo *vinfo;
2657  int i;
2658 
2659  vinfo = itlist->vars;
2660  i = itlist->num_vars;
2661  while (i-- > 0)
2662  {
2663  if (vinfo->varno == varno && vinfo->varattno == varattno)
2664  {
2665  /* Found a match */
2666  Var *newvar = copyVar(var);
2667 
2668  newvar->varno = newvarno;
2669  newvar->varattno = vinfo->resno;
2670  if (newvar->varnosyn > 0)
2671  newvar->varnosyn += rtoffset;
2672  return newvar;
2673  }
2674  vinfo++;
2675  }
2676  return NULL; /* no match */
2677 }
int i
Definition: isn.c:73

References copyVar(), i, indexed_tlist::num_vars, tlist_vinfo::resno, tlist_vinfo::varattno, Var::varattno, tlist_vinfo::varno, Var::varno, Var::varnosyn, and indexed_tlist::vars.

Referenced by fix_join_expr_mutator(), and fix_upper_expr_mutator().

◆ set_append_references()

static Plan * set_append_references ( PlannerInfo root,
Append aplan,
int  rtoffset 
)
static

Definition at line 1617 of file setrefs.c.

1620 {
1621  ListCell *l;
1622 
1623  /*
1624  * Append, like Sort et al, doesn't actually evaluate its targetlist or
1625  * check quals. If it's got exactly one child plan, then it's not doing
1626  * anything useful at all, and we can strip it out.
1627  */
1628  Assert(aplan->plan.qual == NIL);
1629 
1630  /* First, we gotta recurse on the children */
1631  foreach(l, aplan->appendplans)
1632  {
1633  lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset);
1634  }
1635 
1636  /*
1637  * See if it's safe to get rid of the Append entirely. For this to be
1638  * safe, there must be only one child plan and that child plan's parallel
1639  * awareness must match that of the Append's. The reason for the latter
1640  * is that the if the Append is parallel aware and the child is not then
1641  * the calling plan may execute the non-parallel aware child multiple
1642  * times.
1643  */
1644  if (list_length(aplan->appendplans) == 1 &&
1645  ((Plan *) linitial(aplan->appendplans))->parallel_aware == aplan->plan.parallel_aware)
1646  return clean_up_removed_plan_level((Plan *) aplan,
1647  (Plan *) linitial(aplan->appendplans));
1648 
1649  /*
1650  * Otherwise, clean up the Append as needed. It's okay to do this after
1651  * recursing to the children, because set_dummy_tlist_references doesn't
1652  * look at those.
1653  */
1654  set_dummy_tlist_references((Plan *) aplan, rtoffset);
1655 
1656  aplan->apprelids = offset_relid_set(aplan->apprelids, rtoffset);
1657 
1658  if (aplan->part_prune_info)
1659  {
1660  foreach(l, aplan->part_prune_info->prune_infos)
1661  {
1662  List *prune_infos = lfirst(l);
1663  ListCell *l2;
1664 
1665  foreach(l2, prune_infos)
1666  {
1667  PartitionedRelPruneInfo *pinfo = lfirst(l2);
1668 
1669  pinfo->rtindex += rtoffset;
1670  }
1671  }
1672  }
1673 
1674  /* We don't need to recurse to lefttree or righttree ... */
1675  Assert(aplan->plan.lefttree == NULL);
1676  Assert(aplan->plan.righttree == NULL);
1677 
1678  return (Plan *) aplan;
1679 }
static Relids offset_relid_set(Relids relids, int rtoffset)
Definition: setrefs.c:1790
static void set_dummy_tlist_references(Plan *plan, int rtoffset)
Definition: setrefs.c:2483
static Plan * clean_up_removed_plan_level(Plan *parent, Plan *child)
Definition: setrefs.c:1441
static Plan * set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:536
Plan plan
Definition: plannodes.h:254
List * appendplans
Definition: plannodes.h:256
struct Plan * lefttree
Definition: plannodes.h:144
struct Plan * righttree
Definition: plannodes.h:145
bool parallel_aware
Definition: plannodes.h:130
List * qual
Definition: plannodes.h:143

References Append::appendplans, Append::apprelids, Assert(), clean_up_removed_plan_level(), Plan::lefttree, lfirst, linitial, list_length(), NIL, offset_relid_set(), Plan::parallel_aware, Append::part_prune_info, Append::plan, PartitionPruneInfo::prune_infos, Plan::qual, Plan::righttree, PartitionedRelPruneInfo::rtindex, set_dummy_tlist_references(), and set_plan_refs().

Referenced by set_plan_refs().

◆ set_customscan_references()

static void set_customscan_references ( PlannerInfo root,
CustomScan cscan,
int  rtoffset 
)
static

Definition at line 1544 of file setrefs.c.

1547 {
1548  ListCell *lc;
1549 
1550  /* Adjust scanrelid if it's valid */
1551  if (cscan->scan.scanrelid > 0)
1552  cscan->scan.scanrelid += rtoffset;
1553 
1554  if (cscan->custom_scan_tlist != NIL || cscan->scan.scanrelid == 0)
1555  {
1556  /* Adjust tlist, qual, custom_exprs to reference custom scan tuple */
1558 
1559  cscan->scan.plan.targetlist = (List *)
1560  fix_upper_expr(root,
1561  (Node *) cscan->scan.plan.targetlist,
1562  itlist,
1563  INDEX_VAR,
1564  rtoffset,
1565  NUM_EXEC_TLIST((Plan *) cscan));
1566  cscan->scan.plan.qual = (List *)
1567  fix_upper_expr(root,
1568  (Node *) cscan->scan.plan.qual,
1569  itlist,
1570  INDEX_VAR,
1571  rtoffset,
1572  NUM_EXEC_QUAL((Plan *) cscan));
1573  cscan->custom_exprs = (List *)
1574  fix_upper_expr(root,
1575  (Node *) cscan->custom_exprs,
1576  itlist,
1577  INDEX_VAR,
1578  rtoffset,
1579  NUM_EXEC_QUAL((Plan *) cscan));
1580  pfree(itlist);
1581  /* custom_scan_tlist itself just needs fix_scan_list() adjustments */
1582  cscan->custom_scan_tlist =
1583  fix_scan_list(root, cscan->custom_scan_tlist,
1584  rtoffset, NUM_EXEC_TLIST((Plan *) cscan));
1585  }
1586  else
1587  {
1588  /* Adjust tlist, qual, custom_exprs in the standard way */
1589  cscan->scan.plan.targetlist =
1590  fix_scan_list(root, cscan->scan.plan.targetlist,
1591  rtoffset, NUM_EXEC_TLIST((Plan *) cscan));
1592  cscan->scan.plan.qual =
1593  fix_scan_list(root, cscan->scan.plan.qual,
1594  rtoffset, NUM_EXEC_QUAL((Plan *) cscan));
1595  cscan->custom_exprs =
1596  fix_scan_list(root, cscan->custom_exprs,
1597  rtoffset, NUM_EXEC_QUAL((Plan *) cscan));
1598  }
1599 
1600  /* Adjust child plan-nodes recursively, if needed */
1601  foreach(lc, cscan->custom_plans)
1602  {
1603  lfirst(lc) = set_plan_refs(root, (Plan *) lfirst(lc), rtoffset);
1604  }
1605 
1606  cscan->custom_relids = offset_relid_set(cscan->custom_relids, rtoffset);
1607 }
void pfree(void *pointer)
Definition: mcxt.c:1175
#define INDEX_VAR
Definition: primnodes.h:199
#define NUM_EXEC_QUAL(parentplan)
Definition: setrefs.c:98
static indexed_tlist * build_tlist_index(List *tlist)
Definition: setrefs.c:2550
static Node * fix_upper_expr(PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, int newvarno, int rtoffset, double num_exec)
Definition: setrefs.c:2954
#define NUM_EXEC_TLIST(parentplan)
Definition: setrefs.c:97
#define fix_scan_list(root, lst, rtoffset, num_exec)
Definition: setrefs.c:111
List * custom_scan_tlist
Definition: plannodes.h:726
Scan scan
Definition: plannodes.h:720
Bitmapset * custom_relids
Definition: plannodes.h:727
List * custom_exprs
Definition: plannodes.h:724
List * custom_plans
Definition: plannodes.h:723
Plan plan
Definition: plannodes.h:371
Index scanrelid
Definition: plannodes.h:372

References build_tlist_index(), CustomScan::custom_plans, CustomScan::custom_relids, CustomScan::custom_scan_tlist, fix_scan_list, fix_upper_expr(), INDEX_VAR, lfirst, NIL, NUM_EXEC_QUAL, NUM_EXEC_TLIST, offset_relid_set(), pfree(), Scan::plan, Plan::qual, CustomScan::scan, Scan::scanrelid, set_plan_refs(), and Plan::targetlist.

Referenced by set_plan_refs().

◆ set_dummy_tlist_references()

static void set_dummy_tlist_references ( Plan plan,
int  rtoffset 
)
static

Definition at line 2483 of file setrefs.c.

2484 {
2485  List *output_targetlist;
2486  ListCell *l;
2487 
2488  output_targetlist = NIL;
2489  foreach(l, plan->targetlist)
2490  {
2491  TargetEntry *tle = (TargetEntry *) lfirst(l);
2492  Var *oldvar = (Var *) tle->expr;
2493  Var *newvar;
2494 
2495  /*
2496  * As in search_indexed_tlist_for_non_var(), we prefer to keep Consts
2497  * as Consts, not Vars referencing Consts. Here, there's no speed
2498  * advantage to be had, but it makes EXPLAIN output look cleaner, and
2499  * again it avoids confusing the executor.
2500  */
2501  if (IsA(oldvar, Const))
2502  {
2503  /* just reuse the existing TLE node */
2504  output_targetlist = lappend(output_targetlist, tle);
2505  continue;
2506  }
2507 
2508  newvar = makeVar(OUTER_VAR,
2509  tle->resno,
2510  exprType((Node *) oldvar),
2511  exprTypmod((Node *) oldvar),
2512  exprCollation((Node *) oldvar),
2513  0);
2514  if (IsA(oldvar, Var) &&
2515  oldvar->varnosyn > 0)
2516  {
2517  newvar->varnosyn = oldvar->varnosyn + rtoffset;
2518  newvar->varattnosyn = oldvar->varattnosyn;
2519  }
2520  else
2521  {
2522  newvar->varnosyn = 0; /* wasn't ever a plain Var */
2523  newvar->varattnosyn = 0;
2524  }
2525 
2526  tle = flatCopyTargetEntry(tle);
2527  tle->expr = (Expr *) newvar;
2528  output_targetlist = lappend(output_targetlist, tle);
2529  }
2530  plan->targetlist = output_targetlist;
2531 
2532  /* We don't touch plan->qual here */
2533 }
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:272
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:286
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:788

References TargetEntry::expr, exprCollation(), exprType(), exprTypmod(), flatCopyTargetEntry(), if(), IsA, lappend(), lfirst, makeVar(), NIL, OUTER_VAR, TargetEntry::resno, Plan::targetlist, Var::varattnosyn, and Var::varnosyn.

Referenced by set_append_references(), set_hash_references(), set_mergeappend_references(), and set_plan_refs().

◆ set_foreignscan_references()

static void set_foreignscan_references ( PlannerInfo root,
ForeignScan fscan,
int  rtoffset 
)
static

Definition at line 1462 of file setrefs.c.

1465 {
1466  /* Adjust scanrelid if it's valid */
1467  if (fscan->scan.scanrelid > 0)
1468  fscan->scan.scanrelid += rtoffset;
1469 
1470  if (fscan->fdw_scan_tlist != NIL || fscan->scan.scanrelid == 0)
1471  {
1472  /*
1473  * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals to reference
1474  * foreign scan tuple
1475  */
1477 
1478  fscan->scan.plan.targetlist = (List *)
1479  fix_upper_expr(root,
1480  (Node *) fscan->scan.plan.targetlist,
1481  itlist,
1482  INDEX_VAR,
1483  rtoffset,
1484  NUM_EXEC_TLIST((Plan *) fscan));
1485  fscan->scan.plan.qual = (List *)
1486  fix_upper_expr(root,
1487  (Node *) fscan->scan.plan.qual,
1488  itlist,
1489  INDEX_VAR,
1490  rtoffset,
1491  NUM_EXEC_QUAL((Plan *) fscan));
1492  fscan->fdw_exprs = (List *)
1493  fix_upper_expr(root,
1494  (Node *) fscan->fdw_exprs,
1495  itlist,
1496  INDEX_VAR,
1497  rtoffset,
1498  NUM_EXEC_QUAL((Plan *) fscan));
1499  fscan->fdw_recheck_quals = (List *)
1500  fix_upper_expr(root,
1501  (Node *) fscan->fdw_recheck_quals,
1502  itlist,
1503  INDEX_VAR,
1504  rtoffset,
1505  NUM_EXEC_QUAL((Plan *) fscan));
1506  pfree(itlist);
1507  /* fdw_scan_tlist itself just needs fix_scan_list() adjustments */
1508  fscan->fdw_scan_tlist =
1509  fix_scan_list(root, fscan->fdw_scan_tlist,
1510  rtoffset, NUM_EXEC_TLIST((Plan *) fscan));
1511  }
1512  else
1513  {
1514  /*
1515  * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals in the standard
1516  * way
1517  */
1518  fscan->scan.plan.targetlist =
1519  fix_scan_list(root, fscan->scan.plan.targetlist,
1520  rtoffset, NUM_EXEC_TLIST((Plan *) fscan));
1521  fscan->scan.plan.qual =
1522  fix_scan_list(root, fscan->scan.plan.qual,
1523  rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
1524  fscan->fdw_exprs =
1525  fix_scan_list(root, fscan->fdw_exprs,
1526  rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
1527  fscan->fdw_recheck_quals =
1528  fix_scan_list(root, fscan->fdw_recheck_quals,
1529  rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
1530  }
1531 
1532  fscan->fs_relids = offset_relid_set(fscan->fs_relids, rtoffset);
1533 
1534  /* Adjust resultRelation if it's valid */
1535  if (fscan->resultRelation > 0)
1536  fscan->resultRelation += rtoffset;
1537 }
List * fdw_exprs
Definition: plannodes.h:695
Bitmapset * fs_relids
Definition: plannodes.h:699
Index resultRelation
Definition: plannodes.h:693
List * fdw_recheck_quals
Definition: plannodes.h:698
List * fdw_scan_tlist
Definition: plannodes.h:697

References build_tlist_index(), ForeignScan::fdw_scan_tlist, fix_scan_list, fix_upper_expr(), ForeignScan::fs_relids, INDEX_VAR, NIL, NUM_EXEC_QUAL, NUM_EXEC_TLIST, offset_relid_set(), pfree(), Scan::plan, Plan::qual, ForeignScan::resultRelation, ForeignScan::scan, Scan::scanrelid, and Plan::targetlist.

Referenced by set_plan_refs().

◆ set_hash_references()

static void set_hash_references ( PlannerInfo root,
Plan plan,
int  rtoffset 
)
static

Definition at line 1758 of file setrefs.c.

1759 {
1760  Hash *hplan = (Hash *) plan;
1761  Plan *outer_plan = plan->lefttree;
1762  indexed_tlist *outer_itlist;
1763 
1764  /*
1765  * Hash's hashkeys are used when feeding tuples into the hashtable,
1766  * therefore have them reference Hash's outer plan (which itself is the
1767  * inner plan of the HashJoin).
1768  */
1769  outer_itlist = build_tlist_index(outer_plan->targetlist);
1770  hplan->hashkeys = (List *)
1771  fix_upper_expr(root,
1772  (Node *) hplan->hashkeys,
1773  outer_itlist,
1774  OUTER_VAR,
1775  rtoffset,
1776  NUM_EXEC_QUAL(plan));
1777 
1778  /* Hash doesn't project */
1779  set_dummy_tlist_references(plan, rtoffset);
1780 
1781  /* Hash nodes don't have their own quals */
1782  Assert(plan->qual == NIL);
1783 }
List * hashkeys
Definition: plannodes.h:1174

References Assert(), build_tlist_index(), fix_upper_expr(), Hash::hashkeys, Plan::lefttree, NIL, NUM_EXEC_QUAL, OUTER_VAR, Plan::qual, set_dummy_tlist_references(), and Plan::targetlist.

Referenced by set_plan_refs().

◆ set_indexonlyscan_references()

static Plan * set_indexonlyscan_references ( PlannerInfo root,
IndexOnlyScan plan,
int  rtoffset 
)
static

Definition at line 1231 of file setrefs.c.

1234 {
1235  indexed_tlist *index_itlist;
1236  List *stripped_indextlist;
1237  ListCell *lc;
1238 
1239  /*
1240  * Vars in the plan node's targetlist, qual, and recheckqual must only
1241  * reference columns that the index AM can actually return. To ensure
1242  * this, remove non-returnable columns (which are marked as resjunk) from
1243  * the indexed tlist. We can just drop them because the indexed_tlist
1244  * machinery pays attention to TLE resnos, not physical list position.
1245  */
1246  stripped_indextlist = NIL;
1247  foreach(lc, plan->indextlist)
1248  {
1249  TargetEntry *indextle = (TargetEntry *) lfirst(lc);
1250 
1251  if (!indextle->resjunk)
1252  stripped_indextlist = lappend(stripped_indextlist, indextle);
1253  }
1254 
1255  index_itlist = build_tlist_index(stripped_indextlist);
1256 
1257  plan->scan.scanrelid += rtoffset;
1258  plan->scan.plan.targetlist = (List *)
1259  fix_upper_expr(root,
1260  (Node *) plan->scan.plan.targetlist,
1261  index_itlist,
1262  INDEX_VAR,
1263  rtoffset,
1264  NUM_EXEC_TLIST((Plan *) plan));
1265  plan->scan.plan.qual = (List *)
1266  fix_upper_expr(root,
1267  (Node *) plan->scan.plan.qual,
1268  index_itlist,
1269  INDEX_VAR,
1270  rtoffset,
1271  NUM_EXEC_QUAL((Plan *) plan));
1272  plan->recheckqual = (List *)
1273  fix_upper_expr(root,
1274  (Node *) plan->recheckqual,
1275  index_itlist,
1276  INDEX_VAR,
1277  rtoffset,
1278  NUM_EXEC_QUAL((Plan *) plan));
1279  /* indexqual is already transformed to reference index columns */
1280  plan->indexqual = fix_scan_list(root, plan->indexqual,
1281  rtoffset, 1);
1282  /* indexorderby is already transformed to reference index columns */
1283  plan->indexorderby = fix_scan_list(root, plan->indexorderby,
1284  rtoffset, 1);
1285  /* indextlist must NOT be transformed to reference index columns */
1286  plan->indextlist = fix_scan_list(root, plan->indextlist,
1287  rtoffset, NUM_EXEC_TLIST((Plan *) plan));
1288 
1289  pfree(index_itlist);
1290 
1291  return (Plan *) plan;
1292 }
List * indexqual
Definition: plannodes.h:479
List * recheckqual
Definition: plannodes.h:480
List * indextlist
Definition: plannodes.h:482
List * indexorderby
Definition: plannodes.h:481
bool resjunk
Definition: primnodes.h:1835

References build_tlist_index(), fix_scan_list, fix_upper_expr(), INDEX_VAR, IndexOnlyScan::indexorderby, IndexOnlyScan::indexqual, IndexOnlyScan::indextlist, lappend(), lfirst, NIL, NUM_EXEC_QUAL, NUM_EXEC_TLIST, pfree(), Scan::plan, Plan::qual, IndexOnlyScan::recheckqual, TargetEntry::resjunk, IndexOnlyScan::scan, Scan::scanrelid, and Plan::targetlist.

Referenced by set_plan_refs().

◆ set_join_references()

static void set_join_references ( PlannerInfo root,
Join join,
int  rtoffset 
)
static

Definition at line 2145 of file setrefs.c.

2146 {
2147  Plan *outer_plan = join->plan.lefttree;
2148  Plan *inner_plan = join->plan.righttree;
2149  indexed_tlist *outer_itlist;
2150  indexed_tlist *inner_itlist;
2151 
2152  outer_itlist = build_tlist_index(outer_plan->targetlist);
2153  inner_itlist = build_tlist_index(inner_plan->targetlist);
2154 
2155  /*
2156  * First process the joinquals (including merge or hash clauses). These
2157  * are logically below the join so they can always use all values
2158  * available from the input tlists. It's okay to also handle
2159  * NestLoopParams now, because those couldn't refer to nullable
2160  * subexpressions.
2161  */
2162  join->joinqual = fix_join_expr(root,
2163  join->joinqual,
2164  outer_itlist,
2165  inner_itlist,
2166  (Index) 0,
2167  rtoffset,
2168  NUM_EXEC_QUAL((Plan *) join));
2169 
2170  /* Now do join-type-specific stuff */
2171  if (IsA(join, NestLoop))
2172  {
2173  NestLoop *nl = (NestLoop *) join;
2174  ListCell *lc;
2175 
2176  foreach(lc, nl->nestParams)
2177  {
2178  NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
2179 
2180  nlp->paramval = (Var *) fix_upper_expr(root,
2181  (Node *) nlp->paramval,
2182  outer_itlist,
2183  OUTER_VAR,
2184  rtoffset,
2185  NUM_EXEC_TLIST(outer_plan));
2186  /* Check we replaced any PlaceHolderVar with simple Var */
2187  if (!(IsA(nlp->paramval, Var) &&
2188  nlp->paramval->varno == OUTER_VAR))
2189  elog(ERROR, "NestLoopParam was not reduced to a simple Var");
2190  }
2191  }
2192  else if (IsA(join, MergeJoin))
2193  {
2194  MergeJoin *mj = (MergeJoin *) join;
2195 
2196  mj->mergeclauses = fix_join_expr(root,
2197  mj->mergeclauses,
2198  outer_itlist,
2199  inner_itlist,
2200  (Index) 0,
2201  rtoffset,
2202  NUM_EXEC_QUAL((Plan *) join));
2203  }
2204  else if (IsA(join, HashJoin))
2205  {
2206  HashJoin *hj = (HashJoin *) join;
2207 
2208  hj->hashclauses = fix_join_expr(root,
2209  hj->hashclauses,
2210  outer_itlist,
2211  inner_itlist,
2212  (Index) 0,
2213  rtoffset,
2214  NUM_EXEC_QUAL((Plan *) join));
2215 
2216  /*
2217  * HashJoin's hashkeys are used to look for matching tuples from its
2218  * outer plan (not the Hash node!) in the hashtable.
2219  */
2220  hj->hashkeys = (List *) fix_upper_expr(root,
2221  (Node *) hj->hashkeys,
2222  outer_itlist,
2223  OUTER_VAR,
2224  rtoffset,
2225  NUM_EXEC_QUAL((Plan *) join));
2226  }
2227 
2228  /*
2229  * Now we need to fix up the targetlist and qpqual, which are logically
2230  * above the join. This means they should not re-use any input expression
2231  * that was computed in the nullable side of an outer join. Vars and
2232  * PlaceHolderVars are fine, so we can implement this restriction just by
2233  * clearing has_non_vars in the indexed_tlist structs.
2234  *
2235  * XXX This is a grotty workaround for the fact that we don't clearly
2236  * distinguish between a Var appearing below an outer join and the "same"
2237  * Var appearing above it. If we did, we'd not need to hack the matching
2238  * rules this way.
2239  */
2240  switch (join->jointype)
2241  {
2242  case JOIN_LEFT:
2243  case JOIN_SEMI:
2244  case JOIN_ANTI:
2245  inner_itlist->has_non_vars = false;
2246  break;
2247  case JOIN_RIGHT:
2248  outer_itlist->has_non_vars = false;
2249  break;
2250  case JOIN_FULL:
2251  outer_itlist->has_non_vars = false;
2252  inner_itlist->has_non_vars = false;
2253  break;
2254  default:
2255  break;
2256  }
2257 
2258  join->plan.targetlist = fix_join_expr(root,
2259  join->plan.targetlist,
2260  outer_itlist,
2261  inner_itlist,
2262  (Index) 0,
2263  rtoffset,
2264  NUM_EXEC_TLIST((Plan *) join));
2265  join->plan.qual = fix_join_expr(root,
2266  join->plan.qual,
2267  outer_itlist,
2268  inner_itlist,
2269  (Index) 0,
2270  rtoffset,
2271  NUM_EXEC_QUAL((Plan *) join));
2272 
2273  pfree(outer_itlist);
2274  pfree(inner_itlist);
2275 }
@ JOIN_SEMI
Definition: nodes.h:764
@ JOIN_FULL
Definition: nodes.h:752
@ JOIN_RIGHT
Definition: nodes.h:753
@ JOIN_LEFT
Definition: nodes.h:751
@ JOIN_ANTI
Definition: nodes.h:765
static List * fix_join_expr(PlannerInfo *root, List *clauses, indexed_tlist *outer_itlist, indexed_tlist *inner_itlist, Index acceptable_rel, int rtoffset, double num_exec)
Definition: setrefs.c:2801
List * hashclauses
Definition: plannodes.h:834
List * hashkeys
Definition: plannodes.h:842
List * joinqual
Definition: plannodes.h:764
JoinType jointype
Definition: plannodes.h:762
Plan plan
Definition: plannodes.h:761
List * mergeclauses
Definition: plannodes.h:810
Var * paramval
Definition: plannodes.h:788
List * nestParams
Definition: plannodes.h:781

References build_tlist_index(), elog(), ERROR, fix_join_expr(), fix_upper_expr(), indexed_tlist::has_non_vars, HashJoin::hashclauses, HashJoin::hashkeys, IsA, JOIN_ANTI, JOIN_FULL, JOIN_LEFT, JOIN_RIGHT, JOIN_SEMI, Join::joinqual, Join::jointype, Plan::lefttree, lfirst, MergeJoin::mergeclauses, NestLoop::nestParams, NUM_EXEC_QUAL, NUM_EXEC_TLIST, OUTER_VAR, NestLoopParam::paramval, pfree(), Join::plan, Plan::qual, Plan::righttree, Plan::targetlist, and Var::varno.

Referenced by set_plan_refs().

◆ set_mergeappend_references()

static Plan * set_mergeappend_references ( PlannerInfo root,
MergeAppend mplan,
int  rtoffset 
)
static

Definition at line 1689 of file setrefs.c.

1692 {
1693  ListCell *l;
1694 
1695  /*
1696  * MergeAppend, like Sort et al, doesn't actually evaluate its targetlist
1697  * or check quals. If it's got exactly one child plan, then it's not
1698  * doing anything useful at all, and we can strip it out.
1699  */
1700  Assert(mplan->plan.qual == NIL);
1701 
1702  /* First, we gotta recurse on the children */
1703  foreach(l, mplan->mergeplans)
1704  {
1705  lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset);
1706  }
1707 
1708  /*
1709  * See if it's safe to get rid of the MergeAppend entirely. For this to
1710  * be safe, there must be only one child plan and that child plan's
1711  * parallel awareness must match that of the MergeAppend's. The reason
1712  * for the latter is that the if the MergeAppend is parallel aware and the
1713  * child is not then the calling plan may execute the non-parallel aware
1714  * child multiple times.
1715  */
1716  if (list_length(mplan->mergeplans) == 1 &&
1717  ((Plan *) linitial(mplan->mergeplans))->parallel_aware == mplan->plan.parallel_aware)
1718  return clean_up_removed_plan_level((Plan *) mplan,
1719  (Plan *) linitial(mplan->mergeplans));
1720 
1721  /*
1722  * Otherwise, clean up the MergeAppend as needed. It's okay to do this
1723  * after recursing to the children, because set_dummy_tlist_references
1724  * doesn't look at those.
1725  */
1726  set_dummy_tlist_references((Plan *) mplan, rtoffset);
1727 
1728  mplan->apprelids = offset_relid_set(mplan->apprelids, rtoffset);
1729 
1730  if (mplan->part_prune_info)
1731  {
1732  foreach(l, mplan->part_prune_info->prune_infos)
1733  {
1734  List *prune_infos = lfirst(l);
1735  ListCell *l2;
1736 
1737  foreach(l2, prune_infos)
1738  {
1739  PartitionedRelPruneInfo *pinfo = lfirst(l2);
1740 
1741  pinfo->rtindex += rtoffset;
1742  }
1743  }
1744  }
1745 
1746  /* We don't need to recurse to lefttree or righttree ... */
1747  Assert(mplan->plan.lefttree == NULL);
1748  Assert(mplan->plan.righttree == NULL);
1749 
1750  return (Plan *) mplan;
1751 }
List * mergeplans
Definition: plannodes.h:281

References MergeAppend::apprelids, Assert(), clean_up_removed_plan_level(), Plan::lefttree, lfirst, linitial, list_length(), MergeAppend::mergeplans, NIL, offset_relid_set(), Plan::parallel_aware, MergeAppend::part_prune_info, MergeAppend::plan, PartitionPruneInfo::prune_infos, Plan::qual, Plan::righttree, PartitionedRelPruneInfo::rtindex, set_dummy_tlist_references(), and set_plan_refs().

Referenced by set_plan_refs().

◆ set_param_references()

static void set_param_references ( PlannerInfo root,
Plan plan 
)
static

Definition at line 2359 of file setrefs.c.

2360 {
2361  Assert(IsA(plan, Gather) || IsA(plan, GatherMerge));
2362 
2363  if (plan->lefttree->extParam)
2364  {
2365  PlannerInfo *proot;
2366  Bitmapset *initSetParam = NULL;
2367  ListCell *l;
2368 
2369  for (proot = root; proot != NULL; proot = proot->parent_root)
2370  {
2371  foreach(l, proot->init_plans)
2372  {
2373  SubPlan *initsubplan = (SubPlan *) lfirst(l);
2374  ListCell *l2;
2375 
2376  foreach(l2, initsubplan->setParam)
2377  {
2378  initSetParam = bms_add_member(initSetParam, lfirst_int(l2));
2379  }
2380  }
2381  }
2382 
2383  /*
2384  * Remember the list of all external initplan params that are used by
2385  * the children of Gather or Gather merge node.
2386  */
2387  if (IsA(plan, Gather))
2388  ((Gather *) plan)->initParam =
2389  bms_intersect(plan->lefttree->extParam, initSetParam);
2390  else
2391  ((GatherMerge *) plan)->initParam =
2392  bms_intersect(plan->lefttree->extParam, initSetParam);
2393  }
2394 }
Bitmapset * bms_intersect(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:259
Bitmapset * extParam
Definition: plannodes.h:160
List * init_plans
Definition: pathnodes.h:242
PlannerInfo * parent_root
Definition: pathnodes.h:168
List * setParam
Definition: primnodes.h:891

References Assert(), bms_add_member(), bms_intersect(), Plan::extParam, PlannerInfo::init_plans, IsA, Plan::lefttree, lfirst, lfirst_int, PlannerInfo::parent_root, and SubPlan::setParam.

Referenced by set_plan_refs().

◆ set_plan_references()

Plan* set_plan_references ( PlannerInfo root,
Plan plan 
)

Definition at line 259 of file setrefs.c.

260 {
261  Plan *result;
262  PlannerGlobal *glob = root->glob;
263  int rtoffset = list_length(glob->finalrtable);
264  ListCell *lc;
265 
266  /*
267  * Add all the query's RTEs to the flattened rangetable. The live ones
268  * will have their rangetable indexes increased by rtoffset. (Additional
269  * RTEs, not referenced by the Plan tree, might get added after those.)
270  */
271  add_rtes_to_flat_rtable(root, false);
272 
273  /*
274  * Adjust RT indexes of PlanRowMarks and add to final rowmarks list
275  */
276  foreach(lc, root->rowMarks)
277  {
279  PlanRowMark *newrc;
280 
281  /* flat copy is enough since all fields are scalars */
282  newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark));
283  memcpy(newrc, rc, sizeof(PlanRowMark));
284 
285  /* adjust indexes ... but *not* the rowmarkId */
286  newrc->rti += rtoffset;
287  newrc->prti += rtoffset;
288 
289  glob->finalrowmarks = lappend(glob->finalrowmarks, newrc);
290  }
291 
292  /*
293  * Adjust RT indexes of AppendRelInfos and add to final appendrels list.
294  * We assume the AppendRelInfos were built during planning and don't need
295  * to be copied.
296  */
297  foreach(lc, root->append_rel_list)
298  {
299  AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
300 
301  /* adjust RT indexes */
302  appinfo->parent_relid += rtoffset;
303  appinfo->child_relid += rtoffset;
304 
305  /*
306  * Rather than adjust the translated_vars entries, just drop 'em.
307  * Neither the executor nor EXPLAIN currently need that data.
308  */
309  appinfo->translated_vars = NIL;
310 
311  glob->appendRelations = lappend(glob->appendRelations, appinfo);
312  }
313 
314  /* If needed, create workspace for processing AlternativeSubPlans */
315  if (root->hasAlternativeSubPlans)
316  {
317  root->isAltSubplan = (bool *)
318  palloc0(list_length(glob->subplans) * sizeof(bool));
319  root->isUsedSubplan = (bool *)
320  palloc0(list_length(glob->subplans) * sizeof(bool));
321  }
322 
323  /* Now fix the Plan tree */
324  result = set_plan_refs(root, plan, rtoffset);
325 
326  /*
327  * If we have AlternativeSubPlans, it is likely that we now have some
328  * unreferenced subplans in glob->subplans. To avoid expending cycles on
329  * those subplans later, get rid of them by setting those list entries to
330  * NULL. (Note: we can't do this immediately upon processing an
331  * AlternativeSubPlan, because there may be multiple copies of the
332  * AlternativeSubPlan, and they can get resolved differently.)
333  */
334  if (root->hasAlternativeSubPlans)
335  {
336  foreach(lc, glob->subplans)
337  {
338  int ndx = foreach_current_index(lc);
339 
340  /*
341  * If it was used by some AlternativeSubPlan in this query level,
342  * but wasn't selected as best by any AlternativeSubPlan, then we
343  * don't need it. Do not touch subplans that aren't parts of
344  * AlternativeSubPlans.
345  */
346  if (root->isAltSubplan[ndx] && !root->isUsedSubplan[ndx])
347  lfirst(lc) = NULL;
348  }
349  }
350 
351  return result;
352 }
unsigned char bool
Definition: c.h:402
void * palloc0(Size size)
Definition: mcxt.c:1099
#define lfirst_node(type, lc)
Definition: pg_list.h:174
#define foreach_current_index(cell)
Definition: pg_list.h:401
Index child_relid
Definition: pathnodes.h:2539
List * translated_vars
Definition: pathnodes.h:2566
Index parent_relid
Definition: pathnodes.h:2538
Index prti
Definition: plannodes.h:1350
List * subplans
Definition: pathnodes.h:96
List * appendRelations
Definition: pathnodes.h:108
List * finalrowmarks
Definition: pathnodes.h:104
List * append_rel_list
Definition: pathnodes.h:285
List * rowMarks
Definition: pathnodes.h:289

References add_rtes_to_flat_rtable(), PlannerInfo::append_rel_list, PlannerGlobal::appendRelations, AppendRelInfo::child_relid, PlannerGlobal::finalrowmarks, PlannerGlobal::finalrtable, foreach_current_index, PlannerInfo::glob, PlannerInfo::hasAlternativeSubPlans, PlannerInfo::isAltSubplan, PlannerInfo::isUsedSubplan, lappend(), lfirst, lfirst_node, list_length(), NIL, palloc(), palloc0(), AppendRelInfo::parent_relid, PlanRowMark::prti, PlannerInfo::rowMarks, PlanRowMark::rti, set_plan_refs(), PlannerGlobal::subplans, and AppendRelInfo::translated_vars.

Referenced by set_subqueryscan_references(), and standard_planner().

◆ set_plan_refs()

static Plan * set_plan_refs ( PlannerInfo root,
Plan plan,
int  rtoffset 
)
static

Definition at line 536 of file setrefs.c.

537 {
538  ListCell *l;
539 
540  if (plan == NULL)
541  return NULL;
542 
543  /* Assign this node a unique ID. */
544  plan->plan_node_id = root->glob->lastPlanNodeId++;
545 
546  /*
547  * Plan-type-specific fixes
548  */
549  switch (nodeTag(plan))
550  {
551  case T_SeqScan:
552  {
553  SeqScan *splan = (SeqScan *) plan;
554 
555  splan->scan.scanrelid += rtoffset;
556  splan->scan.plan.targetlist =
557  fix_scan_list(root, splan->scan.plan.targetlist,
558  rtoffset, NUM_EXEC_TLIST(plan));
559  splan->scan.plan.qual =
560  fix_scan_list(root, splan->scan.plan.qual,
561  rtoffset, NUM_EXEC_QUAL(plan));
562  }
563  break;
564  case T_SampleScan:
565  {
566  SampleScan *splan = (SampleScan *) plan;
567 
568  splan->scan.scanrelid += rtoffset;
569  splan->scan.plan.targetlist =
570  fix_scan_list(root, splan->scan.plan.targetlist,
571  rtoffset, NUM_EXEC_TLIST(plan));
572  splan->scan.plan.qual =
573  fix_scan_list(root, splan->scan.plan.qual,
574  rtoffset, NUM_EXEC_QUAL(plan));
575  splan->tablesample = (TableSampleClause *)
576  fix_scan_expr(root, (Node *) splan->tablesample,
577  rtoffset, 1);
578  }
579  break;
580  case T_IndexScan:
581  {
582  IndexScan *splan = (IndexScan *) plan;
583 
584  splan->scan.scanrelid += rtoffset;
585  splan->scan.plan.targetlist =
586  fix_scan_list(root, splan->scan.plan.targetlist,
587  rtoffset, NUM_EXEC_TLIST(plan));
588  splan->scan.plan.qual =
589  fix_scan_list(root, splan->scan.plan.qual,
590  rtoffset, NUM_EXEC_QUAL(plan));
591  splan->indexqual =
592  fix_scan_list(root, splan->indexqual,
593  rtoffset, 1);
594  splan->indexqualorig =
595  fix_scan_list(root, splan->indexqualorig,
596  rtoffset, NUM_EXEC_QUAL(plan));
597  splan->indexorderby =
598  fix_scan_list(root, splan->indexorderby,
599  rtoffset, 1);
600  splan->indexorderbyorig =
601  fix_scan_list(root, splan->indexorderbyorig,
602  rtoffset, NUM_EXEC_QUAL(plan));
603  }
604  break;
605  case T_IndexOnlyScan:
606  {
607  IndexOnlyScan *splan = (IndexOnlyScan *) plan;
608 
609  return set_indexonlyscan_references(root, splan, rtoffset);
610  }
611  break;
612  case T_BitmapIndexScan:
613  {
615 
616  splan->scan.scanrelid += rtoffset;
617  /* no need to fix targetlist and qual */
618  Assert(splan->scan.plan.targetlist == NIL);
619  Assert(splan->scan.plan.qual == NIL);
620  splan->indexqual =
621  fix_scan_list(root, splan->indexqual, rtoffset, 1);
622  splan->indexqualorig =
623  fix_scan_list(root, splan->indexqualorig,
624  rtoffset, NUM_EXEC_QUAL(plan));
625  }
626  break;
627  case T_BitmapHeapScan:
628  {
629  BitmapHeapScan *splan = (BitmapHeapScan *) plan;
630 
631  splan->scan.scanrelid += rtoffset;
632  splan->scan.plan.targetlist =
633  fix_scan_list(root, splan->scan.plan.targetlist,
634  rtoffset, NUM_EXEC_TLIST(plan));
635  splan->scan.plan.qual =
636  fix_scan_list(root, splan->scan.plan.qual,
637  rtoffset, NUM_EXEC_QUAL(plan));
638  splan->bitmapqualorig =
639  fix_scan_list(root, splan->bitmapqualorig,
640  rtoffset, NUM_EXEC_QUAL(plan));
641  }
642  break;
643  case T_TidScan:
644  {
645  TidScan *splan = (TidScan *) plan;
646 
647  splan->scan.scanrelid += rtoffset;
648  splan->scan.plan.targetlist =
649  fix_scan_list(root, splan->scan.plan.targetlist,
650  rtoffset, NUM_EXEC_TLIST(plan));
651  splan->scan.plan.qual =
652  fix_scan_list(root, splan->scan.plan.qual,
653  rtoffset, NUM_EXEC_QUAL(plan));
654  splan->tidquals =
655  fix_scan_list(root, splan->tidquals,
656  rtoffset, 1);
657  }
658  break;
659  case T_TidRangeScan:
660  {
661  TidRangeScan *splan = (TidRangeScan *) plan;
662 
663  splan->scan.scanrelid += rtoffset;
664  splan->scan.plan.targetlist =
665  fix_scan_list(root, splan->scan.plan.targetlist,
666  rtoffset, NUM_EXEC_TLIST(plan));
667  splan->scan.plan.qual =
668  fix_scan_list(root, splan->scan.plan.qual,
669  rtoffset, NUM_EXEC_QUAL(plan));
670  splan->tidrangequals =
671  fix_scan_list(root, splan->tidrangequals,
672  rtoffset, 1);
673  }
674  break;
675  case T_SubqueryScan:
676  /* Needs special treatment, see comments below */
677  return set_subqueryscan_references(root,
678  (SubqueryScan *) plan,
679  rtoffset);
680  case T_FunctionScan:
681  {
682  FunctionScan *splan = (FunctionScan *) plan;
683 
684  splan->scan.scanrelid += rtoffset;
685  splan->scan.plan.targetlist =
686  fix_scan_list(root, splan->scan.plan.targetlist,
687  rtoffset, NUM_EXEC_TLIST(plan));
688  splan->scan.plan.qual =
689  fix_scan_list(root, splan->scan.plan.qual,
690  rtoffset, NUM_EXEC_QUAL(plan));
691  splan->functions =
692  fix_scan_list(root, splan->functions, rtoffset, 1);
693  }
694  break;
695  case T_TableFuncScan:
696  {
697  TableFuncScan *splan = (TableFuncScan *) plan;
698 
699  splan->scan.scanrelid += rtoffset;
700  splan->scan.plan.targetlist =
701  fix_scan_list(root, splan->scan.plan.targetlist,
702  rtoffset, NUM_EXEC_TLIST(plan));
703  splan->scan.plan.qual =
704  fix_scan_list(root, splan->scan.plan.qual,
705  rtoffset, NUM_EXEC_QUAL(plan));
706  splan->tablefunc = (TableFunc *)
707  fix_scan_expr(root, (Node *) splan->tablefunc,
708  rtoffset, 1);
709  }
710  break;
711  case T_ValuesScan:
712  {
713  ValuesScan *splan = (ValuesScan *) plan;
714 
715  splan->scan.scanrelid += rtoffset;
716  splan->scan.plan.targetlist =
717  fix_scan_list(root, splan->scan.plan.targetlist,
718  rtoffset, NUM_EXEC_TLIST(plan));
719  splan->scan.plan.qual =
720  fix_scan_list(root, splan->scan.plan.qual,
721  rtoffset, NUM_EXEC_QUAL(plan));
722  splan->values_lists =
723  fix_scan_list(root, splan->values_lists,
724  rtoffset, 1);
725  }
726  break;
727  case T_CteScan:
728  {
729  CteScan *splan = (CteScan *) plan;
730 
731  splan->scan.scanrelid += rtoffset;
732  splan->scan.plan.targetlist =
733  fix_scan_list(root, splan->scan.plan.targetlist,
734  rtoffset, NUM_EXEC_TLIST(plan));
735  splan->scan.plan.qual =
736  fix_scan_list(root, splan->scan.plan.qual,
737  rtoffset, NUM_EXEC_QUAL(plan));
738  }
739  break;
741  {
743 
744  splan->scan.scanrelid += rtoffset;
745  splan->scan.plan.targetlist =
746  fix_scan_list(root, splan->scan.plan.targetlist,
747  rtoffset, NUM_EXEC_TLIST(plan));
748  splan->scan.plan.qual =
749  fix_scan_list(root, splan->scan.plan.qual,
750  rtoffset, NUM_EXEC_QUAL(plan));
751  }
752  break;
753  case T_WorkTableScan:
754  {
755  WorkTableScan *splan = (WorkTableScan *) plan;
756 
757  splan->scan.scanrelid += rtoffset;
758  splan->scan.plan.targetlist =
759  fix_scan_list(root, splan->scan.plan.targetlist,
760  rtoffset, NUM_EXEC_TLIST(plan));
761  splan->scan.plan.qual =
762  fix_scan_list(root, splan->scan.plan.qual,
763  rtoffset, NUM_EXEC_QUAL(plan));
764  }
765  break;
766  case T_ForeignScan:
767  set_foreignscan_references(root, (ForeignScan *) plan, rtoffset);
768  break;
769  case T_CustomScan:
770  set_customscan_references(root, (CustomScan *) plan, rtoffset);
771  break;
772 
773  case T_NestLoop:
774  case T_MergeJoin:
775  case T_HashJoin:
776  set_join_references(root, (Join *) plan, rtoffset);
777  break;
778 
779  case T_Gather:
780  case T_GatherMerge:
781  {
782  set_upper_references(root, plan, rtoffset);
783  set_param_references(root, plan);
784  }
785  break;
786 
787  case T_Hash:
788  set_hash_references(root, plan, rtoffset);
789  break;
790 
791  case T_Memoize:
792  {
793  Memoize *mplan = (Memoize *) plan;
794 
795  /*
796  * Memoize does not evaluate its targetlist. It just uses the
797  * same targetlist from its outer subnode.
798  */
799  set_dummy_tlist_references(plan, rtoffset);
800 
801  mplan->param_exprs = fix_scan_list(root, mplan->param_exprs,
802  rtoffset,
803  NUM_EXEC_TLIST(plan));
804  break;
805  }
806 
807  case T_Material:
808  case T_Sort:
809  case T_IncrementalSort:
810  case T_Unique:
811  case T_SetOp:
812 
813  /*
814  * These plan types don't actually bother to evaluate their
815  * targetlists, because they just return their unmodified input
816  * tuples. Even though the targetlist won't be used by the
817  * executor, we fix it up for possible use by EXPLAIN (not to
818  * mention ease of debugging --- wrong varnos are very confusing).
819  */
820  set_dummy_tlist_references(plan, rtoffset);
821 
822  /*
823  * Since these plan types don't check quals either, we should not
824  * find any qual expression attached to them.
825  */
826  Assert(plan->qual == NIL);
827  break;
828  case T_LockRows:
829  {
830  LockRows *splan = (LockRows *) plan;
831 
832  /*
833  * Like the plan types above, LockRows doesn't evaluate its
834  * tlist or quals. But we have to fix up the RT indexes in
835  * its rowmarks.
836  */
837  set_dummy_tlist_references(plan, rtoffset);
838  Assert(splan->plan.qual == NIL);
839 
840  foreach(l, splan->rowMarks)
841  {
842  PlanRowMark *rc = (PlanRowMark *) lfirst(l);
843 
844  rc->rti += rtoffset;
845  rc->prti += rtoffset;
846  }
847  }
848  break;
849  case T_Limit:
850  {
851  Limit *splan = (Limit *) plan;
852 
853  /*
854  * Like the plan types above, Limit doesn't evaluate its tlist
855  * or quals. It does have live expressions for limit/offset,
856  * however; and those cannot contain subplan variable refs, so
857  * fix_scan_expr works for them.
858  */
859  set_dummy_tlist_references(plan, rtoffset);
860  Assert(splan->plan.qual == NIL);
861 
862  splan->limitOffset =
863  fix_scan_expr(root, splan->limitOffset, rtoffset, 1);
864  splan->limitCount =
865  fix_scan_expr(root, splan->limitCount, rtoffset, 1);
866  }
867  break;
868  case T_Agg:
869  {
870  Agg *agg = (Agg *) plan;
871 
872  /*
873  * If this node is combining partial-aggregation results, we
874  * must convert its Aggrefs to contain references to the
875  * partial-aggregate subexpressions that will be available
876  * from the child plan node.
877  */
878  if (DO_AGGSPLIT_COMBINE(agg->aggsplit))
879  {
880  plan->targetlist = (List *)
882  NULL);
883  plan->qual = (List *)
885  NULL);
886  }
887 
888  set_upper_references(root, plan, rtoffset);
889  }
890  break;
891  case T_Group:
892  set_upper_references(root, plan, rtoffset);
893  break;
894  case T_WindowAgg:
895  {
896  WindowAgg *wplan = (WindowAgg *) plan;
897 
898  /*
899  * Adjust the WindowAgg's run conditions by swapping the
900  * WindowFuncs references out to instead reference the Var in
901  * the scan slot so that when the executor evaluates the
902  * runCondition, it receives the WindowFunc's value from the
903  * slot that the result has just been stored into rather than
904  * evaluating the WindowFunc all over again.
905  */
907  wplan->runCondition,
908  (Plan *) wplan);
909 
910  set_upper_references(root, plan, rtoffset);
911 
912  /*
913  * Like Limit node limit/offset expressions, WindowAgg has
914  * frame offset expressions, which cannot contain subplan
915  * variable refs, so fix_scan_expr works for them.
916  */
917  wplan->startOffset =
918  fix_scan_expr(root, wplan->startOffset, rtoffset, 1);
919  wplan->endOffset =
920  fix_scan_expr(root, wplan->endOffset, rtoffset, 1);
921  wplan->runCondition = fix_scan_list(root,
922  wplan->runCondition,
923  rtoffset,
924  NUM_EXEC_TLIST(plan));
925  wplan->runConditionOrig = fix_scan_list(root,
926  wplan->runConditionOrig,
927  rtoffset,
928  NUM_EXEC_TLIST(plan));
929  }
930  break;
931  case T_Result:
932  {
933  Result *splan = (Result *) plan;
934 
935  /*
936  * Result may or may not have a subplan; if not, it's more
937  * like a scan node than an upper node.
938  */
939  if (splan->plan.lefttree != NULL)
940  set_upper_references(root, plan, rtoffset);
941  else
942  {
943  /*
944  * The tlist of a childless Result could contain
945  * unresolved ROWID_VAR Vars, in case it's representing a
946  * target relation which is completely empty because of
947  * constraint exclusion. Replace any such Vars by null
948  * constants, as though they'd been resolved for a leaf
949  * scan node that doesn't support them. We could have
950  * fix_scan_expr do this, but since the case is only
951  * expected to occur here, it seems safer to special-case
952  * it here and keep the assertions that ROWID_VARs
953  * shouldn't be seen by fix_scan_expr.
954  */
955  foreach(l, splan->plan.targetlist)
956  {
957  TargetEntry *tle = (TargetEntry *) lfirst(l);
958  Var *var = (Var *) tle->expr;
959 
960  if (var && IsA(var, Var) && var->varno == ROWID_VAR)
961  tle->expr = (Expr *) makeNullConst(var->vartype,
962  var->vartypmod,
963  var->varcollid);
964  }
965 
966  splan->plan.targetlist =
967  fix_scan_list(root, splan->plan.targetlist,
968  rtoffset, NUM_EXEC_TLIST(plan));
969  splan->plan.qual =
970  fix_scan_list(root, splan->plan.qual,
971  rtoffset, NUM_EXEC_QUAL(plan));
972  }
973  /* resconstantqual can't contain any subplan variable refs */
974  splan->resconstantqual =
975  fix_scan_expr(root, splan->resconstantqual, rtoffset, 1);
976  }
977  break;
978  case T_ProjectSet:
979  set_upper_references(root, plan, rtoffset);
980  break;
981  case T_ModifyTable:
982  {
983  ModifyTable *splan = (ModifyTable *) plan;
984  Plan *subplan = outerPlan(splan);
985 
986  Assert(splan->plan.targetlist == NIL);
987  Assert(splan->plan.qual == NIL);
988 
989  splan->withCheckOptionLists =
990  fix_scan_list(root, splan->withCheckOptionLists,
991  rtoffset, 1);
992 
993  if (splan->returningLists)
994  {
995  List *newRL = NIL;
996  ListCell *lcrl,
997  *lcrr;
998 
999  /*
1000  * Pass each per-resultrel returningList through
1001  * set_returning_clause_references().
1002  */
1003  Assert(list_length(splan->returningLists) == list_length(splan->resultRelations));
1004  forboth(lcrl, splan->returningLists,
1005  lcrr, splan->resultRelations)
1006  {
1007  List *rlist = (List *) lfirst(lcrl);
1008  Index resultrel = lfirst_int(lcrr);
1009 
1010  rlist = set_returning_clause_references(root,
1011  rlist,
1012  subplan,
1013  resultrel,
1014  rtoffset);
1015  newRL = lappend(newRL, rlist);
1016  }
1017  splan->returningLists = newRL;
1018 
1019  /*
1020  * Set up the visible plan targetlist as being the same as
1021  * the first RETURNING list. This is for the use of
1022  * EXPLAIN; the executor won't pay any attention to the
1023  * targetlist. We postpone this step until here so that
1024  * we don't have to do set_returning_clause_references()
1025  * twice on identical targetlists.
1026  */
1027  splan->plan.targetlist = copyObject(linitial(newRL));
1028  }
1029 
1030  /*
1031  * We treat ModifyTable with ON CONFLICT as a form of 'pseudo
1032  * join', where the inner side is the EXCLUDED tuple.
1033  * Therefore use fix_join_expr to setup the relevant variables
1034  * to INNER_VAR. We explicitly don't create any OUTER_VARs as
1035  * those are already used by RETURNING and it seems better to
1036  * be non-conflicting.
1037  */
1038  if (splan->onConflictSet)
1039  {
1040  indexed_tlist *itlist;
1041 
1042  itlist = build_tlist_index(splan->exclRelTlist);
1043 
1044  splan->onConflictSet =
1045  fix_join_expr(root, splan->onConflictSet,
1046  NULL, itlist,
1047  linitial_int(splan->resultRelations),
1048  rtoffset, NUM_EXEC_QUAL(plan));
1049 
1050  splan->onConflictWhere = (Node *)
1051  fix_join_expr(root, (List *) splan->onConflictWhere,
1052  NULL, itlist,
1053  linitial_int(splan->resultRelations),
1054  rtoffset, NUM_EXEC_QUAL(plan));
1055 
1056  pfree(itlist);
1057 
1058  splan->exclRelTlist =
1059  fix_scan_list(root, splan->exclRelTlist, rtoffset, 1);
1060  }
1061 
1062  /*
1063  * The MERGE statement produces the target rows by performing
1064  * a right join between the target relation and the source
1065  * relation (which could be a plain relation or a subquery).
1066  * The INSERT and UPDATE actions of the MERGE statement
1067  * require access to the columns from the source relation. We
1068  * arrange things so that the source relation attributes are
1069  * available as INNER_VAR and the target relation attributes
1070  * are available from the scan tuple.
1071  */
1072  if (splan->mergeActionLists != NIL)
1073  {
1074  ListCell *lca,
1075  *lcr;
1076 
1077  /*
1078  * Fix the targetList of individual action nodes so that
1079  * the so-called "source relation" Vars are referenced as
1080  * INNER_VAR. Note that for this to work correctly during
1081  * execution, the ecxt_innertuple must be set to the tuple
1082  * obtained by executing the subplan, which is what
1083  * constitutes the "source relation".
1084  *
1085  * We leave the Vars from the result relation (i.e. the
1086  * target relation) unchanged i.e. those Vars would be
1087  * picked from the scan slot. So during execution, we must
1088  * ensure that ecxt_scantuple is setup correctly to refer
1089  * to the tuple from the target relation.
1090  */
1091  indexed_tlist *itlist;
1092 
1093  itlist = build_tlist_index(subplan->targetlist);
1094 
1095  forboth(lca, splan->mergeActionLists,
1096  lcr, splan->resultRelations)
1097  {
1098  List *mergeActionList = lfirst(lca);
1099  Index resultrel = lfirst_int(lcr);
1100 
1101  foreach(l, mergeActionList)
1102  {
1104 
1105  /* Fix targetList of each action. */
1106  action->targetList = fix_join_expr(root,
1107  action->targetList,
1108  NULL, itlist,
1109  resultrel,
1110  rtoffset,
1111  NUM_EXEC_TLIST(plan));
1112 
1113  /* Fix quals too. */
1114  action->qual = (Node *) fix_join_expr(root,
1115  (List *) action->qual,
1116  NULL, itlist,
1117  resultrel,
1118  rtoffset,
1119  NUM_EXEC_QUAL(plan));
1120  }
1121  }
1122  }
1123 
1124  splan->nominalRelation += rtoffset;
1125  if (splan->rootRelation)
1126  splan->rootRelation += rtoffset;
1127  splan->exclRelRTI += rtoffset;
1128 
1129  foreach(l, splan->resultRelations)
1130  {
1131  lfirst_int(l) += rtoffset;
1132  }
1133  foreach(l, splan->rowMarks)
1134  {
1135  PlanRowMark *rc = (PlanRowMark *) lfirst(l);
1136 
1137  rc->rti += rtoffset;
1138  rc->prti += rtoffset;
1139  }
1140 
1141  /*
1142  * Append this ModifyTable node's final result relation RT
1143  * index(es) to the global list for the plan.
1144  */
1145  root->glob->resultRelations =
1147  splan->resultRelations);
1148  if (splan->rootRelation)
1149  {
1150  root->glob->resultRelations =
1152  splan->rootRelation);
1153  }
1154  }
1155  break;
1156  case T_Append:
1157  /* Needs special treatment, see comments below */
1158  return set_append_references(root,
1159  (Append *) plan,
1160  rtoffset);
1161  case T_MergeAppend:
1162  /* Needs special treatment, see comments below */
1163  return set_mergeappend_references(root,
1164  (MergeAppend *) plan,
1165  rtoffset);
1166  case T_RecursiveUnion:
1167  /* This doesn't evaluate targetlist or check quals either */
1168  set_dummy_tlist_references(plan, rtoffset);
1169  Assert(plan->qual == NIL);
1170  break;
1171  case T_BitmapAnd:
1172  {
1173  BitmapAnd *splan = (BitmapAnd *) plan;
1174 
1175  /* BitmapAnd works like Append, but has no tlist */
1176  Assert(splan->plan.targetlist == NIL);
1177  Assert(splan->plan.qual == NIL);
1178  foreach(l, splan->bitmapplans)
1179  {
1180  lfirst(l) = set_plan_refs(root,
1181  (Plan *) lfirst(l),
1182  rtoffset);
1183  }
1184  }
1185  break;
1186  case T_BitmapOr:
1187  {
1188  BitmapOr *splan = (BitmapOr *) plan;
1189 
1190  /* BitmapOr works like Append, but has no tlist */
1191  Assert(splan->plan.targetlist == NIL);
1192  Assert(splan->plan.qual == NIL);
1193  foreach(l, splan->bitmapplans)
1194  {
1195  lfirst(l) = set_plan_refs(root,
1196  (Plan *) lfirst(l),
1197  rtoffset);
1198  }
1199  }
1200  break;
1201  default:
1202  elog(ERROR, "unrecognized node type: %d",
1203  (int) nodeTag(plan));
1204  break;
1205  }
1206 
1207  /*
1208  * Now recurse into child plans, if any
1209  *
1210  * NOTE: it is essential that we recurse into child plans AFTER we set
1211  * subplan references in this plan's tlist and quals. If we did the
1212  * reference-adjustments bottom-up, then we would fail to match this
1213  * plan's var nodes against the already-modified nodes of the children.
1214  */
1215  plan->lefttree = set_plan_refs(root, plan->lefttree, rtoffset);
1216  plan->righttree = set_plan_refs(root, plan->righttree, rtoffset);
1217 
1218  return plan;
1219 }
Datum lca(PG_FUNCTION_ARGS)
Definition: ltree_op.c:501
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:338
#define nodeTag(nodeptr)
Definition: nodes.h:579
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:839
@ T_Unique
Definition: nodes.h:84
@ T_NamedTuplestoreScan
Definition: nodes.h:69
@ T_TidRangeScan
Definition: nodes.h:63
@ T_TableFuncScan
Definition: nodes.h:67
@ T_FunctionScan
Definition: nodes.h:65
@ T_BitmapOr
Definition: nodes.h:54
@ T_Material
Definition: nodes.h:77
@ T_IndexOnlyScan
Definition: nodes.h:59
@ T_Append
Definition: nodes.h:50
@ T_Gather
Definition: nodes.h:85
@ T_BitmapIndexScan
Definition: nodes.h:60
@ T_RecursiveUnion
Definition: nodes.h:52
@ T_LockRows
Definition: nodes.h:89
@ T_Hash
Definition: nodes.h:87
@ T_TidScan
Definition: nodes.h:62
@ T_Limit
Definition: nodes.h:90
@ T_Memoize
Definition: nodes.h:78
@ T_Sort
Definition: nodes.h:79
@ T_SeqScan
Definition: nodes.h:56
@ T_WindowAgg
Definition: nodes.h:83
@ T_ProjectSet
Definition: nodes.h:48
@ T_MergeJoin
Definition: nodes.h:75
@ T_SampleScan
Definition: nodes.h:57
@ T_ValuesScan
Definition: nodes.h:66
@ T_BitmapAnd
Definition: nodes.h:53
@ T_MergeAppend
Definition: nodes.h:51
@ T_Agg
Definition: nodes.h:82
@ T_CteScan
Definition: nodes.h:68
@ T_NestLoop
Definition: nodes.h:74
@ T_IncrementalSort
Definition: nodes.h:80
@ T_CustomScan
Definition: nodes.h:72
@ T_Group
Definition: nodes.h:81
@ T_ModifyTable
Definition: nodes.h:49
@ T_GatherMerge
Definition: nodes.h:86
@ T_SubqueryScan
Definition: nodes.h:64
@ T_SetOp
Definition: nodes.h:88
@ T_Result
Definition: nodes.h:47
@ T_IndexScan
Definition: nodes.h:58
@ T_BitmapHeapScan
Definition: nodes.h:61
@ T_WorkTableScan
Definition: nodes.h:70
@ T_ForeignScan
Definition: nodes.h:71
@ T_HashJoin
Definition: nodes.h:76
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:465
#define linitial_int(l)
Definition: pg_list.h:177
#define outerPlan(node)
Definition: plannodes.h:172
static SPIPlanPtr splan
Definition: regress.c:264
static void set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:1758
static Plan * set_append_references(PlannerInfo *root, Append *aplan, int rtoffset)
Definition: setrefs.c:1617
static Plan * set_mergeappend_references(PlannerInfo *root, MergeAppend *mplan, int rtoffset)
Definition: setrefs.c:1689
static List * set_returning_clause_references(PlannerInfo *root, List *rlist, Plan *topplan, Index resultRelation, int rtoffset)
Definition: setrefs.c:3080
static List * set_windowagg_runcondition_references(PlannerInfo *root, List *runcondition, Plan *plan)
Definition: setrefs.c:3174
static void set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:2296
static void set_param_references(PlannerInfo *root, Plan *plan)
Definition: setrefs.c:2359
static void set_foreignscan_references(PlannerInfo *root, ForeignScan *fscan, int rtoffset)
Definition: setrefs.c:1462
static Plan * set_subqueryscan_references(PlannerInfo *root, SubqueryScan *plan, int rtoffset)
Definition: setrefs.c:1302
static Plan * set_indexonlyscan_references(PlannerInfo *root, IndexOnlyScan *plan, int rtoffset)
Definition: setrefs.c:1231
static void set_customscan_references(PlannerInfo *root, CustomScan *cscan, int rtoffset)
Definition: setrefs.c:1544
static void set_join_references(PlannerInfo *root, Join *join, int rtoffset)
Definition: setrefs.c:2145
static Node * fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset, double num_exec)
Definition: setrefs.c:2016
Definition: plannodes.h:966
AggSplit aggsplit
Definition: plannodes.h:973
List * param_exprs
Definition: plannodes.h:872
int plan_node_id
Definition: plannodes.h:141
int lastPlanNodeId
Definition: pathnodes.h:120
List * resultRelations
Definition: pathnodes.h:106
Oid vartype
Definition: primnodes.h:224
Oid varcollid
Definition: primnodes.h:228
int32 vartypmod
Definition: primnodes.h:226
Node * endOffset
Definition: plannodes.h:1045
List * runConditionOrig
Definition: plannodes.h:1051
Node * startOffset
Definition: plannodes.h:1042
List * runCondition
Definition: plannodes.h:1048

References generate_unaccent_rules::action, Agg::aggsplit, Assert(), build_tlist_index(), convert_combining_aggrefs(), copyObject, DO_AGGSPLIT_COMBINE, elog(), WindowAgg::endOffset, ERROR, TargetEntry::expr, fix_join_expr(), fix_scan_expr(), fix_scan_list, forboth, PlannerInfo::glob, if(), IsA, lappend(), lappend_int(), PlannerGlobal::lastPlanNodeId, lca(), Plan::lefttree, lfirst, lfirst_int, linitial, linitial_int, list_concat(), list_length(), makeNullConst(), NIL, nodeTag, NUM_EXEC_QUAL, NUM_EXEC_TLIST, outerPlan, Memoize::param_exprs, pfree(), Plan::plan_node_id, PlanRowMark::prti, PlannerGlobal::resultRelations, Plan::righttree, ROWID_VAR, PlanRowMark::rti, WindowAgg::runCondition, WindowAgg::runConditionOrig, set_append_references(), set_customscan_references(), set_dummy_tlist_references(), set_foreignscan_references(), set_hash_references(), set_indexonlyscan_references(), set_join_references(), set_mergeappend_references(), set_param_references(), set_returning_clause_references(), set_subqueryscan_references(), set_upper_references(), set_windowagg_runcondition_references(), splan, WindowAgg::startOffset, T_Agg, T_Append, T_BitmapAnd, T_BitmapHeapScan, T_BitmapIndexScan, T_BitmapOr, T_CteScan, T_CustomScan, T_ForeignScan, T_FunctionScan, T_Gather, T_GatherMerge, T_Group, T_Hash, T_HashJoin, T_IncrementalSort, T_IndexOnlyScan, T_IndexScan, T_Limit, T_LockRows, T_Material, T_Memoize, T_MergeAppend, T_MergeJoin, T_ModifyTable, T_NamedTuplestoreScan, T_NestLoop, T_ProjectSet, T_RecursiveUnion, T_Result, T_SampleScan, T_SeqScan, T_SetOp, T_Sort, T_SubqueryScan, T_TableFuncScan, T_TidRangeScan, T_TidScan, T_Unique, T_ValuesScan, T_WindowAgg, T_WorkTableScan, Plan::targetlist, Var::varcollid, Var::varno, Var::vartype, and Var::vartypmod.

Referenced by set_append_references(), set_customscan_references(), set_mergeappend_references(), and set_plan_references().

◆ set_returning_clause_references()

static List * set_returning_clause_references ( PlannerInfo root,
List rlist,
Plan topplan,
Index  resultRelation,
int  rtoffset 
)
static

Definition at line 3080 of file setrefs.c.

3085 {
3086  indexed_tlist *itlist;
3087 
3088  /*
3089  * We can perform the desired Var fixup by abusing the fix_join_expr
3090  * machinery that formerly handled inner indexscan fixup. We search the
3091  * top plan's targetlist for Vars of non-result relations, and use
3092  * fix_join_expr to convert RETURNING Vars into references to those tlist
3093  * entries, while leaving result-rel Vars as-is.
3094  *
3095  * PlaceHolderVars will also be sought in the targetlist, but no
3096  * more-complex expressions will be. Note that it is not possible for a
3097  * PlaceHolderVar to refer to the result relation, since the result is
3098  * never below an outer join. If that case could happen, we'd have to be
3099  * prepared to pick apart the PlaceHolderVar and evaluate its contained
3100  * expression instead.
3101  */
3102  itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
3103 
3104  rlist = fix_join_expr(root,
3105  rlist,
3106  itlist,
3107  NULL,
3108  resultRelation,
3109  rtoffset,
3110  NUM_EXEC_TLIST(topplan));
3111 
3112  pfree(itlist);
3113 
3114  return rlist;
3115 }
static indexed_tlist * build_tlist_index_other_vars(List *tlist, int ignore_rel)
Definition: setrefs.c:2600

References build_tlist_index_other_vars(), fix_join_expr(), NUM_EXEC_TLIST, pfree(), and Plan::targetlist.

Referenced by set_plan_refs().

◆ set_subqueryscan_references()

static Plan * set_subqueryscan_references ( PlannerInfo root,
SubqueryScan plan,
int  rtoffset 
)
static

Definition at line 1302 of file setrefs.c.

1305 {
1306  RelOptInfo *rel;
1307  Plan *result;
1308 
1309  /* Need to look up the subquery's RelOptInfo, since we need its subroot */
1310  rel = find_base_rel(root, plan->scan.scanrelid);
1311 
1312  /* Recursively process the subplan */
1313  plan->subplan = set_plan_references(rel->subroot, plan->subplan);
1314 
1315  if (trivial_subqueryscan(plan))
1316  {
1317  /*
1318  * We can omit the SubqueryScan node and just pull up the subplan.
1319  */
1320  result = clean_up_removed_plan_level((Plan *) plan, plan->subplan);
1321  }
1322  else
1323  {
1324  /*
1325  * Keep the SubqueryScan node. We have to do the processing that
1326  * set_plan_references would otherwise have done on it. Notice we do
1327  * not do set_upper_references() here, because a SubqueryScan will
1328  * always have been created with correct references to its subplan's
1329  * outputs to begin with.
1330  */
1331  plan->scan.scanrelid += rtoffset;
1332  plan->scan.plan.targetlist =
1333  fix_scan_list(root, plan->scan.plan.targetlist,
1334  rtoffset, NUM_EXEC_TLIST((Plan *) plan));
1335  plan->scan.plan.qual =
1336  fix_scan_list(root, plan->scan.plan.qual,
1337  rtoffset, NUM_EXEC_QUAL((Plan *) plan));
1338 
1339  result = (Plan *) plan;
1340  }
1341 
1342  return result;
1343 }
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:375
bool trivial_subqueryscan(SubqueryScan *plan)
Definition: setrefs.c:1371
Plan * set_plan_references(PlannerInfo *root, Plan *plan)
Definition: setrefs.c:259
Plan * subplan
Definition: plannodes.h:584

References clean_up_removed_plan_level(), find_base_rel(), fix_scan_list, NUM_EXEC_QUAL, NUM_EXEC_TLIST, Scan::plan, Plan::qual, SubqueryScan::scan, Scan::scanrelid, set_plan_references(), SubqueryScan::subplan, RelOptInfo::subroot, Plan::targetlist, and trivial_subqueryscan().

Referenced by set_plan_refs().

◆ set_upper_references()

static void set_upper_references ( PlannerInfo root,
Plan plan,
int  rtoffset 
)
static

Definition at line 2296 of file setrefs.c.

2297 {
2298  Plan *subplan = plan->lefttree;
2299  indexed_tlist *subplan_itlist;
2300  List *output_targetlist;
2301  ListCell *l;
2302 
2303  subplan_itlist = build_tlist_index(subplan->targetlist);
2304 
2305  output_targetlist = NIL;
2306  foreach(l, plan->targetlist)
2307  {
2308  TargetEntry *tle = (TargetEntry *) lfirst(l);
2309  Node *newexpr;
2310 
2311  /* If it's a sort/group item, first try to match by sortref */
2312  if (tle->ressortgroupref != 0)
2313  {
2314  newexpr = (Node *)
2316  tle->ressortgroupref,
2317  subplan_itlist,
2318  OUTER_VAR);
2319  if (!newexpr)
2320  newexpr = fix_upper_expr(root,
2321  (Node *) tle->expr,
2322  subplan_itlist,
2323  OUTER_VAR,
2324  rtoffset,
2325  NUM_EXEC_TLIST(plan));
2326  }
2327  else
2328  newexpr = fix_upper_expr(root,
2329  (Node *) tle->expr,
2330  subplan_itlist,
2331  OUTER_VAR,
2332  rtoffset,
2333  NUM_EXEC_TLIST(plan));
2334  tle = flatCopyTargetEntry(tle);
2335  tle->expr = (Expr *) newexpr;
2336  output_targetlist = lappend(output_targetlist, tle);
2337  }
2338  plan->targetlist = output_targetlist;
2339 
2340  plan->qual = (List *)
2341  fix_upper_expr(root,
2342  (Node *) plan->qual,
2343  subplan_itlist,
2344  OUTER_VAR,
2345  rtoffset,
2346  NUM_EXEC_QUAL(plan));
2347 
2348  pfree(subplan_itlist);
2349 }
static Var * search_indexed_tlist_for_sortgroupref(Expr *node, Index sortgroupref, indexed_tlist *itlist, int newvarno)
Definition: setrefs.c:2731

References build_tlist_index(), TargetEntry::expr, fix_upper_expr(), flatCopyTargetEntry(), lappend(), Plan::lefttree, lfirst, NIL, NUM_EXEC_QUAL, NUM_EXEC_TLIST, OUTER_VAR, pfree(), Plan::qual, TargetEntry::ressortgroupref, search_indexed_tlist_for_sortgroupref(), and Plan::targetlist.

Referenced by set_plan_refs().

◆ set_windowagg_runcondition_references()

static List * set_windowagg_runcondition_references ( PlannerInfo root,
List runcondition,
Plan plan 
)
static

Definition at line 3174 of file setrefs.c.

3177 {
3178  List *newlist;
3179  indexed_tlist *itlist;
3180 
3181  itlist = build_tlist_index(plan->targetlist);
3182 
3183  newlist = fix_windowagg_condition_expr(root, runcondition, itlist);
3184 
3185  pfree(itlist);
3186 
3187  return newlist;
3188 }
static List * fix_windowagg_condition_expr(PlannerInfo *root, List *runcondition, indexed_tlist *subplan_itlist)
Definition: setrefs.c:3153

References build_tlist_index(), fix_windowagg_condition_expr(), pfree(), and Plan::targetlist.

Referenced by set_plan_refs().

◆ trivial_subqueryscan()

bool trivial_subqueryscan ( SubqueryScan plan)

Definition at line 1371 of file setrefs.c.

1372 {
1373  int attrno;
1374  ListCell *lp,
1375  *lc;
1376 
1377  /* We might have detected this already; in which case reuse the result */
1378  if (plan->scanstatus == SUBQUERY_SCAN_TRIVIAL)
1379  return true;
1380  if (plan->scanstatus == SUBQUERY_SCAN_NONTRIVIAL)
1381  return false;
1383  /* Initially, mark the SubqueryScan as non-deletable from the plan tree */
1385 
1386  if (plan->scan.plan.qual != NIL)
1387  return false;
1388 
1389  if (list_length(plan->scan.plan.targetlist) !=
1390  list_length(plan->subplan->targetlist))
1391  return false; /* tlists not same length */
1392 
1393  attrno = 1;
1394  forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
1395  {
1396  TargetEntry *ptle = (TargetEntry *) lfirst(lp);
1397  TargetEntry *ctle = (TargetEntry *) lfirst(lc);
1398 
1399  if (ptle->resjunk != ctle->resjunk)
1400  return false; /* tlist doesn't match junk status */
1401 
1402  /*
1403  * We accept either a Var referencing the corresponding element of the
1404  * subplan tlist, or a Const equaling the subplan element. See
1405  * generate_setop_tlist() for motivation.
1406  */
1407  if (ptle->expr && IsA(ptle->expr, Var))
1408  {
1409  Var *var = (Var *) ptle->expr;
1410 
1411  Assert(var->varno == plan->scan.scanrelid);
1412  Assert(var->varlevelsup == 0);
1413  if (var->varattno != attrno)
1414  return false; /* out of order */
1415  }
1416  else if (ptle->expr && IsA(ptle->expr, Const))
1417  {
1418  if (!equal(ptle->expr, ctle->expr))
1419  return false;
1420  }
1421  else
1422  return false;
1423 
1424  attrno++;
1425  }
1426 
1427  /* Re-mark the SubqueryScan as deletable from the plan tree */
1429 
1430  return true;
1431 }
@ SUBQUERY_SCAN_NONTRIVIAL
Definition: plannodes.h:578
@ SUBQUERY_SCAN_UNKNOWN
Definition: plannodes.h:576
@ SUBQUERY_SCAN_TRIVIAL
Definition: plannodes.h:577
SubqueryScanStatus scanstatus
Definition: plannodes.h:585

References Assert(), equal(), TargetEntry::expr, forboth, IsA, lfirst, list_length(), NIL, Scan::plan, Plan::qual, TargetEntry::resjunk, SubqueryScan::scan, Scan::scanrelid, SubqueryScan::scanstatus, SubqueryScan::subplan, SUBQUERY_SCAN_NONTRIVIAL, SUBQUERY_SCAN_TRIVIAL, SUBQUERY_SCAN_UNKNOWN, Plan::targetlist, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by mark_async_capable_plan(), and set_subqueryscan_references().