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 NUM_EXEC_TLIST(parentplan)   ((parentplan)->plan_rows)
 
#define NUM_EXEC_QUAL(parentplan)   ((parentplan)->plan_rows * 2.0)
 
#define ISREGCLASSCONST(con)
 
#define fix_scan_list(root, lst, rtoffset, num_exec)    ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset, num_exec))
 

Functions

static void add_rtes_to_flat_rtable (PlannerInfo *root, bool recursing)
 
static void flatten_unplanned_rtes (PlannerGlobal *glob, RangeTblEntry *rte)
 
static bool flatten_rtes_walker (Node *node, PlannerGlobal *glob)
 
static void add_rte_to_flat_rtable (PlannerGlobal *glob, RangeTblEntry *rte)
 
static Planset_plan_refs (PlannerInfo *root, Plan *plan, int rtoffset)
 
static Planset_indexonlyscan_references (PlannerInfo *root, IndexOnlyScan *plan, int rtoffset)
 
static Planset_subqueryscan_references (PlannerInfo *root, SubqueryScan *plan, int rtoffset)
 
static 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, double num_exec)
 
static Nodefix_scan_expr_mutator (Node *node, fix_scan_expr_context *context)
 
static bool fix_scan_expr_walker (Node *node, fix_scan_expr_context *context)
 
static void set_join_references (PlannerInfo *root, Join *join, int rtoffset)
 
static void set_upper_references (PlannerInfo *root, Plan *plan, int rtoffset)
 
static void set_param_references (PlannerInfo *root, Plan *plan)
 
static Nodeconvert_combining_aggrefs (Node *node, void *context)
 
static void set_dummy_tlist_references (Plan *plan, int rtoffset)
 
static indexed_tlistbuild_tlist_index (List *tlist)
 
static Varsearch_indexed_tlist_for_var (Var *var, indexed_tlist *itlist, int newvarno, int rtoffset)
 
static Varsearch_indexed_tlist_for_non_var (Expr *node, indexed_tlist *itlist, int newvarno)
 
static Varsearch_indexed_tlist_for_sortgroupref (Expr *node, Index sortgroupref, indexed_tlist *itlist, int newvarno)
 
static Listfix_join_expr (PlannerInfo *root, List *clauses, indexed_tlist *outer_itlist, indexed_tlist *inner_itlist, Index acceptable_rel, int rtoffset, double num_exec)
 
static Nodefix_join_expr_mutator (Node *node, fix_join_expr_context *context)
 
static Nodefix_upper_expr (PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, int newvarno, int rtoffset, double num_exec)
 
static Nodefix_upper_expr_mutator (Node *node, fix_upper_expr_context *context)
 
static Listset_returning_clause_references (PlannerInfo *root, List *rlist, Plan *topplan, Index resultRelation, int rtoffset)
 
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 Nodefix_alternative_subplan (PlannerInfo *root, AlternativeSubPlan *asplan, double num_exec)
 
static indexed_tlistbuild_tlist_index_other_vars (List *tlist, int 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,
  num_exec 
)     ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset, num_exec))

Definition at line 104 of file setrefs.c.

◆ ISREGCLASSCONST

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

Definition at line 100 of file setrefs.c.

◆ NUM_EXEC_QUAL

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

Definition at line 91 of file setrefs.c.

◆ NUM_EXEC_TLIST

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

Definition at line 90 of file setrefs.c.

Function Documentation

◆ add_rte_to_flat_rtable()

static void add_rte_to_flat_rtable ( PlannerGlobal glob,
RangeTblEntry rte 
)
static

Definition at line 483 of file setrefs.c.

484 {
485  RangeTblEntry *newrte;
486 
487  /* flat copy to duplicate all the scalar fields */
488  newrte = (RangeTblEntry *) palloc(sizeof(RangeTblEntry));
489  memcpy(newrte, rte, sizeof(RangeTblEntry));
490 
491  /* zap unneeded sub-structure */
492  newrte->tablesample = NULL;
493  newrte->subquery = NULL;
494  newrte->joinaliasvars = NIL;
495  newrte->joinleftcols = NIL;
496  newrte->joinrightcols = NIL;
497  newrte->join_using_alias = NULL;
498  newrte->functions = NIL;
499  newrte->tablefunc = NULL;
500  newrte->values_lists = NIL;
501  newrte->coltypes = NIL;
502  newrte->coltypmods = NIL;
503  newrte->colcollations = NIL;
504  newrte->securityQuals = NIL;
505 
506  glob->finalrtable = lappend(glob->finalrtable, newrte);
507 
508  /*
509  * If it's a plain relation RTE, add the table to relationOids.
510  *
511  * We do this even though the RTE might be unreferenced in the plan tree;
512  * this would correspond to cases such as views that were expanded, child
513  * tables that were eliminated by constraint exclusion, etc. Schema
514  * invalidation on such a rel must still force rebuilding of the plan.
515  *
516  * Note we don't bother to avoid making duplicate list entries. We could,
517  * but it would probably cost more cycles than it would save.
518  */
519  if (newrte->rtekind == RTE_RELATION)
520  glob->relationOids = lappend_oid(glob->relationOids, newrte->relid);
521 }
List * lappend(List *list, void *datum)
Definition: list.c:336
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
void * palloc(Size size)
Definition: mcxt.c:1062
@ RTE_RELATION
Definition: parsenodes.h:990
#define NIL
Definition: pg_list.h:65
List * relationOids
Definition: pathnodes.h:110
List * finalrtable
Definition: pathnodes.h:102
List * colcollations
Definition: parsenodes.h:1141
TableFunc * tablefunc
Definition: parsenodes.h:1107
Alias * join_using_alias
Definition: parsenodes.h:1091
struct TableSampleClause * tablesample
Definition: parsenodes.h:1037
List * securityQuals
Definition: parsenodes.h:1163
Query * subquery
Definition: parsenodes.h:1042
List * coltypes
Definition: parsenodes.h:1139
List * joinrightcols
Definition: parsenodes.h:1084
List * values_lists
Definition: parsenodes.h:1112
List * joinaliasvars
Definition: parsenodes.h:1082
List * coltypmods
Definition: parsenodes.h:1140
List * functions
Definition: parsenodes.h:1101
List * joinleftcols
Definition: parsenodes.h:1083
RTEKind rtekind
Definition: parsenodes.h:1007

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

Referenced by add_rtes_to_flat_rtable(), and flatten_rtes_walker().

◆ add_rtes_to_flat_rtable()

static void add_rtes_to_flat_rtable ( PlannerInfo root,
bool  recursing 
)
static

Definition at line 351 of file setrefs.c.

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

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

Referenced by set_plan_references().

◆ build_tlist_index()

static indexed_tlist * build_tlist_index ( List tlist)
static

Definition at line 2413 of file setrefs.c.

2414 {
2415  indexed_tlist *itlist;
2416  tlist_vinfo *vinfo;
2417  ListCell *l;
2418 
2419  /* Create data structure with enough slots for all tlist entries */
2420  itlist = (indexed_tlist *)
2422  list_length(tlist) * sizeof(tlist_vinfo));
2423 
2424  itlist->tlist = tlist;
2425  itlist->has_ph_vars = false;
2426  itlist->has_non_vars = false;
2427 
2428  /* Find the Vars and fill in the index array */
2429  vinfo = itlist->vars;
2430  foreach(l, tlist)
2431  {
2432  TargetEntry *tle = (TargetEntry *) lfirst(l);
2433 
2434  if (tle->expr && IsA(tle->expr, Var))
2435  {
2436  Var *var = (Var *) tle->expr;
2437 
2438  vinfo->varno = var->varno;
2439  vinfo->varattno = var->varattno;
2440  vinfo->resno = tle->resno;
2441  vinfo++;
2442  }
2443  else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2444  itlist->has_ph_vars = true;
2445  else
2446  itlist->has_non_vars = true;
2447  }
2448 
2449  itlist->num_vars = (vinfo - itlist->vars);
2450 
2451  return itlist;
2452 }
#define offsetof(type, field)
Definition: c.h:727
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
static int list_length(const List *l)
Definition: pg_list.h:149
Expr * expr
Definition: primnodes.h:1455
AttrNumber resno
Definition: primnodes.h:1456
Definition: primnodes.h:187
AttrNumber varattno
Definition: primnodes.h:191
int varno
Definition: primnodes.h:189
tlist_vinfo vars[FLEXIBLE_ARRAY_MEMBER]
Definition: setrefs.c:45
bool has_ph_vars
Definition: setrefs.c:43
bool has_non_vars
Definition: setrefs.c:44
int num_vars
Definition: setrefs.c:42
List * tlist
Definition: setrefs.c:41
AttrNumber resno
Definition: setrefs.c:36
int varno
Definition: setrefs.c:34
AttrNumber varattno
Definition: setrefs.c:35
Definition: regcomp.c:238

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

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

◆ build_tlist_index_other_vars()

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

Definition at line 2463 of file setrefs.c.

2464 {
2465  indexed_tlist *itlist;
2466  tlist_vinfo *vinfo;
2467  ListCell *l;
2468 
2469  /* Create data structure with enough slots for all tlist entries */
2470  itlist = (indexed_tlist *)
2472  list_length(tlist) * sizeof(tlist_vinfo));
2473 
2474  itlist->tlist = tlist;
2475  itlist->has_ph_vars = false;
2476  itlist->has_non_vars = false;
2477 
2478  /* Find the desired Vars and fill in the index array */
2479  vinfo = itlist->vars;
2480  foreach(l, tlist)
2481  {
2482  TargetEntry *tle = (TargetEntry *) lfirst(l);
2483 
2484  if (tle->expr && IsA(tle->expr, Var))
2485  {
2486  Var *var = (Var *) tle->expr;
2487 
2488  if (var->varno != ignore_rel)
2489  {
2490  vinfo->varno = var->varno;
2491  vinfo->varattno = var->varattno;
2492  vinfo->resno = tle->resno;
2493  vinfo++;
2494  }
2495  }
2496  else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2497  itlist->has_ph_vars = true;
2498  }
2499 
2500  itlist->num_vars = (vinfo - itlist->vars);
2501 
2502  return itlist;
2503 }

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

