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
 

Macros

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

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 bool trivial_subqueryscan (SubqueryScan *plan)
 
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)
 
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, Index newvarno, int rtoffset)
 
static Varsearch_indexed_tlist_for_non_var (Expr *node, indexed_tlist *itlist, Index newvarno)
 
static Varsearch_indexed_tlist_for_sortgroupref (Expr *node, Index sortgroupref, indexed_tlist *itlist, Index newvarno)
 
static Listfix_join_expr (PlannerInfo *root, List *clauses, indexed_tlist *outer_itlist, indexed_tlist *inner_itlist, Index acceptable_rel, int rtoffset)
 
static Nodefix_join_expr_mutator (Node *node, fix_join_expr_context *context)
 
static Nodefix_upper_expr (PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, Index newvarno, int rtoffset)
 
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)
 
Planset_plan_references (PlannerInfo *root, Plan *plan)
 
static VarcopyVar (Var *var)
 
static void fix_expr_common (PlannerInfo *root, Node *node)
 
static Nodefix_param_node (PlannerInfo *root, Param *p)
 
static indexed_tlistbuild_tlist_index_other_vars (List *tlist, Index ignore_rel)
 
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 
)    ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset))

◆ ISREGCLASSCONST

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

Definition at line 78 of file setrefs.c.

Referenced by fix_expr_common().

Function Documentation

◆ add_rte_to_flat_rtable()

static void add_rte_to_flat_rtable ( PlannerGlobal glob,
RangeTblEntry rte 
)
static

Definition at line 419 of file setrefs.c.

References RangeTblEntry::colcollations, RangeTblEntry::coltypes, RangeTblEntry::coltypmods, ereport, errcode(), errmsg(), ERROR, PlannerGlobal::finalrtable, RangeTblEntry::functions, IS_SPECIAL_VARNO, RangeTblEntry::joinaliasvars, RangeTblEntry::joinleftcols, RangeTblEntry::joinrightcols, lappend(), lappend_oid(), list_length(), 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().

420 {
421  RangeTblEntry *newrte;
422 
423  /* flat copy to duplicate all the scalar fields */
424  newrte = (RangeTblEntry *) palloc(sizeof(RangeTblEntry));
425  memcpy(newrte, rte, sizeof(RangeTblEntry));
426 
427  /* zap unneeded sub-structure */
428  newrte->tablesample = NULL;
429  newrte->subquery = NULL;
430  newrte->joinaliasvars = NIL;
431  newrte->joinleftcols = NIL;
432  newrte->joinrightcols = NIL;
433  newrte->functions = NIL;
434  newrte->tablefunc = NULL;
435  newrte->values_lists = NIL;
436  newrte->coltypes = NIL;
437  newrte->coltypmods = NIL;
438  newrte->colcollations = NIL;
439  newrte->securityQuals = NIL;
440 
441  glob->finalrtable = lappend(glob->finalrtable, newrte);
442 
443  /*
444  * Check for RT index overflow; it's very unlikely, but if it did happen,
445  * the executor would get confused by varnos that match the special varno
446  * values.
447  */
449  ereport(ERROR,
450  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
451  errmsg("too many range table entries")));
452 
453  /*
454  * If it's a plain relation RTE, add the table to relationOids.
455  *
456  * We do this even though the RTE might be unreferenced in the plan tree;
457  * this would correspond to cases such as views that were expanded, child
458  * tables that were eliminated by constraint exclusion, etc. Schema
459  * invalidation on such a rel must still force rebuilding of the plan.
460  *
461  * Note we don't bother to avoid making duplicate list entries. We could,
462  * but it would probably cost more cycles than it would save.
463  */
464  if (newrte->rtekind == RTE_RELATION)
465  glob->relationOids = lappend_oid(glob->relationOids, newrte->relid);
466 }
#define NIL
Definition: pg_list.h:65
List * joinaliasvars
Definition: parsenodes.h:1051
List * securityQuals
Definition: parsenodes.h:1125
List * coltypmods
Definition: parsenodes.h:1102
int errcode(int sqlerrcode)
Definition: elog.c:610
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
List * colcollations
Definition: parsenodes.h:1103
List * values_lists
Definition: parsenodes.h:1074
#define IS_SPECIAL_VARNO(varno)
Definition: primnodes.h:175
#define ERROR
Definition: elog.h:43
TableFunc * tablefunc
Definition: parsenodes.h:1069
List * joinrightcols
Definition: parsenodes.h:1053
List * lappend(List *list, void *datum)
Definition: list.c:321
#define ereport(elevel,...)
Definition: elog.h:144
List * joinleftcols
Definition: parsenodes.h:1052
List * functions
Definition: parsenodes.h:1063
static int list_length(const List *l)
Definition: pg_list.h:169
List * relationOids
Definition: pathnodes.h:127
RTEKind rtekind
Definition: parsenodes.h:976
List * finalrtable
Definition: pathnodes.h:117
Query * subquery
Definition: parsenodes.h:1011
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:824
List * coltypes
Definition: parsenodes.h:1101
struct TableSampleClause * tablesample
Definition: parsenodes.h:1006

◆ add_rtes_to_flat_rtable()

static void add_rtes_to_flat_rtable ( PlannerInfo root,
bool  recursing 
)
static

Definition at line 287 of file setrefs.c.

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

Referenced by set_plan_references().

288 {
289  PlannerGlobal *glob = root->glob;
290  Index rti;
291  ListCell *lc;
292 
293  /*
294  * Add the query's own RTEs to the flattened rangetable.
295  *
296  * At top level, we must add all RTEs so that their indexes in the
297  * flattened rangetable match up with their original indexes. When
298  * recursing, we only care about extracting relation RTEs.
299  */
300  foreach(lc, root->parse->rtable)
301  {
302  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
303 
304  if (!recursing || rte->rtekind == RTE_RELATION)
305  add_rte_to_flat_rtable(glob, rte);
306  }
307 
308  /*
309  * If there are any dead subqueries, they are not referenced in the Plan
310  * tree, so we must add RTEs contained in them to the flattened rtable
311  * separately. (If we failed to do this, the executor would not perform
312  * expected permission checks for tables mentioned in such subqueries.)
313  *
314  * Note: this pass over the rangetable can't be combined with the previous
315  * one, because that would mess up the numbering of the live RTEs in the
316  * flattened rangetable.
317  */
318  rti = 1;
319  foreach(lc, root->parse->rtable)
320  {
321  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
322 
323  /*
324  * We should ignore inheritance-parent RTEs: their contents have been
325  * pulled up into our rangetable already. Also ignore any subquery
326  * RTEs without matching RelOptInfos, as they likewise have been
327  * pulled up.
328  */
329  if (rte->rtekind == RTE_SUBQUERY && !rte->inh &&
330  rti < root->simple_rel_array_size)
331  {
332  RelOptInfo *rel = root->simple_rel_array[rti];
333 
334  if (rel != NULL)
335  {
336  Assert(rel->relid == rti); /* sanity check on array */
337 
338  /*
339  * The subquery might never have been planned at all, if it
340  * was excluded on the basis of self-contradictory constraints
341  * in our query level. In this case apply
342  * flatten_unplanned_rtes.
343  *
344  * If it was planned but the result rel is dummy, we assume
345  * that it has been omitted from our plan tree (see
346  * set_subquery_pathlist), and recurse to pull up its RTEs.
347  *
348  * Otherwise, it should be represented by a SubqueryScan node
349  * somewhere in our plan tree, and we'll pull up its RTEs when
350  * we process that plan node.
351  *
352  * However, if we're recursing, then we should pull up RTEs
353  * whether the subquery is dummy or not, because we've found
354  * that some upper query level is treating this one as dummy,
355  * and so we won't scan this level's plan tree at all.
356  */
357  if (rel->subroot == NULL)
358  flatten_unplanned_rtes(glob, rte);
359  else if (recursing ||
361  UPPERREL_FINAL, NULL)))
362  add_rtes_to_flat_rtable(rel->subroot, true);
363  }
364  }
365  rti++;
366  }
367 }
Query * parse
Definition: pathnodes.h:179
static void flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte)
Definition: setrefs.c:373
static void add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte)
Definition: setrefs.c:419
struct RelOptInfo ** simple_rel_array
Definition: pathnodes.h:203
PlannerInfo * subroot
Definition: pathnodes.h:709
List * rtable
Definition: parsenodes.h:137
#define IS_DUMMY_REL(r)
Definition: pathnodes.h:1418
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1192
PlannerGlobal * glob
Definition: pathnodes.h:181
Index relid
Definition: pathnodes.h:693
unsigned int Index
Definition: c.h:482
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
static void add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
Definition: setrefs.c:287
RTEKind rtekind
Definition: parsenodes.h:976

◆ build_tlist_index()

static indexed_tlist * build_tlist_index ( List tlist)
static

Definition at line 2152 of file setrefs.c.

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

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

2153 {
2154  indexed_tlist *itlist;
2155  tlist_vinfo *vinfo;
2156  ListCell *l;
2157 
2158  /* Create data structure with enough slots for all tlist entries */
2159  itlist = (indexed_tlist *)
2161  list_length(tlist) * sizeof(tlist_vinfo));
2162 
2163  itlist->tlist = tlist;
2164  itlist->has_ph_vars = false;
2165  itlist->has_non_vars = false;
2166 
2167  /* Find the Vars and fill in the index array */
2168  vinfo = itlist->vars;
2169  foreach(l, tlist)
2170  {
2171  TargetEntry *tle = (TargetEntry *) lfirst(l);
2172 
2173  if (tle->expr && IsA(tle->expr, Var))
2174  {
2175  Var *var = (Var *) tle->expr;
2176 
2177  vinfo->varno = var->varno;
2178  vinfo->varattno = var->varattno;
2179  vinfo->resno = tle->resno;
2180  vinfo++;
2181  }
2182  else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2183  itlist->has_ph_vars = true;
2184  else
2185  itlist->has_non_vars = true;
2186  }
2187 
2188  itlist->num_vars = (vinfo - itlist->vars);
2189 
2190  return itlist;
2191 }
Index varno
Definition: setrefs.c:34
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
tlist_vinfo vars[FLEXIBLE_ARRAY_MEMBER]
Definition: setrefs.c:45
AttrNumber resno
Definition: setrefs.c:36
AttrNumber varattno
Definition: primnodes.h:186
Definition: primnodes.h:181
AttrNumber varattno
Definition: setrefs.c:35
bool has_ph_vars
Definition: setrefs.c:43
int num_vars
Definition: setrefs.c:42
AttrNumber resno
Definition: primnodes.h:1408
Index varno
Definition: primnodes.h:184
bool has_non_vars
Definition: setrefs.c:44
#define lfirst(lc)
Definition: pg_list.h:190
Expr * expr
Definition: primnodes.h:1407
static int list_length(const List *l)
Definition: pg_list.h:169
void * palloc(Size size)
Definition: mcxt.c:949
Definition: regcomp.c:224
#define offsetof(type, field)
Definition: c.h:668
List * tlist
Definition: setrefs.c:41

◆ build_tlist_index_other_vars()

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

Definition at line 2202 of file setrefs.c.

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

Referenced by set_returning_clause_references().

2203 {
2204  indexed_tlist *itlist;
2205  tlist_vinfo *vinfo;
2206  ListCell *l;
2207 
2208  /* Create data structure with enough slots for all tlist entries */
2209  itlist = (indexed_tlist *)
2211  list_length(tlist) * sizeof(tlist_vinfo));
2212 
2213  itlist->tlist = tlist;
2214  itlist->has_ph_vars = false;
2215  itlist->has_non_vars = false;
2216 
2217  /* Find the desired Vars and fill in the index array */
2218  vinfo = itlist->vars;
2219  foreach(l, tlist)
2220  {
2221  TargetEntry *tle = (TargetEntry *) lfirst(l);
2222 
2223  if (tle->expr && IsA(tle->expr, Var))
2224  {
2225  Var *var = (Var *) tle->expr;
2226 
2227  if (var->varno != ignore_rel)
2228  {
2229  vinfo->varno = var->varno;
2230  vinfo->varattno = var->varattno;
2231  vinfo->resno = tle->resno;
2232  vinfo++;
2233  }
2234  }
2235  else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2236  itlist->has_ph_vars = true;
2237  }
2238 
2239  itlist->num_vars = (vinfo - itlist->vars);
2240 
2241  return itlist;
2242 }
Index varno
Definition: setrefs.c:34
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
tlist_vinfo vars[FLEXIBLE_ARRAY_MEMBER]
Definition: setrefs.c:45
AttrNumber resno
Definition: setrefs.c:36
AttrNumber varattno
Definition: primnodes.h:186
Definition: primnodes.h:181
AttrNumber varattno
Definition: setrefs.c:35
bool has_ph_vars
Definition: setrefs.c:43
int num_vars
Definition: setrefs.c:42
AttrNumber resno
Definition: primnodes.h:1408
Index varno
Definition: primnodes.h:184
bool has_non_vars
Definition: setrefs.c:44
#define lfirst(lc)
Definition: pg_list.h:190
Expr * expr
Definition: primnodes.h:1407
static int list_length(const List *l)
Definition: pg_list.h:169
void * palloc(Size size)
Definition: mcxt.c:949
Definition: regcomp.c:224
#define offsetof(type, field)
Definition: c.h:668
List * tlist
Definition: setrefs.c:41

◆ clean_up_removed_plan_level()

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

Definition at line 1163 of file setrefs.c.

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

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

1164 {
1165  /* We have to be sure we don't lose any initplans */
1166  child->initPlan = list_concat(parent->initPlan,
1167  child->initPlan);
1168 
1169  /*
1170  * We also have to transfer the parent's column labeling info into the
1171  * child, else columns sent to client will be improperly labeled if this
1172  * is the topmost plan level. resjunk and so on may be important too.
1173  */
1174  apply_tlist_labeling(child->targetlist, parent->targetlist);
1175 
1176  return child;
1177 }
void apply_tlist_labeling(List *dest_tlist, List *src_tlist)
Definition: tlist.c:340
List * list_concat(List *list1, const List *list2)
Definition: list.c:515
List * targetlist
Definition: plannodes.h:142
List * initPlan
Definition: plannodes.h:146

◆ convert_combining_aggrefs()

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

Definition at line 2016 of file setrefs.c.

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().

