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:1199
@ RTE_RELATION
Definition: parsenodes.h:1011
#define NIL
Definition: pg_list.h:66
List * relationOids
Definition: pathnodes.h:126
List * finalrtable
Definition: pathnodes.h:114
List * colcollations
Definition: parsenodes.h:1164
TableFunc * tablefunc
Definition: parsenodes.h:1130
Alias * join_using_alias
Definition: parsenodes.h:1114
struct TableSampleClause * tablesample
Definition: parsenodes.h:1060
List * securityQuals
Definition: parsenodes.h:1186
Query * subquery
Definition: parsenodes.h:1065
List * coltypes
Definition: parsenodes.h:1162
List * joinrightcols
Definition: parsenodes.h:1107
List * values_lists
Definition: parsenodes.h:1135
List * joinaliasvars
Definition: parsenodes.h:1105
List * coltypmods
Definition: parsenodes.h:1163
List * functions
Definition: parsenodes.h:1124
List * joinleftcols
Definition: parsenodes.h:1106
RTEKind rtekind
Definition: parsenodes.h:1030

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:550
Assert(fmt[strlen(fmt) - 1] !='\n')
@ RTE_SUBQUERY
Definition: parsenodes.h:1012
#define IS_DUMMY_REL(r)
Definition: pathnodes.h:1811
@ UPPERREL_FINAL
Definition: pathnodes.h:79
#define lfirst(lc)
Definition: pg_list.h:170
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1211
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:199
Query * parse
Definition: pathnodes.h:196
List * rtable
Definition: parsenodes.h:155
Index relid
Definition: pathnodes.h:862
PlannerInfo * subroot
Definition: pathnodes.h:892

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, 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 2557 of file setrefs.c.