Referenced by set_returning_clause_references().

◆ clean_up_removed_plan_level()

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

Definition at line 1320 of file setrefs.c.

1321 {
1322  /* We have to be sure we don't lose any initplans */
1323  child->initPlan = list_concat(parent->initPlan,
1324  child->initPlan);
1325 
1326  /*
1327  * We also have to transfer the parent's column labeling info into the
1328  * child, else columns sent to client will be improperly labeled if this
1329  * is the topmost plan level. resjunk and so on may be important too.
1330  */
1331  apply_tlist_labeling(child->targetlist, parent->targetlist);
1332 
1333  return child;
1334 }
List * list_concat(List *list1, const List *list2)
Definition: list.c:540
List * targetlist
Definition: plannodes.h:141
List * initPlan
Definition: plannodes.h:145
void apply_tlist_labeling(List *dest_tlist, List *src_tlist)
Definition: tlist.c:307

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

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

◆ convert_combining_aggrefs()

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

Definition at line 2277 of file setrefs.c.

2278 {
2279  if (node == NULL)
2280  return NULL;
2281  if (IsA(node, Aggref))
2282  {
2283  Aggref *orig_agg = (Aggref *) node;
2284  Aggref *child_agg;
2285  Aggref *parent_agg;
2286 
2287  /* Assert we've not chosen to partial-ize any unsupported cases */
2288  Assert(orig_agg->aggorder == NIL);
2289  Assert(orig_agg->aggdistinct == NIL);
2290 
2291  /*
2292  * Since aggregate calls can't be nested, we needn't recurse into the
2293  * arguments. But for safety, flat-copy the Aggref node itself rather
2294  * than modifying it in-place.
2295  */
2296  child_agg = makeNode(Aggref);
2297  memcpy(child_agg, orig_agg, sizeof(Aggref));
2298 
2299  /*
2300  * For the parent Aggref, we want to copy all the fields of the
2301  * original aggregate *except* the args list, which we'll replace
2302  * below, and the aggfilter expression, which should be applied only
2303  * by the child not the parent. Rather than explicitly knowing about
2304  * all the other fields here, we can momentarily modify child_agg to
2305  * provide a suitable source for copyObject.
2306  */
2307  child_agg->args = NIL;
2308  child_agg->aggfilter = NULL;
2309  parent_agg = copyObject(child_agg);
2310  child_agg->args = orig_agg->args;
2311  child_agg->aggfilter = orig_agg->aggfilter;
2312 
2313  /*
2314  * Now, set up child_agg to represent the first phase of partial
2315  * aggregation. For now, assume serialization is required.
2316  */
2318 
2319  /*
2320  * And set up parent_agg to represent the second phase.
2321  */
2322  parent_agg->args = list_make1(makeTargetEntry((Expr *) child_agg,
2323  1, NULL, false));
2325 
2326  return (Node *) parent_agg;
2327  }
2329  (void *) context);
2330 }
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
Node * expression_tree_mutator(Node *node, Node *(*mutator)(), void *context)
Definition: nodeFuncs.c:2618
#define copyObject(obj)
Definition: nodes.h:655
@ AGGSPLIT_FINAL_DESERIAL
Definition: nodes.h:798
@ AGGSPLIT_INITIAL_SERIAL
Definition: nodes.h:796
#define makeNode(_type_)
Definition: nodes.h:587
#define list_make1(x1)
Definition: pg_list.h:206
void mark_partial_aggref(Aggref *agg, AggSplit aggsplit)
Definition: planner.c:5048
static Node * convert_combining_aggrefs(Node *node, void *context)
Definition: setrefs.c:2277
List * aggdistinct
Definition: primnodes.h:332
List * args
Definition: primnodes.h:330
Expr * aggfilter
Definition: primnodes.h:333
List * aggorder
Definition: primnodes.h:331
Definition: nodes.h:540

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

Referenced by set_plan_refs().

◆ copyVar()

static Var* copyVar ( Var var)
inlinestatic

Definition at line 1675 of file setrefs.c.

1676 {
1677  Var *newvar = (Var *) palloc(sizeof(Var));
1678 
1679  *newvar = *var;
1680  return newvar;
1681 }

References palloc().

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

◆ extract_query_dependencies()

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

Definition at line 3069 of file setrefs.c.

3073 {
3074  PlannerGlobal glob;
3075  PlannerInfo root;
3076 
3077  /* Make up dummy planner state so we can use this module's machinery */
3078  MemSet(&glob, 0, sizeof(glob));
3079  glob.type = T_PlannerGlobal;
3080  glob.relationOids = NIL;
3081  glob.invalItems = NIL;
3082  /* Hack: we use glob.dependsOnRole to collect hasRowSecurity flags */
3083  glob.dependsOnRole = false;
3084 
3085  MemSet(&root, 0, sizeof(root));
3086  root.type = T_PlannerInfo;
3087  root.glob = &glob;
3088 
3089  (void) extract_query_dependencies_walker(query, &root);
3090 
3091  *relationOids = glob.relationOids;
3092  *invalItems = glob.invalItems;
3093  *hasRowSecurity = glob.dependsOnRole;
3094 }
#define MemSet(start, val, len)
Definition: c.h:1008
@ T_PlannerInfo
Definition: nodes.h:223
@ T_PlannerGlobal
Definition: nodes.h:224
bool extract_query_dependencies_walker(Node *node, PlannerInfo *context)
Definition: setrefs.c:3105
NodeTag type
Definition: pathnodes.h:92
bool dependsOnRole
Definition: pathnodes.h:124
List * invalItems
Definition: pathnodes.h:112
NodeTag type
Definition: pathnodes.h:160

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

Referenced by CompleteCachedPlan(), and RevalidateCachedQuery().

◆ extract_query_dependencies_walker()

bool extract_query_dependencies_walker ( Node node,
PlannerInfo context 
)

Definition at line 3105 of file setrefs.c.

3106 {
3107  if (node == NULL)
3108  return false;
3109  Assert(!IsA(node, PlaceHolderVar));
3110  if (IsA(node, Query))
3111  {
3112  Query *query = (Query *) node;
3113  ListCell *lc;
3114 
3115  if (query->commandType == CMD_UTILITY)
3116  {
3117  /*
3118  * Ignore utility statements, except those (such as EXPLAIN) that
3119  * contain a parsed-but-not-planned query.
3120  */
3121  query = UtilityContainsQuery(query->utilityStmt);
3122  if (query == NULL)
3123  return false;
3124  }
3125 
3126  /* Remember if any Query has RLS quals applied by rewriter */
3127  if (query->hasRowSecurity)
3128  context->glob->dependsOnRole = true;
3129 
3130  /* Collect relation OIDs in this Query's rtable */
3131  foreach(lc, query->rtable)
3132  {
3133  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3134 
3135  if (rte->rtekind == RTE_RELATION)
3136  context->glob->relationOids =
3137  lappend_oid(context->glob->relationOids, rte->relid);
3138  else if (rte->rtekind == RTE_NAMEDTUPLESTORE &&
3139  OidIsValid(rte->relid))
3140  context->glob->relationOids =
3141  lappend_oid(context->glob->relationOids,
3142  rte->relid);
3143  }
3144 
3145  /* And recurse into the query's subexpressions */
3147  (void *) context, 0);
3148  }
3149  /* Extract function dependencies and check for regclass Consts */
3150  fix_expr_common(context, node);
3152  (void *) context);
3153 }
#define OidIsValid(objectId)
Definition: c.h:710
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2375
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1904
@ CMD_UTILITY
Definition: nodes.h:690
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:997
static void fix_expr_common(PlannerInfo *root, Node *node)
Definition: setrefs.c:1697
bool hasRowSecurity
Definition: parsenodes.h:140
CmdType commandType
Definition: parsenodes.h:119
Node * utilityStmt
Definition: parsenodes.h:127
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2155

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

Referenced by expression_planner_with_deps(), and extract_query_dependencies().

◆ fix_alternative_subplan()

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

Definition at line 1823 of file setrefs.c.

1825 {
1826  SubPlan *bestplan = NULL;
1827  Cost bestcost = 0;
1828  ListCell *lc;
1829 
1830  /*
1831  * Compute the estimated cost of each subplan assuming num_exec
1832  * executions, and keep the cheapest one. In event of exact equality of
1833  * estimates, we prefer the later plan; this is a bit arbitrary, but in
1834  * current usage it biases us to break ties against fast-start subplans.
1835  */
1836  Assert(asplan->subplans != NIL);
1837 
1838  foreach(lc, asplan->subplans)
1839  {
1840  SubPlan *curplan = (SubPlan *) lfirst(lc);
1841  Cost curcost;
1842 
1843  curcost = curplan->startup_cost + num_exec * curplan->per_call_cost;
1844  if (bestplan == NULL || curcost <= bestcost)
1845  {
1846  bestplan = curplan;
1847  bestcost = curcost;
1848  }
1849 
1850  /* Also mark all subplans that are in AlternativeSubPlans */
1851  root->isAltSubplan[curplan->plan_id - 1] = true;
1852  }
1853 
1854  /* Mark the subplan we selected */
1855  root->isUsedSubplan[bestplan->plan_id - 1] = true;
1856 
1857  return (Node *) bestplan;
1858 }
double Cost
Definition: nodes.h:673
bool * isAltSubplan
Definition: pathnodes.h:372
bool * isUsedSubplan
Definition: pathnodes.h:373
int plan_id
Definition: primnodes.h:752
Cost startup_cost
Definition: primnodes.h:775
Cost per_call_cost
Definition: primnodes.h:776

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

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