2017 {
2018  if (node == NULL)
2019  return NULL;
2020  if (IsA(node, Aggref))
2021  {
2022  Aggref *orig_agg = (Aggref *) node;
2023  Aggref *child_agg;
2024  Aggref *parent_agg;
2025 
2026  /* Assert we've not chosen to partial-ize any unsupported cases */
2027  Assert(orig_agg->aggorder == NIL);
2028  Assert(orig_agg->aggdistinct == NIL);
2029 
2030  /*
2031  * Since aggregate calls can't be nested, we needn't recurse into the
2032  * arguments. But for safety, flat-copy the Aggref node itself rather
2033  * than modifying it in-place.
2034  */
2035  child_agg = makeNode(Aggref);
2036  memcpy(child_agg, orig_agg, sizeof(Aggref));
2037 
2038  /*
2039  * For the parent Aggref, we want to copy all the fields of the
2040  * original aggregate *except* the args list, which we'll replace
2041  * below, and the aggfilter expression, which should be applied only
2042  * by the child not the parent. Rather than explicitly knowing about
2043  * all the other fields here, we can momentarily modify child_agg to
2044  * provide a suitable source for copyObject.
2045  */
2046  child_agg->args = NIL;
2047  child_agg->aggfilter = NULL;
2048  parent_agg = copyObject(child_agg);
2049  child_agg->args = orig_agg->args;
2050  child_agg->aggfilter = orig_agg->aggfilter;
2051 
2052  /*
2053  * Now, set up child_agg to represent the first phase of partial
2054  * aggregation. For now, assume serialization is required.
2055  */
2057 
2058  /*
2059  * And set up parent_agg to represent the second phase.
2060  */
2061  parent_agg->args = list_make1(makeTargetEntry((Expr *) child_agg,
2062  1, NULL, false));
2064 
2065  return (Node *) parent_agg;
2066  }
2068  (void *) context);
2069 }
List * aggdistinct
Definition: primnodes.h:321
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
Node * expression_tree_mutator(Node *node, Node *(*mutator)(), void *context)
Definition: nodeFuncs.c:2516
void mark_partial_aggref(Aggref *agg, AggSplit aggsplit)
Definition: planner.c:5392
Definition: nodes.h:529
List * args
Definition: primnodes.h:319
#define list_make1(x1)
Definition: pg_list.h:227
List * aggorder
Definition: primnodes.h:320
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
static Node * convert_combining_aggrefs(Node *node, void *context)
Definition: setrefs.c:2016
#define makeNode(_type_)
Definition: nodes.h:577
#define Assert(condition)
Definition: c.h:745
Expr * aggfilter
Definition: primnodes.h:322
#define copyObject(obj)
Definition: nodes.h:645

◆ copyVar()

static Var* copyVar ( Var var)
inlinestatic

Definition at line 1497 of file setrefs.c.

References palloc().

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

1498 {
1499  Var *newvar = (Var *) palloc(sizeof(Var));
1500 
1501  *newvar = *var;
1502  return newvar;
1503 }
Definition: primnodes.h:181
void * palloc(Size size)
Definition: mcxt.c:949

◆ extract_query_dependencies()

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

Definition at line 2791 of file setrefs.c.

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

Referenced by CompleteCachedPlan(), and RevalidateCachedQuery().

2795 {
2796  PlannerGlobal glob;
2797  PlannerInfo root;
2798 
2799  /* Make up dummy planner state so we can use this module's machinery */
2800  MemSet(&glob, 0, sizeof(glob));
2801  glob.type = T_PlannerGlobal;
2802  glob.relationOids = NIL;
2803  glob.invalItems = NIL;
2804  /* Hack: we use glob.dependsOnRole to collect hasRowSecurity flags */
2805  glob.dependsOnRole = false;
2806 
2807  MemSet(&root, 0, sizeof(root));
2808  root.type = T_PlannerInfo;
2809  root.glob = &glob;
2810 
2811  (void) extract_query_dependencies_walker(query, &root);
2812 
2813  *relationOids = glob.relationOids;
2814  *invalItems = glob.invalItems;
2815  *hasRowSecurity = glob.dependsOnRole;
2816 }
#define NIL
Definition: pg_list.h:65
#define MemSet(start, val, len)
Definition: c.h:978
bool dependsOnRole
Definition: pathnodes.h:141
PlannerGlobal * glob
Definition: pathnodes.h:181
List * invalItems
Definition: pathnodes.h:129
NodeTag type
Definition: pathnodes.h:177
bool extract_query_dependencies_walker(Node *node, PlannerInfo *context)
Definition: setrefs.c:2827
NodeTag type
Definition: pathnodes.h:107
List * relationOids
Definition: pathnodes.h:127

◆ extract_query_dependencies_walker()

bool extract_query_dependencies_walker ( Node node,
PlannerInfo context 
)

Definition at line 2827 of file setrefs.c.

References Assert, CMD_UTILITY, Query::commandType, PlannerGlobal::dependsOnRole, expression_tree_walker(), extract_query_dependencies_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(), extract_query_dependencies(), and extract_query_dependencies_walker().

2828 {
2829  if (node == NULL)
2830  return false;
2831  Assert(!IsA(node, PlaceHolderVar));
2832  if (IsA(node, Query))
2833  {
2834  Query *query = (Query *) node;
2835  ListCell *lc;
2836 
2837  if (query->commandType == CMD_UTILITY)
2838  {
2839  /*
2840  * Ignore utility statements, except those (such as EXPLAIN) that
2841  * contain a parsed-but-not-planned query.
2842  */
2843  query = UtilityContainsQuery(query->utilityStmt);
2844  if (query == NULL)
2845  return false;
2846  }
2847 
2848  /* Remember if any Query has RLS quals applied by rewriter */
2849  if (query->hasRowSecurity)
2850  context->glob->dependsOnRole = true;
2851 
2852  /* Collect relation OIDs in this Query's rtable */
2853  foreach(lc, query->rtable)
2854  {
2855  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2856 
2857  if (rte->rtekind == RTE_RELATION)
2858  context->glob->relationOids =
2859  lappend_oid(context->glob->relationOids, rte->relid);
2860  else if (rte->rtekind == RTE_NAMEDTUPLESTORE &&
2861  OidIsValid(rte->relid))
2862  context->glob->relationOids =
2863  lappend_oid(context->glob->relationOids,
2864  rte->relid);
2865  }
2866 
2867  /* And recurse into the query's subexpressions */
2869  (void *) context, 0);
2870  }
2871  /* Extract function dependencies and check for regclass Consts */
2872  fix_expr_common(context, node);
2874  (void *) context);
2875 }
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2273
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
Node * utilityStmt
Definition: parsenodes.h:120
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
#define OidIsValid(objectId)
Definition: c.h:651
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2063
bool dependsOnRole
Definition: pathnodes.h:141
List * rtable
Definition: parsenodes.h:137
PlannerGlobal * glob
Definition: pathnodes.h:181
bool extract_query_dependencies_walker(Node *node, PlannerInfo *context)
Definition: setrefs.c:2827
static void fix_expr_common(PlannerInfo *root, Node *node)
Definition: setrefs.c:1519
CmdType commandType
Definition: parsenodes.h:112
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1839
List * relationOids
Definition: pathnodes.h:127
RTEKind rtekind
Definition: parsenodes.h:976
bool hasRowSecurity
Definition: parsenodes.h:133

◆ fix_expr_common()

static void fix_expr_common ( PlannerInfo root,
Node node 
)
static

Definition at line 1519 of file setrefs.c.

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

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

1520 {
1521  /* We assume callers won't call us on a NULL pointer */
1522  if (IsA(node, Aggref))
1523  {
1525  ((Aggref *) node)->aggfnoid);
1526  }
1527  else if (IsA(node, WindowFunc))
1528  {
1530  ((WindowFunc *) node)->winfnoid);
1531  }
1532  else if (IsA(node, FuncExpr))
1533  {
1535  ((FuncExpr *) node)->funcid);
1536  }
1537  else if (IsA(node, OpExpr))
1538  {
1539  set_opfuncid((OpExpr *) node);
1541  ((OpExpr *) node)->opfuncid);
1542  }
1543  else if (IsA(node, DistinctExpr))
1544  {
1545  set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1547  ((DistinctExpr *) node)->opfuncid);
1548  }
1549  else if (IsA(node, NullIfExpr))
1550  {
1551  set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1553  ((NullIfExpr *) node)->opfuncid);
1554  }
1555  else if (IsA(node, ScalarArrayOpExpr))
1556  {
1559  ((ScalarArrayOpExpr *) node)->opfuncid);
1560  }
1561  else if (IsA(node, Const))
1562  {
1563  Const *con = (Const *) node;
1564 
1565  /* Check for regclass reference */
1566  if (ISREGCLASSCONST(con))
1567  root->glob->relationOids =
1568  lappend_oid(root->glob->relationOids,
1570  }
1571  else if (IsA(node, GroupingFunc))
1572  {
1573  GroupingFunc *g = (GroupingFunc *) node;
1574  AttrNumber *grouping_map = root->grouping_map;
1575 
1576  /* If there are no grouping sets, we don't need this. */
1577 
1578  Assert(grouping_map || g->cols == NIL);
1579 
1580  if (grouping_map)
1581  {
1582  ListCell *lc;
1583  List *cols = NIL;
1584 
1585  foreach(lc, g->refs)
1586  {
1587  cols = lappend_int(cols, grouping_map[lfirst_int(lc)]);
1588  }
1589 
1590  Assert(!g->cols || equal(cols, g->cols));
1591 
1592  if (!g->cols)
1593  g->cols = cols;
1594  }
1595  }
1596 }
Datum constvalue
Definition: primnodes.h:214
#define NIL
Definition: pg_list.h:65
#define ISREGCLASSCONST(con)
Definition: setrefs.c:78
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
List * refs
Definition: primnodes.h:361
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3033
#define DatumGetObjectId(X)
Definition: postgres.h:500
AttrNumber * grouping_map
Definition: pathnodes.h:328
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
#define lfirst_int(lc)
Definition: pg_list.h:191
PlannerGlobal * glob
Definition: pathnodes.h:181
List * lappend_int(List *list, int datum)
Definition: list.c:339
List * cols
Definition: primnodes.h:362
void record_plan_function_dependency(PlannerInfo *root, Oid funcid)
Definition: setrefs.c:2710
#define Assert(condition)
Definition: c.h:745
List * relationOids
Definition: pathnodes.h:127
void set_opfuncid(OpExpr *opexpr)
Definition: nodeFuncs.c:1618
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21
void set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
Definition: nodeFuncs.c:1629

◆ 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 
)
static

Definition at line 2397 of file setrefs.c.

References fix_join_expr_context::acceptable_rel, fix_join_expr_mutator(), fix_join_expr_context::inner_itlist, 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().

2403 {
2404  fix_join_expr_context context;
2405 
2406  context.root = root;
2407  context.outer_itlist = outer_itlist;
2408  context.inner_itlist = inner_itlist;
2409  context.acceptable_rel = acceptable_rel;
2410  context.rtoffset = rtoffset;
2411  return (List *) fix_join_expr_mutator((Node *) clauses, &context);
2412 }
indexed_tlist * inner_itlist
Definition: setrefs.c:58
Definition: nodes.h:529
static Node * fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
Definition: setrefs.c:2415
PlannerInfo * root
Definition: setrefs.c:56
indexed_tlist * outer_itlist
Definition: setrefs.c:57
Definition: pg_list.h:50

◆ fix_join_expr_mutator()

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

Definition at line 2415 of file setrefs.c.

References fix_join_expr_context::acceptable_rel, copyVar(), elog, ERROR, expression_tree_mutator(), 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::outer_itlist, OUTER_VAR, PlaceHolderVar::phexpr, fix_join_expr_context::root, fix_join_expr_context::rtoffset, search_indexed_tlist_for_non_var(), search_indexed_tlist_for_var(), Var::varno, and Var::varnosyn.

Referenced by fix_join_expr().

2416 {
2417  Var *newvar;
2418 
2419  if (node == NULL)
2420  return NULL;
2421  if (IsA(node, Var))
2422  {
2423  Var *var = (Var *) node;
2424 
2425  /* Look for the var in the input tlists, first in the outer */
2426  if (context->outer_itlist)
2427  {
2428  newvar = search_indexed_tlist_for_var(var,
2429  context->outer_itlist,
2430  OUTER_VAR,
2431  context->rtoffset);
2432  if (newvar)
2433  return (Node *) newvar;
2434  }
2435 
2436  /* then in the inner. */
2437  if (context->inner_itlist)
2438  {
2439  newvar = search_indexed_tlist_for_var(var,
2440  context->inner_itlist,
2441  INNER_VAR,
2442  context->rtoffset);
2443  if (newvar)
2444  return (Node *) newvar;
2445  }
2446 
2447  /* If it's for acceptable_rel, adjust and return it */
2448  if (var->varno == context->acceptable_rel)
2449  {
2450  var = copyVar(var);
2451  var->varno += context->rtoffset;
2452  if (var->varnosyn > 0)
2453  var->varnosyn += context->rtoffset;
2454  return (Node *) var;
2455  }
2456 
2457  /* No referent found for Var */
2458  elog(ERROR, "variable not found in subplan target lists");
2459  }
2460  if (IsA(node, PlaceHolderVar))
2461  {
2462  PlaceHolderVar *phv = (PlaceHolderVar *) node;
2463 
2464  /* See if the PlaceHolderVar has bubbled up from a lower plan node */
2465  if (context->outer_itlist && context->outer_itlist->has_ph_vars)
2466  {
2467  newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2468  context->outer_itlist,
2469  OUTER_VAR);
2470  if (newvar)
2471  return (Node *) newvar;
2472  }
2473  if (context->inner_itlist && context->inner_itlist->has_ph_vars)
2474  {
2475  newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2476  context->inner_itlist,
2477  INNER_VAR);
2478  if (newvar)
2479  return (Node *) newvar;
2480  }
2481 
2482  /* If not supplied by input plans, evaluate the contained expr */
2483  return fix_join_expr_mutator((Node *) phv->phexpr, context);
2484  }
2485  /* Try matching more complex expressions too, if tlists have any */
2486  if (context->outer_itlist && context->outer_itlist->has_non_vars)
2487  {
2488  newvar = search_indexed_tlist_for_non_var((Expr *) node,
2489  context->outer_itlist,
2490  OUTER_VAR);
2491  if (newvar)
2492  return (Node *) newvar;
2493  }
2494  if (context->inner_itlist && context->inner_itlist->has_non_vars)
2495  {
2496  newvar = search_indexed_tlist_for_non_var((Expr *) node,
2497  context->inner_itlist,
2498  INNER_VAR);
2499  if (newvar)
2500  return (Node *) newvar;
2501  }
2502  /* Special cases (apply only AFTER failing to match to lower tlist) */
2503  if (IsA(node, Param))
2504  return fix_param_node(context->root, (Param *) node);
2505  fix_expr_common(context->root, node);
2506  return expression_tree_mutator(node,
2508  (void *) context);
2509 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
indexed_tlist * inner_itlist
Definition: setrefs.c:58
Node * expression_tree_mutator(Node *node, Node *(*mutator)(), void *context)
Definition: nodeFuncs.c:2516
static Node * fix_param_node(PlannerInfo *root, Param *p)
Definition: setrefs.c:1607
Definition: nodes.h:529
Definition: primnodes.h:181
static Node * fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
Definition: setrefs.c:2415
bool has_ph_vars
Definition: setrefs.c:43
#define ERROR
Definition: elog.h:43
static Var * copyVar(Var *var)
Definition: setrefs.c:1497
PlannerInfo * root
Definition: setrefs.c:56
Index varnosyn
Definition: primnodes.h:194
Index varno
Definition: primnodes.h:184
bool has_non_vars
Definition: setrefs.c:44
static Var * search_indexed_tlist_for_non_var(Expr *node, indexed_tlist *itlist, Index newvarno)
Definition: setrefs.c:2293
static void fix_expr_common(PlannerInfo *root, Node *node)
Definition: setrefs.c:1519
#define INNER_VAR
Definition: primnodes.h:171
static Var * search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist, Index newvarno, int rtoffset)
Definition: setrefs.c:2253
#define elog(elevel,...)
Definition: elog.h:214
indexed_tlist * outer_itlist
Definition: setrefs.c:57
#define OUTER_VAR
Definition: primnodes.h:172