2558 {
2559  indexed_tlist *itlist;
2560  tlist_vinfo *vinfo;
2561  ListCell *l;
2562 
2563  /* Create data structure with enough slots for all tlist entries */
2564  itlist = (indexed_tlist *)
2565  palloc(offsetof(indexed_tlist, vars) +
2566  list_length(tlist) * sizeof(tlist_vinfo));
2567 
2568  itlist->tlist = tlist;
2569  itlist->has_ph_vars = false;
2570  itlist->has_non_vars = false;
2571 
2572  /* Find the Vars and fill in the index array */
2573  vinfo = itlist->vars;
2574  foreach(l, tlist)
2575  {
2576  TargetEntry *tle = (TargetEntry *) lfirst(l);
2577 
2578  if (tle->expr && IsA(tle->expr, Var))
2579  {
2580  Var *var = (Var *) tle->expr;
2581 
2582  vinfo->varno = var->varno;
2583  vinfo->varattno = var->varattno;
2584  vinfo->resno = tle->resno;
2585  vinfo++;
2586  }
2587  else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2588  itlist->has_ph_vars = true;
2589  else
2590  itlist->has_non_vars = true;
2591  }
2592 
2593  itlist->num_vars = (vinfo - itlist->vars);
2594 
2595  return itlist;
2596 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:162
static int list_length(const List *l)
Definition: pg_list.h:150
Expr * expr
Definition: primnodes.h:1555
AttrNumber resno
Definition: primnodes.h:1556
Definition: primnodes.h:205
AttrNumber varattno
Definition: primnodes.h:217
int varno
Definition: primnodes.h:212
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:282

References TargetEntry::expr, indexed_tlist::has_non_vars, indexed_tlist::has_ph_vars, IsA, lfirst, list_length(), indexed_tlist::num_vars, 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 2607 of file setrefs.c.

2608 {
2609  indexed_tlist *itlist;
2610  tlist_vinfo *vinfo;
2611  ListCell *l;
2612 
2613  /* Create data structure with enough slots for all tlist entries */
2614  itlist = (indexed_tlist *)
2615  palloc(offsetof(indexed_tlist, vars) +
2616  list_length(tlist) * sizeof(tlist_vinfo));
2617 
2618  itlist->tlist = tlist;
2619  itlist->has_ph_vars = false;
2620  itlist->has_non_vars = false;
2621 
2622  /* Find the desired Vars and fill in the index array */
2623  vinfo = itlist->vars;
2624  foreach(l, tlist)
2625  {
2626  TargetEntry *tle = (TargetEntry *) lfirst(l);
2627 
2628  if (tle->expr && IsA(tle->expr, Var))
2629  {
2630  Var *var = (Var *) tle->expr;
2631 
2632  if (var->varno != ignore_rel)
2633  {
2634  vinfo->varno = var->varno;
2635  vinfo->varattno = var->varattno;
2636  vinfo->resno = tle->resno;
2637  vinfo++;
2638  }
2639  }
2640  else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2641  itlist->has_ph_vars = true;
2642  }
2643 
2644  itlist->num_vars = (vinfo - itlist->vars);
2645 
2646  return itlist;
2647 }
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, 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:150
List * initPlan
Definition: plannodes.h:154
void apply_tlist_labeling(List *dest_tlist, List *src_tlist)
Definition: tlist.c:318

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 2421 of file setrefs.c.

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

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 1819 of file setrefs.c.

1820 {
1821  Var *newvar = (Var *) palloc(sizeof(Var));
1822 
1823  *newvar = *var;
1824  return newvar;
1825 }

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 3290 of file setrefs.c.

3294 {
3295  PlannerGlobal glob;
3296  PlannerInfo root;
3297 
3298  /* Make up dummy planner state so we can use this module's machinery */
3299  MemSet(&glob, 0, sizeof(glob));
3300  glob.type = T_PlannerGlobal;
3301  glob.relationOids = NIL;
3302  glob.invalItems = NIL;
3303  /* Hack: we use glob.dependsOnRole to collect hasRowSecurity flags */
3304  glob.dependsOnRole = false;
3305 
3306  MemSet(&root, 0, sizeof(root));
3307  root.type = T_PlannerInfo;
3308  root.glob = &glob;
3309 
3310  (void) extract_query_dependencies_walker(query, &root);
3311 
3312  *relationOids = glob.relationOids;
3313  *invalItems = glob.invalItems;
3314  *hasRowSecurity = glob.dependsOnRole;
3315 }
#define MemSet(start, val, len)
Definition: c.h:953
bool extract_query_dependencies_walker(Node *node, PlannerInfo *context)
Definition: setrefs.c:3326
bool dependsOnRole
Definition: pathnodes.h:147
List * invalItems
Definition: pathnodes.h:129

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

Referenced by CompleteCachedPlan(), and RevalidateCachedQuery().

◆ extract_query_dependencies_walker()

bool extract_query_dependencies_walker ( Node node,
PlannerInfo context 
)

Definition at line 3326 of file setrefs.c.

3327 {
3328  if (node == NULL)
3329  return false;
3330  Assert(!IsA(node, PlaceHolderVar));
3331  if (IsA(node, Query))
3332  {
3333  Query *query = (Query *) node;
3334  ListCell *lc;
3335 
3336  if (query->commandType == CMD_UTILITY)
3337  {
3338  /*
3339  * Ignore utility statements, except those (such as EXPLAIN) that
3340  * contain a parsed-but-not-planned query.
3341  */
3342  query = UtilityContainsQuery(query->utilityStmt);
3343  if (query == NULL)
3344  return false;
3345  }
3346 
3347  /* Remember if any Query has RLS quals applied by rewriter */
3348  if (query->hasRowSecurity)
3349  context->glob->dependsOnRole = true;
3350 
3351  /* Collect relation OIDs in this Query's rtable */
3352  foreach(lc, query->rtable)
3353  {
3354  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3355 
3356  if (rte->rtekind == RTE_RELATION)
3357  context->glob->relationOids =
3358  lappend_oid(context->glob->relationOids, rte->relid);
3359  else if (rte->rtekind == RTE_NAMEDTUPLESTORE &&
3360  OidIsValid(rte->relid))
3361  context->glob->relationOids =
3362  lappend_oid(context->glob->relationOids,
3363  rte->relid);
3364  }
3365 
3366  /* And recurse into the query's subexpressions */
3368  (void *) context, 0);
3369  }
3370  /* Extract function dependencies and check for regclass Consts */
3371  fix_expr_common(context, node);
3373  (void *) context);
3374 }
#define OidIsValid(objectId)
Definition: c.h:711
#define query_tree_walker(q, w, c, f)
Definition: nodeFuncs.h:156
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:151
@ CMD_UTILITY
Definition: nodes.h:264
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1018
static void fix_expr_common(PlannerInfo *root, Node *node)
Definition: setrefs.c:1841
bool hasRowSecurity
Definition: parsenodes.h:149
CmdType commandType
Definition: parsenodes.h:124
Node * utilityStmt
Definition: parsenodes.h:136
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 1967 of file setrefs.c.

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