◆ fix_expr_common()

static void fix_expr_common ( PlannerInfo root,
Node node 
)
static

Definition at line 1697 of file setrefs.c.

1698 {
1699  /* We assume callers won't call us on a NULL pointer */
1700  if (IsA(node, Aggref))
1701  {
1703  ((Aggref *) node)->aggfnoid);
1704  }
1705  else if (IsA(node, WindowFunc))
1706  {
1708  ((WindowFunc *) node)->winfnoid);
1709  }
1710  else if (IsA(node, FuncExpr))
1711  {
1713  ((FuncExpr *) node)->funcid);
1714  }
1715  else if (IsA(node, OpExpr))
1716  {
1717  set_opfuncid((OpExpr *) node);
1719  ((OpExpr *) node)->opfuncid);
1720  }
1721  else if (IsA(node, DistinctExpr))
1722  {
1723  set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1725  ((DistinctExpr *) node)->opfuncid);
1726  }
1727  else if (IsA(node, NullIfExpr))
1728  {
1729  set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1731  ((NullIfExpr *) node)->opfuncid);
1732  }
1733  else if (IsA(node, ScalarArrayOpExpr))
1734  {
1735  ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) node;
1736 
1737  set_sa_opfuncid(saop);
1739 
1740  if (!OidIsValid(saop->hashfuncid))
1742 
1743  if (!OidIsValid(saop->negfuncid))
1745  }
1746  else if (IsA(node, Const))
1747  {
1748  Const *con = (Const *) node;
1749 
1750  /* Check for regclass reference */
1751  if (ISREGCLASSCONST(con))
1752  root->glob->relationOids =
1753  lappend_oid(root->glob->relationOids,
1755  }
1756  else if (IsA(node, GroupingFunc))
1757  {
1758  GroupingFunc *g = (GroupingFunc *) node;
1759  AttrNumber *grouping_map = root->grouping_map;
1760 
1761  /* If there are no grouping sets, we don't need this. */
1762 
1763  Assert(grouping_map || g->cols == NIL);
1764 
1765  if (grouping_map)
1766  {
1767  ListCell *lc;
1768  List *cols = NIL;
1769 
1770  foreach(lc, g->refs)
1771  {
1772  cols = lappend_int(cols, grouping_map[lfirst_int(lc)]);
1773  }
1774 
1775  Assert(!g->cols || equal(cols, g->cols));
1776 
1777  if (!g->cols)
1778  g->cols = cols;
1779  }
1780  }
1781 }
int16 AttrNumber
Definition: attnum.h:21
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3170
List * lappend_int(List *list, int datum)
Definition: list.c:354
void set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
Definition: nodeFuncs.c:1694
void set_opfuncid(OpExpr *opexpr)
Definition: nodeFuncs.c:1683
#define lfirst_int(lc)
Definition: pg_list.h:170
#define DatumGetObjectId(X)
Definition: postgres.h:544
void record_plan_function_dependency(PlannerInfo *root, Oid funcid)
Definition: setrefs.c:2988
#define ISREGCLASSCONST(con)
Definition: setrefs.c:100
Datum constvalue
Definition: primnodes.h:219
List * refs
Definition: primnodes.h:374
List * cols
Definition: primnodes.h:375
Definition: pg_list.h:51
AttrNumber * grouping_map
Definition: pathnodes.h:332

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

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

◆ fix_join_expr()

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

Definition at line 2659 of file setrefs.c.

2666 {
2667  fix_join_expr_context context;
2668 
2669  context.root = root;
2670  context.outer_itlist = outer_itlist;
2671  context.inner_itlist = inner_itlist;
2672  context.acceptable_rel = acceptable_rel;
2673  context.rtoffset = rtoffset;
2674  context.num_exec = num_exec;
2675  return (List *) fix_join_expr_mutator((Node *) clauses, &context);
2676 }
static Node * fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
Definition: setrefs.c:2679
indexed_tlist * outer_itlist
Definition: setrefs.c:58
PlannerInfo * root
Definition: setrefs.c:57
indexed_tlist * inner_itlist
Definition: setrefs.c:59

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

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

◆ fix_join_expr_mutator()

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

Definition at line 2679 of file setrefs.c.

2680 {
2681  Var *newvar;
2682 
2683  if (node == NULL)
2684  return NULL;
2685  if (IsA(node, Var))
2686  {
2687  Var *var = (Var *) node;
2688 
2689  /* Look for the var in the input tlists, first in the outer */
2690  if (context->outer_itlist)
2691  {
2692  newvar = search_indexed_tlist_for_var(var,
2693  context->outer_itlist,
2694  OUTER_VAR,
2695  context->rtoffset);
2696  if (newvar)
2697  return (Node *) newvar;
2698  }
2699 
2700  /* then in the inner. */
2701  if (context->inner_itlist)
2702  {
2703  newvar = search_indexed_tlist_for_var(var,
2704  context->inner_itlist,
2705  INNER_VAR,
2706  context->rtoffset);
2707  if (newvar)
2708  return (Node *) newvar;
2709  }
2710 
2711  /* If it's for acceptable_rel, adjust and return it */
2712  if (var->varno == context->acceptable_rel)
2713  {
2714  var = copyVar(var);
2715  var->varno += context->rtoffset;
2716  if (var->varnosyn > 0)
2717  var->varnosyn += context->rtoffset;
2718  return (Node *) var;
2719  }
2720 
2721  /* No referent found for Var */
2722  elog(ERROR, "variable not found in subplan target lists");
2723  }
2724  if (IsA(node, PlaceHolderVar))
2725  {
2726  PlaceHolderVar *phv = (PlaceHolderVar *) node;
2727 
2728  /* See if the PlaceHolderVar has bubbled up from a lower plan node */
2729  if (context->outer_itlist && context->outer_itlist->has_ph_vars)
2730  {
2731  newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2732  context->outer_itlist,
2733  OUTER_VAR);
2734  if (newvar)
2735  return (Node *) newvar;
2736  }
2737  if (context->inner_itlist && context->inner_itlist->has_ph_vars)
2738  {
2739  newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2740  context->inner_itlist,
2741  INNER_VAR);
2742  if (newvar)
2743  return (Node *) newvar;
2744  }
2745 
2746  /* If not supplied by input plans, evaluate the contained expr */
2747  return fix_join_expr_mutator((Node *) phv->phexpr, context);
2748  }
2749  /* Try matching more complex expressions too, if tlists have any */
2750  if (context->outer_itlist && context->outer_itlist->has_non_vars)
2751  {
2752  newvar = search_indexed_tlist_for_non_var((Expr *) node,
2753  context->outer_itlist,
2754  OUTER_VAR);
2755  if (newvar)
2756  return (Node *) newvar;
2757  }
2758  if (context->inner_itlist && context->inner_itlist->has_non_vars)
2759  {
2760  newvar = search_indexed_tlist_for_non_var((Expr *) node,
2761  context->inner_itlist,
2762  INNER_VAR);
2763  if (newvar)
2764  return (Node *) newvar;
2765  }
2766  /* Special cases (apply only AFTER failing to match to lower tlist) */
2767  if (IsA(node, Param))
2768  return fix_param_node(context->root, (Param *) node);
2769  if (IsA(node, AlternativeSubPlan))
2771  (AlternativeSubPlan *) node,
2772  context->num_exec),
2773  context);
2774  fix_expr_common(context->root, node);
2775  return expression_tree_mutator(node,
2777  (void *) context);
2778 }
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
#define OUTER_VAR
Definition: primnodes.h:176
#define INNER_VAR
Definition: primnodes.h:175
static Node * fix_param_node(PlannerInfo *root, Param *p)
Definition: setrefs.c:1792
static Var * search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist, int newvarno, int rtoffset)
Definition: setrefs.c:2514
static Node * fix_alternative_subplan(PlannerInfo *root, AlternativeSubPlan *asplan, double num_exec)
Definition: setrefs.c:1823
static Var * search_indexed_tlist_for_non_var(Expr *node, indexed_tlist *itlist, int newvarno)
Definition: setrefs.c:2554
static Var * copyVar(Var *var)
Definition: setrefs.c:1675
Index varnosyn
Definition: primnodes.h:199

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

Referenced by fix_join_expr().

◆ fix_param_node()

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

Definition at line 1792 of file setrefs.c.

1793 {
1794  if (p->paramkind == PARAM_MULTIEXPR)
1795  {
1796  int subqueryid = p->paramid >> 16;
1797  int colno = p->paramid & 0xFFFF;
1798  List *params;
1799 
1800  if (subqueryid <= 0 ||
1801  subqueryid > list_length(root->multiexpr_params))
1802  elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
1803  params = (List *) list_nth(root->multiexpr_params, subqueryid - 1);
1804  if (colno <= 0 || colno > list_length(params))
1805  elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
1806  return copyObject(list_nth(params, colno - 1));
1807  }
1808  return (Node *) copyObject(p);
1809 }
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
@ PARAM_MULTIEXPR
Definition: primnodes.h:261
int paramid
Definition: primnodes.h:268
ParamKind paramkind
Definition: primnodes.h:267
List * multiexpr_params
Definition: pathnodes.h:246

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

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

◆ fix_scan_expr()

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

Definition at line 1879 of file setrefs.c.