◆ fix_param_node()

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

Definition at line 1607 of file setrefs.c.

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().

1608 {
1609  if (p->paramkind == PARAM_MULTIEXPR)
1610  {
1611  int subqueryid = p->paramid >> 16;
1612  int colno = p->paramid & 0xFFFF;
1613  List *params;
1614 
1615  if (subqueryid <= 0 ||
1616  subqueryid > list_length(root->multiexpr_params))
1617  elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
1618  params = (List *) list_nth(root->multiexpr_params, subqueryid - 1);
1619  if (colno <= 0 || colno > list_length(params))
1620  elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
1621  return copyObject(list_nth(params, colno - 1));
1622  }
1623  return (Node *) copyObject(p);
1624 }
ParamKind paramkind
Definition: primnodes.h:262
Definition: nodes.h:529
List * multiexpr_params
Definition: pathnodes.h:263
#define ERROR
Definition: elog.h:43
static void * list_nth(const List *list, int n)
Definition: pg_list.h:277
int paramid
Definition: primnodes.h:263
static int list_length(const List *l)
Definition: pg_list.h:169
#define elog(elevel,...)
Definition: elog.h:214
#define copyObject(obj)
Definition: nodes.h:645
Definition: pg_list.h:50

◆ fix_scan_expr()

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

Definition at line 1637 of file setrefs.c.

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

Referenced by set_plan_refs().

1638 {
1639  fix_scan_expr_context context;
1640 
1641  context.root = root;
1642  context.rtoffset = rtoffset;
1643 
1644  if (rtoffset != 0 ||
1645  root->multiexpr_params != NIL ||
1646  root->glob->lastPHId != 0 ||
1647  root->minmax_aggs != NIL)
1648  {
1649  return fix_scan_expr_mutator(node, &context);
1650  }
1651  else
1652  {
1653  /*
1654  * If rtoffset == 0, we don't need to change any Vars, and if there
1655  * are no MULTIEXPR subqueries then we don't need to replace
1656  * PARAM_MULTIEXPR Params, and if there are no placeholders anywhere
1657  * we won't need to remove them, and if there are no minmax Aggrefs we
1658  * won't need to replace them. Then it's OK to just scribble on the
1659  * input node tree instead of copying (since the only change, filling
1660  * in any unset opfuncid fields, is harmless). This saves just enough
1661  * cycles to be noticeable on trivial queries.
1662  */
1663  (void) fix_scan_expr_walker(node, &context);
1664  return node;
1665  }
1666 }
#define NIL
Definition: pg_list.h:65
PlannerInfo * root
Definition: setrefs.c:50
List * minmax_aggs
Definition: pathnodes.h:329
List * multiexpr_params
Definition: pathnodes.h:263
PlannerGlobal * glob
Definition: pathnodes.h:181
static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
Definition: setrefs.c:1738
static Node * fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
Definition: setrefs.c:1669
Index lastPHId
Definition: pathnodes.h:133

◆ fix_scan_expr_mutator()

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

Definition at line 1669 of file setrefs.c.

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

Referenced by fix_scan_expr().

1670 {
1671  if (node == NULL)
1672  return NULL;
1673  if (IsA(node, Var))
1674  {
1675  Var *var = copyVar((Var *) node);
1676 
1677  Assert(var->varlevelsup == 0);
1678 
1679  /*
1680  * We should not see any Vars marked INNER_VAR or OUTER_VAR. But an
1681  * indexqual expression could contain INDEX_VAR Vars.
1682  */
1683  Assert(var->varno != INNER_VAR);
1684  Assert(var->varno != OUTER_VAR);
1685  if (!IS_SPECIAL_VARNO(var->varno))
1686  var->varno += context->rtoffset;
1687  if (var->varnosyn > 0)
1688  var->varnosyn += context->rtoffset;
1689  return (Node *) var;
1690  }
1691  if (IsA(node, Param))
1692  return fix_param_node(context->root, (Param *) node);
1693  if (IsA(node, Aggref))
1694  {
1695  Aggref *aggref = (Aggref *) node;
1696 
1697  /* See if the Aggref should be replaced by a Param */
1698  if (context->root->minmax_aggs != NIL &&
1699  list_length(aggref->args) == 1)
1700  {
1701  TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
1702  ListCell *lc;
1703 
1704  foreach(lc, context->root->minmax_aggs)
1705  {
1706  MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
1707 
1708  if (mminfo->aggfnoid == aggref->aggfnoid &&
1709  equal(mminfo->target, curTarget->expr))
1710  return (Node *) copyObject(mminfo->param);
1711  }
1712  }
1713  /* If no match, just fall through to process it normally */
1714  }
1715  if (IsA(node, CurrentOfExpr))
1716  {
1717  CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
1718 
1719  Assert(cexpr->cvarno != INNER_VAR);
1720  Assert(cexpr->cvarno != OUTER_VAR);
1721  if (!IS_SPECIAL_VARNO(cexpr->cvarno))
1722  cexpr->cvarno += context->rtoffset;
1723  return (Node *) cexpr;
1724  }
1725  if (IsA(node, PlaceHolderVar))
1726  {
1727  /* At scan level, we should always just evaluate the contained expr */
1728  PlaceHolderVar *phv = (PlaceHolderVar *) node;
1729 
1730  return fix_scan_expr_mutator((Node *) phv->phexpr, context);
1731  }
1732  fix_expr_common(context->root, node);
1734  (void *) context);
1735 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
Index varlevelsup
Definition: primnodes.h:191
Node * expression_tree_mutator(Node *node, Node *(*mutator)(), void *context)
Definition: nodeFuncs.c:2516
static Node * fix_param_node(PlannerInfo *root, Param *p)
Definition: setrefs.c:1607
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3033
Param * param
Definition: pathnodes.h:2329
PlannerInfo * root
Definition: setrefs.c:50
Definition: nodes.h:529
List * args
Definition: primnodes.h:319
List * minmax_aggs
Definition: pathnodes.h:329
Definition: primnodes.h:181
#define IS_SPECIAL_VARNO(varno)
Definition: primnodes.h:175
#define linitial(l)
Definition: pg_list.h:195
static Var * copyVar(Var *var)
Definition: setrefs.c:1497
Index varnosyn
Definition: primnodes.h:194
Index varno
Definition: primnodes.h:184
static Node * fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
Definition: setrefs.c:1669
Oid aggfnoid
Definition: primnodes.h:312
static void fix_expr_common(PlannerInfo *root, Node *node)
Definition: setrefs.c:1519
#define INNER_VAR
Definition: primnodes.h:171
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
Expr * target
Definition: pathnodes.h:2325
Expr * expr
Definition: primnodes.h:1407
static int list_length(const List *l)
Definition: pg_list.h:169
#define copyObject(obj)
Definition: nodes.h:645
#define OUTER_VAR
Definition: primnodes.h:172

◆ fix_scan_expr_walker()

static bool fix_scan_expr_walker ( Node node,
fix_scan_expr_context context 
)
static

Definition at line 1738 of file setrefs.c.

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

Referenced by fix_scan_expr().

1739 {
1740  if (node == NULL)
1741  return false;
1742  Assert(!IsA(node, PlaceHolderVar));
1743  fix_expr_common(context->root, node);
1745  (void *) context);
1746 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
PlannerInfo * root
Definition: setrefs.c:50
static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
Definition: setrefs.c:1738
static void fix_expr_common(PlannerInfo *root, Node *node)
Definition: setrefs.c:1519
#define Assert(condition)
Definition: c.h:745
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1839

◆ fix_upper_expr()

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

Definition at line 2542 of file setrefs.c.

References fix_upper_expr_mutator(), fix_upper_expr_context::newvarno, 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().

2547 {
2548  fix_upper_expr_context context;
2549 
2550  context.root = root;
2551  context.subplan_itlist = subplan_itlist;
2552  context.newvarno = newvarno;
2553  context.rtoffset = rtoffset;
2554  return fix_upper_expr_mutator(node, &context);
2555 }
static Node * fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
Definition: setrefs.c:2558
PlannerInfo * root
Definition: setrefs.c:65
indexed_tlist * subplan_itlist
Definition: setrefs.c:66

◆ fix_upper_expr_mutator()

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

Definition at line 2558 of file setrefs.c.

References Aggref::aggfnoid, MinMaxAggInfo::aggfnoid, Aggref::args, copyObject, elog, equal(), ERROR, TargetEntry::expr, expression_tree_mutator(), 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, MinMaxAggInfo::param, PlaceHolderVar::phexpr, fix_upper_expr_context::root, fix_upper_expr_context::rtoffset, search_indexed_tlist_for_non_var(), search_indexed_tlist_for_var(), fix_upper_expr_context::subplan_itlist, and MinMaxAggInfo::target.

Referenced by fix_upper_expr().

2559 {
2560  Var *newvar;
2561 
2562  if (node == NULL)
2563  return NULL;
2564  if (IsA(node, Var))
2565  {
2566  Var *var = (Var *) node;
2567 
2568  newvar = search_indexed_tlist_for_var(var,
2569  context->subplan_itlist,
2570  context->newvarno,
2571  context->rtoffset);
2572  if (!newvar)
2573  elog(ERROR, "variable not found in subplan target list");
2574  return (Node *) newvar;
2575  }
2576  if (IsA(node, PlaceHolderVar))
2577  {
2578  PlaceHolderVar *phv = (PlaceHolderVar *) node;
2579 
2580  /* See if the PlaceHolderVar has bubbled up from a lower plan node */
2581  if (context->subplan_itlist->has_ph_vars)
2582  {
2583  newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2584  context->subplan_itlist,
2585  context->newvarno);
2586  if (newvar)
2587  return (Node *) newvar;
2588  }
2589  /* If not supplied by input plan, evaluate the contained expr */
2590  return fix_upper_expr_mutator((Node *) phv->phexpr, context);
2591  }
2592  /* Try matching more complex expressions too, if tlist has any */
2593  if (context->subplan_itlist->has_non_vars)
2594  {
2595  newvar = search_indexed_tlist_for_non_var((Expr *) node,
2596  context->subplan_itlist,
2597  context->newvarno);
2598  if (newvar)
2599  return (Node *) newvar;
2600  }
2601  /* Special cases (apply only AFTER failing to match to lower tlist) */
2602  if (IsA(node, Param))
2603  return fix_param_node(context->root, (Param *) node);
2604  if (IsA(node, Aggref))
2605  {
2606  Aggref *aggref = (Aggref *) node;
2607 
2608  /* See if the Aggref should be replaced by a Param */
2609  if (context->root->minmax_aggs != NIL &&
2610  list_length(aggref->args) == 1)
2611  {
2612  TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
2613  ListCell *lc;
2614 
2615  foreach(lc, context->root->minmax_aggs)
2616  {
2617  MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
2618 
2619  if (mminfo->aggfnoid == aggref->aggfnoid &&
2620  equal(mminfo->target, curTarget->expr))
2621  return (Node *) copyObject(mminfo->param);
2622  }
2623  }
2624  /* If no match, just fall through to process it normally */
2625  }
2626  fix_expr_common(context->root, node);
2627  return expression_tree_mutator(node,
2629  (void *) context);
2630 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
Node * expression_tree_mutator(Node *node, Node *(*mutator)(), void *context)
Definition: nodeFuncs.c:2516
static Node * fix_param_node(PlannerInfo *root, Param *p)
Definition: setrefs.c:1607
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3033
Param * param
Definition: pathnodes.h:2329
Definition: nodes.h:529
List * args
Definition: primnodes.h:319
List * minmax_aggs
Definition: pathnodes.h:329
Definition: primnodes.h:181
bool has_ph_vars
Definition: setrefs.c:43
#define linitial(l)
Definition: pg_list.h:195
#define ERROR
Definition: elog.h:43
static Node * fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
Definition: setrefs.c:2558
bool has_non_vars
Definition: setrefs.c:44
static Var * search_indexed_tlist_for_non_var(Expr *node, indexed_tlist *itlist, Index newvarno)
Definition: setrefs.c:2293
Oid aggfnoid
Definition: primnodes.h:312
static void fix_expr_common(PlannerInfo *root, Node *node)
Definition: setrefs.c:1519
#define lfirst(lc)
Definition: pg_list.h:190
Expr * target
Definition: pathnodes.h:2325
static Var * search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist, Index newvarno, int rtoffset)
Definition: setrefs.c:2253
Expr * expr
Definition: primnodes.h:1407
static int list_length(const List *l)
Definition: pg_list.h:169
#define elog(elevel,...)
Definition: elog.h:214
PlannerInfo * root
Definition: setrefs.c:65
#define copyObject(obj)
Definition: nodes.h:645
indexed_tlist * subplan_itlist
Definition: setrefs.c:66

◆ flatten_rtes_walker()

static bool flatten_rtes_walker ( Node node,
PlannerGlobal glob 
)
static

Definition at line 383 of file setrefs.c.

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().

384 {
385  if (node == NULL)
386  return false;
387  if (IsA(node, RangeTblEntry))
388  {
389  RangeTblEntry *rte = (RangeTblEntry *) node;
390 
391  /* As above, we need only save relation RTEs */
392  if (rte->rtekind == RTE_RELATION)
393  add_rte_to_flat_rtable(glob, rte);
394  return false;
395  }
396  if (IsA(node, Query))
397  {
398  /* Recurse into subselects */
399  return query_tree_walker((Query *) node,
401  (void *) glob,
403  }
405  (void *) glob);
406 }
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2273
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
#define QTW_EXAMINE_RTES_BEFORE
Definition: nodeFuncs.h:25
static void add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte)
Definition: setrefs.c:419
static bool flatten_rtes_walker(Node *node, PlannerGlobal *glob)
Definition: setrefs.c:383
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1839
RTEKind rtekind
Definition: parsenodes.h:976