References Assert(), 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 1841 of file setrefs.c.

1842 {
1843  /* We assume callers won't call us on a NULL pointer */
1844  if (IsA(node, Aggref))
1845  {
1847  ((Aggref *) node)->aggfnoid);
1848  }
1849  else if (IsA(node, WindowFunc))
1850  {
1852  ((WindowFunc *) node)->winfnoid);
1853  }
1854  else if (IsA(node, FuncExpr))
1855  {
1857  ((FuncExpr *) node)->funcid);
1858  }
1859  else if (IsA(node, OpExpr))
1860  {
1861  set_opfuncid((OpExpr *) node);
1863  ((OpExpr *) node)->opfuncid);
1864  }
1865  else if (IsA(node, DistinctExpr))
1866  {
1867  set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1869  ((DistinctExpr *) node)->opfuncid);
1870  }
1871  else if (IsA(node, NullIfExpr))
1872  {
1873  set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1875  ((NullIfExpr *) node)->opfuncid);
1876  }
1877  else if (IsA(node, ScalarArrayOpExpr))
1878  {
1879  ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) node;
1880 
1881  set_sa_opfuncid(saop);
1882  record_plan_function_dependency(root, saop->opfuncid);
1883 
1884  if (!OidIsValid(saop->hashfuncid))
1885  record_plan_function_dependency(root, saop->hashfuncid);
1886 
1887  if (!OidIsValid(saop->negfuncid))
1888  record_plan_function_dependency(root, saop->negfuncid);
1889  }
1890  else if (IsA(node, Const))
1891  {
1892  Const *con = (Const *) node;
1893 
1894  /* Check for regclass reference */
1895  if (ISREGCLASSCONST(con))
1896  root->glob->relationOids =
1897  lappend_oid(root->glob->relationOids,
1899  }
1900  else if (IsA(node, GroupingFunc))
1901  {
1902  GroupingFunc *g = (GroupingFunc *) node;
1903  AttrNumber *grouping_map = root->grouping_map;
1904 
1905  /* If there are no grouping sets, we don't need this. */
1906 
1907  Assert(grouping_map || g->cols == NIL);
1908 
1909  if (grouping_map)
1910  {
1911  ListCell *lc;
1912  List *cols = NIL;
1913 
1914  foreach(lc, g->refs)
1915  {
1916  cols = lappend_int(cols, grouping_map[lfirst_int(lc)]);
1917  }
1918 
1919  Assert(!g->cols || equal(cols, g->cols));
1920 
1921  if (!g->cols)
1922  g->cols = cols;
1923  }
1924  }
1925 }
int16 AttrNumber
Definition: attnum.h:21
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:225
List * lappend_int(List *list, int datum)
Definition: list.c:356
void set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
Definition: nodeFuncs.c:1683
void set_opfuncid(OpExpr *opexpr)
Definition: nodeFuncs.c:1672
#define lfirst_int(lc)
Definition: pg_list.h:171
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:590
void record_plan_function_dependency(PlannerInfo *root, Oid funcid)
Definition: setrefs.c:3209
#define ISREGCLASSCONST(con)
Definition: setrefs.c:107
Datum constvalue
Definition: primnodes.h:263
Definition: pg_list.h:52