1880 {
1881  fix_scan_expr_context context;
1882 
1883  context.root = root;
1884  context.rtoffset = rtoffset;
1885  context.num_exec = num_exec;
1886 
1887  if (rtoffset != 0 ||
1888  root->multiexpr_params != NIL ||
1889  root->glob->lastPHId != 0 ||
1890  root->minmax_aggs != NIL ||
1891  root->hasAlternativeSubPlans)
1892  {
1893  return fix_scan_expr_mutator(node, &context);
1894  }
1895  else
1896  {
1897  /*
1898  * If rtoffset == 0, we don't need to change any Vars, and if there
1899  * are no MULTIEXPR subqueries then we don't need to replace
1900  * PARAM_MULTIEXPR Params, and if there are no placeholders anywhere
1901  * we won't need to remove them, and if there are no minmax Aggrefs we
1902  * won't need to replace them, and if there are no AlternativeSubPlans
1903  * we won't need to remove them. Then it's OK to just scribble on the
1904  * input node tree instead of copying (since the only change, filling
1905  * in any unset opfuncid fields, is harmless). This saves just enough
1906  * cycles to be noticeable on trivial queries.
1907  */
1908  (void) fix_scan_expr_walker(node, &context);
1909  return node;
1910  }
1911 }
static Node * fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
Definition: setrefs.c:1914
static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
Definition: setrefs.c:1987
Index lastPHId
Definition: pathnodes.h:116
List * minmax_aggs
Definition: pathnodes.h:333
bool hasAlternativeSubPlans
Definition: pathnodes.h:351
PlannerInfo * root
Definition: setrefs.c:50

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

Referenced by set_plan_refs().

◆ fix_scan_expr_mutator()

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

Definition at line 1914 of file setrefs.c.

1915 {
1916  if (node == NULL)
1917  return NULL;
1918  if (IsA(node, Var))
1919  {
1920  Var *var = copyVar((Var *) node);
1921 
1922  Assert(var->varlevelsup == 0);
1923 
1924  /*
1925  * We should not see Vars marked INNER_VAR, OUTER_VAR, or ROWID_VAR.
1926  * But an indexqual expression could contain INDEX_VAR Vars.
1927  */
1928  Assert(var->varno != INNER_VAR);
1929  Assert(var->varno != OUTER_VAR);
1930  Assert(var->varno != ROWID_VAR);
1931  if (!IS_SPECIAL_VARNO(var->varno))
1932  var->varno += context->rtoffset;
1933  if (var->varnosyn > 0)
1934  var->varnosyn += context->rtoffset;
1935  return (Node *) var;
1936  }
1937  if (IsA(node, Param))
1938  return fix_param_node(context->root, (Param *) node);
1939  if (IsA(node, Aggref))
1940  {
1941  Aggref *aggref = (Aggref *) node;
1942 
1943  /* See if the Aggref should be replaced by a Param */
1944  if (context->root->minmax_aggs != NIL &&
1945  list_length(aggref->args) == 1)
1946  {
1947  TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
1948  ListCell *lc;
1949 
1950  foreach(lc, context->root->minmax_aggs)
1951  {
1952  MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
1953 
1954  if (mminfo->aggfnoid == aggref->aggfnoid &&
1955  equal(mminfo->target, curTarget->expr))
1956  return (Node *) copyObject(mminfo->param);
1957  }
1958  }
1959  /* If no match, just fall through to process it normally */
1960  }
1961  if (IsA(node, CurrentOfExpr))
1962  {
1963  CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
1964 
1965  Assert(!IS_SPECIAL_VARNO(cexpr->cvarno));
1966  cexpr->cvarno += context->rtoffset;
1967  return (Node *) cexpr;
1968  }
1969  if (IsA(node, PlaceHolderVar))
1970  {
1971  /* At scan level, we should always just evaluate the contained expr */
1972  PlaceHolderVar *phv = (PlaceHolderVar *) node;
1973 
1974  return fix_scan_expr_mutator((Node *) phv->phexpr, context);
1975  }
1976  if (IsA(node, AlternativeSubPlan))
1978  (AlternativeSubPlan *) node,
1979  context->num_exec),
1980  context);
1981  fix_expr_common(context->root, node);
1983  (void *) context);
1984 }
#define linitial(l)
Definition: pg_list.h:174
#define ROWID_VAR
Definition: primnodes.h:178
#define IS_SPECIAL_VARNO(varno)
Definition: primnodes.h:180
Oid aggfnoid
Definition: primnodes.h:323
Param * param
Definition: pathnodes.h:2438
Expr * target
Definition: pathnodes.h:2434
Index varlevelsup
Definition: primnodes.h:196

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

Referenced by fix_scan_expr().

◆ fix_scan_expr_walker()

static bool fix_scan_expr_walker ( Node node,
fix_scan_expr_context context 
)
static

Definition at line 1987 of file setrefs.c.

1988 {
1989  if (node == NULL)
1990  return false;
1991  Assert(!(IsA(node, Var) && ((Var *) node)->varno == ROWID_VAR));
1992  Assert(!IsA(node, PlaceHolderVar));
1993  Assert(!IsA(node, AlternativeSubPlan));
1994  fix_expr_common(context->root, node);
1996  (void *) context);
1997 }

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

Referenced by fix_scan_expr().

◆ fix_upper_expr()

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

Definition at line 2812 of file setrefs.c.

2818 {
2819  fix_upper_expr_context context;
2820 
2821  context.root = root;
2822  context.subplan_itlist = subplan_itlist;
2823  context.newvarno = newvarno;
2824  context.rtoffset = rtoffset;
2825  context.num_exec = num_exec;
2826  return fix_upper_expr_mutator(node, &context);
2827 }
static Node * fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
Definition: setrefs.c:2830
indexed_tlist * subplan_itlist
Definition: setrefs.c:68
PlannerInfo * root
Definition: setrefs.c:67

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

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

◆ fix_upper_expr_mutator()

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

Definition at line 2830 of file setrefs.c.

2831 {
2832  Var *newvar;
2833 
2834  if (node == NULL)
2835  return NULL;
2836  if (IsA(node, Var))
2837  {
2838  Var *var = (Var *) node;
2839 
2840  newvar = search_indexed_tlist_for_var(var,
2841  context->subplan_itlist,
2842  context->newvarno,
2843  context->rtoffset);
2844  if (!newvar)
2845  elog(ERROR, "variable not found in subplan target list");
2846  return (Node *) newvar;
2847  }
2848  if (IsA(node, PlaceHolderVar))
2849  {
2850  PlaceHolderVar *phv = (PlaceHolderVar *) node;
2851 
2852  /* See if the PlaceHolderVar has bubbled up from a lower plan node */
2853  if (context->subplan_itlist->has_ph_vars)
2854  {
2855  newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2856  context->subplan_itlist,
2857  context->newvarno);
2858  if (newvar)
2859  return (Node *) newvar;
2860  }
2861  /* If not supplied by input plan, evaluate the contained expr */
2862  return fix_upper_expr_mutator((Node *) phv->phexpr, context);
2863  }
2864  /* Try matching more complex expressions too, if tlist has any */
2865  if (context->subplan_itlist->has_non_vars)
2866  {
2867  newvar = search_indexed_tlist_for_non_var((Expr *) node,
2868  context->subplan_itlist,
2869  context->newvarno);
2870  if (newvar)
2871  return (Node *) newvar;
2872  }
2873  /* Special cases (apply only AFTER failing to match to lower tlist) */
2874  if (IsA(node, Param))
2875  return fix_param_node(context->root, (Param *) node);
2876  if (IsA(node, Aggref))
2877  {
2878  Aggref *aggref = (Aggref *) node;
2879 
2880  /* See if the Aggref should be replaced by a Param */
2881  if (context->root->minmax_aggs != NIL &&
2882  list_length(aggref->args) == 1)
2883  {
2884  TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
2885  ListCell *lc;
2886 
2887  foreach(lc, context->root->minmax_aggs)
2888  {
2889  MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
2890 
2891  if (mminfo->aggfnoid == aggref->aggfnoid &&
2892  equal(mminfo->target, curTarget->expr))
2893  return (Node *) copyObject(mminfo->param);
2894  }
2895  }
2896  /* If no match, just fall through to process it normally */
2897  }
2898  if (IsA(node, AlternativeSubPlan))
2900  (AlternativeSubPlan *) node,
2901  context->num_exec),
2902  context);
2903  fix_expr_common(context->root, node);
2904  return expression_tree_mutator(node,
2906  (void *) context);
2907 }

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

Referenced by fix_upper_expr().

◆ flatten_rtes_walker()

static bool flatten_rtes_walker ( Node node,
PlannerGlobal glob 
)
static

Definition at line 447 of file setrefs.c.

448 {
449  if (node == NULL)
450  return false;
451  if (IsA(node, RangeTblEntry))
452  {
453  RangeTblEntry *rte = (RangeTblEntry *) node;
454 
455  /* As above, we need only save relation RTEs */
456  if (rte->rtekind == RTE_RELATION)
457  add_rte_to_flat_rtable(glob, rte);
458  return false;
459  }
460  if (IsA(node, Query))
461  {
462  /* Recurse into subselects */
463  return query_tree_walker((Query *) node,
465  (void *) glob,
467  }
469  (void *) glob);
470 }
#define QTW_EXAMINE_RTES_BEFORE
Definition: nodeFuncs.h:25
static bool flatten_rtes_walker(Node *node, PlannerGlobal *glob)
Definition: setrefs.c:447

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

Referenced by flatten_unplanned_rtes().

◆ flatten_unplanned_rtes()

static void flatten_unplanned_rtes ( PlannerGlobal glob,
RangeTblEntry rte 
)
static

Definition at line 437 of file setrefs.c.