◆ flatten_unplanned_rtes()

static void flatten_unplanned_rtes ( PlannerGlobal glob,
RangeTblEntry rte 
)
static

Definition at line 373 of file setrefs.c.

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

Referenced by add_rtes_to_flat_rtable().

374 {
375  /* Use query_tree_walker to find all RTEs in the parse tree */
376  (void) query_tree_walker(rte->subquery,
378  (void *) glob,
380 }
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2273
#define QTW_EXAMINE_RTES_BEFORE
Definition: nodeFuncs.h:25
static bool flatten_rtes_walker(Node *node, PlannerGlobal *glob)
Definition: setrefs.c:383
Query * subquery
Definition: parsenodes.h:1011

◆ offset_relid_set()

static Relids offset_relid_set ( Relids  relids,
int  rtoffset 
)
static

Definition at line 1475 of file setrefs.c.

References bms_add_member(), and bms_next_member().

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

1476 {
1477  Relids result = NULL;
1478  int rtindex;
1479 
1480  /* If there's no offset to apply, we needn't recompute the value */
1481  if (rtoffset == 0)
1482  return relids;
1483  rtindex = -1;
1484  while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
1485  result = bms_add_member(result, rtindex + rtoffset);
1486  return result;
1487 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736

◆ record_plan_function_dependency()

void record_plan_function_dependency ( PlannerInfo root,
Oid  funcid 
)

Definition at line 2710 of file setrefs.c.

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

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

2711 {
2712  /*
2713  * For performance reasons, we don't bother to track built-in functions;
2714  * we just assume they'll never change (or at least not in ways that'd
2715  * invalidate plans using them). For this purpose we can consider a
2716  * built-in function to be one with OID less than FirstBootstrapObjectId.
2717  * Note that the OID generator guarantees never to generate such an OID
2718  * after startup, even at OID wraparound.
2719  */
2720  if (funcid >= (Oid) FirstBootstrapObjectId)
2721  {
2722  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
2723 
2724  /*
2725  * It would work to use any syscache on pg_proc, but the easiest is
2726  * PROCOID since we already have the function's OID at hand. Note
2727  * that plancache.c knows we use PROCOID.
2728  */
2729  inval_item->cacheId = PROCOID;
2730  inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
2731  ObjectIdGetDatum(funcid));
2732 
2733  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
2734  }
2735 }
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:201
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
PlannerGlobal * glob
Definition: pathnodes.h:181
#define FirstBootstrapObjectId
Definition: transam.h:154
List * lappend(List *list, void *datum)
Definition: list.c:321
List * invalItems
Definition: pathnodes.h:129
uint32 hashValue
Definition: plannodes.h:1248
#define makeNode(_type_)
Definition: nodes.h:577

◆ record_plan_type_dependency()

void record_plan_type_dependency ( PlannerInfo root,
Oid  typid 
)

Definition at line 2750 of file setrefs.c.

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

Referenced by eval_const_expressions_mutator().

2751 {
2752  /*
2753  * As in record_plan_function_dependency, ignore the possibility that
2754  * someone would change a built-in domain.
2755  */
2756  if (typid >= (Oid) FirstBootstrapObjectId)
2757  {
2758  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
2759 
2760  /*
2761  * It would work to use any syscache on pg_type, but the easiest is
2762  * TYPEOID since we already have the type's OID at hand. Note that
2763  * plancache.c knows we use TYPEOID.
2764  */
2765  inval_item->cacheId = TYPEOID;
2766  inval_item->hashValue = GetSysCacheHashValue1(TYPEOID,
2767  ObjectIdGetDatum(typid));
2768 
2769  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
2770  }
2771 }
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:201
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
PlannerGlobal * glob
Definition: pathnodes.h:181
#define FirstBootstrapObjectId
Definition: transam.h:154
List * lappend(List *list, void *datum)
Definition: list.c:321
List * invalItems
Definition: pathnodes.h:129
uint32 hashValue
Definition: plannodes.h:1248
#define makeNode(_type_)
Definition: nodes.h:577

◆ search_indexed_tlist_for_non_var()

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

Definition at line 2293 of file setrefs.c.

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

Referenced by fix_join_expr_mutator(), and fix_upper_expr_mutator().

2295 {
2296  TargetEntry *tle;
2297 
2298  /*
2299  * If it's a simple Const, replacing it with a Var is silly, even if there
2300  * happens to be an identical Const below; a Var is more expensive to
2301  * execute than a Const. What's more, replacing it could confuse some
2302  * places in the executor that expect to see simple Consts for, eg,
2303  * dropped columns.
2304  */
2305  if (IsA(node, Const))
2306  return NULL;
2307 
2308  tle = tlist_member(node, itlist->tlist);
2309  if (tle)
2310  {
2311  /* Found a matching subplan output expression */
2312  Var *newvar;
2313 
2314  newvar = makeVarFromTargetEntry(newvarno, tle);
2315  newvar->varnosyn = 0; /* wasn't ever a plain Var */
2316  newvar->varattnosyn = 0;
2317  return newvar;
2318  }
2319  return NULL; /* no match */
2320 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
Var * makeVarFromTargetEntry(Index varno, TargetEntry *tle)
Definition: makefuncs.c:103
Definition: primnodes.h:181
Index varnosyn
Definition: primnodes.h:194
AttrNumber varattnosyn
Definition: primnodes.h:195
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:73
List * tlist
Definition: setrefs.c:41

◆ search_indexed_tlist_for_sortgroupref()

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

Definition at line 2333 of file setrefs.c.

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

Referenced by set_upper_references().

2337 {
2338  ListCell *lc;
2339 
2340  foreach(lc, itlist->tlist)
2341  {
2342  TargetEntry *tle = (TargetEntry *) lfirst(lc);
2343 
2344  /* The equal() check should be redundant, but let's be paranoid */
2345  if (tle->ressortgroupref == sortgroupref &&
2346  equal(node, tle->expr))
2347  {
2348  /* Found a matching subplan output expression */
2349  Var *newvar;
2350 
2351  newvar = makeVarFromTargetEntry(newvarno, tle);
2352  newvar->varnosyn = 0; /* wasn't ever a plain Var */
2353  newvar->varattnosyn = 0;
2354  return newvar;
2355  }
2356  }
2357  return NULL; /* no match */
2358 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3033
Var * makeVarFromTargetEntry(Index varno, TargetEntry *tle)
Definition: makefuncs.c:103
Definition: primnodes.h:181
Index varnosyn
Definition: primnodes.h:194
AttrNumber varattnosyn
Definition: primnodes.h:195
#define lfirst(lc)
Definition: pg_list.h:190
Expr * expr
Definition: primnodes.h:1407
Index ressortgroupref
Definition: primnodes.h:1410
List * tlist
Definition: setrefs.c:41

◆ search_indexed_tlist_for_var()

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

Definition at line 2253 of file setrefs.c.

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

Referenced by fix_join_expr_mutator(), and fix_upper_expr_mutator().

2255 {
2256  Index varno = var->varno;
2257  AttrNumber varattno = var->varattno;
2258  tlist_vinfo *vinfo;
2259  int i;
2260 
2261  vinfo = itlist->vars;
2262  i = itlist->num_vars;
2263  while (i-- > 0)
2264  {
2265  if (vinfo->varno == varno && vinfo->varattno == varattno)
2266  {
2267  /* Found a match */
2268  Var *newvar = copyVar(var);
2269 
2270  newvar->varno = newvarno;
2271  newvar->varattno = vinfo->resno;
2272  if (newvar->varnosyn > 0)
2273  newvar->varnosyn += rtoffset;
2274  return newvar;
2275  }
2276  vinfo++;
2277  }
2278  return NULL; /* no match */
2279 }
Index varno
Definition: setrefs.c:34
tlist_vinfo vars[FLEXIBLE_ARRAY_MEMBER]
Definition: setrefs.c:45
AttrNumber resno
Definition: setrefs.c:36
AttrNumber varattno
Definition: primnodes.h:186
Definition: primnodes.h:181
AttrNumber varattno
Definition: setrefs.c:35
int num_vars
Definition: setrefs.c:42
static Var * copyVar(Var *var)
Definition: setrefs.c:1497
Index varnosyn
Definition: primnodes.h:194
Index varno
Definition: primnodes.h:184
unsigned int Index
Definition: c.h:482
int i
int16 AttrNumber
Definition: attnum.h:21

◆ set_append_references()

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

Definition at line 1319 of file setrefs.c.

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

Referenced by set_plan_refs().

1322 {
1323  ListCell *l;
1324 
1325  /*
1326  * Append, like Sort et al, doesn't actually evaluate its targetlist or
1327  * check quals. If it's got exactly one child plan, then it's not doing
1328  * anything useful at all, and we can strip it out.
1329  */
1330  Assert(aplan->plan.qual == NIL);
1331 
1332  /* First, we gotta recurse on the children */
1333  foreach(l, aplan->appendplans)
1334  {
1335  lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset);
1336  }
1337 
1338  /* Now, if there's just one, forget the Append and return that child */
1339  if (list_length(aplan->appendplans) == 1)
1340  return clean_up_removed_plan_level((Plan *) aplan,
1341  (Plan *) linitial(aplan->appendplans));
1342 
1343  /*
1344  * Otherwise, clean up the Append as needed. It's okay to do this after
1345  * recursing to the children, because set_dummy_tlist_references doesn't
1346  * look at those.
1347  */
1348  set_dummy_tlist_references((Plan *) aplan, rtoffset);
1349 
1350  aplan->apprelids = offset_relid_set(aplan->apprelids, rtoffset);
1351 
1352  if (aplan->part_prune_info)
1353  {
1354  foreach(l, aplan->part_prune_info->prune_infos)
1355  {
1356  List *prune_infos = lfirst(l);
1357  ListCell *l2;
1358 
1359  foreach(l2, prune_infos)
1360  {
1361  PartitionedRelPruneInfo *pinfo = lfirst(l2);
1362 
1363  pinfo->rtindex += rtoffset;
1364  }
1365  }
1366  }
1367 
1368  /* We don't need to recurse to lefttree or righttree ... */
1369  Assert(aplan->plan.lefttree == NULL);
1370  Assert(aplan->plan.righttree == NULL);
1371 
1372  return (Plan *) aplan;
1373 }
#define NIL
Definition: pg_list.h:65
List * qual
Definition: plannodes.h:143
static Relids offset_relid_set(Relids relids, int rtoffset)
Definition: setrefs.c:1475
static Plan * set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:472
List * appendplans
Definition: plannodes.h:255
struct Plan * righttree
Definition: plannodes.h:145
#define linitial(l)
Definition: pg_list.h:195
static Plan * clean_up_removed_plan_level(Plan *parent, Plan *child)
Definition: setrefs.c:1163
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169
struct Plan * lefttree
Definition: plannodes.h:144
Definition: pg_list.h:50
static void set_dummy_tlist_references(Plan *plan, int rtoffset)
Definition: setrefs.c:2085
Plan plan
Definition: plannodes.h:253

◆ set_customscan_references()

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

Definition at line 1253 of file setrefs.c.

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

Referenced by set_plan_refs().

1256 {
1257  ListCell *lc;
1258 
1259  /* Adjust scanrelid if it's valid */
1260  if (cscan->scan.scanrelid > 0)
1261  cscan->scan.scanrelid += rtoffset;
1262 
1263  if (cscan->custom_scan_tlist != NIL || cscan->scan.scanrelid == 0)
1264  {
1265  /* Adjust tlist, qual, custom_exprs to reference custom scan tuple */
1267 
1268  cscan->scan.plan.targetlist = (List *)
1269  fix_upper_expr(root,
1270  (Node *) cscan->scan.plan.targetlist,
1271  itlist,
1272  INDEX_VAR,
1273  rtoffset);
1274  cscan->scan.plan.qual = (List *)
1275  fix_upper_expr(root,
1276  (Node *) cscan->scan.plan.qual,
1277  itlist,
1278  INDEX_VAR,
1279  rtoffset);
1280  cscan->custom_exprs = (List *)
1281  fix_upper_expr(root,
1282  (Node *) cscan->custom_exprs,
1283  itlist,
1284  INDEX_VAR,
1285  rtoffset);
1286  pfree(itlist);
1287  /* custom_scan_tlist itself just needs fix_scan_list() adjustments */
1288  cscan->custom_scan_tlist =
1289  fix_scan_list(root, cscan->custom_scan_tlist, rtoffset);
1290  }
1291  else
1292  {
1293  /* Adjust tlist, qual, custom_exprs in the standard way */
1294  cscan->scan.plan.targetlist =
1295  fix_scan_list(root, cscan->scan.plan.targetlist, rtoffset);
1296  cscan->scan.plan.qual =
1297  fix_scan_list(root, cscan->scan.plan.qual, rtoffset);
1298  cscan->custom_exprs =
1299  fix_scan_list(root, cscan->custom_exprs, rtoffset);
1300  }
1301 
1302  /* Adjust child plan-nodes recursively, if needed */
1303  foreach(lc, cscan->custom_plans)
1304  {
1305  lfirst(lc) = set_plan_refs(root, (Plan *) lfirst(lc), rtoffset);
1306  }
1307 
1308  cscan->custom_relids = offset_relid_set(cscan->custom_relids, rtoffset);
1309 }
#define NIL
Definition: pg_list.h:65
List * qual
Definition: plannodes.h:143
Plan plan
Definition: plannodes.h:344
Index scanrelid
Definition: plannodes.h:345
Definition: nodes.h:529
List * custom_exprs
Definition: plannodes.h:646
static Relids offset_relid_set(Relids relids, int rtoffset)
Definition: setrefs.c:1475
List * custom_plans
Definition: plannodes.h:645
static Plan * set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:472
void pfree(void *pointer)
Definition: mcxt.c:1056
static Node * fix_upper_expr(PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, Index newvarno, int rtoffset)
Definition: setrefs.c:2542
Scan scan
Definition: plannodes.h:642
#define lfirst(lc)
Definition: pg_list.h:190
List * custom_scan_tlist
Definition: plannodes.h:648
static indexed_tlist * build_tlist_index(List *tlist)
Definition: setrefs.c:2152
Bitmapset * custom_relids
Definition: plannodes.h:649
List * targetlist
Definition: plannodes.h:142
#define INDEX_VAR
Definition: primnodes.h:173
Definition: pg_list.h:50
#define fix_scan_list(root, lst, rtoffset)
Definition: setrefs.c:82

◆ set_dummy_tlist_references()

static void set_dummy_tlist_references ( Plan plan,
int  rtoffset 
)
static

Definition at line 2085 of file setrefs.c.

References TargetEntry::expr, exprCollation(), exprType(), exprTypmod(), flatCopyTargetEntry(), 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().

2086 {
2087  List *output_targetlist;
2088  ListCell *l;
2089 
2090  output_targetlist = NIL;
2091  foreach(l, plan->targetlist)
2092  {
2093  TargetEntry *tle = (TargetEntry *) lfirst(l);
2094  Var *oldvar = (Var *) tle->expr;
2095  Var *newvar;
2096 
2097  /*
2098  * As in search_indexed_tlist_for_non_var(), we prefer to keep Consts
2099  * as Consts, not Vars referencing Consts. Here, there's no speed
2100  * advantage to be had, but it makes EXPLAIN output look cleaner, and
2101  * again it avoids confusing the executor.
2102  */
2103  if (IsA(oldvar, Const))
2104  {
2105  /* just reuse the existing TLE node */
2106  output_targetlist = lappend(output_targetlist, tle);
2107  continue;
2108  }
2109 
2110  newvar = makeVar(OUTER_VAR,
2111  tle->resno,
2112  exprType((Node *) oldvar),
2113  exprTypmod((Node *) oldvar),
2114  exprCollation((Node *) oldvar),
2115  0);
2116  if (IsA(oldvar, Var) &&
2117  oldvar->varnosyn > 0)
2118  {
2119  newvar->varnosyn = oldvar->varnosyn + rtoffset;
2120  newvar->varattnosyn = oldvar->varattnosyn;
2121  }
2122  else
2123  {
2124  newvar->varnosyn = 0; /* wasn't ever a plain Var */
2125  newvar->varattnosyn = 0;
2126  }
2127 
2128  tle = flatCopyTargetEntry(tle);
2129  tle->expr = (Expr *) newvar;
2130  output_targetlist = lappend(output_targetlist, tle);
2131  }
2132  plan->targetlist = output_targetlist;
2133 
2134  /* We don't touch plan->qual here */
2135 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:275
Definition: nodes.h:529
Definition: primnodes.h:181
AttrNumber resno
Definition: primnodes.h:1408
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:271
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
List * lappend(List *list, void *datum)
Definition: list.c:321
#define lfirst(lc)
Definition: pg_list.h:190
Expr * expr
Definition: primnodes.h:1407
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:719
List * targetlist
Definition: plannodes.h:142
Definition: pg_list.h:50
#define OUTER_VAR
Definition: primnodes.h:172

◆ set_foreignscan_references()

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

Definition at line 1184 of file setrefs.c.

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

Referenced by set_plan_refs().

1187 {
1188  /* Adjust scanrelid if it's valid */
1189  if (fscan->scan.scanrelid > 0)
1190  fscan->scan.scanrelid += rtoffset;
1191 
1192  if (fscan->fdw_scan_tlist != NIL || fscan->scan.scanrelid == 0)
1193  {
1194  /*
1195  * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals to reference
1196  * foreign scan tuple
1197  */
1199 
1200  fscan->scan.plan.targetlist = (List *)
1201  fix_upper_expr(root,
1202  (Node *) fscan->scan.plan.targetlist,
1203  itlist,
1204  INDEX_VAR,
1205  rtoffset);
1206  fscan->scan.plan.qual = (List *)
1207  fix_upper_expr(root,
1208  (Node *) fscan->scan.plan.qual,
1209  itlist,
1210  INDEX_VAR,
1211  rtoffset);
1212  fscan->fdw_exprs = (List *)
1213  fix_upper_expr(root,
1214  (Node *) fscan->fdw_exprs,
1215  itlist,
1216  INDEX_VAR,
1217  rtoffset);
1218  fscan->fdw_recheck_quals = (List *)
1219  fix_upper_expr(root,
1220  (Node *) fscan->fdw_recheck_quals,
1221  itlist,
1222  INDEX_VAR,
1223  rtoffset);
1224  pfree(itlist);
1225  /* fdw_scan_tlist itself just needs fix_scan_list() adjustments */
1226  fscan->fdw_scan_tlist =
1227  fix_scan_list(root, fscan->fdw_scan_tlist, rtoffset);
1228  }
1229  else
1230  {
1231  /*
1232  * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals in the standard
1233  * way
1234  */
1235  fscan->scan.plan.targetlist =
1236  fix_scan_list(root, fscan->scan.plan.targetlist, rtoffset);
1237  fscan->scan.plan.qual =
1238  fix_scan_list(root, fscan->scan.plan.qual, rtoffset);
1239  fscan->fdw_exprs =
1240  fix_scan_list(root, fscan->fdw_exprs, rtoffset);
1241  fscan->fdw_recheck_quals =
1242  fix_scan_list(root, fscan->fdw_recheck_quals, rtoffset);
1243  }
1244 
1245  fscan->fs_relids = offset_relid_set(fscan->fs_relids, rtoffset);
1246 }
#define NIL
Definition: pg_list.h:65
List * qual
Definition: plannodes.h:143
Plan plan
Definition: plannodes.h:344
Index scanrelid
Definition: plannodes.h:345
List * fdw_exprs
Definition: plannodes.h:617
Definition: nodes.h:529
List * fdw_scan_tlist
Definition: plannodes.h:619
static Relids offset_relid_set(Relids relids, int rtoffset)
Definition: setrefs.c:1475
void pfree(void *pointer)
Definition: mcxt.c:1056
List * fdw_recheck_quals
Definition: plannodes.h:620
static Node * fix_upper_expr(PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, Index newvarno, int rtoffset)
Definition: setrefs.c:2542
static indexed_tlist * build_tlist_index(List *tlist)
Definition: setrefs.c:2152
List * targetlist
Definition: plannodes.h:142
#define INDEX_VAR
Definition: primnodes.h:173
Definition: pg_list.h:50
#define fix_scan_list(root, lst, rtoffset)
Definition: setrefs.c:82
Bitmapset * fs_relids
Definition: plannodes.h:621

◆ set_hash_references()

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

Definition at line 1444 of file setrefs.c.

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

Referenced by set_plan_refs().

1445 {
1446  Hash *hplan = (Hash *) plan;
1447  Plan *outer_plan = plan->lefttree;
1448  indexed_tlist *outer_itlist;
1449 
1450  /*
1451  * Hash's hashkeys are used when feeding tuples into the hashtable,
1452  * therefore have them reference Hash's outer plan (which itself is the
1453  * inner plan of the HashJoin).
1454  */
1455  outer_itlist = build_tlist_index(outer_plan->targetlist);
1456  hplan->hashkeys = (List *)
1457  fix_upper_expr(root,
1458  (Node *) hplan->hashkeys,
1459  outer_itlist,
1460  OUTER_VAR,
1461  rtoffset);
1462 
1463  /* Hash doesn't project */
1464  set_dummy_tlist_references(plan, rtoffset);
1465 
1466  /* Hash nodes don't have their own quals */
1467  Assert(plan->qual == NIL);
1468 }
#define NIL
Definition: pg_list.h:65
List * qual
Definition: plannodes.h:143
Definition: nodes.h:529
static Node * fix_upper_expr(PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, Index newvarno, int rtoffset)
Definition: setrefs.c:2542
List * hashkeys
Definition: plannodes.h:930
#define Assert(condition)
Definition: c.h:745
static indexed_tlist * build_tlist_index(List *tlist)
Definition: setrefs.c:2152
struct Plan * lefttree
Definition: plannodes.h:144
List * targetlist
Definition: plannodes.h:142
Definition: pg_list.h:50
#define OUTER_VAR
Definition: primnodes.h:172
static void set_dummy_tlist_references(Plan *plan, int rtoffset)
Definition: setrefs.c:2085

◆ set_indexonlyscan_references()

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

Definition at line 1015 of file setrefs.c.

References build_tlist_index(), fix_scan_list, fix_upper_expr(), INDEX_VAR, IndexOnlyScan::indexorderby, IndexOnlyScan::indexqual, IndexOnlyScan::indextlist, pfree(), Scan::plan, Plan::qual, IndexOnlyScan::scan, Scan::scanrelid, and Plan::targetlist.

Referenced by set_plan_refs().

1018 {
1019  indexed_tlist *index_itlist;
1020 
1021  index_itlist = build_tlist_index(plan->indextlist);
1022 
1023  plan->scan.scanrelid += rtoffset;
1024  plan->scan.plan.targetlist = (List *)
1025  fix_upper_expr(root,
1026  (Node *) plan->scan.plan.targetlist,
1027  index_itlist,
1028  INDEX_VAR,
1029  rtoffset);
1030  plan->scan.plan.qual = (List *)
1031  fix_upper_expr(root,
1032  (Node *) plan->scan.plan.qual,
1033  index_itlist,
1034  INDEX_VAR,
1035  rtoffset);
1036  /* indexqual is already transformed to reference index columns */
1037  plan->indexqual = fix_scan_list(root, plan->indexqual, rtoffset);
1038  /* indexorderby is already transformed to reference index columns */
1039  plan->indexorderby = fix_scan_list(root, plan->indexorderby, rtoffset);
1040  /* indextlist must NOT be transformed to reference index columns */
1041  plan->indextlist = fix_scan_list(root, plan->indextlist, rtoffset);
1042 
1043  pfree(index_itlist);
1044 
1045  return (Plan *) plan;
1046 }
List * qual
Definition: plannodes.h:143
Plan plan
Definition: plannodes.h:344
Index scanrelid
Definition: plannodes.h:345
Definition: nodes.h:529
void pfree(void *pointer)
Definition: mcxt.c:1056
static Node * fix_upper_expr(PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, Index newvarno, int rtoffset)
Definition: setrefs.c:2542
List * indextlist
Definition: plannodes.h:437
List * indexorderby
Definition: plannodes.h:436
static indexed_tlist * build_tlist_index(List *tlist)
Definition: setrefs.c:2152
List * indexqual
Definition: plannodes.h:435
List * targetlist
Definition: plannodes.h:142
#define INDEX_VAR
Definition: primnodes.h:173
Definition: pg_list.h:50
#define fix_scan_list(root, lst, rtoffset)
Definition: setrefs.c:82

◆ set_join_references()

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

Definition at line 1757 of file setrefs.c.

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

Referenced by set_plan_refs().

1758 {
1759  Plan *outer_plan = join->plan.lefttree;
1760  Plan *inner_plan = join->plan.righttree;
1761  indexed_tlist *outer_itlist;
1762  indexed_tlist *inner_itlist;
1763 
1764  outer_itlist = build_tlist_index(outer_plan->targetlist);
1765  inner_itlist = build_tlist_index(inner_plan->targetlist);
1766 
1767  /*
1768  * First process the joinquals (including merge or hash clauses). These
1769  * are logically below the join so they can always use all values
1770  * available from the input tlists. It's okay to also handle
1771  * NestLoopParams now, because those couldn't refer to nullable
1772  * subexpressions.
1773  */
1774  join->joinqual = fix_join_expr(root,
1775  join->joinqual,
1776  outer_itlist,
1777  inner_itlist,
1778  (Index) 0,
1779  rtoffset);
1780 
1781  /* Now do join-type-specific stuff */
1782  if (IsA(join, NestLoop))
1783  {
1784  NestLoop *nl = (NestLoop *) join;
1785  ListCell *lc;
1786 
1787  foreach(lc, nl->nestParams)
1788  {
1789  NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
1790 
1791  nlp->paramval = (Var *) fix_upper_expr(root,
1792  (Node *) nlp->paramval,
1793  outer_itlist,
1794  OUTER_VAR,
1795  rtoffset);
1796  /* Check we replaced any PlaceHolderVar with simple Var */
1797  if (!(IsA(nlp->paramval, Var) &&
1798  nlp->paramval->varno == OUTER_VAR))
1799  elog(ERROR, "NestLoopParam was not reduced to a simple Var");
1800  }
1801  }
1802  else if (IsA(join, MergeJoin))
1803  {
1804  MergeJoin *mj = (MergeJoin *) join;
1805 
1806  mj->mergeclauses = fix_join_expr(root,
1807  mj->mergeclauses,
1808  outer_itlist,
1809  inner_itlist,
1810  (Index) 0,
1811  rtoffset);
1812  }
1813  else if (IsA(join, HashJoin))
1814  {
1815  HashJoin *hj = (HashJoin *) join;
1816 
1817  hj->hashclauses = fix_join_expr(root,
1818  hj->hashclauses,
1819  outer_itlist,
1820  inner_itlist,
1821  (Index) 0,
1822  rtoffset);
1823 
1824  /*
1825  * HashJoin's hashkeys are used to look for matching tuples from its
1826  * outer plan (not the Hash node!) in the hashtable.
1827  */
1828  hj->hashkeys = (List *) fix_upper_expr(root,
1829  (Node *) hj->hashkeys,
1830  outer_itlist,
1831  OUTER_VAR,
1832  rtoffset);
1833  }
1834 
1835  /*
1836  * Now we need to fix up the targetlist and qpqual, which are logically
1837  * above the join. This means they should not re-use any input expression
1838  * that was computed in the nullable side of an outer join. Vars and
1839  * PlaceHolderVars are fine, so we can implement this restriction just by
1840  * clearing has_non_vars in the indexed_tlist structs.
1841  *
1842  * XXX This is a grotty workaround for the fact that we don't clearly
1843  * distinguish between a Var appearing below an outer join and the "same"
1844  * Var appearing above it. If we did, we'd not need to hack the matching
1845  * rules this way.
1846  */
1847  switch (join->jointype)
1848  {
1849  case JOIN_LEFT:
1850  case JOIN_SEMI:
1851  case JOIN_ANTI:
1852  inner_itlist->has_non_vars = false;
1853  break;
1854  case JOIN_RIGHT:
1855  outer_itlist->has_non_vars = false;
1856  break;
1857  case JOIN_FULL:
1858  outer_itlist->has_non_vars = false;
1859  inner_itlist->has_non_vars = false;
1860  break;
1861  default:
1862  break;
1863  }
1864 
1865  join->plan.targetlist = fix_join_expr(root,
1866  join->plan.targetlist,
1867  outer_itlist,
1868  inner_itlist,
1869  (Index) 0,
1870  rtoffset);
1871  join->plan.qual = fix_join_expr(root,
1872  join->plan.qual,
1873  outer_itlist,
1874  inner_itlist,
1875  (Index) 0,
1876  rtoffset);
1877 
1878  pfree(outer_itlist);
1879  pfree(inner_itlist);
1880 }
List * qual
Definition: plannodes.h:143
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
List * nestParams
Definition: plannodes.h:703
List * hashkeys
Definition: plannodes.h:751
List * hashclauses
Definition: plannodes.h:743
Definition: nodes.h:529
Definition: primnodes.h:181
List * mergeclauses
Definition: plannodes.h:728
static List * fix_join_expr(PlannerInfo *root, List *clauses, indexed_tlist *outer_itlist, indexed_tlist *inner_itlist, Index acceptable_rel, int rtoffset)
Definition: setrefs.c:2397
JoinType jointype
Definition: plannodes.h:684
struct Plan * righttree
Definition: plannodes.h:145
void pfree(void *pointer)
Definition: mcxt.c:1056
Var * paramval
Definition: plannodes.h:710
#define ERROR
Definition: elog.h:43
static Node * fix_upper_expr(PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, Index newvarno, int rtoffset)
Definition: setrefs.c:2542
Index varno
Definition: primnodes.h:184
bool has_non_vars
Definition: setrefs.c:44
unsigned int Index
Definition: c.h:482
#define lfirst(lc)
Definition: pg_list.h:190
static indexed_tlist * build_tlist_index(List *tlist)
Definition: setrefs.c:2152
struct Plan * lefttree
Definition: plannodes.h:144
List * targetlist
Definition: plannodes.h:142
#define elog(elevel,...)
Definition: elog.h:214
Definition: pg_list.h:50
#define OUTER_VAR
Definition: primnodes.h:172
List * joinqual
Definition: plannodes.h:686
Plan plan
Definition: plannodes.h:683

◆ set_mergeappend_references()

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

Definition at line 1383 of file setrefs.c.

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

Referenced by set_plan_refs().

1386 {
1387  ListCell *l;
1388 
1389  /*
1390  * MergeAppend, like Sort et al, doesn't actually evaluate its targetlist
1391  * or check quals. If it's got exactly one child plan, then it's not
1392  * doing anything useful at all, and we can strip it out.
1393  */
1394  Assert(mplan->plan.qual == NIL);
1395 
1396  /* First, we gotta recurse on the children */
1397  foreach(l, mplan->mergeplans)
1398  {
1399  lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset);
1400  }
1401 
1402  /* Now, if there's just one, forget the MergeAppend and return that child */
1403  if (list_length(mplan->mergeplans) == 1)
1404  return clean_up_removed_plan_level((Plan *) mplan,
1405  (Plan *) linitial(mplan->mergeplans));
1406 
1407  /*
1408  * Otherwise, clean up the MergeAppend as needed. It's okay to do this
1409  * after recursing to the children, because set_dummy_tlist_references
1410  * doesn't look at those.
1411  */
1412  set_dummy_tlist_references((Plan *) mplan, rtoffset);
1413 
1414  mplan->apprelids = offset_relid_set(mplan->apprelids, rtoffset);
1415 
1416  if (mplan->part_prune_info)
1417  {
1418  foreach(l, mplan->part_prune_info->prune_infos)
1419  {
1420  List *prune_infos = lfirst(l);
1421  ListCell *l2;
1422 
1423  foreach(l2, prune_infos)
1424  {
1425  PartitionedRelPruneInfo *pinfo = lfirst(l2);
1426 
1427  pinfo->rtindex += rtoffset;
1428  }
1429  }
1430  }
1431 
1432  /* We don't need to recurse to lefttree or righttree ... */
1433  Assert(mplan->plan.lefttree == NULL);
1434  Assert(mplan->plan.righttree == NULL);
1435 
1436  return (Plan *) mplan;
1437 }
#define NIL
Definition: pg_list.h:65
List * qual
Definition: plannodes.h:143
static Relids offset_relid_set(Relids relids, int rtoffset)
Definition: setrefs.c:1475
static Plan * set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:472
struct Plan * righttree
Definition: plannodes.h:145
#define linitial(l)
Definition: pg_list.h:195
static Plan * clean_up_removed_plan_level(Plan *parent, Plan *child)
Definition: setrefs.c:1163
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169
struct Plan * lefttree
Definition: plannodes.h:144
List * mergeplans
Definition: plannodes.h:276
Definition: pg_list.h:50
static void set_dummy_tlist_references(Plan *plan, int rtoffset)
Definition: setrefs.c:2085

◆ set_param_references()

static void set_param_references ( PlannerInfo root,
Plan plan 
)
static

Definition at line 1961 of file setrefs.c.

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

Referenced by set_plan_refs().

1962 {
1963  Assert(IsA(plan, Gather) || IsA(plan, GatherMerge));
1964 
1965  if (plan->lefttree->extParam)
1966  {
1967  PlannerInfo *proot;
1968  Bitmapset *initSetParam = NULL;
1969  ListCell *l;
1970 
1971  for (proot = root; proot != NULL; proot = proot->parent_root)
1972  {
1973  foreach(l, proot->init_plans)
1974  {
1975  SubPlan *initsubplan = (SubPlan *) lfirst(l);
1976  ListCell *l2;
1977 
1978  foreach(l2, initsubplan->setParam)
1979  {
1980  initSetParam = bms_add_member(initSetParam, lfirst_int(l2));
1981  }
1982  }
1983  }
1984 
1985  /*
1986  * Remember the list of all external initplan params that are used by
1987  * the children of Gather or Gather merge node.
1988  */
1989  if (IsA(plan, Gather))
1990  ((Gather *) plan)->initParam =
1991  bms_intersect(plan->lefttree->extParam, initSetParam);
1992  else
1993  ((GatherMerge *) plan)->initParam =
1994  bms_intersect(plan->lefttree->extParam, initSetParam);
1995  }
1996 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
PlannerInfo * parent_root
Definition: pathnodes.h:185
#define lfirst_int(lc)
Definition: pg_list.h:191
Bitmapset * bms_intersect(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:259
List * init_plans
Definition: pathnodes.h:259
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
List * setParam
Definition: primnodes.h:727
Bitmapset * extParam
Definition: plannodes.h:160
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
struct Plan * lefttree
Definition: plannodes.h:144

◆ set_plan_references()

Plan* set_plan_references ( PlannerInfo root,
Plan plan 
)

Definition at line 223 of file setrefs.c.

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

Referenced by set_subqueryscan_references(), and standard_planner().

224 {
225  PlannerGlobal *glob = root->glob;
226  int rtoffset = list_length(glob->finalrtable);
227  ListCell *lc;
228 
229  /*
230  * Add all the query's RTEs to the flattened rangetable. The live ones
231  * will have their rangetable indexes increased by rtoffset. (Additional
232  * RTEs, not referenced by the Plan tree, might get added after those.)
233  */
234  add_rtes_to_flat_rtable(root, false);
235 
236  /*
237  * Adjust RT indexes of PlanRowMarks and add to final rowmarks list
238  */
239  foreach(lc, root->rowMarks)
240  {
242  PlanRowMark *newrc;
243 
244  /* flat copy is enough since all fields are scalars */
245  newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark));
246  memcpy(newrc, rc, sizeof(PlanRowMark));
247 
248  /* adjust indexes ... but *not* the rowmarkId */
249  newrc->rti += rtoffset;
250  newrc->prti += rtoffset;
251 
252  glob->finalrowmarks = lappend(glob->finalrowmarks, newrc);
253  }
254 
255  /*
256  * Adjust RT indexes of AppendRelInfos and add to final appendrels list.
257  * We assume the AppendRelInfos were built during planning and don't need
258  * to be copied.
259  */
260  foreach(lc, root->append_rel_list)
261  {
262  AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
263 
264  /* adjust RT indexes */
265  appinfo->parent_relid += rtoffset;
266  appinfo->child_relid += rtoffset;
267 
268  /*
269  * Rather than adjust the translated_vars entries, just drop 'em.
270  * Neither the executor nor EXPLAIN currently need that data.
271  */
272  appinfo->translated_vars = NIL;
273 
274  glob->appendRelations = lappend(glob->appendRelations, appinfo);
275  }
276 
277  /* Now fix the Plan tree */
278  return set_plan_refs(root, plan, rtoffset);
279 }
#define NIL
Definition: pg_list.h:65
List * rowMarks
Definition: pathnodes.h:292
List * appendRelations
Definition: pathnodes.h:125
Index prti
Definition: plannodes.h:1078
List * translated_vars
Definition: pathnodes.h:2257
static Plan * set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:472
#define lfirst_node(type, lc)
Definition: pg_list.h:193
PlannerGlobal * glob
Definition: pathnodes.h:181
List * lappend(List *list, void *datum)
Definition: list.c:321
List * append_rel_list
Definition: pathnodes.h:290
static void add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
Definition: setrefs.c:287
static int list_length(const List *l)
Definition: pg_list.h:169
List * finalrtable
Definition: pathnodes.h:117
void * palloc(Size size)
Definition: mcxt.c:949
Index child_relid
Definition: pathnodes.h:2230
Index parent_relid
Definition: pathnodes.h:2229
List * finalrowmarks
Definition: pathnodes.h:119

◆ set_plan_refs()

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

Definition at line 472 of file setrefs.c.

References Agg::aggsplit, Assert, BitmapAnd::bitmapplans, BitmapOr::bitmapplans, BitmapHeapScan::bitmapqualorig, build_tlist_index(), convert_combining_aggrefs(), copyObject, DO_AGGSPLIT_COMBINE, elog, WindowAgg::endOffset, ERROR, ModifyTable::exclRelRTI, ModifyTable::exclRelTlist, fix_join_expr(), fix_scan_expr(), fix_scan_list, forthree, FunctionScan::functions, PlannerInfo::glob, IndexScan::indexorderby, IndexScan::indexorderbyorig, IndexScan::indexqual, BitmapIndexScan::indexqual, IndexScan::indexqualorig, BitmapIndexScan::indexqualorig, lappend(), lappend_int(), PlannerGlobal::lastPlanNodeId, Plan::lefttree, lfirst, lfirst_int, Limit::limitCount, Limit::limitOffset, linitial, linitial_int, list_concat(), list_length(), NIL, nodeTag, ModifyTable::nominalRelation, ModifyTable::onConflictSet, ModifyTable::onConflictWhere, pfree(), Result::plan, ModifyTable::plan, BitmapAnd::plan, BitmapOr::plan, Scan::plan, LockRows::plan, Limit::plan, Plan::plan_node_id, ModifyTable::plans, PlanRowMark::prti, Plan::qual, Result::resconstantqual, PlannerGlobal::resultRelations, ModifyTable::resultRelations, ModifyTable::resultRelIndex, ModifyTable::returningLists, Plan::righttree, ModifyTable::rootRelation, PlannerGlobal::rootResultRelations, ModifyTable::rootResultRelIndex, ModifyTable::rowMarks, LockRows::rowMarks, PlanRowMark::rti, SampleScan::scan, IndexScan::scan, BitmapIndexScan::scan, BitmapHeapScan::scan, TidScan::scan, FunctionScan::scan, ValuesScan::scan, TableFuncScan::scan, CteScan::scan, NamedTuplestoreScan::scan, WorkTableScan::scan, Scan::scanrelid, 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(), splan, WindowAgg::startOffset, T_Agg, T_Append, T_BitmapAnd, T_BitmapHeapScan, T_BitmapIndexScan, T_BitmapOr, T_CteScan, T_CustomScan, T_ForeignScan, T_FunctionScan, T_Gather, T_GatherMerge, T_Group, T_Hash, T_HashJoin, T_IncrementalSort, T_IndexOnlyScan, T_IndexScan, T_Limit, T_LockRows, T_Material, T_MergeAppend, T_MergeJoin, T_ModifyTable, T_NamedTuplestoreScan, T_NestLoop, T_ProjectSet, T_RecursiveUnion, T_Result, T_SampleScan, T_SeqScan, T_SetOp, T_Sort, T_SubqueryScan, T_TableFuncScan, T_TidScan, T_Unique, T_ValuesScan, T_WindowAgg, T_WorkTableScan, TableFuncScan::tablefunc, SampleScan::tablesample, Plan::targetlist, TidScan::tidquals, ValuesScan::values_lists, and ModifyTable::withCheckOptionLists.

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

473 {
474  ListCell *l;
475 
476  if (plan == NULL)
477  return NULL;
478 
479  /* Assign this node a unique ID. */
480  plan->plan_node_id = root->glob->lastPlanNodeId++;
481 
482  /*
483  * Plan-type-specific fixes
484  */
485  switch (nodeTag(plan))
486  {
487  case T_SeqScan:
488  {
489  SeqScan *splan = (SeqScan *) plan;
490 
491  splan->scanrelid += rtoffset;
492  splan->plan.targetlist =
493  fix_scan_list(root, splan->plan.targetlist, rtoffset);
494  splan->plan.qual =
495  fix_scan_list(root, splan->plan.qual, rtoffset);
496  }
497  break;
498  case T_SampleScan:
499  {
500  SampleScan *splan = (SampleScan *) plan;
501 
502  splan->scan.scanrelid += rtoffset;
503  splan->scan.plan.targetlist =
504  fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
505  splan->scan.plan.qual =
506  fix_scan_list(root, splan->scan.plan.qual, rtoffset);
507  splan->tablesample = (TableSampleClause *)
508  fix_scan_expr(root, (Node *) splan->tablesample, rtoffset);
509  }
510  break;
511  case T_IndexScan:
512  {
513  IndexScan *splan = (IndexScan *) plan;
514 
515  splan->scan.scanrelid += rtoffset;
516  splan->scan.plan.targetlist =
517  fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
518  splan->scan.plan.qual =
519  fix_scan_list(root, splan->scan.plan.qual, rtoffset);
520  splan->indexqual =
521  fix_scan_list(root, splan->indexqual, rtoffset);
522  splan->indexqualorig =
523  fix_scan_list(root, splan->indexqualorig, rtoffset);
524  splan->indexorderby =
525  fix_scan_list(root, splan->indexorderby, rtoffset);
526  splan->indexorderbyorig =
527  fix_scan_list(root, splan->indexorderbyorig, rtoffset);
528  }
529  break;
530  case T_IndexOnlyScan:
531  {
532  IndexOnlyScan *splan = (IndexOnlyScan *) plan;
533 
534  return set_indexonlyscan_references(root, splan, rtoffset);
535  }
536  break;
537  case T_BitmapIndexScan:
538  {
539  BitmapIndexScan *splan = (BitmapIndexScan *) plan;
540 
541  splan->scan.scanrelid += rtoffset;
542  /* no need to fix targetlist and qual */
543  Assert(splan->scan.plan.targetlist == NIL);
544  Assert(splan->scan.plan.qual == NIL);
545  splan->indexqual =
546  fix_scan_list(root, splan->indexqual, rtoffset);
547  splan->indexqualorig =
548  fix_scan_list(root, splan->indexqualorig, rtoffset);
549  }
550  break;
551  case T_BitmapHeapScan:
552  {
553  BitmapHeapScan *splan = (BitmapHeapScan *) plan;
554 
555  splan->scan.scanrelid += rtoffset;
556  splan->scan.plan.targetlist =
557  fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
558  splan->scan.plan.qual =
559  fix_scan_list(root, splan->scan.plan.qual, rtoffset);
560  splan->bitmapqualorig =
561  fix_scan_list(root, splan->bitmapqualorig, rtoffset);
562  }
563  break;
564  case T_TidScan:
565  {
566  TidScan *splan = (TidScan *) plan;
567 
568  splan->scan.scanrelid += rtoffset;
569  splan->scan.plan.targetlist =
570  fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
571  splan->scan.plan.qual =
572  fix_scan_list(root, splan->scan.plan.qual, rtoffset);
573  splan->tidquals =
574  fix_scan_list(root, splan->tidquals, rtoffset);
575  }
576  break;
577  case T_SubqueryScan:
578  /* Needs special treatment, see comments below */
579  return set_subqueryscan_references(root,
580  (SubqueryScan *) plan,
581  rtoffset);
582  case T_FunctionScan:
583  {
584  FunctionScan *splan = (FunctionScan *) plan;
585 
586  splan->scan.scanrelid += rtoffset;
587  splan->scan.plan.targetlist =
588  fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
589  splan->scan.plan.qual =
590  fix_scan_list(root, splan->scan.plan.qual, rtoffset);
591  splan->functions =
592  fix_scan_list(root, splan->functions, rtoffset);
593  }
594  break;
595  case T_TableFuncScan:
596  {
597  TableFuncScan *splan = (TableFuncScan *) plan;
598 
599  splan->scan.scanrelid += rtoffset;
600  splan->scan.plan.targetlist =
601  fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
602  splan->scan.plan.qual =
603  fix_scan_list(root, splan->scan.plan.qual, rtoffset);
604  splan->tablefunc = (TableFunc *)
605  fix_scan_expr(root, (Node *) splan->tablefunc, rtoffset);
606  }
607  break;
608  case T_ValuesScan:
609  {
610  ValuesScan *splan = (ValuesScan *) plan;
611 
612  splan->scan.scanrelid += rtoffset;
613  splan->scan.plan.targetlist =
614  fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
615  splan->scan.plan.qual =
616  fix_scan_list(root, splan->scan.plan.qual, rtoffset);
617  splan->values_lists =
618  fix_scan_list(root, splan->values_lists, rtoffset);
619  }
620  break;
621  case T_CteScan:
622  {
623  CteScan *splan = (CteScan *) plan;
624 
625  splan->scan.scanrelid += rtoffset;
626  splan->scan.plan.targetlist =
627  fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
628  splan->scan.plan.qual =
629  fix_scan_list(root, splan->scan.plan.qual, rtoffset);
630  }
631  break;
633  {
634  NamedTuplestoreScan *splan = (NamedTuplestoreScan *) plan;
635 
636  splan->scan.scanrelid += rtoffset;
637  splan->scan.plan.targetlist =
638  fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
639  splan->scan.plan.qual =
640  fix_scan_list(root, splan->scan.plan.qual, rtoffset);
641  }
642  break;
643  case T_WorkTableScan:
644  {
645  WorkTableScan *splan = (WorkTableScan *) plan;
646 
647  splan->scan.scanrelid += rtoffset;
648  splan->scan.plan.targetlist =
649  fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
650  splan->scan.plan.qual =
651  fix_scan_list(root, splan->scan.plan.qual, rtoffset);
652  }
653  break;
654  case T_ForeignScan:
655  set_foreignscan_references(root, (ForeignScan *) plan, rtoffset);
656  break;
657  case T_CustomScan:
658  set_customscan_references(root, (CustomScan *) plan, rtoffset);
659  break;
660 
661  case T_NestLoop:
662  case T_MergeJoin:
663  case T_HashJoin:
664  set_join_references(root, (Join *) plan, rtoffset);
665  break;
666 
667  case T_Gather:
668  case T_GatherMerge:
669  {
670  set_upper_references(root, plan, rtoffset);
671  set_param_references(root, plan);
672  }
673  break;
674 
675  case T_Hash:
676  set_hash_references(root, plan, rtoffset);
677  break;
678 
679  case T_Material:
680  case T_Sort:
681  case T_IncrementalSort:
682  case T_Unique:
683  case T_SetOp:
684 
685  /*
686  * These plan types don't actually bother to evaluate their
687  * targetlists, because they just return their unmodified input
688  * tuples. Even though the targetlist won't be used by the
689  * executor, we fix it up for possible use by EXPLAIN (not to
690  * mention ease of debugging --- wrong varnos are very confusing).
691  */
692  set_dummy_tlist_references(plan, rtoffset);
693 
694  /*
695  * Since these plan types don't check quals either, we should not
696  * find any qual expression attached to them.
697  */
698  Assert(plan->qual == NIL);
699  break;
700  case T_LockRows:
701  {
702  LockRows *splan = (LockRows *) plan;
703 
704  /*
705  * Like the plan types above, LockRows doesn't evaluate its
706  * tlist or quals. But we have to fix up the RT indexes in
707  * its rowmarks.
708  */
709  set_dummy_tlist_references(plan, rtoffset);
710  Assert(splan->plan.qual == NIL);
711 
712  foreach(l, splan->rowMarks)
713  {
714  PlanRowMark *rc = (PlanRowMark *) lfirst(l);
715 
716  rc->rti += rtoffset;
717  rc->prti += rtoffset;
718  }
719  }
720  break;
721  case T_Limit:
722  {
723  Limit *splan = (Limit *) plan;
724 
725  /*
726  * Like the plan types above, Limit doesn't evaluate its tlist
727  * or quals. It does have live expressions for limit/offset,
728  * however; and those cannot contain subplan variable refs, so
729  * fix_scan_expr works for them.
730  */
731  set_dummy_tlist_references(plan, rtoffset);
732  Assert(splan->plan.qual == NIL);
733 
734  splan->limitOffset =
735  fix_scan_expr(root, splan->limitOffset, rtoffset);
736  splan->limitCount =
737  fix_scan_expr(root, splan->limitCount, rtoffset);
738  }
739  break;
740  case T_Agg:
741  {
742  Agg *agg = (Agg *) plan;
743 
744  /*
745  * If this node is combining partial-aggregation results, we
746  * must convert its Aggrefs to contain references to the
747  * partial-aggregate subexpressions that will be available
748  * from the child plan node.
749  */
750  if (DO_AGGSPLIT_COMBINE(agg->aggsplit))
751  {
752  plan->targetlist = (List *)
754  NULL);
755  plan->qual = (List *)
757  NULL);
758  }
759 
760  set_upper_references(root, plan, rtoffset);
761  }
762  break;
763  case T_Group:
764  set_upper_references(root, plan, rtoffset);
765  break;
766  case T_WindowAgg:
767  {
768  WindowAgg *wplan = (WindowAgg *) plan;
769 
770  set_upper_references(root, plan, rtoffset);
771 
772  /*
773  * Like Limit node limit/offset expressions, WindowAgg has
774  * frame offset expressions, which cannot contain subplan
775  * variable refs, so fix_scan_expr works for them.
776  */
777  wplan->startOffset =
778  fix_scan_expr(root, wplan->startOffset, rtoffset);
779  wplan->endOffset =
780  fix_scan_expr(root, wplan->endOffset, rtoffset);
781  }
782  break;
783  case T_Result:
784  {
785  Result *splan = (Result *) plan;
786 
787  /*
788  * Result may or may not have a subplan; if not, it's more
789  * like a scan node than an upper node.
790  */
791  if (splan->plan.lefttree != NULL)
792  set_upper_references(root, plan, rtoffset);
793  else
794  {
795  splan->plan.targetlist =
796  fix_scan_list(root, splan->plan.targetlist, rtoffset);
797  splan->plan.qual =
798  fix_scan_list(root, splan->plan.qual, rtoffset);
799  }
800  /* resconstantqual can't contain any subplan variable refs */
801  splan->resconstantqual =
802  fix_scan_expr(root, splan->resconstantqual, rtoffset);
803  }
804  break;
805  case T_ProjectSet:
806  set_upper_references(root, plan, rtoffset);
807  break;
808  case T_ModifyTable:
809  {
810  ModifyTable *splan = (ModifyTable *) plan;
811 
812  Assert(splan->plan.targetlist == NIL);
813  Assert(splan->plan.qual == NIL);
814 
815  splan->withCheckOptionLists =
816  fix_scan_list(root, splan->withCheckOptionLists, rtoffset);
817 
818  if (splan->returningLists)
819  {
820  List *newRL = NIL;
821  ListCell *lcrl,
822  *lcrr,
823  *lcp;
824 
825  /*
826  * Pass each per-subplan returningList through
827  * set_returning_clause_references().
828  */
830  Assert(list_length(splan->returningLists) == list_length(splan->plans));
831  forthree(lcrl, splan->returningLists,
832  lcrr, splan->resultRelations,
833  lcp, splan->plans)
834  {
835  List *rlist = (List *) lfirst(lcrl);
836  Index resultrel = lfirst_int(lcrr);
837  Plan *subplan = (Plan *) lfirst(lcp);
838 
839  rlist = set_returning_clause_references(root,
840  rlist,
841  subplan,
842  resultrel,
843  rtoffset);
844  newRL = lappend(newRL, rlist);
845  }
846  splan->returningLists = newRL;
847 
848  /*
849  * Set up the visible plan targetlist as being the same as
850  * the first RETURNING list. This is for the use of
851  * EXPLAIN; the executor won't pay any attention to the
852  * targetlist. We postpone this step until here so that
853  * we don't have to do set_returning_clause_references()
854  * twice on identical targetlists.
855  */
856  splan->plan.targetlist = copyObject(linitial(newRL));
857  }
858 
859  /*
860  * We treat ModifyTable with ON CONFLICT as a form of 'pseudo
861  * join', where the inner side is the EXCLUDED tuple.
862  * Therefore use fix_join_expr to setup the relevant variables
863  * to INNER_VAR. We explicitly don't create any OUTER_VARs as
864  * those are already used by RETURNING and it seems better to
865  * be non-conflicting.
866  */
867  if (splan->onConflictSet)
868  {
869  indexed_tlist *itlist;
870 
871  itlist = build_tlist_index(splan->exclRelTlist);
872 
873  splan->onConflictSet =
874  fix_join_expr(root, splan->onConflictSet,
875  NULL, itlist,
877  rtoffset);
878 
879  splan->onConflictWhere = (Node *)
880  fix_join_expr(root, (List *) splan->onConflictWhere,
881  NULL, itlist,
883  rtoffset);
884 
885  pfree(itlist);
886 
887  splan->exclRelTlist =
888  fix_scan_list(root, splan->exclRelTlist, rtoffset);
889  }
890 
891  splan->nominalRelation += rtoffset;
892  if (splan->rootRelation)
893  splan->rootRelation += rtoffset;
894  splan->exclRelRTI += rtoffset;
895 
896  foreach(l, splan->resultRelations)
897  {
898  lfirst_int(l) += rtoffset;
899  }
900  foreach(l, splan->rowMarks)
901  {
902  PlanRowMark *rc = (PlanRowMark *) lfirst(l);
903 
904  rc->rti += rtoffset;
905  rc->prti += rtoffset;
906  }
907  foreach(l, splan->plans)
908  {
909  lfirst(l) = set_plan_refs(root,
910  (Plan *) lfirst(l),
911  rtoffset);
912  }
913 
914  /*
915  * Append this ModifyTable node's final result relation RT
916  * index(es) to the global list for the plan, and set its
917  * resultRelIndex to reflect their starting position in the
918  * global list.
919  */
921  root->glob->resultRelations =
923  splan->resultRelations);
924 
925  /*
926  * If the main target relation is a partitioned table, also
927  * add the partition root's RT index to rootResultRelations,
928  * and remember its index in that list in rootResultRelIndex.
929  */
930  if (splan->rootRelation)
931  {
932  splan->rootResultRelIndex =
934  root->glob->rootResultRelations =
936  splan->rootRelation);
937  }
938  }
939  break;
940  case T_Append:
941  /* Needs special treatment, see comments below */
942  return set_append_references(root,
943  (Append *) plan,
944  rtoffset);
945  case T_MergeAppend:
946  /* Needs special treatment, see comments below */
947  return set_mergeappend_references(root,
948  (MergeAppend *) plan,
949  rtoffset);
950  case T_RecursiveUnion:
951  /* This doesn't evaluate targetlist or check quals either */
952  set_dummy_tlist_references(plan, rtoffset);
953  Assert(plan->qual == NIL);
954  break;
955  case T_BitmapAnd:
956  {
957  BitmapAnd *splan = (BitmapAnd *) plan;
958 
959  /* BitmapAnd works like Append, but has no tlist */
960  Assert(splan->plan.targetlist == NIL);
961  Assert(splan->plan.qual == NIL);
962  foreach(l, splan->bitmapplans)
963  {
964  lfirst(l) = set_plan_refs(root,
965  (Plan *) lfirst(l),
966  rtoffset);
967  }
968  }
969  break;
970  case T_BitmapOr:
971  {
972  BitmapOr *splan = (BitmapOr *) plan;
973 
974  /* BitmapOr works like Append, but has no tlist */
975  Assert(splan->plan.targetlist == NIL);
976  Assert(splan->plan.qual == NIL);
977  foreach(l, splan->bitmapplans)
978  {
979  lfirst(l) = set_plan_refs(root,
980  (Plan *) lfirst(l),
981  rtoffset);
982  }
983  }
984  break;
985  default:
986  elog(ERROR, "unrecognized node type: %d",
987  (int) nodeTag(plan));
988  break;
989  }
990 
991  /*
992  * Now recurse into child plans, if any
993  *
994  * NOTE: it is essential that we recurse into child plans AFTER we set
995  * subplan references in this plan's tlist and quals. If we did the
996  * reference-adjustments bottom-up, then we would fail to match this
997  * plan's var nodes against the already-modified nodes of the children.
998  */
999  plan->lefttree = set_plan_refs(root, plan->lefttree, rtoffset);
1000  plan->righttree = set_plan_refs(root, plan->righttree, rtoffset);
1001 
1002  return plan;
1003 }
List * bitmapplans
Definition: plannodes.h:319
#define NIL
Definition: pg_list.h:65
Plan plan
Definition: plannodes.h:188
List * qual
Definition: plannodes.h:143
Definition: nodes.h:79
Plan plan
Definition: plannodes.h:344
Plan plan
Definition: plannodes.h:982
Index nominalRelation
Definition: plannodes.h:223
Definition: nodes.h:81
Index scanrelid
Definition: plannodes.h:345
Plan plan
Definition: plannodes.h:968
List * withCheckOptionLists
Definition: plannodes.h:230
List * functions
Definition: plannodes.h:525
static void set_join_references(PlannerInfo *root, Join *join, int rtoffset)
Definition: setrefs.c:1757
int resultRelIndex
Definition: plannodes.h:227
#define forthree(cell1, list1, cell2, list2, cell3, list3)
Definition: pg_list.h:464
int lastPlanNodeId
Definition: pathnodes.h:137
List * indexqual
Definition: plannodes.h:463
List * tidquals
Definition: plannodes.h:493
TableFunc * tablefunc
Definition: plannodes.h:546
int plan_node_id
Definition: plannodes.h:141
List * resultRelations
Definition: pathnodes.h:121
List * indexqualorig
Definition: plannodes.h:407
struct TableSampleClause * tablesample
Definition: plannodes.h:362
Definition: nodes.h:529
List * list_concat(List *list1, const List *list2)
Definition: list.c:515
Definition: nodes.h:49
Index prti
Definition: plannodes.h:1078
List * values_lists
Definition: plannodes.h:536
static void set_param_references(PlannerInfo *root, Plan *plan)
Definition: setrefs.c:1961
Definition: nodes.h:76
Scan scan
Definition: plannodes.h:535
Node * limitOffset
Definition: plannodes.h:983
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:791
static Plan * set_append_references(PlannerInfo *root, Append *aplan, int rtoffset)
Definition: setrefs.c:1319
List * plans
Definition: plannodes.h:229
static Plan * set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:472
List * onConflictSet
Definition: plannodes.h:238
int rootResultRelIndex
Definition: plannodes.h:228
Index rootRelation
Definition: plannodes.h:224
List * resultRelations
Definition: plannodes.h:226
static void set_foreignscan_references(PlannerInfo *root, ForeignScan *fscan, int rtoffset)
Definition: setrefs.c:1184
static List * fix_join_expr(PlannerInfo *root, List *clauses, indexed_tlist *outer_itlist, indexed_tlist *inner_itlist, Index acceptable_rel, int rtoffset)
Definition: setrefs.c:2397
List * rootResultRelations
Definition: pathnodes.h:123
#define linitial_int(l)
Definition: pg_list.h:196
Node * startOffset
Definition: plannodes.h:850
Node * resconstantqual
Definition: plannodes.h:189
List * rowMarks
Definition: plannodes.h:234
struct Plan * righttree
Definition: plannodes.h:145
void pfree(void *pointer)
Definition: mcxt.c:1056
#define linitial(l)
Definition: pg_list.h:195
Definition: nodes.h:46
#define ERROR
Definition: elog.h:43
List * indexorderbyorig
Definition: plannodes.h:409
#define lfirst_int(lc)
Definition: pg_list.h:191
Scan scan
Definition: plannodes.h:360
Scan scan
Definition: plannodes.h:555
Node * limitCount
Definition: plannodes.h:984
Scan scan
Definition: plannodes.h:404
Definition: nodes.h:78
PlannerGlobal * glob
Definition: pathnodes.h:181
Node * endOffset
Definition: plannodes.h:851
static SPIPlanPtr splan
Definition: regress.c:259
static void set_customscan_references(PlannerInfo *root, CustomScan *cscan, int rtoffset)
Definition: setrefs.c:1253
static Plan * set_subqueryscan_references(PlannerInfo *root, SubqueryScan *plan, int rtoffset)
Definition: setrefs.c:1056
List * indexqual
Definition: plannodes.h:406
List * bitmapqualorig
Definition: plannodes.h:479
List * lappend_int(List *list, int datum)
Definition: list.c:339
List * lappend(List *list, void *datum)
Definition: list.c:321
Plan plan
Definition: plannodes.h:332
static Plan * set_indexonlyscan_references(PlannerInfo *root, IndexOnlyScan *plan, int rtoffset)
Definition: setrefs.c:1015
List * bitmapplans
Definition: plannodes.h:334
static void set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:1901
unsigned int Index
Definition: c.h:482
Definition: nodes.h:84
static Node * convert_combining_aggrefs(Node *node, void *context)
Definition: setrefs.c:2016
List * indexorderby
Definition: plannodes.h:408
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
AggSplit aggsplit
Definition: plannodes.h:820
List * rowMarks
Definition: plannodes.h:969
static indexed_tlist * build_tlist_index(List *tlist)
Definition: setrefs.c:2152
Scan scan
Definition: plannodes.h:492
static int list_length(const List *l)
Definition: pg_list.h:169
struct Plan * lefttree
Definition: plannodes.h:144
List * indexqualorig
Definition: plannodes.h:464
#define nodeTag(nodeptr)
Definition: nodes.h:534
List * targetlist
Definition: plannodes.h:142
Definition: nodes.h:85
static List * set_returning_clause_references(PlannerInfo *root, List *rlist, Plan *topplan, Index resultRelation, int rtoffset)
Definition: setrefs.c:2661
Definition: nodes.h:82
#define elog(elevel,...)
Definition: elog.h:214
static Node * fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset)
Definition: setrefs.c:1637
List * returningLists
Definition: plannodes.h:231
Plan plan
Definition: plannodes.h:318
Definition: plannodes.h:816
#define copyObject(obj)
Definition: nodes.h:645
Index exclRelRTI
Definition: plannodes.h:240
static Plan * set_mergeappend_references(PlannerInfo *root, MergeAppend *mplan, int rtoffset)
Definition: setrefs.c:1383
Definition: pg_list.h:50
#define fix_scan_list(root, lst, rtoffset)
Definition: setrefs.c:82
static void set_dummy_tlist_references(Plan *plan, int rtoffset)
Definition: setrefs.c:2085
List * exclRelTlist
Definition: plannodes.h:241
static void set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:1444
Node * onConflictWhere
Definition: plannodes.h:239
Definition: nodes.h:87