References Assert(), Const::constvalue, DatumGetObjectId(), equal(), PlannerInfo::glob, IsA, ISREGCLASSCONST, lappend_int(), lappend_oid(), lfirst_int, NIL, OidIsValid, record_plan_function_dependency(), 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 2808 of file setrefs.c.

2815 {
2816  fix_join_expr_context context;
2817 
2818  context.root = root;
2819  context.outer_itlist = outer_itlist;
2820  context.inner_itlist = inner_itlist;
2821  context.acceptable_rel = acceptable_rel;
2822  context.rtoffset = rtoffset;
2823  context.num_exec = num_exec;
2824  return (List *) fix_join_expr_mutator((Node *) clauses, &context);
2825 }
static Node * fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
Definition: setrefs.c:2828
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 2828 of file setrefs.c.

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

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, fix_join_expr_context::root, fix_join_expr_context::rtoffset, search_indexed_tlist_for_non_var(), search_indexed_tlist_for_var(), and Var::varno.

Referenced by fix_join_expr().

◆ fix_param_node()

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

Definition at line 1936 of file setrefs.c.

1937 {
1938  if (p->paramkind == PARAM_MULTIEXPR)
1939  {
1940  int subqueryid = p->paramid >> 16;
1941  int colno = p->paramid & 0xFFFF;
1942  List *params;
1943 
1944  if (subqueryid <= 0 ||
1945  subqueryid > list_length(root->multiexpr_params))
1946  elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
1947  params = (List *) list_nth(root->multiexpr_params, subqueryid - 1);
1948  if (colno <= 0 || colno > list_length(params))
1949  elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
1950  return copyObject(list_nth(params, colno - 1));
1951  }
1952  return (Node *) copyObject(p);
1953 }
static void * list_nth(const List *list, int n)
Definition: pg_list.h:297
@ PARAM_MULTIEXPR
Definition: primnodes.h:305
int paramid
Definition: primnodes.h:312
ParamKind paramkind
Definition: primnodes.h:311
List * multiexpr_params
Definition: pathnodes.h:298

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 2023 of file setrefs.c.

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

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

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, fix_scan_expr_context::root, ROWID_VAR, fix_scan_expr_context::rtoffset, MinMaxAggInfo::target, Var::varlevelsup, and Var::varno.

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 2131 of file setrefs.c.

2132 {
2133  if (node == NULL)
2134  return false;
2135  Assert(!(IsA(node, Var) && ((Var *) node)->varno == ROWID_VAR));
2136  Assert(!IsA(node, PlaceHolderVar));
2137  Assert(!IsA(node, AlternativeSubPlan));
2138  fix_expr_common(context->root, node);
2140  (void *) context);
2141 }

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 2961 of file setrefs.c.

2967 {
2968  fix_upper_expr_context context;
2969 
2970  context.root = root;
2971  context.subplan_itlist = subplan_itlist;
2972  context.newvarno = newvarno;
2973  context.rtoffset = rtoffset;
2974  context.num_exec = num_exec;
2975  return fix_upper_expr_mutator(node, &context);
2976 }
static Node * fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
Definition: setrefs.c:2979
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 2979 of file setrefs.c.

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

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, 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 3160 of file setrefs.c.

3163 {
3165 
3166  context.root = root;
3167  context.subplan_itlist = subplan_itlist;
3168  context.newvarno = 0;
3169 
3170  return (List *) fix_windowagg_condition_expr_mutator((Node *) runcondition,
3171  &context);
3172 }
static Node * fix_windowagg_condition_expr_mutator(Node *node, fix_windowagg_cond_context *context)
Definition: setrefs.c:3130
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 3130 of file setrefs.c.