438 {
439  /* Use query_tree_walker to find all RTEs in the parse tree */
440  (void) query_tree_walker(rte->subquery,
442  (void *) glob,
444 }

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

Referenced by add_rtes_to_flat_rtable().

◆ offset_relid_set()

static Relids offset_relid_set ( Relids  relids,
int  rtoffset 
)
static

Definition at line 1653 of file setrefs.c.

1654 {
1655  Relids result = NULL;
1656  int rtindex;
1657 
1658  /* If there's no offset to apply, we needn't recompute the value */
1659  if (rtoffset == 0)
1660  return relids;
1661  rtindex = -1;
1662  while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
1663  result = bms_add_member(result, rtindex + rtoffset);
1664  return result;
1665 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1045
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:738

References bms_add_member(), and bms_next_member().

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

◆ record_plan_function_dependency()

void record_plan_function_dependency ( PlannerInfo root,
Oid  funcid 
)

Definition at line 2988 of file setrefs.c.

2989 {
2990  /*
2991  * For performance reasons, we don't bother to track built-in functions;
2992  * we just assume they'll never change (or at least not in ways that'd
2993  * invalidate plans using them). For this purpose we can consider a
2994  * built-in function to be one with OID less than FirstUnpinnedObjectId.
2995  * Note that the OID generator guarantees never to generate such an OID
2996  * after startup, even at OID wraparound.
2997  */
2998  if (funcid >= (Oid) FirstUnpinnedObjectId)
2999  {
3000  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3001 
3002  /*
3003  * It would work to use any syscache on pg_proc, but the easiest is
3004  * PROCOID since we already have the function's OID at hand. Note
3005  * that plancache.c knows we use PROCOID.
3006  */
3007  inval_item->cacheId = PROCOID;
3008  inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
3009  ObjectIdGetDatum(funcid));
3010 
3011  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3012  }
3013 }
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
unsigned int Oid
Definition: postgres_ext.h:31
uint32 hashValue
Definition: plannodes.h:1309
@ PROCOID
Definition: syscache.h:77
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:204
#define FirstUnpinnedObjectId
Definition: transam.h:196

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

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

◆ record_plan_type_dependency()

void record_plan_type_dependency ( PlannerInfo root,
Oid  typid 
)

Definition at line 3028 of file setrefs.c.

3029 {
3030  /*
3031  * As in record_plan_function_dependency, ignore the possibility that
3032  * someone would change a built-in domain.
3033  */
3034  if (typid >= (Oid) FirstUnpinnedObjectId)
3035  {
3036  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3037 
3038  /*
3039  * It would work to use any syscache on pg_type, but the easiest is
3040  * TYPEOID since we already have the type's OID at hand. Note that
3041  * plancache.c knows we use TYPEOID.
3042  */
3043  inval_item->cacheId = TYPEOID;
3044  inval_item->hashValue = GetSysCacheHashValue1(TYPEOID,
3045  ObjectIdGetDatum(typid));
3046 
3047  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3048  }
3049 }
@ TYPEOID
Definition: syscache.h:112

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

Referenced by eval_const_expressions_mutator().

◆ search_indexed_tlist_for_non_var()

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

Definition at line 2554 of file setrefs.c.

2556 {
2557  TargetEntry *tle;
2558 
2559  /*
2560  * If it's a simple Const, replacing it with a Var is silly, even if there
2561  * happens to be an identical Const below; a Var is more expensive to
2562  * execute than a Const. What's more, replacing it could confuse some
2563  * places in the executor that expect to see simple Consts for, eg,
2564  * dropped columns.
2565  */
2566  if (IsA(node, Const))
2567  return NULL;
2568 
2569  tle = tlist_member(node, itlist->tlist);
2570  if (tle)
2571  {
2572  /* Found a matching subplan output expression */
2573  Var *newvar;
2574 
2575  newvar = makeVarFromTargetEntry(newvarno, tle);
2576  newvar->varnosyn = 0; /* wasn't ever a plain Var */
2577  newvar->varattnosyn = 0;
2578  return newvar;
2579  }
2580  return NULL; /* no match */
2581 }
Var * makeVarFromTargetEntry(int varno, TargetEntry *tle)
Definition: makefuncs.c:103
AttrNumber varattnosyn
Definition: primnodes.h:200
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:68

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

Referenced by fix_join_expr_mutator(), and fix_upper_expr_mutator().

◆ search_indexed_tlist_for_sortgroupref()

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

Definition at line 2594 of file setrefs.c.

2598 {
2599  ListCell *lc;
2600 
2601  foreach(lc, itlist->tlist)
2602  {
2603  TargetEntry *tle = (TargetEntry *) lfirst(lc);
2604 
2605  /* The equal() check should be redundant, but let's be paranoid */
2606  if (tle->ressortgroupref == sortgroupref &&
2607  equal(node, tle->expr))
2608  {
2609  /* Found a matching subplan output expression */
2610  Var *newvar;
2611 
2612  newvar = makeVarFromTargetEntry(newvarno, tle);
2613  newvar->varnosyn = 0; /* wasn't ever a plain Var */
2614  newvar->varattnosyn = 0;
2615  return newvar;
2616  }
2617  }
2618  return NULL; /* no match */
2619 }
Index ressortgroupref
Definition: primnodes.h:1458

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

Referenced by set_upper_references().

◆ search_indexed_tlist_for_var()

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

Definition at line 2514 of file setrefs.c.

2516 {
2517  int varno = var->varno;
2518  AttrNumber varattno = var->varattno;
2519  tlist_vinfo *vinfo;
2520  int i;
2521 
2522  vinfo = itlist->vars;
2523  i = itlist->num_vars;
2524  while (i-- > 0)
2525  {
2526  if (vinfo->varno == varno && vinfo->varattno == varattno)
2527  {
2528  /* Found a match */
2529  Var *newvar = copyVar(var);
2530 
2531  newvar->varno = newvarno;
2532  newvar->varattno = vinfo->resno;
2533  if (newvar->varnosyn > 0)
2534  newvar->varnosyn += rtoffset;
2535  return newvar;
2536  }
2537  vinfo++;
2538  }
2539  return NULL; /* no match */
2540 }
int i
Definition: isn.c:73

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

Referenced by fix_join_expr_mutator(), and fix_upper_expr_mutator().

◆ set_append_references()

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

Definition at line 1496 of file setrefs.c.

1499 {
1500  ListCell *l;
1501 
1502  /*
1503  * Append, like Sort et al, doesn't actually evaluate its targetlist or
1504  * check quals. If it's got exactly one child plan, then it's not doing
1505  * anything useful at all, and we can strip it out.
1506  */
1507  Assert(aplan->plan.qual == NIL);
1508 
1509  /* First, we gotta recurse on the children */
1510  foreach(l, aplan->appendplans)
1511  {
1512  lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset);
1513  }
1514 
1515  /* Now, if there's just one, forget the Append and return that child */
1516  if (list_length(aplan->appendplans) == 1)
1517  return clean_up_removed_plan_level((Plan *) aplan,
1518  (Plan *) linitial(aplan->appendplans));
1519 
1520  /*
1521  * Otherwise, clean up the Append as needed. It's okay to do this after
1522  * recursing to the children, because set_dummy_tlist_references doesn't
1523  * look at those.
1524  */
1525  set_dummy_tlist_references((Plan *) aplan, rtoffset);
1526 
1527  aplan->apprelids = offset_relid_set(aplan->apprelids, rtoffset);
1528 
1529  if (aplan->part_prune_info)
1530  {
1531  foreach(l, aplan->part_prune_info->prune_infos)
1532  {
1533  List *prune_infos = lfirst(l);
1534  ListCell *l2;
1535 
1536  foreach(l2, prune_infos)
1537  {
1538  PartitionedRelPruneInfo *pinfo = lfirst(l2);
1539 
1540  pinfo->rtindex += rtoffset;
1541  }
1542  }
1543  }
1544 
1545  /* We don't need to recurse to lefttree or righttree ... */
1546  Assert(aplan->plan.lefttree == NULL);
1547  Assert(aplan->plan.righttree == NULL);
1548 
1549  return (Plan *) aplan;
1550 }
static Relids offset_relid_set(Relids relids, int rtoffset)
Definition: setrefs.c:1653
static void set_dummy_tlist_references(Plan *plan, int rtoffset)
Definition: setrefs.c:2346
static Plan * clean_up_removed_plan_level(Plan *parent, Plan *child)
Definition: setrefs.c:1320
static Plan * set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:527
Plan plan
Definition: plannodes.h:251
List * appendplans
Definition: plannodes.h:253
struct Plan * lefttree
Definition: plannodes.h:143
struct Plan * righttree
Definition: plannodes.h:144
List * qual
Definition: plannodes.h:142

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

Referenced by set_plan_refs().

◆ set_customscan_references()

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

Definition at line 1423 of file setrefs.c.