◆ set_returning_clause_references()

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

Definition at line 2661 of file setrefs.c.

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

Referenced by set_plan_refs().

2666 {
2667  indexed_tlist *itlist;
2668 
2669  /*
2670  * We can perform the desired Var fixup by abusing the fix_join_expr
2671  * machinery that formerly handled inner indexscan fixup. We search the
2672  * top plan's targetlist for Vars of non-result relations, and use
2673  * fix_join_expr to convert RETURNING Vars into references to those tlist
2674  * entries, while leaving result-rel Vars as-is.
2675  *
2676  * PlaceHolderVars will also be sought in the targetlist, but no
2677  * more-complex expressions will be. Note that it is not possible for a
2678  * PlaceHolderVar to refer to the result relation, since the result is
2679  * never below an outer join. If that case could happen, we'd have to be
2680  * prepared to pick apart the PlaceHolderVar and evaluate its contained
2681  * expression instead.
2682  */
2683  itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
2684 
2685  rlist = fix_join_expr(root,
2686  rlist,
2687  itlist,
2688  NULL,
2689  resultRelation,
2690  rtoffset);
2691 
2692  pfree(itlist);
2693 
2694  return rlist;
2695 }
static List * fix_join_expr(PlannerInfo *root, List *clauses, indexed_tlist *outer_itlist, indexed_tlist *inner_itlist, Index acceptable_rel, int rtoffset)
Definition: setrefs.c:2397
void pfree(void *pointer)
Definition: mcxt.c:1056
static indexed_tlist * build_tlist_index_other_vars(List *tlist, Index ignore_rel)
Definition: setrefs.c:2202
List * targetlist
Definition: plannodes.h:142