3132 {
3133  if (node == NULL)
3134  return NULL;
3135 
3136  if (IsA(node, WindowFunc))
3137  {
3138  Var *newvar;
3139 
3140  newvar = search_indexed_tlist_for_non_var((Expr *) node,
3141  context->subplan_itlist,
3142  context->newvarno);
3143  if (newvar)
3144  return (Node *) newvar;
3145  elog(ERROR, "WindowFunc not found in subplan target lists");
3146  }
3147 
3148  return expression_tree_mutator(node,
3150  (void *) context);
3151 }

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:27
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 1797 of file setrefs.c.

1798 {
1799  Relids result = NULL;
1800  int rtindex;
1801 
1802  /* If there's no offset to apply, we needn't recompute the value */
1803  if (rtoffset == 0)
1804  return relids;
1805  rtindex = -1;
1806  while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
1807  result = bms_add_member(result, rtindex + rtoffset);
1808  return result;
1809 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1047
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:739

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 3209 of file setrefs.c.

3210 {
3211  /*
3212  * For performance reasons, we don't bother to track built-in functions;
3213  * we just assume they'll never change (or at least not in ways that'd
3214  * invalidate plans using them). For this purpose we can consider a
3215  * built-in function to be one with OID less than FirstUnpinnedObjectId.
3216  * Note that the OID generator guarantees never to generate such an OID
3217  * after startup, even at OID wraparound.
3218  */
3219  if (funcid >= (Oid) FirstUnpinnedObjectId)
3220  {
3221  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3222 
3223  /*
3224  * It would work to use any syscache on pg_proc, but the easiest is
3225  * PROCOID since we already have the function's OID at hand. Note
3226  * that plancache.c knows we use PROCOID.
3227  */
3228  inval_item->cacheId = PROCOID;
3229  inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
3230  ObjectIdGetDatum(funcid));
3231 
3232  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3233  }
3234 }
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:600
unsigned int Oid
Definition: postgres_ext.h:31
uint32 hashValue
Definition: plannodes.h:1564
@ 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 3249 of file setrefs.c.

3250 {
3251  /*
3252  * As in record_plan_function_dependency, ignore the possibility that
3253  * someone would change a built-in domain.
3254  */
3255  if (typid >= (Oid) FirstUnpinnedObjectId)
3256  {
3257  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3258 
3259  /*
3260  * It would work to use any syscache on pg_type, but the easiest is
3261  * TYPEOID since we already have the type's OID at hand. Note that
3262  * plancache.c knows we use TYPEOID.
3263  */
3264  inval_item->cacheId = TYPEOID;
3265  inval_item->hashValue = GetSysCacheHashValue1(TYPEOID,
3266  ObjectIdGetDatum(typid));
3267 
3268  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3269  }
3270 }
@ 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 2698 of file setrefs.c.

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

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

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 2738 of file setrefs.c.

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

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

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 2658 of file setrefs.c.