1426 {
1427  ListCell *lc;
1428 
1429  /* Adjust scanrelid if it's valid */
1430  if (cscan->scan.scanrelid > 0)
1431  cscan->scan.scanrelid += rtoffset;
1432 
1433  if (cscan->custom_scan_tlist != NIL || cscan->scan.scanrelid == 0)
1434  {
1435  /* Adjust tlist, qual, custom_exprs to reference custom scan tuple */
1437 
1438  cscan->scan.plan.targetlist = (List *)
1439  fix_upper_expr(root,
1440  (Node *) cscan->scan.plan.targetlist,
1441  itlist,
1442  INDEX_VAR,
1443  rtoffset,
1444  NUM_EXEC_TLIST((Plan *) cscan));
1445  cscan->scan.plan.qual = (List *)
1446  fix_upper_expr(root,
1447  (Node *) cscan->scan.plan.qual,
1448  itlist,
1449  INDEX_VAR,
1450  rtoffset,
1451  NUM_EXEC_QUAL((Plan *) cscan));
1452  cscan->custom_exprs = (List *)
1453  fix_upper_expr(root,
1454  (Node *) cscan->custom_exprs,
1455  itlist,
1456  INDEX_VAR,
1457  rtoffset,
1458  NUM_EXEC_QUAL((Plan *) cscan));
1459  pfree(itlist);
1460  /* custom_scan_tlist itself just needs fix_scan_list() adjustments */
1461  cscan->custom_scan_tlist =
1462  fix_scan_list(root, cscan->custom_scan_tlist,
1463  rtoffset, NUM_EXEC_TLIST((Plan *) cscan));
1464  }
1465  else
1466  {
1467  /* Adjust tlist, qual, custom_exprs in the standard way */
1468  cscan->scan.plan.targetlist =
1469  fix_scan_list(root, cscan->scan.plan.targetlist,
1470  rtoffset, NUM_EXEC_TLIST((Plan *) cscan));
1471  cscan->scan.plan.qual =
1472  fix_scan_list(root, cscan->scan.plan.qual,
1473  rtoffset, NUM_EXEC_QUAL((Plan *) cscan));
1474  cscan->custom_exprs =
1475  fix_scan_list(root, cscan->custom_exprs,
1476  rtoffset, NUM_EXEC_QUAL((Plan *) cscan));
1477  }
1478 
1479  /* Adjust child plan-nodes recursively, if needed */
1480  foreach(lc, cscan->custom_plans)
1481  {
1482  lfirst(lc) = set_plan_refs(root, (Plan *) lfirst(lc), rtoffset);
1483  }
1484 
1485  cscan->custom_relids = offset_relid_set(cscan->custom_relids, rtoffset);
1486 }
void pfree(void *pointer)
Definition: mcxt.c:1169
#define INDEX_VAR
Definition: primnodes.h:177
#define NUM_EXEC_QUAL(parentplan)
Definition: setrefs.c:91
static indexed_tlist * build_tlist_index(List *tlist)
Definition: setrefs.c:2413
static Node * fix_upper_expr(PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, int newvarno, int rtoffset, double num_exec)
Definition: setrefs.c:2812
#define NUM_EXEC_TLIST(parentplan)
Definition: setrefs.c:90
#define fix_scan_list(root, lst, rtoffset, num_exec)
Definition: setrefs.c:104
List * custom_scan_tlist
Definition: plannodes.h:686
Scan scan
Definition: plannodes.h:680
Bitmapset * custom_relids
Definition: plannodes.h:687
List * custom_exprs
Definition: plannodes.h:684
List * custom_plans
Definition: plannodes.h:683
Plan plan
Definition: plannodes.h:343
Index scanrelid
Definition: plannodes.h:344

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

Referenced by set_plan_refs().

◆ set_dummy_tlist_references()

static void set_dummy_tlist_references ( Plan plan,
int  rtoffset 
)
static

Definition at line 2346 of file setrefs.c.

2347 {
2348  List *output_targetlist;
2349  ListCell *l;
2350 
2351  output_targetlist = NIL;
2352  foreach(l, plan->targetlist)
2353  {
2354  TargetEntry *tle = (TargetEntry *) lfirst(l);
2355  Var *oldvar = (Var *) tle->expr;
2356  Var *newvar;
2357 
2358  /*
2359  * As in search_indexed_tlist_for_non_var(), we prefer to keep Consts
2360  * as Consts, not Vars referencing Consts. Here, there's no speed
2361  * advantage to be had, but it makes EXPLAIN output look cleaner, and
2362  * again it avoids confusing the executor.
2363  */
2364  if (IsA(oldvar, Const))
2365  {
2366  /* just reuse the existing TLE node */
2367  output_targetlist = lappend(output_targetlist, tle);
2368  continue;
2369  }
2370 
2371  newvar = makeVar(OUTER_VAR,
2372  tle->resno,
2373  exprType((Node *) oldvar),
2374  exprTypmod((Node *) oldvar),
2375  exprCollation((Node *) oldvar),
2376  0);
2377  if (IsA(oldvar, Var) &&
2378  oldvar->varnosyn > 0)
2379  {
2380  newvar->varnosyn = oldvar->varnosyn + rtoffset;
2381  newvar->varattnosyn = oldvar->varattnosyn;
2382  }
2383  else
2384  {
2385  newvar->varnosyn = 0; /* wasn't ever a plain Var */
2386  newvar->varattnosyn = 0;
2387  }
2388 
2389  tle = flatCopyTargetEntry(tle);
2390  tle->expr = (Expr *) newvar;
2391  output_targetlist = lappend(output_targetlist, tle);
2392  }
2393  plan->targetlist = output_targetlist;
2394 
2395  /* We don't touch plan->qual here */
2396 }
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:271
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:267
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:759

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

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

◆ set_foreignscan_references()

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

Definition at line 1341 of file setrefs.c.