◆ set_subqueryscan_references()

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

Definition at line 1056 of file setrefs.c.

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

Referenced by set_plan_refs().

1059 {
1060  RelOptInfo *rel;
1061  Plan *result;
1062 
1063  /* Need to look up the subquery's RelOptInfo, since we need its subroot */
1064  rel = find_base_rel(root, plan->scan.scanrelid);
1065 
1066  /* Recursively process the subplan */
1067  plan->subplan = set_plan_references(rel->subroot, plan->subplan);
1068 
1069  if (trivial_subqueryscan(plan))
1070  {
1071  /*
1072  * We can omit the SubqueryScan node and just pull up the subplan.
1073  */
1074  result = clean_up_removed_plan_level((Plan *) plan, plan->subplan);
1075  }
1076  else
1077  {
1078  /*
1079  * Keep the SubqueryScan node. We have to do the processing that
1080  * set_plan_references would otherwise have done on it. Notice we do
1081  * not do set_upper_references() here, because a SubqueryScan will
1082  * always have been created with correct references to its subplan's
1083  * outputs to begin with.
1084  */
1085  plan->scan.scanrelid += rtoffset;
1086  plan->scan.plan.targetlist =
1087  fix_scan_list(root, plan->scan.plan.targetlist, rtoffset);
1088  plan->scan.plan.qual =
1089  fix_scan_list(root, plan->scan.plan.qual, rtoffset);
1090 
1091  result = (Plan *) plan;
1092  }
1093 
1094  return result;
1095 }
List * qual
Definition: plannodes.h:143
Plan plan
Definition: plannodes.h:344
Index scanrelid
Definition: plannodes.h:345
static bool trivial_subqueryscan(SubqueryScan *plan)
Definition: setrefs.c:1105
PlannerInfo * subroot
Definition: pathnodes.h:709
static Plan * clean_up_removed_plan_level(Plan *parent, Plan *child)
Definition: setrefs.c:1163
List * targetlist
Definition: plannodes.h:142
Plan * set_plan_references(PlannerInfo *root, Plan *plan)
Definition: setrefs.c:223
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:374
#define fix_scan_list(root, lst, rtoffset)
Definition: setrefs.c:82
Plan * subplan
Definition: plannodes.h:515