2660 {
2661  int varno = var->varno;
2662  AttrNumber varattno = var->varattno;
2663  tlist_vinfo *vinfo;
2664  int i;
2665 
2666  vinfo = itlist->vars;
2667  i = itlist->num_vars;
2668  while (i-- > 0)
2669  {
2670  if (vinfo->varno == varno && vinfo->varattno == varattno)
2671  {
2672  /* Found a match */
2673  Var *newvar = copyVar(var);
2674 
2675  newvar->varno = newvarno;
2676  newvar->varattno = vinfo->resno;
2677  if (newvar->varnosyn > 0)
2678  newvar->varnosyn += rtoffset;
2679  return newvar;
2680  }
2681  vinfo++;
2682  }
2683  return NULL; /* no match */
2684 }
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, 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 the Append's. The reason for the latter is that
1640  * if the Append is parallel aware and the child is not, then the calling
1641  * plan may execute the non-parallel aware child multiple times. (If you
1642  * change these rules, update create_append_path to match.)
1643  */
1644  if (list_length(aplan->appendplans) == 1)
1645  {
1646  Plan *p = (Plan *) linitial(aplan->appendplans);
1647 
1648  if (p->parallel_aware == aplan->plan.parallel_aware)
1649  return clean_up_removed_plan_level((Plan *) aplan, p);
1650  }
1651 
1652  /*
1653  * Otherwise, clean up the Append as needed. It's okay to do this after
1654  * recursing to the children, because set_dummy_tlist_references doesn't
1655  * look at those.
1656  */
1657  set_dummy_tlist_references((Plan *) aplan, rtoffset);
1658 
1659  aplan->apprelids = offset_relid_set(aplan->apprelids, rtoffset);
1660 
1661  if (aplan->part_prune_info)
1662  {
1663  foreach(l, aplan->part_prune_info->prune_infos)
1664  {
1665  List *prune_infos = lfirst(l);
1666  ListCell *l2;
1667 
1668  foreach(l2, prune_infos)
1669  {
1670  PartitionedRelPruneInfo *pinfo = lfirst(l2);
1671 
1672  pinfo->rtindex += rtoffset;
1673  }
1674  }
1675  }
1676 
1677  /* We don't need to recurse to lefttree or righttree ... */
1678  Assert(aplan->plan.lefttree == NULL);
1679  Assert(aplan->plan.righttree == NULL);
1680 
1681  return (Plan *) aplan;
1682 }
static Relids offset_relid_set(Relids relids, int rtoffset)
Definition: setrefs.c:1797
static void set_dummy_tlist_references(Plan *plan, int rtoffset)
Definition: setrefs.c:2490
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
struct PartitionPruneInfo * part_prune_info
Definition: plannodes.h:274
Bitmapset * apprelids
Definition: plannodes.h:263
Plan plan
Definition: plannodes.h:262
List * appendplans
Definition: plannodes.h:264
struct Plan * lefttree
Definition: plannodes.h:152
struct Plan * righttree
Definition: plannodes.h:153
bool parallel_aware
Definition: plannodes.h:138
List * qual
Definition: plannodes.h:151

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:1306
#define INDEX_VAR
Definition: primnodes.h:195
#define NUM_EXEC_QUAL(parentplan)
Definition: setrefs.c:98
static indexed_tlist * build_tlist_index(List *tlist)
Definition: setrefs.c:2557
static Node * fix_upper_expr(PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, int newvarno, int rtoffset, double num_exec)
Definition: setrefs.c:2961
#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:738
Scan scan
Definition: plannodes.h:732
Bitmapset * custom_relids
Definition: plannodes.h:739
List * custom_exprs
Definition: plannodes.h:736
List * custom_plans
Definition: plannodes.h:735
Index scanrelid
Definition: plannodes.h:384

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(), Plan::qual, CustomScan::scan, Scan::scanrelid, and set_plan_refs().

Referenced by set_plan_refs().

◆ set_dummy_tlist_references()

static void set_dummy_tlist_references ( Plan plan,
int  rtoffset 
)
static

Definition at line 2490 of file setrefs.c.

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

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

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:707
Bitmapset * fs_relids
Definition: plannodes.h:711
Index resultRelation
Definition: plannodes.h:705
List * fdw_recheck_quals
Definition: plannodes.h:710
List * fdw_scan_tlist
Definition: plannodes.h:709

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(), Plan::qual, ForeignScan::resultRelation, ForeignScan::scan, and Scan::scanrelid.

Referenced by set_plan_refs().

◆ set_hash_references()

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

Definition at line 1765 of file setrefs.c.

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

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:491
List * recheckqual
Definition: plannodes.h:492
List * indextlist
Definition: plannodes.h:494
List * indexorderby
Definition: plannodes.h:493
bool resjunk
Definition: primnodes.h:1562

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(), IndexOnlyScan::recheckqual, TargetEntry::resjunk, IndexOnlyScan::scan, and Scan::scanrelid.