1344 {
1345  /* Adjust scanrelid if it's valid */
1346  if (fscan->scan.scanrelid > 0)
1347  fscan->scan.scanrelid += rtoffset;
1348 
1349  if (fscan->fdw_scan_tlist != NIL || fscan->scan.scanrelid == 0)
1350  {
1351  /*
1352  * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals to reference
1353  * foreign scan tuple
1354  */
1356 
1357  fscan->scan.plan.targetlist = (List *)
1358  fix_upper_expr(root,
1359  (Node *) fscan->scan.plan.targetlist,
1360  itlist,
1361  INDEX_VAR,
1362  rtoffset,
1363  NUM_EXEC_TLIST((Plan *) fscan));
1364  fscan->scan.plan.qual = (List *)
1365  fix_upper_expr(root,
1366  (Node *) fscan->scan.plan.qual,
1367  itlist,
1368  INDEX_VAR,
1369  rtoffset,
1370  NUM_EXEC_QUAL((Plan *) fscan));
1371  fscan->fdw_exprs = (List *)
1372  fix_upper_expr(root,
1373  (Node *) fscan->fdw_exprs,
1374  itlist,
1375  INDEX_VAR,
1376  rtoffset,
1377  NUM_EXEC_QUAL((Plan *) fscan));
1378  fscan->fdw_recheck_quals = (List *)
1379  fix_upper_expr(root,
1380  (Node *) fscan->fdw_recheck_quals,
1381  itlist,
1382  INDEX_VAR,
1383  rtoffset,
1384  NUM_EXEC_QUAL((Plan *) fscan));
1385  pfree(itlist);
1386  /* fdw_scan_tlist itself just needs fix_scan_list() adjustments */
1387  fscan->fdw_scan_tlist =
1388  fix_scan_list(root, fscan->fdw_scan_tlist,
1389  rtoffset, NUM_EXEC_TLIST((Plan *) fscan));
1390  }
1391  else
1392  {
1393  /*
1394  * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals in the standard
1395  * way
1396  */
1397  fscan->scan.plan.targetlist =
1398  fix_scan_list(root, fscan->scan.plan.targetlist,
1399  rtoffset, NUM_EXEC_TLIST((Plan *) fscan));
1400  fscan->scan.plan.qual =
1401  fix_scan_list(root, fscan->scan.plan.qual,
1402  rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
1403  fscan->fdw_exprs =
1404  fix_scan_list(root, fscan->fdw_exprs,
1405  rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
1406  fscan->fdw_recheck_quals =
1407  fix_scan_list(root, fscan->fdw_recheck_quals,
1408  rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
1409  }
1410 
1411  fscan->fs_relids = offset_relid_set(fscan->fs_relids, rtoffset);
1412 
1413  /* Adjust resultRelation if it's valid */
1414  if (fscan->resultRelation > 0)
1415  fscan->resultRelation += rtoffset;
1416 }
List * fdw_exprs
Definition: plannodes.h:655
Bitmapset * fs_relids
Definition: plannodes.h:659
Index resultRelation
Definition: plannodes.h:653
List * fdw_recheck_quals
Definition: plannodes.h:658
List * fdw_scan_tlist
Definition: plannodes.h:657

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

Referenced by set_plan_refs().

◆ set_hash_references()

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

Definition at line 1621 of file setrefs.c.

1622 {
1623  Hash *hplan = (Hash *) plan;
1624  Plan *outer_plan = plan->lefttree;
1625  indexed_tlist *outer_itlist;
1626 
1627  /*
1628  * Hash's hashkeys are used when feeding tuples into the hashtable,
1629  * therefore have them reference Hash's outer plan (which itself is the
1630  * inner plan of the HashJoin).
1631  */
1632  outer_itlist = build_tlist_index(outer_plan->targetlist);
1633  hplan->hashkeys = (List *)
1634  fix_upper_expr(root,
1635  (Node *) hplan->hashkeys,
1636  outer_itlist,
1637  OUTER_VAR,
1638  rtoffset,
1639  NUM_EXEC_QUAL(plan));
1640 
1641  /* Hash doesn't project */
1642  set_dummy_tlist_references(plan, rtoffset);
1643 
1644  /* Hash nodes don't have their own quals */
1645  Assert(plan->qual == NIL);
1646 }
List * hashkeys
Definition: plannodes.h:992

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

Referenced by set_plan_refs().

◆ set_indexonlyscan_references()

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

Definition at line 1140 of file setrefs.c.

1143 {
1144  indexed_tlist *index_itlist;
1145  List *stripped_indextlist;
1146  ListCell *lc;
1147 
1148  /*
1149  * Vars in the plan node's targetlist, qual, and recheckqual must only
1150  * reference columns that the index AM can actually return. To ensure
1151  * this, remove non-returnable columns (which are marked as resjunk) from
1152  * the indexed tlist. We can just drop them because the indexed_tlist
1153  * machinery pays attention to TLE resnos, not physical list position.
1154  */
1155  stripped_indextlist = NIL;
1156  foreach(lc, plan->indextlist)
1157  {
1158  TargetEntry *indextle = (TargetEntry *) lfirst(lc);
1159 
1160  if (!indextle->resjunk)
1161  stripped_indextlist = lappend(stripped_indextlist, indextle);
1162  }
1163 
1164  index_itlist = build_tlist_index(stripped_indextlist);
1165 
1166  plan->scan.scanrelid += rtoffset;
1167  plan->scan.plan.targetlist = (List *)
1168  fix_upper_expr(root,
1169  (Node *) plan->scan.plan.targetlist,
1170  index_itlist,
1171  INDEX_VAR,
1172  rtoffset,
1173  NUM_EXEC_TLIST((Plan *) plan));
1174  plan->scan.plan.qual = (List *)
1175  fix_upper_expr(root,
1176  (Node *) plan->scan.plan.qual,
1177  index_itlist,
1178  INDEX_VAR,
1179  rtoffset,
1180  NUM_EXEC_QUAL((Plan *) plan));
1181  plan->recheckqual = (List *)
1182  fix_upper_expr(root,
1183  (Node *) plan->recheckqual,
1184  index_itlist,
1185  INDEX_VAR,
1186  rtoffset,
1187  NUM_EXEC_QUAL((Plan *) plan));
1188  /* indexqual is already transformed to reference index columns */
1189  plan->indexqual = fix_scan_list(root, plan->indexqual,
1190  rtoffset, 1);
1191  /* indexorderby is already transformed to reference index columns */
1192  plan->indexorderby = fix_scan_list(root, plan->indexorderby,
1193  rtoffset, 1);
1194  /* indextlist must NOT be transformed to reference index columns */
1195  plan->indextlist = fix_scan_list(root, plan->indextlist,
1196  rtoffset, NUM_EXEC_TLIST((Plan *) plan));
1197 
1198  pfree(index_itlist);
1199 
1200  return (Plan *) plan;
1201 }
List * indexqual
Definition: plannodes.h:451
List * recheckqual
Definition: plannodes.h:452
List * indextlist
Definition: plannodes.h:454
List * indexorderby
Definition: plannodes.h:453
bool resjunk
Definition: primnodes.h:1462

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

Referenced by set_plan_refs().

◆ set_join_references()

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

Definition at line 2008 of file setrefs.c.

2009 {
2010  Plan *outer_plan = join->plan.lefttree;
2011  Plan *inner_plan = join->plan.righttree;
2012  indexed_tlist *outer_itlist;
2013  indexed_tlist *inner_itlist;
2014 
2015  outer_itlist = build_tlist_index(outer_plan->targetlist);
2016  inner_itlist = build_tlist_index(inner_plan->targetlist);
2017 
2018  /*
2019  * First process the joinquals (including merge or hash clauses). These
2020  * are logically below the join so they can always use all values
2021  * available from the input tlists. It's okay to also handle
2022  * NestLoopParams now, because those couldn't refer to nullable
2023  * subexpressions.
2024  */
2025  join->joinqual = fix_join_expr(root,
2026  join->joinqual,
2027  outer_itlist,
2028  inner_itlist,
2029  (Index) 0,
2030  rtoffset,
2031  NUM_EXEC_QUAL((Plan *) join));
2032 
2033  /* Now do join-type-specific stuff */
2034  if (IsA(join, NestLoop))
2035  {
2036  NestLoop *nl = (NestLoop *) join;
2037  ListCell *lc;
2038 
2039  foreach(lc, nl->nestParams)
2040  {
2041  NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
2042 
2043  nlp->paramval = (Var *) fix_upper_expr(root,
2044  (Node *) nlp->paramval,
2045  outer_itlist,
2046  OUTER_VAR,
2047  rtoffset,
2048  NUM_EXEC_TLIST(outer_plan));
2049  /* Check we replaced any PlaceHolderVar with simple Var */
2050  if (!(IsA(nlp->paramval, Var) &&
2051  nlp->paramval->varno == OUTER_VAR))
2052  elog(ERROR, "NestLoopParam was not reduced to a simple Var");
2053  }
2054  }
2055  else if (IsA(join, MergeJoin))
2056  {
2057  MergeJoin *mj = (MergeJoin *) join;
2058 
2059  mj->mergeclauses = fix_join_expr(root,
2060  mj->mergeclauses,
2061  outer_itlist,
2062  inner_itlist,
2063  (Index) 0,
2064  rtoffset,
2065  NUM_EXEC_QUAL((Plan *) join));
2066  }
2067  else if (IsA(join, HashJoin))
2068  {
2069  HashJoin *hj = (HashJoin *) join;
2070 
2071  hj->hashclauses = fix_join_expr(root,
2072  hj->hashclauses,
2073  outer_itlist,
2074  inner_itlist,
2075  (Index) 0,
2076  rtoffset,
2077  NUM_EXEC_QUAL((Plan *) join));
2078 
2079  /*
2080  * HashJoin's hashkeys are used to look for matching tuples from its
2081  * outer plan (not the Hash node!) in the hashtable.
2082  */
2083  hj->hashkeys = (List *) fix_upper_expr(root,
2084  (Node *) hj->hashkeys,
2085  outer_itlist,
2086  OUTER_VAR,
2087  rtoffset,
2088  NUM_EXEC_QUAL((Plan *) join));
2089  }
2090 
2091  /*
2092  * Now we need to fix up the targetlist and qpqual, which are logically
2093  * above the join. This means they should not re-use any input expression
2094  * that was computed in the nullable side of an outer join. Vars and
2095  * PlaceHolderVars are fine, so we can implement this restriction just by
2096  * clearing has_non_vars in the indexed_tlist structs.
2097  *
2098  * XXX This is a grotty workaround for the fact that we don't clearly
2099  * distinguish between a Var appearing below an outer join and the "same"
2100  * Var appearing above it. If we did, we'd not need to hack the matching
2101  * rules this way.
2102  */
2103  switch (join->jointype)
2104  {
2105  case JOIN_LEFT:
2106  case JOIN_SEMI:
2107  case JOIN_ANTI:
2108  inner_itlist->has_non_vars = false;
2109  break;
2110  case JOIN_RIGHT:
2111  outer_itlist->has_non_vars = false;
2112  break;
2113  case JOIN_FULL:
2114  outer_itlist->has_non_vars = false;
2115  inner_itlist->has_non_vars = false;
2116  break;
2117  default:
2118  break;
2119  }
2120 
2121  join->plan.targetlist = fix_join_expr(root,
2122  join->plan.targetlist,
2123  outer_itlist,
2124  inner_itlist,
2125  (Index) 0,
2126  rtoffset,
2127  NUM_EXEC_TLIST((Plan *) join));
2128  join->plan.qual = fix_join_expr(root,
2129  join->plan.qual,
2130  outer_itlist,
2131  inner_itlist,
2132  (Index) 0,
2133  rtoffset,
2134  NUM_EXEC_QUAL((Plan *) join));
2135 
2136  pfree(outer_itlist);
2137  pfree(inner_itlist);
2138 }
@ JOIN_SEMI
Definition: nodes.h:727
@ JOIN_FULL
Definition: nodes.h:715
@ JOIN_RIGHT
Definition: nodes.h:716
@ JOIN_LEFT
Definition: nodes.h:714
@ JOIN_ANTI
Definition: nodes.h:728
static List * fix_join_expr(PlannerInfo *root, List *clauses, indexed_tlist *outer_itlist, indexed_tlist *inner_itlist, Index acceptable_rel, int rtoffset, double num_exec)
Definition: setrefs.c:2659
List * hashclauses
Definition: plannodes.h:781
List * hashkeys
Definition: plannodes.h:789
List * joinqual
Definition: plannodes.h:724
JoinType jointype
Definition: plannodes.h:722
Plan plan
Definition: plannodes.h:721
List * mergeclauses
Definition: plannodes.h:766
Var * paramval
Definition: plannodes.h:748
List * nestParams
Definition: plannodes.h:741

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

Referenced by set_plan_refs().

◆ set_mergeappend_references()

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

Definition at line 1560 of file setrefs.c.

1563 {
1564  ListCell *l;
1565 
1566  /*
1567  * MergeAppend, like Sort et al, doesn't actually evaluate its targetlist
1568  * or check quals. If it's got exactly one child plan, then it's not
1569  * doing anything useful at all, and we can strip it out.
1570  */
1571  Assert(mplan->plan.qual == NIL);
1572 
1573  /* First, we gotta recurse on the children */
1574  foreach(l, mplan->mergeplans)
1575  {
1576  lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset);
1577  }
1578 
1579  /* Now, if there's just one, forget the MergeAppend and return that child */
1580  if (list_length(mplan->mergeplans) == 1)
1581  return clean_up_removed_plan_level((Plan *) mplan,
1582  (Plan *) linitial(mplan->mergeplans));
1583 
1584  /*
1585  * Otherwise, clean up the MergeAppend as needed. It's okay to do this
1586  * after recursing to the children, because set_dummy_tlist_references
1587  * doesn't look at those.
1588  */
1589  set_dummy_tlist_references((Plan *) mplan, rtoffset);
1590 
1591  mplan->apprelids = offset_relid_set(mplan->apprelids, rtoffset);
1592 
1593  if (mplan->part_prune_info)
1594  {
1595  foreach(l, mplan->part_prune_info->prune_infos)
1596  {
1597  List *prune_infos = lfirst(l);
1598  ListCell *l2;
1599 
1600  foreach(l2, prune_infos)
1601  {
1602  PartitionedRelPruneInfo *pinfo = lfirst(l2);
1603 
1604  pinfo->rtindex += rtoffset;
1605  }
1606  }
1607  }
1608 
1609  /* We don't need to recurse to lefttree or righttree ... */
1610  Assert(mplan->plan.lefttree == NULL);
1611  Assert(mplan->plan.righttree == NULL);
1612 
1613  return (Plan *) mplan;
1614 }
List * mergeplans
Definition: plannodes.h:275

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

Referenced by set_plan_refs().

◆ set_param_references()

static void set_param_references ( PlannerInfo root,
Plan plan 
)
static

Definition at line 2222 of file setrefs.c.

2223 {
2224  Assert(IsA(plan, Gather) || IsA(plan, GatherMerge));
2225 
2226  if (plan->lefttree->extParam)
2227  {
2228  PlannerInfo *proot;
2229  Bitmapset *initSetParam = NULL;
2230  ListCell *l;
2231 
2232  for (proot = root; proot != NULL; proot = proot->parent_root)
2233  {
2234  foreach(l, proot->init_plans)
2235  {
2236  SubPlan *initsubplan = (SubPlan *) lfirst(l);
2237  ListCell *l2;
2238 
2239  foreach(l2, initsubplan->setParam)
2240  {
2241  initSetParam = bms_add_member(initSetParam, lfirst_int(l2));
2242  }
2243  }
2244  }
2245 
2246  /*
2247  * Remember the list of all external initplan params that are used by
2248  * the children of Gather or Gather merge node.
2249  */
2250  if (IsA(plan, Gather))
2251  ((Gather *) plan)->initParam =
2252  bms_intersect(plan->lefttree->extParam, initSetParam);
2253  else
2254  ((GatherMerge *) plan)->initParam =
2255  bms_intersect(plan->lefttree->extParam, initSetParam);
2256  }
2257 }
Bitmapset * bms_intersect(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:259
Bitmapset * extParam
Definition: plannodes.h:159
List * init_plans
Definition: pathnodes.h:242
PlannerInfo * parent_root
Definition: pathnodes.h:168
List * setParam
Definition: primnodes.h:770

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

Referenced by set_plan_refs().

◆ set_plan_references()

Plan* set_plan_references ( PlannerInfo root,
Plan plan 
)

Definition at line 250 of file setrefs.c.

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

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

Referenced by set_subqueryscan_references(), and standard_planner().

◆ set_plan_refs()

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

Definition at line 527 of file setrefs.c.

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

References Agg::aggsplit, Assert(), build_tlist_index(), convert_combining_aggrefs(), copyObject, DO_AGGSPLIT_COMBINE, elog, WindowAgg::endOffset, ERROR, TargetEntry::expr, fix_join_expr(), fix_scan_expr(), fix_scan_list, forboth, PlannerInfo::glob, if(), IsA, lappend(), lappend_int(), PlannerGlobal::lastPlanNodeId, Plan::lefttree, lfirst, lfirst_int, linitial, linitial_int, list_concat(), list_length(), makeNullConst(), NIL, nodeTag, NUM_EXEC_QUAL, NUM_EXEC_TLIST, outerPlan, Memoize::param_exprs, pfree(), Plan::plan_node_id, PlanRowMark::prti, PlannerGlobal::resultRelations, Plan::righttree, ROWID_VAR, PlanRowMark::rti, 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_Memoize, T_MergeAppend, T_MergeJoin, T_ModifyTable, T_NamedTuplestoreScan, T_NestLoop, T_ProjectSet, T_RecursiveUnion, T_Result, T_SampleScan, T_SeqScan, T_SetOp, T_Sort, T_SubqueryScan, T_TableFuncScan, T_TidRangeScan, T_TidScan, T_Unique, T_ValuesScan, T_WindowAgg, T_WorkTableScan, Var::varcollid, Var::varno, Var::vartype, and Var::vartypmod.

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

◆ set_returning_clause_references()

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

Definition at line 2938 of file setrefs.c.

2943 {
2944  indexed_tlist *itlist;
2945 
2946  /*
2947  * We can perform the desired Var fixup by abusing the fix_join_expr
2948  * machinery that formerly handled inner indexscan fixup. We search the
2949  * top plan's targetlist for Vars of non-result relations, and use
2950  * fix_join_expr to convert RETURNING Vars into references to those tlist
2951  * entries, while leaving result-rel Vars as-is.
2952  *
2953  * PlaceHolderVars will also be sought in the targetlist, but no
2954  * more-complex expressions will be. Note that it is not possible for a
2955  * PlaceHolderVar to refer to the result relation, since the result is
2956  * never below an outer join. If that case could happen, we'd have to be
2957  * prepared to pick apart the PlaceHolderVar and evaluate its contained
2958  * expression instead.
2959  */
2960  itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
2961 
2962  rlist = fix_join_expr(root,
2963  rlist,
2964  itlist,
2965  NULL,
2966  resultRelation,
2967  rtoffset,
2968  NUM_EXEC_TLIST(topplan));
2969 
2970  pfree(itlist);
2971 
2972  return rlist;
2973 }
static indexed_tlist * build_tlist_index_other_vars(List *tlist, int ignore_rel)
Definition: setrefs.c:2463

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

Referenced by set_plan_refs().

◆ set_subqueryscan_references()

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

Definition at line 1211 of file setrefs.c.

1214 {
1215  RelOptInfo *rel;
1216  Plan *result;
1217 
1218  /* Need to look up the subquery's RelOptInfo, since we need its subroot */
1219  rel = find_base_rel(root, plan->scan.scanrelid);
1220 
1221  /* Recursively process the subplan */
1222  plan->subplan = set_plan_references(rel->subroot, plan->subplan);
1223 
1224  if (trivial_subqueryscan(plan))
1225  {
1226  /*
1227  * We can omit the SubqueryScan node and just pull up the subplan.
1228  */
1229  result = clean_up_removed_plan_level((Plan *) plan, plan->subplan);
1230  }
1231  else
1232  {
1233  /*
1234  * Keep the SubqueryScan node. We have to do the processing that
1235  * set_plan_references would otherwise have done on it. Notice we do
1236  * not do set_upper_references() here, because a SubqueryScan will
1237  * always have been created with correct references to its subplan's
1238  * outputs to begin with.
1239  */
1240  plan->scan.scanrelid += rtoffset;
1241  plan->scan.plan.targetlist =
1242  fix_scan_list(root, plan->scan.plan.targetlist,
1243  rtoffset, NUM_EXEC_TLIST((Plan *) plan));
1244  plan->scan.plan.qual =
1245  fix_scan_list(root, plan->scan.plan.qual,
1246  rtoffset, NUM_EXEC_QUAL((Plan *) plan));
1247 
1248  result = (Plan *) plan;
1249  }
1250 
1251  return result;
1252 }
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:375
static bool trivial_subqueryscan(SubqueryScan *plan)
Definition: setrefs.c:1262
Plan * set_plan_references(PlannerInfo *root, Plan *plan)
Definition: setrefs.c:250
Plan * subplan
Definition: plannodes.h:545

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

Referenced by set_plan_refs().

◆ set_upper_references()

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

Definition at line 2159 of file setrefs.c.

2160 {
2161  Plan *subplan = plan->lefttree;
2162  indexed_tlist *subplan_itlist;
2163  List *output_targetlist;
2164  ListCell *l;
2165 
2166  subplan_itlist = build_tlist_index(subplan->targetlist);
2167 
2168  output_targetlist = NIL;
2169  foreach(l, plan->targetlist)
2170  {
2171  TargetEntry *tle = (TargetEntry *) lfirst(l);
2172  Node *newexpr;
2173 
2174  /* If it's a sort/group item, first try to match by sortref */
2175  if (tle->ressortgroupref != 0)
2176  {
2177  newexpr = (Node *)
2179  tle->ressortgroupref,
2180  subplan_itlist,
2181  OUTER_VAR);
2182  if (!newexpr)
2183  newexpr = fix_upper_expr(root,
2184  (Node *) tle->expr,
2185  subplan_itlist,
2186  OUTER_VAR,
2187  rtoffset,
2188  NUM_EXEC_TLIST(plan));
2189  }
2190  else
2191  newexpr = fix_upper_expr(root,
2192  (Node *) tle->expr,
2193  subplan_itlist,
2194  OUTER_VAR,
2195  rtoffset,
2196  NUM_EXEC_TLIST(plan));
2197  tle = flatCopyTargetEntry(tle);
2198  tle->expr = (Expr *) newexpr;
2199  output_targetlist = lappend(output_targetlist, tle);
2200  }
2201  plan->targetlist = output_targetlist;
2202 
2203  plan->qual = (List *)
2204  fix_upper_expr(root,
2205  (Node *) plan->qual,
2206  subplan_itlist,
2207  OUTER_VAR,
2208  rtoffset,
2209  NUM_EXEC_QUAL(plan));
2210 
2211  pfree(subplan_itlist);
2212 }
static Var * search_indexed_tlist_for_sortgroupref(Expr *node, Index sortgroupref, indexed_tlist *itlist, int newvarno)
Definition: setrefs.c:2594

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

Referenced by set_plan_refs().

◆ trivial_subqueryscan()

static bool trivial_subqueryscan ( SubqueryScan plan)
static

Definition at line 1262 of file setrefs.c.

1263 {
1264  int attrno;
1265  ListCell *lp,
1266  *lc;
1267 
1268  if (plan->scan.plan.qual != NIL)
1269  return false;
1270 
1271  if (list_length(plan->scan.plan.targetlist) !=
1272  list_length(plan->subplan->targetlist))
1273  return false; /* tlists not same length */
1274 
1275  attrno = 1;
1276  forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
1277  {
1278  TargetEntry *ptle = (TargetEntry *) lfirst(lp);
1279  TargetEntry *ctle = (TargetEntry *) lfirst(lc);
1280 
1281  if (ptle->resjunk != ctle->resjunk)
1282  return false; /* tlist doesn't match junk status */
1283 
1284  /*
1285  * We accept either a Var referencing the corresponding element of the
1286  * subplan tlist, or a Const equaling the subplan element. See
1287  * generate_setop_tlist() for motivation.
1288  */
1289  if (ptle->expr && IsA(ptle->expr, Var))
1290  {
1291  Var *var = (Var *) ptle->expr;
1292 
1293  Assert(var->varno == plan->scan.scanrelid);
1294  Assert(var->varlevelsup == 0);
1295  if (var->varattno != attrno)
1296  return false; /* out of order */
1297  }
1298  else if (ptle->expr && IsA(ptle->expr, Const))
1299  {
1300  if (!equal(ptle->expr, ctle->expr))
1301  return false;
1302  }
1303  else
1304  return false;
1305 
1306  attrno++;
1307  }
1308 
1309  return true;
1310 }

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