◆ set_upper_references()

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

Definition at line 1901 of file setrefs.c.

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

Referenced by set_plan_refs().

1902 {
1903  Plan *subplan = plan->lefttree;
1904  indexed_tlist *subplan_itlist;
1905  List *output_targetlist;
1906  ListCell *l;
1907 
1908  subplan_itlist = build_tlist_index(subplan->targetlist);
1909 
1910  output_targetlist = NIL;
1911  foreach(l, plan->targetlist)
1912  {
1913  TargetEntry *tle = (TargetEntry *) lfirst(l);
1914  Node *newexpr;
1915 
1916  /* If it's a sort/group item, first try to match by sortref */
1917  if (tle->ressortgroupref != 0)
1918  {
1919  newexpr = (Node *)
1921  tle->ressortgroupref,
1922  subplan_itlist,
1923  OUTER_VAR);
1924  if (!newexpr)
1925  newexpr = fix_upper_expr(root,
1926  (Node *) tle->expr,
1927  subplan_itlist,
1928  OUTER_VAR,
1929  rtoffset);
1930  }
1931  else
1932  newexpr = fix_upper_expr(root,
1933  (Node *) tle->expr,
1934  subplan_itlist,
1935  OUTER_VAR,
1936  rtoffset);
1937  tle = flatCopyTargetEntry(tle);
1938  tle->expr = (Expr *) newexpr;
1939  output_targetlist = lappend(output_targetlist, tle);
1940  }
1941  plan->targetlist = output_targetlist;
1942 
1943  plan->qual = (List *)
1944  fix_upper_expr(root,
1945  (Node *) plan->qual,
1946  subplan_itlist,
1947  OUTER_VAR,
1948  rtoffset);
1949 
1950  pfree(subplan_itlist);
1951 }
#define NIL
Definition: pg_list.h:65
List * qual
Definition: plannodes.h:143
Definition: nodes.h:529
void pfree(void *pointer)
Definition: mcxt.c:1056
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:271
static Node * fix_upper_expr(PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, Index newvarno, int rtoffset)
Definition: setrefs.c:2542
List * lappend(List *list, void *datum)
Definition: list.c:321
#define lfirst(lc)
Definition: pg_list.h:190
Expr * expr
Definition: primnodes.h:1407
static indexed_tlist * build_tlist_index(List *tlist)
Definition: setrefs.c:2152
struct Plan * lefttree
Definition: plannodes.h:144
List * targetlist
Definition: plannodes.h:142
Index ressortgroupref
Definition: primnodes.h:1410
static Var * search_indexed_tlist_for_sortgroupref(Expr *node, Index sortgroupref, indexed_tlist *itlist, Index newvarno)
Definition: setrefs.c:2333
Definition: pg_list.h:50
#define OUTER_VAR
Definition: primnodes.h:172