Referenced by set_plan_refs().

◆ set_join_references()

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

Definition at line 2152 of file setrefs.c.

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

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, lfirst, MergeJoin::mergeclauses, NestLoop::nestParams, NUM_EXEC_QUAL, NUM_EXEC_TLIST, OUTER_VAR, NestLoopParam::paramval, pfree(), 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 1692 of file setrefs.c.

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

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 2366 of file setrefs.c.

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

References Assert(), bms_add_member(), bms_intersect(), Plan::extParam, PlannerInfo::init_plans, IsA, Plan::lefttree, lfirst, lfirst_int, 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:392
void * palloc0(Size size)
Definition: mcxt.c:1230
#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:2746
List * translated_vars
Definition: pathnodes.h:2773
Index parent_relid
Definition: pathnodes.h:2745
Index prti
Definition: plannodes.h:1374
List * subplans
Definition: pathnodes.h:105
List * appendRelations
Definition: pathnodes.h:123
List * finalrowmarks
Definition: pathnodes.h:117
List * append_rel_list
Definition: pathnodes.h:349
List * rowMarks
Definition: pathnodes.h:355

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, 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;
740  case T_NamedTuplestoreScan:
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:337
#define nodeTag(nodeptr)
Definition: nodes.h:116
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:376
#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:180
static SPIPlanPtr splan
Definition: regress.c:265
static void set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:1765
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:1692
static List * set_returning_clause_references(PlannerInfo *root, List *rlist, Plan *topplan, Index resultRelation, int rtoffset)
Definition: setrefs.c:3087
static List * set_windowagg_runcondition_references(PlannerInfo *root, List *runcondition, Plan *plan)
Definition: setrefs.c:3181
static void set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:2303
static void set_param_references(PlannerInfo *root, Plan *plan)
Definition: setrefs.c:2366
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:2152
static Node * fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset, double num_exec)
Definition: setrefs.c:2023
Definition: plannodes.h:988
AggSplit aggsplit
Definition: plannodes.h:995
List * param_exprs
Definition: plannodes.h:894
int plan_node_id
Definition: plannodes.h:149
int lastPlanNodeId
Definition: pathnodes.h:141
List * resultRelations
Definition: pathnodes.h:120
Oid vartype
Definition: primnodes.h:220
Oid varcollid
Definition: primnodes.h:224
int32 vartypmod
Definition: primnodes.h:222
Node * endOffset
Definition: plannodes.h:1067
List * runConditionOrig
Definition: plannodes.h:1073
Node * startOffset
Definition: plannodes.h:1064
List * runCondition
Definition: plannodes.h:1070

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, 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 3087 of file setrefs.c.

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

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:360
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:596

References clean_up_removed_plan_level(), find_base_rel(), fix_scan_list, NUM_EXEC_QUAL, NUM_EXEC_TLIST, Plan::qual, SubqueryScan::scan, Scan::scanrelid, set_plan_references(), SubqueryScan::subplan, RelOptInfo::subroot, 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 2303 of file setrefs.c.

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

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 3181 of file setrefs.c.

3184 {
3185  List *newlist;
3186  indexed_tlist *itlist;
3187 
3188  itlist = build_tlist_index(plan->targetlist);
3189 
3190  newlist = fix_windowagg_condition_expr(root, runcondition, itlist);
3191 
3192  pfree(itlist);
3193 
3194  return newlist;
3195 }
static List * fix_windowagg_condition_expr(PlannerInfo *root, List *runcondition, indexed_tlist *subplan_itlist)
Definition: setrefs.c:3160

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:590
@ SUBQUERY_SCAN_UNKNOWN
Definition: plannodes.h:588
@ SUBQUERY_SCAN_TRIVIAL
Definition: plannodes.h:589
SubqueryScanStatus scanstatus
Definition: plannodes.h:597

References Assert(), equal(), TargetEntry::expr, forboth, IsA, lfirst, list_length(), NIL, 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().