◆ trivial_subqueryscan()

static bool trivial_subqueryscan ( SubqueryScan plan)
static

Definition at line 1105 of file setrefs.c.

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

Referenced by set_subqueryscan_references().

1106 {
1107  int attrno;
1108  ListCell *lp,
1109  *lc;
1110 
1111  if (plan->scan.plan.qual != NIL)
1112  return false;
1113 
1114  if (list_length(plan->scan.plan.targetlist) !=
1115  list_length(plan->subplan->targetlist))
1116  return false; /* tlists not same length */
1117 
1118  attrno = 1;
1119  forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
1120  {
1121  TargetEntry *ptle = (TargetEntry *) lfirst(lp);
1122  TargetEntry *ctle = (TargetEntry *) lfirst(lc);
1123 
1124  if (ptle->resjunk != ctle->resjunk)
1125  return false; /* tlist doesn't match junk status */
1126 
1127  /*
1128  * We accept either a Var referencing the corresponding element of the
1129  * subplan tlist, or a Const equaling the subplan element. See
1130  * generate_setop_tlist() for motivation.
1131  */
1132  if (ptle->expr && IsA(ptle->expr, Var))
1133  {
1134  Var *var = (Var *) ptle->expr;
1135 
1136  Assert(var->varno == plan->scan.scanrelid);
1137  Assert(var->varlevelsup == 0);
1138  if (var->varattno != attrno)
1139  return false; /* out of order */
1140  }
1141  else if (ptle->expr && IsA(ptle->expr, Const))
1142  {
1143  if (!equal(ptle->expr, ctle->expr))
1144  return false;
1145  }
1146  else
1147  return false;
1148 
1149  attrno++;
1150  }
1151 
1152  return true;
1153 }
#define NIL
Definition: pg_list.h:65
List * qual
Definition: plannodes.h:143
Plan plan
Definition: plannodes.h:344
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
Index varlevelsup
Definition: primnodes.h:191
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:419
Index scanrelid
Definition: plannodes.h:345
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3033
AttrNumber varattno
Definition: primnodes.h:186
Definition: primnodes.h:181
bool resjunk
Definition: primnodes.h:1414
Index varno
Definition: primnodes.h:184
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
Expr * expr
Definition: primnodes.h:1407
static int list_length(const List *l)
Definition: pg_list.h:169
List * targetlist
Definition: plannodes.h:142
Plan * subplan
Definition: plannodes.h:515