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/subselect.h"
#include "optimizer/tlist.h"
#include "parser/parse_relation.h"
#include "tcop/utility.h"
#include "utils/syscache.h"
Include dependency graph for setrefs.c:

Go to the source code of this file.

Data Structures

struct  tlist_vinfo
 
struct  indexed_tlist
 
struct  fix_scan_expr_context
 
struct  fix_join_expr_context
 
struct  fix_upper_expr_context
 
struct  fix_windowagg_cond_context
 
struct  flatten_rtes_walker_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))
 

Enumerations

enum  NullingRelsMatch { NRM_EQUAL , NRM_SUBSET , NRM_SUPERSET }
 

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, flatten_rtes_walker_context *cxt)
 
static void add_rte_to_flat_rtable (PlannerGlobal *glob, List *rteperminfos, RangeTblEntry *rte)
 
static Planset_plan_refs (PlannerInfo *root, Plan *plan, int rtoffset)
 
static Planset_indexonlyscan_references (PlannerInfo *root, IndexOnlyScan *plan, int rtoffset)
 
static Planset_subqueryscan_references (PlannerInfo *root, SubqueryScan *plan, int rtoffset)
 
static Planclean_up_removed_plan_level (Plan *parent, Plan *child)
 
static void set_foreignscan_references (PlannerInfo *root, ForeignScan *fscan, int rtoffset)
 
static void set_customscan_references (PlannerInfo *root, CustomScan *cscan, int rtoffset)
 
static Planset_append_references (PlannerInfo *root, Append *aplan, int rtoffset)
 
static Planset_mergeappend_references (PlannerInfo *root, MergeAppend *mplan, int rtoffset)
 
static void set_hash_references (PlannerInfo *root, Plan *plan, int rtoffset)
 
static Relids offset_relid_set (Relids relids, int rtoffset)
 
static Nodefix_scan_expr (PlannerInfo *root, Node *node, int rtoffset, double num_exec)
 
static Nodefix_scan_expr_mutator (Node *node, fix_scan_expr_context *context)
 
static bool fix_scan_expr_walker (Node *node, fix_scan_expr_context *context)
 
static void set_join_references (PlannerInfo *root, Join *join, int rtoffset)
 
static void set_upper_references (PlannerInfo *root, Plan *plan, int rtoffset)
 
static void set_param_references (PlannerInfo *root, Plan *plan)
 
static Nodeconvert_combining_aggrefs (Node *node, void *context)
 
static void set_dummy_tlist_references (Plan *plan, int rtoffset)
 
static indexed_tlistbuild_tlist_index (List *tlist)
 
static Varsearch_indexed_tlist_for_var (Var *var, indexed_tlist *itlist, int newvarno, int rtoffset, NullingRelsMatch nrm_match)
 
static Varsearch_indexed_tlist_for_phv (PlaceHolderVar *phv, indexed_tlist *itlist, int newvarno, NullingRelsMatch nrm_match)
 
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, NullingRelsMatch nrm_match, 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, NullingRelsMatch nrm_match, double num_exec)
 
static Nodefix_upper_expr_mutator (Node *node, fix_upper_expr_context *context)
 
static Listset_returning_clause_references (PlannerInfo *root, List *rlist, Plan *topplan, Index resultRelation, int rtoffset)
 
static Listset_windowagg_runcondition_references (PlannerInfo *root, List *runcondition, Plan *plan)
 
Planset_plan_references (PlannerInfo *root, Plan *plan)
 
bool trivial_subqueryscan (SubqueryScan *plan)
 
static VarcopyVar (Var *var)
 
static void fix_expr_common (PlannerInfo *root, Node *node)
 
static Nodefix_param_node (PlannerInfo *root, Param *p)
 
static Nodefix_alternative_subplan (PlannerInfo *root, AlternativeSubPlan *asplan, double num_exec)
 
static indexed_tlistbuild_tlist_index_other_vars (List *tlist, int ignore_rel)
 
static Nodefix_windowagg_condition_expr_mutator (Node *node, fix_windowagg_cond_context *context)
 
static Listfix_windowagg_condition_expr (PlannerInfo *root, List *runcondition, indexed_tlist *subplan_itlist)
 
Paramfind_minmax_agg_replacement_param (PlannerInfo *root, Aggref *aggref)
 
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 129 of file setrefs.c.

◆ ISREGCLASSCONST

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

Definition at line 125 of file setrefs.c.

◆ NUM_EXEC_QUAL

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

Definition at line 116 of file setrefs.c.

◆ NUM_EXEC_TLIST

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

Definition at line 115 of file setrefs.c.

Enumeration Type Documentation

◆ NullingRelsMatch

Enumerator
NRM_EQUAL 
NRM_SUBSET 
NRM_SUPERSET 

Definition at line 33 of file setrefs.c.

34 {
35  NRM_EQUAL, /* expect exact match of nullingrels */
36  NRM_SUBSET, /* actual Var may have a subset of input */
37  NRM_SUPERSET, /* actual Var may have a superset of input */
NullingRelsMatch
Definition: setrefs.c:34
@ NRM_EQUAL
Definition: setrefs.c:35
@ NRM_SUPERSET
Definition: setrefs.c:37
@ NRM_SUBSET
Definition: setrefs.c:36

Function Documentation

◆ add_rte_to_flat_rtable()

static void add_rte_to_flat_rtable ( PlannerGlobal glob,
List rteperminfos,
RangeTblEntry rte 
)
static

Definition at line 538 of file setrefs.c.

540 {
541  RangeTblEntry *newrte;
542 
543  /* flat copy to duplicate all the scalar fields */
544  newrte = (RangeTblEntry *) palloc(sizeof(RangeTblEntry));
545  memcpy(newrte, rte, sizeof(RangeTblEntry));
546 
547  /* zap unneeded sub-structure */
548  newrte->tablesample = NULL;
549  newrte->subquery = NULL;
550  newrte->joinaliasvars = NIL;
551  newrte->joinleftcols = NIL;
552  newrte->joinrightcols = NIL;
553  newrte->join_using_alias = NULL;
554  newrte->functions = NIL;
555  newrte->tablefunc = NULL;
556  newrte->values_lists = NIL;
557  newrte->coltypes = NIL;
558  newrte->coltypmods = NIL;
559  newrte->colcollations = NIL;
560  newrte->securityQuals = NIL;
561 
562  glob->finalrtable = lappend(glob->finalrtable, newrte);
563 
564  /*
565  * If it's a plain relation RTE (or a subquery that was once a view
566  * reference), add the relation OID to relationOids.
567  *
568  * We do this even though the RTE might be unreferenced in the plan tree;
569  * this would correspond to cases such as views that were expanded, child
570  * tables that were eliminated by constraint exclusion, etc. Schema
571  * invalidation on such a rel must still force rebuilding of the plan.
572  *
573  * Note we don't bother to avoid making duplicate list entries. We could,
574  * but it would probably cost more cycles than it would save.
575  */
576  if (newrte->rtekind == RTE_RELATION ||
577  (newrte->rtekind == RTE_SUBQUERY && OidIsValid(newrte->relid)))
578  glob->relationOids = lappend_oid(glob->relationOids, newrte->relid);
579 
580  /*
581  * Add a copy of the RTEPermissionInfo, if any, corresponding to this RTE
582  * to the flattened global list.
583  */
584  if (rte->perminfoindex > 0)
585  {
586  RTEPermissionInfo *perminfo;
587  RTEPermissionInfo *newperminfo;
588 
589  /* Get the existing one from this query's rteperminfos. */
590  perminfo = getRTEPermissionInfo(rteperminfos, newrte);
591 
592  /*
593  * Add a new one to finalrteperminfos and copy the contents of the
594  * existing one into it. Note that addRTEPermissionInfo() also
595  * updates newrte->perminfoindex to point to newperminfo in
596  * finalrteperminfos.
597  */
598  newrte->perminfoindex = 0; /* expected by addRTEPermissionInfo() */
599  newperminfo = addRTEPermissionInfo(&glob->finalrteperminfos, newrte);
600  memcpy(newperminfo, perminfo, sizeof(RTEPermissionInfo));
601  }
602 }
#define OidIsValid(objectId)
Definition: c.h:775
List * lappend(List *list, void *datum)
Definition: list.c:339
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
void * palloc(Size size)
Definition: mcxt.c:1316
RTEPermissionInfo * addRTEPermissionInfo(List **rteperminfos, RangeTblEntry *rte)
RTEPermissionInfo * getRTEPermissionInfo(List *rteperminfos, RangeTblEntry *rte)
@ RTE_SUBQUERY
Definition: parsenodes.h:1029
@ RTE_RELATION
Definition: parsenodes.h:1028
#define NIL
Definition: pg_list.h:68
List * relationOids
Definition: pathnodes.h:132
List * finalrteperminfos
Definition: pathnodes.h:120
List * finalrtable
Definition: pathnodes.h:117
TableFunc * tablefunc
Definition: parsenodes.h:1194
struct TableSampleClause * tablesample
Definition: parsenodes.h:1108
Query * subquery
Definition: parsenodes.h:1114
List * values_lists
Definition: parsenodes.h:1200
List * functions
Definition: parsenodes.h:1187
RTEKind rtekind
Definition: parsenodes.h:1057

References addRTEPermissionInfo(), PlannerGlobal::finalrtable, PlannerGlobal::finalrteperminfos, RangeTblEntry::functions, getRTEPermissionInfo(), lappend(), lappend_oid(), NIL, OidIsValid, palloc(), PlannerGlobal::relationOids, RangeTblEntry::relid, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, 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 391 of file setrefs.c.

392 {
393  PlannerGlobal *glob = root->glob;
394  Index rti;
395  ListCell *lc;
396 
397  /*
398  * Add the query's own RTEs to the flattened rangetable.
399  *
400  * At top level, we must add all RTEs so that their indexes in the
401  * flattened rangetable match up with their original indexes. When
402  * recursing, we only care about extracting relation RTEs (and subquery
403  * RTEs that were once relation RTEs).
404  */
405  foreach(lc, root->parse->rtable)
406  {
407  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
408 
409  if (!recursing || rte->rtekind == RTE_RELATION ||
410  (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)))
411  add_rte_to_flat_rtable(glob, root->parse->rteperminfos, rte);
412  }
413 
414  /*
415  * If there are any dead subqueries, they are not referenced in the Plan
416  * tree, so we must add RTEs contained in them to the flattened rtable
417  * separately. (If we failed to do this, the executor would not perform
418  * expected permission checks for tables mentioned in such subqueries.)
419  *
420  * Note: this pass over the rangetable can't be combined with the previous
421  * one, because that would mess up the numbering of the live RTEs in the
422  * flattened rangetable.
423  */
424  rti = 1;
425  foreach(lc, root->parse->rtable)
426  {
427  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
428 
429  /*
430  * We should ignore inheritance-parent RTEs: their contents have been
431  * pulled up into our rangetable already. Also ignore any subquery
432  * RTEs without matching RelOptInfos, as they likewise have been
433  * pulled up.
434  */
435  if (rte->rtekind == RTE_SUBQUERY && !rte->inh &&
436  rti < root->simple_rel_array_size)
437  {
438  RelOptInfo *rel = root->simple_rel_array[rti];
439 
440  if (rel != NULL)
441  {
442  Assert(rel->relid == rti); /* sanity check on array */
443 
444  /*
445  * The subquery might never have been planned at all, if it
446  * was excluded on the basis of self-contradictory constraints
447  * in our query level. In this case apply
448  * flatten_unplanned_rtes.
449  *
450  * If it was planned but the result rel is dummy, we assume
451  * that it has been omitted from our plan tree (see
452  * set_subquery_pathlist), and recurse to pull up its RTEs.
453  *
454  * Otherwise, it should be represented by a SubqueryScan node
455  * somewhere in our plan tree, and we'll pull up its RTEs when
456  * we process that plan node.
457  *
458  * However, if we're recursing, then we should pull up RTEs
459  * whether the subquery is dummy or not, because we've found
460  * that some upper query level is treating this one as dummy,
461  * and so we won't scan this level's plan tree at all.
462  */
463  if (rel->subroot == NULL)
464  flatten_unplanned_rtes(glob, rte);
465  else if (recursing ||
467  UPPERREL_FINAL, NULL)))
468  add_rtes_to_flat_rtable(rel->subroot, true);
469  }
470  }
471  rti++;
472  }
473 }
#define Assert(condition)
Definition: c.h:858
unsigned int Index
Definition: c.h:614
#define IS_DUMMY_REL(r)
Definition: pathnodes.h:1935
@ UPPERREL_FINAL
Definition: pathnodes.h:79
#define lfirst(lc)
Definition: pg_list.h:172
tree ctl root
Definition: radixtree.h:1880
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1470
static void add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
Definition: setrefs.c:391
static void add_rte_to_flat_rtable(PlannerGlobal *glob, List *rteperminfos, RangeTblEntry *rte)
Definition: setrefs.c:538
static void flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte)
Definition: setrefs.c:480
Index relid
Definition: pathnodes.h:908
PlannerInfo * subroot
Definition: pathnodes.h:943

References add_rte_to_flat_rtable(), Assert, fetch_upper_rel(), flatten_unplanned_rtes(), RangeTblEntry::inh, IS_DUMMY_REL, lfirst, OidIsValid, RangeTblEntry::relid, RelOptInfo::relid, root, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, RelOptInfo::subroot, and UPPERREL_FINAL.

Referenced by set_plan_references().

◆ build_tlist_index()

static indexed_tlist * build_tlist_index ( List tlist)
static

Definition at line 2676 of file setrefs.c.

2677 {
2678  indexed_tlist *itlist;
2679  tlist_vinfo *vinfo;
2680  ListCell *l;
2681 
2682  /* Create data structure with enough slots for all tlist entries */
2683  itlist = (indexed_tlist *)
2684  palloc(offsetof(indexed_tlist, vars) +
2685  list_length(tlist) * sizeof(tlist_vinfo));
2686 
2687  itlist->tlist = tlist;
2688  itlist->has_ph_vars = false;
2689  itlist->has_non_vars = false;
2690 
2691  /* Find the Vars and fill in the index array */
2692  vinfo = itlist->vars;
2693  foreach(l, tlist)
2694  {
2695  TargetEntry *tle = (TargetEntry *) lfirst(l);
2696 
2697  if (tle->expr && IsA(tle->expr, Var))
2698  {
2699  Var *var = (Var *) tle->expr;
2700 
2701  vinfo->varno = var->varno;
2702  vinfo->varattno = var->varattno;
2703  vinfo->resno = tle->resno;
2704  vinfo->varnullingrels = var->varnullingrels;
2705  vinfo++;
2706  }
2707  else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2708  itlist->has_ph_vars = true;
2709  else
2710  itlist->has_non_vars = true;
2711  }
2712 
2713  itlist->num_vars = (vinfo - itlist->vars);
2714 
2715  return itlist;
2716 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
static int list_length(const List *l)
Definition: pg_list.h:152
Expr * expr
Definition: primnodes.h:2157
AttrNumber resno
Definition: primnodes.h:2159
Definition: primnodes.h:248
AttrNumber varattno
Definition: primnodes.h:260
int varno
Definition: primnodes.h:255
tlist_vinfo vars[FLEXIBLE_ARRAY_MEMBER]
Definition: setrefs.c:54
bool has_ph_vars
Definition: setrefs.c:52
bool has_non_vars
Definition: setrefs.c:53
int num_vars
Definition: setrefs.c:51
List * tlist
Definition: setrefs.c:50
AttrNumber resno
Definition: setrefs.c:44
Bitmapset * varnullingrels
Definition: setrefs.c:45
int varno
Definition: setrefs.c:42
AttrNumber varattno
Definition: setrefs.c:43
Definition: regcomp.c:281

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

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

◆ build_tlist_index_other_vars()

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

Definition at line 2727 of file setrefs.c.

2728 {
2729  indexed_tlist *itlist;
2730  tlist_vinfo *vinfo;
2731  ListCell *l;
2732 
2733  /* Create data structure with enough slots for all tlist entries */
2734  itlist = (indexed_tlist *)
2735  palloc(offsetof(indexed_tlist, vars) +
2736  list_length(tlist) * sizeof(tlist_vinfo));
2737 
2738  itlist->tlist = tlist;
2739  itlist->has_ph_vars = false;
2740  itlist->has_non_vars = false;
2741 
2742  /* Find the desired Vars and fill in the index array */
2743  vinfo = itlist->vars;
2744  foreach(l, tlist)
2745  {
2746  TargetEntry *tle = (TargetEntry *) lfirst(l);
2747 
2748  if (tle->expr && IsA(tle->expr, Var))
2749  {
2750  Var *var = (Var *) tle->expr;
2751 
2752  if (var->varno != ignore_rel)
2753  {
2754  vinfo->varno = var->varno;
2755  vinfo->varattno = var->varattno;
2756  vinfo->resno = tle->resno;
2757  vinfo->varnullingrels = var->varnullingrels;
2758  vinfo++;
2759  }
2760  }
2761  else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2762  itlist->has_ph_vars = true;
2763  }
2764 
2765  itlist->num_vars = (vinfo - itlist->vars);
2766 
2767  return itlist;
2768 }
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77

References TargetEntry::expr, indexed_tlist::has_non_vars, indexed_tlist::has_ph_vars, if(), IsA, lfirst, list_length(), indexed_tlist::num_vars, palloc(), tlist_vinfo::resno, TargetEntry::resno, indexed_tlist::tlist, tlist_vinfo::varattno, Var::varattno, tlist_vinfo::varno, Var::varno, tlist_vinfo::varnullingrels, 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 1534 of file setrefs.c.

1535 {
1536  /*
1537  * We have to be sure we don't lose any initplans, so move any that were
1538  * attached to the parent plan to the child. If any are parallel-unsafe,
1539  * the child is no longer parallel-safe. As a cosmetic matter, also add
1540  * the initplans' run costs to the child's costs.
1541  */
1542  if (parent->initPlan)
1543  {
1544  Cost initplan_cost;
1545  bool unsafe_initplans;
1546 
1548  &initplan_cost, &unsafe_initplans);
1549  child->startup_cost += initplan_cost;
1550  child->total_cost += initplan_cost;
1551  if (unsafe_initplans)
1552  child->parallel_safe = false;
1553 
1554  /*
1555  * Attach plans this way so that parent's initplans are processed
1556  * before any pre-existing initplans of the child. Probably doesn't
1557  * matter, but let's preserve the ordering just in case.
1558  */
1559  child->initPlan = list_concat(parent->initPlan,
1560  child->initPlan);
1561  }
1562 
1563  /*
1564  * We also have to transfer the parent's column labeling info into the
1565  * child, else columns sent to client will be improperly labeled if this
1566  * is the topmost plan level. resjunk and so on may be important too.
1567  */
1568  apply_tlist_labeling(child->targetlist, parent->targetlist);
1569 
1570  return child;
1571 }
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
double Cost
Definition: nodes.h:251
Cost total_cost
Definition: plannodes.h:129
Cost startup_cost
Definition: plannodes.h:128
bool parallel_safe
Definition: plannodes.h:141
List * targetlist
Definition: plannodes.h:152
List * initPlan
Definition: plannodes.h:156
void SS_compute_initplan_cost(List *init_plans, Cost *initplan_cost_p, bool *unsafe_initplans_p)
Definition: subselect.c:2198
void apply_tlist_labeling(List *dest_tlist, List *src_tlist)
Definition: tlist.c:318

References apply_tlist_labeling(), Plan::initPlan, list_concat(), Plan::parallel_safe, SS_compute_initplan_cost(), Plan::startup_cost, Plan::targetlist, and Plan::total_cost.

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

2541 {
2542  if (node == NULL)
2543  return NULL;
2544  if (IsA(node, Aggref))
2545  {
2546  Aggref *orig_agg = (Aggref *) node;
2547  Aggref *child_agg;
2548  Aggref *parent_agg;
2549 
2550  /* Assert we've not chosen to partial-ize any unsupported cases */
2551  Assert(orig_agg->aggorder == NIL);
2552  Assert(orig_agg->aggdistinct == NIL);
2553 
2554  /*
2555  * Since aggregate calls can't be nested, we needn't recurse into the
2556  * arguments. But for safety, flat-copy the Aggref node itself rather
2557  * than modifying it in-place.
2558  */
2559  child_agg = makeNode(Aggref);
2560  memcpy(child_agg, orig_agg, sizeof(Aggref));
2561 
2562  /*
2563  * For the parent Aggref, we want to copy all the fields of the
2564  * original aggregate *except* the args list, which we'll replace
2565  * below, and the aggfilter expression, which should be applied only
2566  * by the child not the parent. Rather than explicitly knowing about
2567  * all the other fields here, we can momentarily modify child_agg to
2568  * provide a suitable source for copyObject.
2569  */
2570  child_agg->args = NIL;
2571  child_agg->aggfilter = NULL;
2572  parent_agg = copyObject(child_agg);
2573  child_agg->args = orig_agg->args;
2574  child_agg->aggfilter = orig_agg->aggfilter;
2575 
2576  /*
2577  * Now, set up child_agg to represent the first phase of partial
2578  * aggregation. For now, assume serialization is required.
2579  */
2581 
2582  /*
2583  * And set up parent_agg to represent the second phase.
2584  */
2585  parent_agg->args = list_make1(makeTargetEntry((Expr *) child_agg,
2586  1, NULL, false));
2588 
2589  return (Node *) parent_agg;
2590  }
2592  (void *) context);
2593 }
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:240
#define expression_tree_mutator(n, m, c)
Definition: nodeFuncs.h:153
#define copyObject(obj)
Definition: nodes.h:224
@ AGGSPLIT_FINAL_DESERIAL
Definition: nodes.h:380
@ AGGSPLIT_INITIAL_SERIAL
Definition: nodes.h:378
#define makeNode(_type_)
Definition: nodes.h:155
#define list_make1(x1)
Definition: pg_list.h:212
void mark_partial_aggref(Aggref *agg, AggSplit aggsplit)
Definition: planner.c:5512
tree context
Definition: radixtree.h:1829
static Node * convert_combining_aggrefs(Node *node, void *context)
Definition: setrefs.c:2540
List * aggdistinct
Definition: primnodes.h:474
List * args
Definition: primnodes.h:468
Expr * aggfilter
Definition: primnodes.h:477
List * aggorder
Definition: primnodes.h:471
Definition: nodes.h:129

References Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggorder, AGGSPLIT_FINAL_DESERIAL, AGGSPLIT_INITIAL_SERIAL, Aggref::args, Assert, context, 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 1944 of file setrefs.c.

1945 {
1946  Var *newvar = (Var *) palloc(sizeof(Var));
1947 
1948  *newvar = *var;
1949  return newvar;
1950 }

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

3545 {
3546  PlannerGlobal glob;
3547  PlannerInfo root;
3548 
3549  /* Make up dummy planner state so we can use this module's machinery */
3550  MemSet(&glob, 0, sizeof(glob));
3551  glob.type = T_PlannerGlobal;
3552  glob.relationOids = NIL;
3553  glob.invalItems = NIL;
3554  /* Hack: we use glob.dependsOnRole to collect hasRowSecurity flags */
3555  glob.dependsOnRole = false;
3556 
3557  MemSet(&root, 0, sizeof(root));
3558  root.type = T_PlannerInfo;
3559  root.glob = &glob;
3560 
3561  (void) extract_query_dependencies_walker(query, &root);
3562 
3563  *relationOids = glob.relationOids;
3564  *invalItems = glob.invalItems;
3565  *hasRowSecurity = glob.dependsOnRole;
3566 }
#define MemSet(start, val, len)
Definition: c.h:1020
bool extract_query_dependencies_walker(Node *node, PlannerInfo *context)
Definition: setrefs.c:3577
bool dependsOnRole
Definition: pathnodes.h:153
List * invalItems
Definition: pathnodes.h:135

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

Referenced by CompleteCachedPlan(), and RevalidateCachedQuery().

◆ extract_query_dependencies_walker()

bool extract_query_dependencies_walker ( Node node,
PlannerInfo context 
)

Definition at line 3577 of file setrefs.c.

3578 {
3579  if (node == NULL)
3580  return false;
3581  Assert(!IsA(node, PlaceHolderVar));
3582  if (IsA(node, Query))
3583  {
3584  Query *query = (Query *) node;
3585  ListCell *lc;
3586 
3587  if (query->commandType == CMD_UTILITY)
3588  {
3589  /*
3590  * This logic must handle any utility command for which parse
3591  * analysis was nontrivial (cf. stmt_requires_parse_analysis).
3592  *
3593  * Notably, CALL requires its own processing.
3594  */
3595  if (IsA(query->utilityStmt, CallStmt))
3596  {
3597  CallStmt *callstmt = (CallStmt *) query->utilityStmt;
3598 
3599  /* We need not examine funccall, just the transformed exprs */
3600  (void) extract_query_dependencies_walker((Node *) callstmt->funcexpr,
3601  context);
3602  (void) extract_query_dependencies_walker((Node *) callstmt->outargs,
3603  context);
3604  return false;
3605  }
3606 
3607  /*
3608  * Ignore other utility statements, except those (such as EXPLAIN)
3609  * that contain a parsed-but-not-planned query. For those, we
3610  * just need to transfer our attention to the contained query.
3611  */
3612  query = UtilityContainsQuery(query->utilityStmt);
3613  if (query == NULL)
3614  return false;
3615  }
3616 
3617  /* Remember if any Query has RLS quals applied by rewriter */
3618  if (query->hasRowSecurity)
3619  context->glob->dependsOnRole = true;
3620 
3621  /* Collect relation OIDs in this Query's rtable */
3622  foreach(lc, query->rtable)
3623  {
3624  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3625 
3626  if (rte->rtekind == RTE_RELATION ||
3627  (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)) ||
3628  (rte->rtekind == RTE_NAMEDTUPLESTORE && OidIsValid(rte->relid)))
3629  context->glob->relationOids =
3630  lappend_oid(context->glob->relationOids, rte->relid);
3631  }
3632 
3633  /* And recurse into the query's subexpressions */
3635  (void *) context, 0);
3636  }
3637  /* Extract function dependencies and check for regclass Consts */
3638  fix_expr_common(context, node);
3640  (void *) context);
3641 }
#define query_tree_walker(q, w, c, f)
Definition: nodeFuncs.h:156
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:151
@ CMD_UTILITY
Definition: nodes.h:270
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1035
static void fix_expr_common(PlannerInfo *root, Node *node)
Definition: setrefs.c:1966
FuncExpr * funcexpr
Definition: parsenodes.h:3518
List * outargs
Definition: parsenodes.h:3520
List * rtable
Definition: parsenodes.h:168
CmdType commandType
Definition: parsenodes.h:121
Node * utilityStmt
Definition: parsenodes.h:136
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2176

References Assert, CMD_UTILITY, Query::commandType, context, expression_tree_walker, fix_expr_common(), CallStmt::funcexpr, IsA, lappend_oid(), lfirst, OidIsValid, CallStmt::outargs, query_tree_walker, RangeTblEntry::relid, Query::rtable, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, UtilityContainsQuery(), and Query::utilityStmt.

Referenced by expression_planner_with_deps(), and extract_query_dependencies().

◆ find_minmax_agg_replacement_param()

Param* find_minmax_agg_replacement_param ( PlannerInfo root,
Aggref aggref 
)

Definition at line 3427 of file setrefs.c.

3428 {
3429  if (root->minmax_aggs != NIL &&
3430  list_length(aggref->args) == 1)
3431  {
3432  TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
3433  ListCell *lc;
3434 
3435  foreach(lc, root->minmax_aggs)
3436  {
3437  MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
3438 
3439  if (mminfo->aggfnoid == aggref->aggfnoid &&
3440  equal(mminfo->target, curTarget->expr))
3441  return mminfo->param;
3442  }
3443  }
3444  return NULL;
3445 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
#define linitial(l)
Definition: pg_list.h:178
Oid aggfnoid
Definition: primnodes.h:444
Param * param
Definition: pathnodes.h:3121
Expr * target
Definition: pathnodes.h:3106

References MinMaxAggInfo::aggfnoid, Aggref::aggfnoid, Aggref::args, equal(), TargetEntry::expr, lfirst, linitial, list_length(), NIL, MinMaxAggInfo::param, root, and MinMaxAggInfo::target.

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

◆ fix_alternative_subplan()

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

Definition at line 2092 of file setrefs.c.

2094 {
2095  SubPlan *bestplan = NULL;
2096  Cost bestcost = 0;
2097  ListCell *lc;
2098 
2099  /*
2100  * Compute the estimated cost of each subplan assuming num_exec
2101  * executions, and keep the cheapest one. In event of exact equality of
2102  * estimates, we prefer the later plan; this is a bit arbitrary, but in
2103  * current usage it biases us to break ties against fast-start subplans.
2104  */
2105  Assert(asplan->subplans != NIL);
2106 
2107  foreach(lc, asplan->subplans)
2108  {
2109  SubPlan *curplan = (SubPlan *) lfirst(lc);
2110  Cost curcost;
2111 
2112  curcost = curplan->startup_cost + num_exec * curplan->per_call_cost;
2113  if (bestplan == NULL || curcost <= bestcost)
2114  {
2115  bestplan = curplan;
2116  bestcost = curcost;
2117  }
2118 
2119  /* Also mark all subplans that are in AlternativeSubPlans */
2120  root->isAltSubplan[curplan->plan_id - 1] = true;
2121  }
2122 
2123  /* Mark the subplan we selected */
2124  root->isUsedSubplan[bestplan->plan_id - 1] = true;
2125 
2126  return (Node *) bestplan;
2127 }
int plan_id
Definition: primnodes.h:1040
Cost startup_cost
Definition: primnodes.h:1063
Cost per_call_cost
Definition: primnodes.h:1064

References Assert, lfirst, NIL, SubPlan::per_call_cost, SubPlan::plan_id, root, 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 1966 of file setrefs.c.

1967 {
1968  /* We assume callers won't call us on a NULL pointer */
1969  if (IsA(node, Aggref))
1970  {
1972  ((Aggref *) node)->aggfnoid);
1973  }
1974  else if (IsA(node, WindowFunc))
1975  {
1977  ((WindowFunc *) node)->winfnoid);
1978  }
1979  else if (IsA(node, FuncExpr))
1980  {
1982  ((FuncExpr *) node)->funcid);
1983  }
1984  else if (IsA(node, OpExpr))
1985  {
1986  set_opfuncid((OpExpr *) node);
1988  ((OpExpr *) node)->opfuncid);
1989  }
1990  else if (IsA(node, DistinctExpr))
1991  {
1992  set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
1994  ((DistinctExpr *) node)->opfuncid);
1995  }
1996  else if (IsA(node, NullIfExpr))
1997  {
1998  set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
2000  ((NullIfExpr *) node)->opfuncid);
2001  }
2002  else if (IsA(node, ScalarArrayOpExpr))
2003  {
2004  ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) node;
2005 
2006  set_sa_opfuncid(saop);
2007  record_plan_function_dependency(root, saop->opfuncid);
2008 
2009  if (OidIsValid(saop->hashfuncid))
2010  record_plan_function_dependency(root, saop->hashfuncid);
2011 
2012  if (OidIsValid(saop->negfuncid))
2013  record_plan_function_dependency(root, saop->negfuncid);
2014  }
2015  else if (IsA(node, Const))
2016  {
2017  Const *con = (Const *) node;
2018 
2019  /* Check for regclass reference */
2020  if (ISREGCLASSCONST(con))
2021  root->glob->relationOids =
2022  lappend_oid(root->glob->relationOids,
2023  DatumGetObjectId(con->constvalue));
2024  }
2025  else if (IsA(node, GroupingFunc))
2026  {
2027  GroupingFunc *g = (GroupingFunc *) node;
2028  AttrNumber *grouping_map = root->grouping_map;
2029 
2030  /* If there are no grouping sets, we don't need this. */
2031 
2032  Assert(grouping_map || g->cols == NIL);
2033 
2034  if (grouping_map)
2035  {
2036  ListCell *lc;
2037  List *cols = NIL;
2038 
2039  foreach(lc, g->refs)
2040  {
2041  cols = lappend_int(cols, grouping_map[lfirst_int(lc)]);
2042  }
2043 
2044  Assert(!g->cols || equal(cols, g->cols));
2045 
2046  if (!g->cols)
2047  g->cols = cols;
2048  }
2049  }
2050 }
int16 AttrNumber
Definition: attnum.h:21
List * lappend_int(List *list, int datum)
Definition: list.c:357
void set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
Definition: nodeFuncs.c:1879
void set_opfuncid(OpExpr *opexpr)
Definition: nodeFuncs.c:1868
#define lfirst_int(lc)
Definition: pg_list.h:173
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:242
void record_plan_function_dependency(PlannerInfo *root, Oid funcid)
Definition: setrefs.c:3460
#define ISREGCLASSCONST(con)
Definition: setrefs.c:125
Definition: pg_list.h:54

References Assert, DatumGetObjectId(), equal(), IsA, ISREGCLASSCONST, lappend_int(), lappend_oid(), lfirst_int, NIL, OidIsValid, record_plan_function_dependency(), root, 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,
NullingRelsMatch  nrm_match,
double  num_exec 
)
static

Definition at line 3021 of file setrefs.c.

3029 {
3031 
3032  context.root = root;
3033  context.outer_itlist = outer_itlist;
3034  context.inner_itlist = inner_itlist;
3035  context.acceptable_rel = acceptable_rel;
3036  context.rtoffset = rtoffset;
3037  context.nrm_match = nrm_match;
3038  context.num_exec = num_exec;
3039  return (List *) fix_join_expr_mutator((Node *) clauses, &context);
3040 }
static Node * fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
Definition: setrefs.c:3043

References context, fix_join_expr_mutator(), and root.

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

3044 {
3045  Var *newvar;
3046 
3047  if (node == NULL)
3048  return NULL;
3049  if (IsA(node, Var))
3050  {
3051  Var *var = (Var *) node;
3052 
3053  /* Look for the var in the input tlists, first in the outer */
3054  if (context->outer_itlist)
3055  {
3056  newvar = search_indexed_tlist_for_var(var,
3057  context->outer_itlist,
3058  OUTER_VAR,
3059  context->rtoffset,
3060  context->nrm_match);
3061  if (newvar)
3062  return (Node *) newvar;
3063  }
3064 
3065  /* then in the inner. */
3066  if (context->inner_itlist)
3067  {
3068  newvar = search_indexed_tlist_for_var(var,
3069  context->inner_itlist,
3070  INNER_VAR,
3071  context->rtoffset,
3072  context->nrm_match);
3073  if (newvar)
3074  return (Node *) newvar;
3075  }
3076 
3077  /* If it's for acceptable_rel, adjust and return it */
3078  if (var->varno == context->acceptable_rel)
3079  {
3080  var = copyVar(var);
3081  var->varno += context->rtoffset;
3082  if (var->varnosyn > 0)
3083  var->varnosyn += context->rtoffset;
3084  return (Node *) var;
3085  }
3086 
3087  /* No referent found for Var */
3088  elog(ERROR, "variable not found in subplan target lists");
3089  }
3090  if (IsA(node, PlaceHolderVar))
3091  {
3092  PlaceHolderVar *phv = (PlaceHolderVar *) node;
3093 
3094  /* See if the PlaceHolderVar has bubbled up from a lower plan node */
3095  if (context->outer_itlist && context->outer_itlist->has_ph_vars)
3096  {
3097  newvar = search_indexed_tlist_for_phv(phv,
3098  context->outer_itlist,
3099  OUTER_VAR,
3100  context->nrm_match);
3101  if (newvar)
3102  return (Node *) newvar;
3103  }
3104  if (context->inner_itlist && context->inner_itlist->has_ph_vars)
3105  {
3106  newvar = search_indexed_tlist_for_phv(phv,
3107  context->inner_itlist,
3108  INNER_VAR,
3109  context->nrm_match);
3110  if (newvar)
3111  return (Node *) newvar;
3112  }
3113 
3114  /* If not supplied by input plans, evaluate the contained expr */
3115  /* XXX can we assert something about phnullingrels? */
3116  return fix_join_expr_mutator((Node *) phv->phexpr, context);
3117  }
3118  /* Try matching more complex expressions too, if tlists have any */
3119  if (context->outer_itlist && context->outer_itlist->has_non_vars)
3120  {
3121  newvar = search_indexed_tlist_for_non_var((Expr *) node,
3122  context->outer_itlist,
3123  OUTER_VAR);
3124  if (newvar)
3125  return (Node *) newvar;
3126  }
3127  if (context->inner_itlist && context->inner_itlist->has_non_vars)
3128  {
3129  newvar = search_indexed_tlist_for_non_var((Expr *) node,
3130  context->inner_itlist,
3131  INNER_VAR);
3132  if (newvar)
3133  return (Node *) newvar;
3134  }
3135  /* Special cases (apply only AFTER failing to match to lower tlist) */
3136  if (IsA(node, Param))
3137  return fix_param_node(context->root, (Param *) node);
3138  if (IsA(node, AlternativeSubPlan))
3140  (AlternativeSubPlan *) node,
3141  context->num_exec),
3142  context);
3143  fix_expr_common(context->root, node);
3144  return expression_tree_mutator(node,
3146  (void *) context);
3147 }
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define OUTER_VAR
Definition: primnodes.h:237
#define INNER_VAR
Definition: primnodes.h:236
static Node * fix_param_node(PlannerInfo *root, Param *p)
Definition: setrefs.c:2061
static Node * fix_alternative_subplan(PlannerInfo *root, AlternativeSubPlan *asplan, double num_exec)
Definition: setrefs.c:2092
static Var * search_indexed_tlist_for_non_var(Expr *node, indexed_tlist *itlist, int newvarno)
Definition: setrefs.c:2903
static Var * search_indexed_tlist_for_phv(PlaceHolderVar *phv, indexed_tlist *itlist, int newvarno, NullingRelsMatch nrm_match)
Definition: setrefs.c:2850
static Var * copyVar(Var *var)
Definition: setrefs.c:1944
static Var * search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist, int newvarno, int rtoffset, NullingRelsMatch nrm_match)
Definition: setrefs.c:2785

References context, copyVar(), elog, ERROR, expression_tree_mutator, fix_alternative_subplan(), fix_expr_common(), fix_param_node(), INNER_VAR, IsA, OUTER_VAR, search_indexed_tlist_for_non_var(), search_indexed_tlist_for_phv(), search_indexed_tlist_for_var(), and Var::varno.

Referenced by fix_join_expr().

◆ fix_param_node()

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

Definition at line 2061 of file setrefs.c.

2062 {
2063  if (p->paramkind == PARAM_MULTIEXPR)
2064  {
2065  int subqueryid = p->paramid >> 16;
2066  int colno = p->paramid & 0xFFFF;
2067  List *params;
2068 
2069  if (subqueryid <= 0 ||
2070  subqueryid > list_length(root->multiexpr_params))
2071  elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
2072  params = (List *) list_nth(root->multiexpr_params, subqueryid - 1);
2073  if (colno <= 0 || colno > list_length(params))
2074  elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
2075  return copyObject(list_nth(params, colno - 1));
2076  }
2077  return (Node *) copyObject(p);
2078 }
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
@ PARAM_MULTIEXPR
Definition: primnodes.h:370
int paramid
Definition: primnodes.h:377
ParamKind paramkind
Definition: primnodes.h:376

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

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

2149 {
2151 
2152  context.root = root;
2153  context.rtoffset = rtoffset;
2154  context.num_exec = num_exec;
2155 
2156  if (rtoffset != 0 ||
2157  root->multiexpr_params != NIL ||
2158  root->glob->lastPHId != 0 ||
2159  root->minmax_aggs != NIL ||
2160  root->hasAlternativeSubPlans)
2161  {
2162  return fix_scan_expr_mutator(node, &context);
2163  }
2164  else
2165  {
2166  /*
2167  * If rtoffset == 0, we don't need to change any Vars, and if there
2168  * are no MULTIEXPR subqueries then we don't need to replace
2169  * PARAM_MULTIEXPR Params, and if there are no placeholders anywhere
2170  * we won't need to remove them, and if there are no minmax Aggrefs we
2171  * won't need to replace them, and if there are no AlternativeSubPlans
2172  * we won't need to remove them. Then it's OK to just scribble on the
2173  * input node tree instead of copying (since the only change, filling
2174  * in any unset opfuncid fields, is harmless). This saves just enough
2175  * cycles to be noticeable on trivial queries.
2176  */
2177  (void) fix_scan_expr_walker(node, &context);
2178  return node;
2179  }
2180 }
static Node * fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
Definition: setrefs.c:2183
static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
Definition: setrefs.c:2249

References context, fix_scan_expr_mutator(), fix_scan_expr_walker(), NIL, and root.

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

2184 {
2185  if (node == NULL)
2186  return NULL;
2187  if (IsA(node, Var))
2188  {
2189  Var *var = copyVar((Var *) node);
2190 
2191  Assert(var->varlevelsup == 0);
2192 
2193  /*
2194  * We should not see Vars marked INNER_VAR, OUTER_VAR, or ROWID_VAR.
2195  * But an indexqual expression could contain INDEX_VAR Vars.
2196  */
2197  Assert(var->varno != INNER_VAR);
2198  Assert(var->varno != OUTER_VAR);
2199  Assert(var->varno != ROWID_VAR);
2200  if (!IS_SPECIAL_VARNO(var->varno))
2201  var->varno += context->rtoffset;
2202  if (var->varnosyn > 0)
2203  var->varnosyn += context->rtoffset;
2204  return (Node *) var;
2205  }
2206  if (IsA(node, Param))
2207  return fix_param_node(context->root, (Param *) node);
2208  if (IsA(node, Aggref))
2209  {
2210  Aggref *aggref = (Aggref *) node;
2211  Param *aggparam;
2212 
2213  /* See if the Aggref should be replaced by a Param */
2214  aggparam = find_minmax_agg_replacement_param(context->root, aggref);
2215  if (aggparam != NULL)
2216  {
2217  /* Make a copy of the Param for paranoia's sake */
2218  return (Node *) copyObject(aggparam);
2219  }
2220  /* If no match, just fall through to process it normally */
2221  }
2222  if (IsA(node, CurrentOfExpr))
2223  {
2224  CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
2225 
2226  Assert(!IS_SPECIAL_VARNO(cexpr->cvarno));
2227  cexpr->cvarno += context->rtoffset;
2228  return (Node *) cexpr;
2229  }
2230  if (IsA(node, PlaceHolderVar))
2231  {
2232  /* At scan level, we should always just evaluate the contained expr */
2233  PlaceHolderVar *phv = (PlaceHolderVar *) node;
2234 
2235  /* XXX can we assert something about phnullingrels? */
2236  return fix_scan_expr_mutator((Node *) phv->phexpr, context);
2237  }
2238  if (IsA(node, AlternativeSubPlan))
2240  (AlternativeSubPlan *) node,
2241  context->num_exec),
2242  context);
2243  fix_expr_common(context->root, node);
2245  (void *) context);
2246 }
#define ROWID_VAR
Definition: primnodes.h:239
#define IS_SPECIAL_VARNO(varno)
Definition: primnodes.h:241
Param * find_minmax_agg_replacement_param(PlannerInfo *root, Aggref *aggref)
Definition: setrefs.c:3427
Index varlevelsup
Definition: primnodes.h:280

References Assert, context, copyObject, copyVar(), CurrentOfExpr::cvarno, expression_tree_mutator, find_minmax_agg_replacement_param(), fix_alternative_subplan(), fix_expr_common(), fix_param_node(), INNER_VAR, IS_SPECIAL_VARNO, IsA, OUTER_VAR, ROWID_VAR, Var::varlevelsup, and Var::varno.

Referenced by fix_scan_expr().

◆ fix_scan_expr_walker()

static bool fix_scan_expr_walker ( Node node,
fix_scan_expr_context context 
)
static

Definition at line 2249 of file setrefs.c.

2250 {
2251  if (node == NULL)
2252  return false;
2253  Assert(!(IsA(node, Var) && ((Var *) node)->varno == ROWID_VAR));
2254  Assert(!IsA(node, PlaceHolderVar));
2255  Assert(!IsA(node, AlternativeSubPlan));
2256  fix_expr_common(context->root, node);
2258  (void *) context);
2259 }

References Assert, context, expression_tree_walker, fix_expr_common(), IsA, 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,
NullingRelsMatch  nrm_match,
double  num_exec 
)
static

Definition at line 3182 of file setrefs.c.

3189 {
3191 
3192  context.root = root;
3193  context.subplan_itlist = subplan_itlist;
3194  context.newvarno = newvarno;
3195  context.rtoffset = rtoffset;
3196  context.nrm_match = nrm_match;
3197  context.num_exec = num_exec;
3198  return fix_upper_expr_mutator(node, &context);
3199 }
static Node * fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
Definition: setrefs.c:3202

References context, fix_upper_expr_mutator(), and root.

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

3203 {
3204  Var *newvar;
3205 
3206  if (node == NULL)
3207  return NULL;
3208  if (IsA(node, Var))
3209  {
3210  Var *var = (Var *) node;
3211 
3212  newvar = search_indexed_tlist_for_var(var,
3213  context->subplan_itlist,
3214  context->newvarno,
3215  context->rtoffset,
3216  context->nrm_match);
3217  if (!newvar)
3218  elog(ERROR, "variable not found in subplan target list");
3219  return (Node *) newvar;
3220  }
3221  if (IsA(node, PlaceHolderVar))
3222  {
3223  PlaceHolderVar *phv = (PlaceHolderVar *) node;
3224 
3225  /* See if the PlaceHolderVar has bubbled up from a lower plan node */
3226  if (context->subplan_itlist->has_ph_vars)
3227  {
3228  newvar = search_indexed_tlist_for_phv(phv,
3229  context->subplan_itlist,
3230  context->newvarno,
3231  context->nrm_match);
3232  if (newvar)
3233  return (Node *) newvar;
3234  }
3235  /* If not supplied by input plan, evaluate the contained expr */
3236  /* XXX can we assert something about phnullingrels? */
3237  return fix_upper_expr_mutator((Node *) phv->phexpr, context);
3238  }
3239  /* Try matching more complex expressions too, if tlist has any */
3240  if (context->subplan_itlist->has_non_vars)
3241  {
3242  newvar = search_indexed_tlist_for_non_var((Expr *) node,
3243  context->subplan_itlist,
3244  context->newvarno);
3245  if (newvar)
3246  return (Node *) newvar;
3247  }
3248  /* Special cases (apply only AFTER failing to match to lower tlist) */
3249  if (IsA(node, Param))
3250  return fix_param_node(context->root, (Param *) node);
3251  if (IsA(node, Aggref))
3252  {
3253  Aggref *aggref = (Aggref *) node;
3254  Param *aggparam;
3255 
3256  /* See if the Aggref should be replaced by a Param */
3257  aggparam = find_minmax_agg_replacement_param(context->root, aggref);
3258  if (aggparam != NULL)
3259  {
3260  /* Make a copy of the Param for paranoia's sake */
3261  return (Node *) copyObject(aggparam);
3262  }
3263  /* If no match, just fall through to process it normally */
3264  }
3265  if (IsA(node, AlternativeSubPlan))
3267  (AlternativeSubPlan *) node,
3268  context->num_exec),
3269  context);
3270  fix_expr_common(context->root, node);
3271  return expression_tree_mutator(node,
3273  (void *) context);
3274 }

References context, copyObject, elog, ERROR, expression_tree_mutator, find_minmax_agg_replacement_param(), fix_alternative_subplan(), fix_expr_common(), fix_param_node(), IsA, search_indexed_tlist_for_non_var(), search_indexed_tlist_for_phv(), and search_indexed_tlist_for_var().

Referenced by fix_upper_expr().

◆ fix_windowagg_condition_expr()

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

Definition at line 3379 of file setrefs.c.

3382 {
3384 
3385  context.root = root;
3386  context.subplan_itlist = subplan_itlist;
3387  context.newvarno = 0;
3388 
3389  return (List *) fix_windowagg_condition_expr_mutator((Node *) runcondition,
3390  &context);
3391 }
static Node * fix_windowagg_condition_expr_mutator(Node *node, fix_windowagg_cond_context *context)
Definition: setrefs.c:3349

References context, fix_windowagg_condition_expr_mutator(), and root.

Referenced by set_windowagg_runcondition_references().

◆ fix_windowagg_condition_expr_mutator()

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

Definition at line 3349 of file setrefs.c.

3351 {
3352  if (node == NULL)
3353  return NULL;
3354 
3355  if (IsA(node, WindowFunc))
3356  {
3357  Var *newvar;
3358 
3359  newvar = search_indexed_tlist_for_non_var((Expr *) node,
3360  context->subplan_itlist,
3361  context->newvarno);
3362  if (newvar)
3363  return (Node *) newvar;
3364  elog(ERROR, "WindowFunc not found in subplan target lists");
3365  }
3366 
3367  return expression_tree_mutator(node,
3369  (void *) context);
3370 }

References context, elog, ERROR, expression_tree_mutator, IsA, and search_indexed_tlist_for_non_var().

Referenced by fix_windowagg_condition_expr().

◆ flatten_rtes_walker()

static bool flatten_rtes_walker ( Node node,
flatten_rtes_walker_context cxt 
)
static

Definition at line 492 of file setrefs.c.

493 {
494  if (node == NULL)
495  return false;
496  if (IsA(node, RangeTblEntry))
497  {
498  RangeTblEntry *rte = (RangeTblEntry *) node;
499 
500  /* As above, we need only save relation RTEs and former relations */
501  if (rte->rtekind == RTE_RELATION ||
502  (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)))
503  add_rte_to_flat_rtable(cxt->glob, cxt->query->rteperminfos, rte);
504  return false;
505  }
506  if (IsA(node, Query))
507  {
508  /*
509  * Recurse into subselects. Must update cxt->query to this query so
510  * that the rtable and rteperminfos correspond with each other.
511  */
512  Query *save_query = cxt->query;
513  bool result;
514 
515  cxt->query = (Query *) node;
516  result = query_tree_walker((Query *) node,
518  (void *) cxt,
520  cxt->query = save_query;
521  return result;
522  }
524  (void *) cxt);
525 }
#define QTW_EXAMINE_RTES_BEFORE
Definition: nodeFuncs.h:27
static bool flatten_rtes_walker(Node *node, flatten_rtes_walker_context *cxt)
Definition: setrefs.c:492
PlannerGlobal * glob
Definition: setrefs.c:95

References add_rte_to_flat_rtable(), expression_tree_walker, flatten_rtes_walker_context::glob, IsA, OidIsValid, QTW_EXAMINE_RTES_BEFORE, flatten_rtes_walker_context::query, query_tree_walker, RangeTblEntry::relid, RTE_RELATION, RTE_SUBQUERY, and RangeTblEntry::rtekind.

Referenced by flatten_unplanned_rtes().

◆ flatten_unplanned_rtes()

static void flatten_unplanned_rtes ( PlannerGlobal glob,
RangeTblEntry rte 
)
static

Definition at line 480 of file setrefs.c.

481 {
482  flatten_rtes_walker_context cxt = {glob, rte->subquery};
483 
484  /* Use query_tree_walker to find all RTEs in the parse tree */
485  (void) query_tree_walker(rte->subquery,
487  (void *) &cxt,
489 }

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

1923 {
1924  Relids result = NULL;
1925  int rtindex;
1926 
1927  /* If there's no offset to apply, we needn't recompute the value */
1928  if (rtoffset == 0)
1929  return relids;
1930  rtindex = -1;
1931  while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
1932  result = bms_add_member(result, rtindex + rtoffset);
1933  return result;
1934 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815

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

3461 {
3462  /*
3463  * For performance reasons, we don't bother to track built-in functions;
3464  * we just assume they'll never change (or at least not in ways that'd
3465  * invalidate plans using them). For this purpose we can consider a
3466  * built-in function to be one with OID less than FirstUnpinnedObjectId.
3467  * Note that the OID generator guarantees never to generate such an OID
3468  * after startup, even at OID wraparound.
3469  */
3470  if (funcid >= (Oid) FirstUnpinnedObjectId)
3471  {
3472  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3473 
3474  /*
3475  * It would work to use any syscache on pg_proc, but the easiest is
3476  * PROCOID since we already have the function's OID at hand. Note
3477  * that plancache.c knows we use PROCOID.
3478  */
3479  inval_item->cacheId = PROCOID;
3480  inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
3481  ObjectIdGetDatum(funcid));
3482 
3483  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3484  }
3485 }
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
unsigned int Oid
Definition: postgres_ext.h:31
uint32 hashValue
Definition: plannodes.h:1573
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:113
#define FirstUnpinnedObjectId
Definition: transam.h:196

References PlanInvalItem::cacheId, FirstUnpinnedObjectId, GetSysCacheHashValue1, PlanInvalItem::hashValue, lappend(), makeNode, ObjectIdGetDatum(), and root.

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

3501 {
3502  /*
3503  * As in record_plan_function_dependency, ignore the possibility that
3504  * someone would change a built-in domain.
3505  */
3506  if (typid >= (Oid) FirstUnpinnedObjectId)
3507  {
3508  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3509 
3510  /*
3511  * It would work to use any syscache on pg_type, but the easiest is
3512  * TYPEOID since we already have the type's OID at hand. Note that
3513  * plancache.c knows we use TYPEOID.
3514  */
3515  inval_item->cacheId = TYPEOID;
3516  inval_item->hashValue = GetSysCacheHashValue1(TYPEOID,
3517  ObjectIdGetDatum(typid));
3518 
3519  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3520  }
3521 }

References PlanInvalItem::cacheId, FirstUnpinnedObjectId, GetSysCacheHashValue1, PlanInvalItem::hashValue, lappend(), makeNode, ObjectIdGetDatum(), and root.

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

2905 {
2906  TargetEntry *tle;
2907 
2908  /*
2909  * If it's a simple Const, replacing it with a Var is silly, even if there
2910  * happens to be an identical Const below; a Var is more expensive to
2911  * execute than a Const. What's more, replacing it could confuse some
2912  * places in the executor that expect to see simple Consts for, eg,
2913  * dropped columns.
2914  */
2915  if (IsA(node, Const))
2916  return NULL;
2917 
2918  tle = tlist_member(node, itlist->tlist);
2919  if (tle)
2920  {
2921  /* Found a matching subplan output expression */
2922  Var *newvar;
2923 
2924  newvar = makeVarFromTargetEntry(newvarno, tle);
2925  newvar->varnosyn = 0; /* wasn't ever a plain Var */
2926  newvar->varattnosyn = 0;
2927  return newvar;
2928  }
2929  return NULL; /* no match */
2930 }
Var * makeVarFromTargetEntry(int varno, TargetEntry *tle)
Definition: makefuncs.c:105
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:79

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

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

◆ search_indexed_tlist_for_phv()

static Var * search_indexed_tlist_for_phv ( PlaceHolderVar phv,
indexed_tlist itlist,
int  newvarno,
NullingRelsMatch  nrm_match 
)
static

Definition at line 2850 of file setrefs.c.

2853 {
2854  ListCell *lc;
2855 
2856  foreach(lc, itlist->tlist)
2857  {
2858  TargetEntry *tle = (TargetEntry *) lfirst(lc);
2859 
2860  if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2861  {
2862  PlaceHolderVar *subphv = (PlaceHolderVar *) tle->expr;
2863  Var *newvar;
2864 
2865  /*
2866  * Analogously to search_indexed_tlist_for_var, we match on phid
2867  * only. We don't use equal(), partially for speed but mostly
2868  * because phnullingrels might not be exactly equal.
2869  */
2870  if (phv->phid != subphv->phid)
2871  continue;
2872 
2873  /* Verify that we kept all the nullingrels machinations straight */
2874  if (!(nrm_match == NRM_SUBSET ?
2875  bms_is_subset(phv->phnullingrels, subphv->phnullingrels) :
2876  nrm_match == NRM_SUPERSET ?
2877  bms_is_subset(subphv->phnullingrels, phv->phnullingrels) :
2878  bms_equal(subphv->phnullingrels, phv->phnullingrels)))
2879  elog(ERROR, "wrong phnullingrels %s (expected %s) for PlaceHolderVar %d",
2880  bmsToString(phv->phnullingrels),
2881  bmsToString(subphv->phnullingrels),
2882  phv->phid);
2883 
2884  /* Found a matching subplan output expression */
2885  newvar = makeVarFromTargetEntry(newvarno, tle);
2886  newvar->varnosyn = 0; /* wasn't ever a plain Var */
2887  newvar->varattnosyn = 0;
2888  return newvar;
2889  }
2890  }
2891  return NULL; /* no match */
2892 }
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:142
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:412
char * bmsToString(const Bitmapset *bms)
Definition: outfuncs.c:808
Relids phnullingrels
Definition: pathnodes.h:2779

References bms_equal(), bms_is_subset(), bmsToString(), elog, ERROR, TargetEntry::expr, if(), IsA, lfirst, makeVarFromTargetEntry(), NRM_SUBSET, NRM_SUPERSET, PlaceHolderVar::phid, PlaceHolderVar::phnullingrels, and indexed_tlist::tlist.

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

2947 {
2948  ListCell *lc;
2949 
2950  foreach(lc, itlist->tlist)
2951  {
2952  TargetEntry *tle = (TargetEntry *) lfirst(lc);
2953 
2954  /*
2955  * Usually the equal() check is redundant, but in setop plans it may
2956  * not be, since prepunion.c assigns ressortgroupref equal to the
2957  * column resno without regard to whether that matches the topmost
2958  * level's sortgrouprefs and without regard to whether any implicit
2959  * coercions are added in the setop tree. We might have to clean that
2960  * up someday; but for now, just ignore any false matches.
2961  */
2962  if (tle->ressortgroupref == sortgroupref &&
2963  equal(node, tle->expr))
2964  {
2965  /* Found a matching subplan output expression */
2966  Var *newvar;
2967 
2968  newvar = makeVarFromTargetEntry(newvarno, tle);
2969  newvar->varnosyn = 0; /* wasn't ever a plain Var */
2970  newvar->varattnosyn = 0;
2971  return newvar;
2972  }
2973  }
2974  return NULL; /* no match */
2975 }
Index ressortgroupref
Definition: primnodes.h:2163

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

Referenced by set_upper_references().

◆ search_indexed_tlist_for_var()

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

Definition at line 2785 of file setrefs.c.

2788 {
2789  int varno = var->varno;
2790  AttrNumber varattno = var->varattno;
2791  tlist_vinfo *vinfo;
2792  int i;
2793 
2794  vinfo = itlist->vars;
2795  i = itlist->num_vars;
2796  while (i-- > 0)
2797  {
2798  if (vinfo->varno == varno && vinfo->varattno == varattno)
2799  {
2800  /* Found a match */
2801  Var *newvar = copyVar(var);
2802 
2803  /*
2804  * Verify that we kept all the nullingrels machinations straight.
2805  *
2806  * XXX we skip the check for system columns and whole-row Vars.
2807  * That's because such Vars might be row identity Vars, which are
2808  * generated without any varnullingrels. It'd be hard to do
2809  * otherwise, since they're normally made very early in planning,
2810  * when we haven't looked at the jointree yet and don't know which
2811  * joins might null such Vars. Doesn't seem worth the expense to
2812  * make them fully valid. (While it's slightly annoying that we
2813  * thereby lose checking for user-written references to such
2814  * columns, it seems unlikely that a bug in nullingrels logic
2815  * would affect only system columns.)
2816  */
2817  if (!(varattno <= 0 ||
2818  (nrm_match == NRM_SUBSET ?
2819  bms_is_subset(var->varnullingrels, vinfo->varnullingrels) :
2820  nrm_match == NRM_SUPERSET ?
2821  bms_is_subset(vinfo->varnullingrels, var->varnullingrels) :
2822  bms_equal(vinfo->varnullingrels, var->varnullingrels))))
2823  elog(ERROR, "wrong varnullingrels %s (expected %s) for Var %d/%d",
2824  bmsToString(var->varnullingrels),
2825  bmsToString(vinfo->varnullingrels),
2826  varno, varattno);
2827 
2828  newvar->varno = newvarno;
2829  newvar->varattno = vinfo->resno;
2830  if (newvar->varnosyn > 0)
2831  newvar->varnosyn += rtoffset;
2832  return newvar;
2833  }
2834  vinfo++;
2835  }
2836  return NULL; /* no match */
2837 }
int i
Definition: isn.c:73

References bms_equal(), bms_is_subset(), bmsToString(), copyVar(), elog, ERROR, i, NRM_SUBSET, NRM_SUPERSET, indexed_tlist::num_vars, tlist_vinfo::resno, tlist_vinfo::varattno, Var::varattno, tlist_vinfo::varno, Var::varno, tlist_vinfo::varnullingrels, 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 1741 of file setrefs.c.

1744 {
1745  ListCell *l;
1746 
1747  /*
1748  * Append, like Sort et al, doesn't actually evaluate its targetlist or
1749  * check quals. If it's got exactly one child plan, then it's not doing
1750  * anything useful at all, and we can strip it out.
1751  */
1752  Assert(aplan->plan.qual == NIL);
1753 
1754  /* First, we gotta recurse on the children */
1755  foreach(l, aplan->appendplans)
1756  {
1757  lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset);
1758  }
1759 
1760  /*
1761  * See if it's safe to get rid of the Append entirely. For this to be
1762  * safe, there must be only one child plan and that child plan's parallel
1763  * awareness must match the Append's. The reason for the latter is that
1764  * if the Append is parallel aware and the child is not, then the calling
1765  * plan may execute the non-parallel aware child multiple times. (If you
1766  * change these rules, update create_append_path to match.)
1767  */
1768  if (list_length(aplan->appendplans) == 1)
1769  {
1770  Plan *p = (Plan *) linitial(aplan->appendplans);
1771 
1772  if (p->parallel_aware == aplan->plan.parallel_aware)
1773  return clean_up_removed_plan_level((Plan *) aplan, p);
1774  }
1775 
1776  /*
1777  * Otherwise, clean up the Append as needed. It's okay to do this after
1778  * recursing to the children, because set_dummy_tlist_references doesn't
1779  * look at those.
1780  */
1781  set_dummy_tlist_references((Plan *) aplan, rtoffset);
1782 
1783  aplan->apprelids = offset_relid_set(aplan->apprelids, rtoffset);
1784 
1785  if (aplan->part_prune_info)
1786  {
1787  foreach(l, aplan->part_prune_info->prune_infos)
1788  {
1789  List *prune_infos = lfirst(l);
1790  ListCell *l2;
1791 
1792  foreach(l2, prune_infos)
1793  {
1794  PartitionedRelPruneInfo *pinfo = lfirst(l2);
1795 
1796  pinfo->rtindex += rtoffset;
1797  }
1798  }
1799  }
1800 
1801  /* We don't need to recurse to lefttree or righttree ... */
1802  Assert(aplan->plan.lefttree == NULL);
1803  Assert(aplan->plan.righttree == NULL);
1804 
1805  return (Plan *) aplan;
1806 }
static Relids offset_relid_set(Relids relids, int rtoffset)
Definition: setrefs.c:1922
static void set_dummy_tlist_references(Plan *plan, int rtoffset)
Definition: setrefs.c:2609
static Plan * clean_up_removed_plan_level(Plan *parent, Plan *child)
Definition: setrefs.c:1534
static Plan * set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:608
struct PartitionPruneInfo * part_prune_info
Definition: plannodes.h:279
Bitmapset * apprelids
Definition: plannodes.h:268
Plan plan
Definition: plannodes.h:267
List * appendplans
Definition: plannodes.h:269
struct Plan * lefttree
Definition: plannodes.h:154
struct Plan * righttree
Definition: plannodes.h:155
bool parallel_aware
Definition: plannodes.h:140
List * qual
Definition: plannodes.h:153

References Append::appendplans, Append::apprelids, Assert, clean_up_removed_plan_level(), Plan::lefttree, lfirst, linitial, list_length(), NIL, offset_relid_set(), Plan::parallel_aware, Append::part_prune_info, Append::plan, PartitionPruneInfo::prune_infos, Plan::qual, Plan::righttree, root, 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 1665 of file setrefs.c.

1668 {
1669  ListCell *lc;
1670 
1671  /* Adjust scanrelid if it's valid */
1672  if (cscan->scan.scanrelid > 0)
1673  cscan->scan.scanrelid += rtoffset;
1674 
1675  if (cscan->custom_scan_tlist != NIL || cscan->scan.scanrelid == 0)
1676  {
1677  /* Adjust tlist, qual, custom_exprs to reference custom scan tuple */
1679 
1680  cscan->scan.plan.targetlist = (List *)
1682  (Node *) cscan->scan.plan.targetlist,
1683  itlist,
1684  INDEX_VAR,
1685  rtoffset,
1686  NRM_EQUAL,
1687  NUM_EXEC_TLIST((Plan *) cscan));
1688  cscan->scan.plan.qual = (List *)
1690  (Node *) cscan->scan.plan.qual,
1691  itlist,
1692  INDEX_VAR,
1693  rtoffset,
1694  NRM_EQUAL,
1695  NUM_EXEC_QUAL((Plan *) cscan));
1696  cscan->custom_exprs = (List *)
1698  (Node *) cscan->custom_exprs,
1699  itlist,
1700  INDEX_VAR,
1701  rtoffset,
1702  NRM_EQUAL,
1703  NUM_EXEC_QUAL((Plan *) cscan));
1704  pfree(itlist);
1705  /* custom_scan_tlist itself just needs fix_scan_list() adjustments */
1706  cscan->custom_scan_tlist =
1708  rtoffset, NUM_EXEC_TLIST((Plan *) cscan));
1709  }
1710  else
1711  {
1712  /* Adjust tlist, qual, custom_exprs in the standard way */
1713  cscan->scan.plan.targetlist =
1714  fix_scan_list(root, cscan->scan.plan.targetlist,
1715  rtoffset, NUM_EXEC_TLIST((Plan *) cscan));
1716  cscan->scan.plan.qual =
1717  fix_scan_list(root, cscan->scan.plan.qual,
1718  rtoffset, NUM_EXEC_QUAL((Plan *) cscan));
1719  cscan->custom_exprs =
1721  rtoffset, NUM_EXEC_QUAL((Plan *) cscan));
1722  }
1723 
1724  /* Adjust child plan-nodes recursively, if needed */
1725  foreach(lc, cscan->custom_plans)
1726  {
1727  lfirst(lc) = set_plan_refs(root, (Plan *) lfirst(lc), rtoffset);
1728  }
1729 
1730  cscan->custom_relids = offset_relid_set(cscan->custom_relids, rtoffset);
1731 }
void pfree(void *pointer)
Definition: mcxt.c:1520
#define INDEX_VAR
Definition: primnodes.h:238
#define NUM_EXEC_QUAL(parentplan)
Definition: setrefs.c:116
static indexed_tlist * build_tlist_index(List *tlist)
Definition: setrefs.c:2676
static Node * fix_upper_expr(PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, int newvarno, int rtoffset, NullingRelsMatch nrm_match, double num_exec)
Definition: setrefs.c:3182
#define NUM_EXEC_TLIST(parentplan)
Definition: setrefs.c:115
#define fix_scan_list(root, lst, rtoffset, num_exec)
Definition: setrefs.c:129
List * custom_scan_tlist
Definition: plannodes.h:747
Scan scan
Definition: plannodes.h:741
Bitmapset * custom_relids
Definition: plannodes.h:748
List * custom_exprs
Definition: plannodes.h:745
List * custom_plans
Definition: plannodes.h:744
Index scanrelid
Definition: plannodes.h:389

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

Referenced by set_plan_refs().

◆ set_dummy_tlist_references()

static void set_dummy_tlist_references ( Plan plan,
int  rtoffset 
)
static

Definition at line 2609 of file setrefs.c.

2610 {
2611  List *output_targetlist;
2612  ListCell *l;
2613 
2614  output_targetlist = NIL;
2615  foreach(l, plan->targetlist)
2616  {
2617  TargetEntry *tle = (TargetEntry *) lfirst(l);
2618  Var *oldvar = (Var *) tle->expr;
2619  Var *newvar;
2620 
2621  /*
2622  * As in search_indexed_tlist_for_non_var(), we prefer to keep Consts
2623  * as Consts, not Vars referencing Consts. Here, there's no speed
2624  * advantage to be had, but it makes EXPLAIN output look cleaner, and
2625  * again it avoids confusing the executor.
2626  */
2627  if (IsA(oldvar, Const))
2628  {
2629  /* just reuse the existing TLE node */
2630  output_targetlist = lappend(output_targetlist, tle);
2631  continue;
2632  }
2633 
2634  newvar = makeVar(OUTER_VAR,
2635  tle->resno,
2636  exprType((Node *) oldvar),
2637  exprTypmod((Node *) oldvar),
2638  exprCollation((Node *) oldvar),
2639  0);
2640  if (IsA(oldvar, Var) &&
2641  oldvar->varnosyn > 0)
2642  {
2643  newvar->varnosyn = oldvar->varnosyn + rtoffset;
2644  newvar->varattnosyn = oldvar->varattnosyn;
2645  }
2646  else
2647  {
2648  newvar->varnosyn = 0; /* wasn't ever a plain Var */
2649  newvar->varattnosyn = 0;
2650  }
2651 
2652  tle = flatCopyTargetEntry(tle);
2653  tle->expr = (Expr *) newvar;
2654  output_targetlist = lappend(output_targetlist, tle);
2655  }
2656  plan->targetlist = output_targetlist;
2657 
2658  /* We don't touch plan->qual here */
2659 }
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:273
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:298
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:816
#define plan(x)
Definition: pg_regress.c:162

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

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

1581 {
1582  /* Adjust scanrelid if it's valid */
1583  if (fscan->scan.scanrelid > 0)
1584  fscan->scan.scanrelid += rtoffset;
1585 
1586  if (fscan->fdw_scan_tlist != NIL || fscan->scan.scanrelid == 0)
1587  {
1588  /*
1589  * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals to reference
1590  * foreign scan tuple
1591  */
1593 
1594  fscan->scan.plan.targetlist = (List *)
1596  (Node *) fscan->scan.plan.targetlist,
1597  itlist,
1598  INDEX_VAR,
1599  rtoffset,
1600  NRM_EQUAL,
1601  NUM_EXEC_TLIST((Plan *) fscan));
1602  fscan->scan.plan.qual = (List *)
1604  (Node *) fscan->scan.plan.qual,
1605  itlist,
1606  INDEX_VAR,
1607  rtoffset,
1608  NRM_EQUAL,
1609  NUM_EXEC_QUAL((Plan *) fscan));
1610  fscan->fdw_exprs = (List *)
1612  (Node *) fscan->fdw_exprs,
1613  itlist,
1614  INDEX_VAR,
1615  rtoffset,
1616  NRM_EQUAL,
1617  NUM_EXEC_QUAL((Plan *) fscan));
1618  fscan->fdw_recheck_quals = (List *)
1620  (Node *) fscan->fdw_recheck_quals,
1621  itlist,
1622  INDEX_VAR,
1623  rtoffset,
1624  NRM_EQUAL,
1625  NUM_EXEC_QUAL((Plan *) fscan));
1626  pfree(itlist);
1627  /* fdw_scan_tlist itself just needs fix_scan_list() adjustments */
1628  fscan->fdw_scan_tlist =
1630  rtoffset, NUM_EXEC_TLIST((Plan *) fscan));
1631  }
1632  else
1633  {
1634  /*
1635  * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals in the standard
1636  * way
1637  */
1638  fscan->scan.plan.targetlist =
1639  fix_scan_list(root, fscan->scan.plan.targetlist,
1640  rtoffset, NUM_EXEC_TLIST((Plan *) fscan));
1641  fscan->scan.plan.qual =
1642  fix_scan_list(root, fscan->scan.plan.qual,
1643  rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
1644  fscan->fdw_exprs =
1645  fix_scan_list(root, fscan->fdw_exprs,
1646  rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
1647  fscan->fdw_recheck_quals =
1649  rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
1650  }
1651 
1652  fscan->fs_relids = offset_relid_set(fscan->fs_relids, rtoffset);
1653  fscan->fs_base_relids = offset_relid_set(fscan->fs_base_relids, rtoffset);
1654 
1655  /* Adjust resultRelation if it's valid */
1656  if (fscan->resultRelation > 0)
1657  fscan->resultRelation += rtoffset;
1658 }
List * fdw_exprs
Definition: plannodes.h:715
Bitmapset * fs_relids
Definition: plannodes.h:719
Bitmapset * fs_base_relids
Definition: plannodes.h:720
Index resultRelation
Definition: plannodes.h:711
List * fdw_recheck_quals
Definition: plannodes.h:718
List * fdw_scan_tlist
Definition: plannodes.h:717

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

Referenced by set_plan_refs().

◆ set_hash_references()

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

Definition at line 1889 of file setrefs.c.

1890 {
1891  Hash *hplan = (Hash *) plan;
1892  Plan *outer_plan = plan->lefttree;
1893  indexed_tlist *outer_itlist;
1894 
1895  /*
1896  * Hash's hashkeys are used when feeding tuples into the hashtable,
1897  * therefore have them reference Hash's outer plan (which itself is the
1898  * inner plan of the HashJoin).
1899  */
1900  outer_itlist = build_tlist_index(outer_plan->targetlist);
1901  hplan->hashkeys = (List *)
1903  (Node *) hplan->hashkeys,
1904  outer_itlist,
1905  OUTER_VAR,
1906  rtoffset,
1907  NRM_EQUAL,
1908  NUM_EXEC_QUAL(plan));
1909 
1910  /* Hash doesn't project */
1911  set_dummy_tlist_references(plan, rtoffset);
1912 
1913  /* Hash nodes don't have their own quals */
1914  Assert(plan->qual == NIL);
1915 }
List * hashkeys
Definition: plannodes.h:1205

References Assert, build_tlist_index(), fix_upper_expr(), Hash::hashkeys, NIL, NRM_EQUAL, NUM_EXEC_QUAL, OUTER_VAR, plan, root, 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 1321 of file setrefs.c.

1324 {
1325  indexed_tlist *index_itlist;
1326  List *stripped_indextlist;
1327  ListCell *lc;
1328 
1329  /*
1330  * Vars in the plan node's targetlist, qual, and recheckqual must only
1331  * reference columns that the index AM can actually return. To ensure
1332  * this, remove non-returnable columns (which are marked as resjunk) from
1333  * the indexed tlist. We can just drop them because the indexed_tlist
1334  * machinery pays attention to TLE resnos, not physical list position.
1335  */
1336  stripped_indextlist = NIL;
1337  foreach(lc, plan->indextlist)
1338  {
1339  TargetEntry *indextle = (TargetEntry *) lfirst(lc);
1340 
1341  if (!indextle->resjunk)
1342  stripped_indextlist = lappend(stripped_indextlist, indextle);
1343  }
1344 
1345  index_itlist = build_tlist_index(stripped_indextlist);
1346 
1347  plan->scan.scanrelid += rtoffset;
1348  plan->scan.plan.targetlist = (List *)
1350  (Node *) plan->scan.plan.targetlist,
1351  index_itlist,
1352  INDEX_VAR,
1353  rtoffset,
1354  NRM_EQUAL,
1355  NUM_EXEC_TLIST((Plan *) plan));
1356  plan->scan.plan.qual = (List *)
1358  (Node *) plan->scan.plan.qual,
1359  index_itlist,
1360  INDEX_VAR,
1361  rtoffset,
1362  NRM_EQUAL,
1363  NUM_EXEC_QUAL((Plan *) plan));
1364  plan->recheckqual = (List *)
1366  (Node *) plan->recheckqual,
1367  index_itlist,
1368  INDEX_VAR,
1369  rtoffset,
1370  NRM_EQUAL,
1371  NUM_EXEC_QUAL((Plan *) plan));
1372  /* indexqual is already transformed to reference index columns */
1373  plan->indexqual = fix_scan_list(root, plan->indexqual,
1374  rtoffset, 1);
1375  /* indexorderby is already transformed to reference index columns */
1376  plan->indexorderby = fix_scan_list(root, plan->indexorderby,
1377  rtoffset, 1);
1378  /* indextlist must NOT be transformed to reference index columns */
1379  plan->indextlist = fix_scan_list(root, plan->indextlist,
1380  rtoffset, NUM_EXEC_TLIST((Plan *) plan));
1381 
1382  pfree(index_itlist);
1383 
1384  return (Plan *) plan;
1385 }

References build_tlist_index(), fix_scan_list, fix_upper_expr(), INDEX_VAR, lappend(), lfirst, NIL, NRM_EQUAL, NUM_EXEC_QUAL, NUM_EXEC_TLIST, pfree(), plan, and root.

Referenced by set_plan_refs().

◆ set_join_references()

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

Definition at line 2270 of file setrefs.c.

2271 {
2272  Plan *outer_plan = join->plan.lefttree;
2273  Plan *inner_plan = join->plan.righttree;
2274  indexed_tlist *outer_itlist;
2275  indexed_tlist *inner_itlist;
2276 
2277  outer_itlist = build_tlist_index(outer_plan->targetlist);
2278  inner_itlist = build_tlist_index(inner_plan->targetlist);
2279 
2280  /*
2281  * First process the joinquals (including merge or hash clauses). These
2282  * are logically below the join so they can always use all values
2283  * available from the input tlists. It's okay to also handle
2284  * NestLoopParams now, because those couldn't refer to nullable
2285  * subexpressions.
2286  */
2287  join->joinqual = fix_join_expr(root,
2288  join->joinqual,
2289  outer_itlist,
2290  inner_itlist,
2291  (Index) 0,
2292  rtoffset,
2293  NRM_EQUAL,
2294  NUM_EXEC_QUAL((Plan *) join));
2295 
2296  /* Now do join-type-specific stuff */
2297  if (IsA(join, NestLoop))
2298  {
2299  NestLoop *nl = (NestLoop *) join;
2300  ListCell *lc;
2301 
2302  foreach(lc, nl->nestParams)
2303  {
2304  NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
2305 
2306  /*
2307  * Because we don't reparameterize parameterized paths to match
2308  * the outer-join level at which they are used, Vars seen in the
2309  * NestLoopParam expression may have nullingrels that are just a
2310  * subset of those in the Vars actually available from the outer
2311  * side. (Lateral references can also cause this, as explained in
2312  * the comments for identify_current_nestloop_params.) Not
2313  * checking this exactly is a bit grotty, but the work needed to
2314  * make things match up perfectly seems well out of proportion to
2315  * the value.
2316  */
2317  nlp->paramval = (Var *) fix_upper_expr(root,
2318  (Node *) nlp->paramval,
2319  outer_itlist,
2320  OUTER_VAR,
2321  rtoffset,
2322  NRM_SUBSET,
2323  NUM_EXEC_TLIST(outer_plan));
2324  /* Check we replaced any PlaceHolderVar with simple Var */
2325  if (!(IsA(nlp->paramval, Var) &&
2326  nlp->paramval->varno == OUTER_VAR))
2327  elog(ERROR, "NestLoopParam was not reduced to a simple Var");
2328  }
2329  }
2330  else if (IsA(join, MergeJoin))
2331  {
2332  MergeJoin *mj = (MergeJoin *) join;
2333 
2335  mj->mergeclauses,
2336  outer_itlist,
2337  inner_itlist,
2338  (Index) 0,
2339  rtoffset,
2340  NRM_EQUAL,
2341  NUM_EXEC_QUAL((Plan *) join));
2342  }
2343  else if (IsA(join, HashJoin))
2344  {
2345  HashJoin *hj = (HashJoin *) join;
2346 
2348  hj->hashclauses,
2349  outer_itlist,
2350  inner_itlist,
2351  (Index) 0,
2352  rtoffset,
2353  NRM_EQUAL,
2354  NUM_EXEC_QUAL((Plan *) join));
2355 
2356  /*
2357  * HashJoin's hashkeys are used to look for matching tuples from its
2358  * outer plan (not the Hash node!) in the hashtable.
2359  */
2360  hj->hashkeys = (List *) fix_upper_expr(root,
2361  (Node *) hj->hashkeys,
2362  outer_itlist,
2363  OUTER_VAR,
2364  rtoffset,
2365  NRM_EQUAL,
2366  NUM_EXEC_QUAL((Plan *) join));
2367  }
2368 
2369  /*
2370  * Now we need to fix up the targetlist and qpqual, which are logically
2371  * above the join. This means that, if it's not an inner join, any Vars
2372  * and PHVs appearing here should have nullingrels that include the
2373  * effects of the outer join, ie they will have nullingrels equal to the
2374  * input Vars' nullingrels plus the bit added by the outer join. We don't
2375  * currently have enough info available here to identify what that should
2376  * be, so we just tell fix_join_expr to accept superset nullingrels
2377  * matches instead of exact ones.
2378  */
2379  join->plan.targetlist = fix_join_expr(root,
2380  join->plan.targetlist,
2381  outer_itlist,
2382  inner_itlist,
2383  (Index) 0,
2384  rtoffset,
2385  (join->jointype == JOIN_INNER ? NRM_EQUAL : NRM_SUPERSET),
2386  NUM_EXEC_TLIST((Plan *) join));
2387  join->plan.qual = fix_join_expr(root,
2388  join->plan.qual,
2389  outer_itlist,
2390  inner_itlist,
2391  (Index) 0,
2392  rtoffset,
2393  (join->jointype == JOIN_INNER ? NRM_EQUAL : NRM_SUPERSET),
2394  NUM_EXEC_QUAL((Plan *) join));
2395 
2396  pfree(outer_itlist);
2397  pfree(inner_itlist);
2398 }
@ JOIN_INNER
Definition: nodes.h:293
static List * fix_join_expr(PlannerInfo *root, List *clauses, indexed_tlist *outer_itlist, indexed_tlist *inner_itlist, Index acceptable_rel, int rtoffset, NullingRelsMatch nrm_match, double num_exec)
Definition: setrefs.c:3021
List * hashclauses
Definition: plannodes.h:865
List * hashkeys
Definition: plannodes.h:873
List * joinqual
Definition: plannodes.h:793
JoinType jointype
Definition: plannodes.h:791
List * mergeclauses
Definition: plannodes.h:841
Var * paramval
Definition: plannodes.h:819
List * nestParams
Definition: plannodes.h:810

References build_tlist_index(), elog, ERROR, fix_join_expr(), fix_upper_expr(), HashJoin::hashclauses, HashJoin::hashkeys, IsA, JOIN_INNER, Join::joinqual, Join::jointype, lfirst, MergeJoin::mergeclauses, NestLoop::nestParams, NRM_EQUAL, NRM_SUBSET, NRM_SUPERSET, NUM_EXEC_QUAL, NUM_EXEC_TLIST, OUTER_VAR, NestLoopParam::paramval, pfree(), root, 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 1816 of file setrefs.c.

1819 {
1820  ListCell *l;
1821 
1822  /*
1823  * MergeAppend, like Sort et al, doesn't actually evaluate its targetlist
1824  * or check quals. If it's got exactly one child plan, then it's not
1825  * doing anything useful at all, and we can strip it out.
1826  */
1827  Assert(mplan->plan.qual == NIL);
1828 
1829  /* First, we gotta recurse on the children */
1830  foreach(l, mplan->mergeplans)
1831  {
1832  lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset);
1833  }
1834 
1835  /*
1836  * See if it's safe to get rid of the MergeAppend entirely. For this to
1837  * be safe, there must be only one child plan and that child plan's
1838  * parallel awareness must match the MergeAppend's. The reason for the
1839  * latter is that if the MergeAppend is parallel aware and the child is
1840  * not, then the calling plan may execute the non-parallel aware child
1841  * multiple times. (If you change these rules, update
1842  * create_merge_append_path to match.)
1843  */
1844  if (list_length(mplan->mergeplans) == 1)
1845  {
1846  Plan *p = (Plan *) linitial(mplan->mergeplans);
1847 
1848  if (p->parallel_aware == mplan->plan.parallel_aware)
1849  return clean_up_removed_plan_level((Plan *) mplan, p);
1850  }
1851 
1852  /*
1853  * Otherwise, clean up the MergeAppend as needed. It's okay to do this
1854  * after recursing to the children, because set_dummy_tlist_references
1855  * doesn't look at those.
1856  */
1857  set_dummy_tlist_references((Plan *) mplan, rtoffset);
1858 
1859  mplan->apprelids = offset_relid_set(mplan->apprelids, rtoffset);
1860 
1861  if (mplan->part_prune_info)
1862  {
1863  foreach(l, mplan->part_prune_info->prune_infos)
1864  {
1865  List *prune_infos = lfirst(l);
1866  ListCell *l2;
1867 
1868  foreach(l2, prune_infos)
1869  {
1870  PartitionedRelPruneInfo *pinfo = lfirst(l2);
1871 
1872  pinfo->rtindex += rtoffset;
1873  }
1874  }
1875  }
1876 
1877  /* We don't need to recurse to lefttree or righttree ... */
1878  Assert(mplan->plan.lefttree == NULL);
1879  Assert(mplan->plan.righttree == NULL);
1880 
1881  return (Plan *) mplan;
1882 }
struct PartitionPruneInfo * part_prune_info
Definition: plannodes.h:314
Bitmapset * apprelids
Definition: plannodes.h:292
List * mergeplans
Definition: plannodes.h:294

References MergeAppend::apprelids, Assert, clean_up_removed_plan_level(), Plan::lefttree, lfirst, linitial, list_length(), MergeAppend::mergeplans, NIL, offset_relid_set(), Plan::parallel_aware, MergeAppend::part_prune_info, MergeAppend::plan, PartitionPruneInfo::prune_infos, Plan::qual, Plan::righttree, root, 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 2485 of file setrefs.c.

2486 {
2488 
2489  if (plan->lefttree->extParam)
2490  {
2491  PlannerInfo *proot;
2492  Bitmapset *initSetParam = NULL;
2493  ListCell *l;
2494 
2495  for (proot = root; proot != NULL; proot = proot->parent_root)
2496  {
2497  foreach(l, proot->init_plans)
2498  {
2499  SubPlan *initsubplan = (SubPlan *) lfirst(l);
2500  ListCell *l2;
2501 
2502  foreach(l2, initsubplan->setParam)
2503  {
2504  initSetParam = bms_add_member(initSetParam, lfirst_int(l2));
2505  }
2506  }
2507  }
2508 
2509  /*
2510  * Remember the list of all external initplan params that are used by
2511  * the children of Gather or Gather merge node.
2512  */
2513  if (IsA(plan, Gather))
2514  ((Gather *) plan)->initParam =
2515  bms_intersect(plan->lefttree->extParam, initSetParam);
2516  else
2517  ((GatherMerge *) plan)->initParam =
2518  bms_intersect(plan->lefttree->extParam, initSetParam);
2519  }
2520 }
Bitmapset * bms_intersect(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:292
List * init_plans
Definition: pathnodes.h:299
List * setParam
Definition: primnodes.h:1058

References Assert, bms_add_member(), bms_intersect(), PlannerInfo::init_plans, IsA, lfirst, lfirst_int, plan, root, and SubPlan::setParam.

Referenced by set_plan_refs().

◆ set_plan_references()

Plan* set_plan_references ( PlannerInfo root,
Plan plan 
)

Definition at line 287 of file setrefs.c.

288 {
289  Plan *result;
290  PlannerGlobal *glob = root->glob;
291  int rtoffset = list_length(glob->finalrtable);
292  ListCell *lc;
293 
294  /*
295  * Add all the query's RTEs to the flattened rangetable. The live ones
296  * will have their rangetable indexes increased by rtoffset. (Additional
297  * RTEs, not referenced by the Plan tree, might get added after those.)
298  */
300 
301  /*
302  * Adjust RT indexes of PlanRowMarks and add to final rowmarks list
303  */
304  foreach(lc, root->rowMarks)
305  {
307  PlanRowMark *newrc;
308 
309  /* flat copy is enough since all fields are scalars */
310  newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark));
311  memcpy(newrc, rc, sizeof(PlanRowMark));
312 
313  /* adjust indexes ... but *not* the rowmarkId */
314  newrc->rti += rtoffset;
315  newrc->prti += rtoffset;
316 
317  glob->finalrowmarks = lappend(glob->finalrowmarks, newrc);
318  }
319 
320  /*
321  * Adjust RT indexes of AppendRelInfos and add to final appendrels list.
322  * We assume the AppendRelInfos were built during planning and don't need
323  * to be copied.
324  */
325  foreach(lc, root->append_rel_list)
326  {
327  AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
328 
329  /* adjust RT indexes */
330  appinfo->parent_relid += rtoffset;
331  appinfo->child_relid += rtoffset;
332 
333  /*
334  * Rather than adjust the translated_vars entries, just drop 'em.
335  * Neither the executor nor EXPLAIN currently need that data.
336  */
337  appinfo->translated_vars = NIL;
338 
339  glob->appendRelations = lappend(glob->appendRelations, appinfo);
340  }
341 
342  /* If needed, create workspace for processing AlternativeSubPlans */
343  if (root->hasAlternativeSubPlans)
344  {
345  root->isAltSubplan = (bool *)
346  palloc0(list_length(glob->subplans) * sizeof(bool));
347  root->isUsedSubplan = (bool *)
348  palloc0(list_length(glob->subplans) * sizeof(bool));
349  }
350 
351  /* Now fix the Plan tree */
352  result = set_plan_refs(root, plan, rtoffset);
353 
354  /*
355  * If we have AlternativeSubPlans, it is likely that we now have some
356  * unreferenced subplans in glob->subplans. To avoid expending cycles on
357  * those subplans later, get rid of them by setting those list entries to
358  * NULL. (Note: we can't do this immediately upon processing an
359  * AlternativeSubPlan, because there may be multiple copies of the
360  * AlternativeSubPlan, and they can get resolved differently.)
361  */
362  if (root->hasAlternativeSubPlans)
363  {
364  foreach(lc, glob->subplans)
365  {
366  int ndx = foreach_current_index(lc);
367 
368  /*
369  * If it was used by some AlternativeSubPlan in this query level,
370  * but wasn't selected as best by any AlternativeSubPlan, then we
371  * don't need it. Do not touch subplans that aren't parts of
372  * AlternativeSubPlans.
373  */
374  if (root->isAltSubplan[ndx] && !root->isUsedSubplan[ndx])
375  lfirst(lc) = NULL;
376  }
377  }
378 
379  return result;
380 }
unsigned char bool
Definition: c.h:456
void * palloc0(Size size)
Definition: mcxt.c:1346
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define foreach_current_index(var_or_cell)
Definition: pg_list.h:403
Index child_relid
Definition: pathnodes.h:2958
List * translated_vars
Definition: pathnodes.h:2985
Index parent_relid
Definition: pathnodes.h:2957
Index prti
Definition: plannodes.h:1383
List * subplans
Definition: pathnodes.h:105
List * appendRelations
Definition: pathnodes.h:129
List * finalrowmarks
Definition: pathnodes.h:123

References add_rtes_to_flat_rtable(), PlannerGlobal::appendRelations, AppendRelInfo::child_relid, PlannerGlobal::finalrowmarks, PlannerGlobal::finalrtable, foreach_current_index, lappend(), lfirst, lfirst_node, list_length(), NIL, palloc(), palloc0(), AppendRelInfo::parent_relid, plan, PlanRowMark::prti, root, 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 608 of file setrefs.c.

609 {
610  ListCell *l;
611 
612  if (plan == NULL)
613  return NULL;
614 
615  /* Assign this node a unique ID. */
616  plan->plan_node_id = root->glob->lastPlanNodeId++;
617 
618  /*
619  * Plan-type-specific fixes
620  */
621  switch (nodeTag(plan))
622  {
623  case T_SeqScan:
624  {
625  SeqScan *splan = (SeqScan *) plan;
626 
627  splan->scan.scanrelid += rtoffset;
628  splan->scan.plan.targetlist =
629  fix_scan_list(root, splan->scan.plan.targetlist,
630  rtoffset, NUM_EXEC_TLIST(plan));
631  splan->scan.plan.qual =
632  fix_scan_list(root, splan->scan.plan.qual,
633  rtoffset, NUM_EXEC_QUAL(plan));
634  }
635  break;
636  case T_SampleScan:
637  {
639 
640  splan->scan.scanrelid += rtoffset;
641  splan->scan.plan.targetlist =
642  fix_scan_list(root, splan->scan.plan.targetlist,
643  rtoffset, NUM_EXEC_TLIST(plan));
644  splan->scan.plan.qual =
645  fix_scan_list(root, splan->scan.plan.qual,
646  rtoffset, NUM_EXEC_QUAL(plan));
647  splan->tablesample = (TableSampleClause *)
648  fix_scan_expr(root, (Node *) splan->tablesample,
649  rtoffset, 1);
650  }
651  break;
652  case T_IndexScan:
653  {
654  IndexScan *splan = (IndexScan *) plan;
655 
656  splan->scan.scanrelid += rtoffset;
657  splan->scan.plan.targetlist =
658  fix_scan_list(root, splan->scan.plan.targetlist,
659  rtoffset, NUM_EXEC_TLIST(plan));
660  splan->scan.plan.qual =
661  fix_scan_list(root, splan->scan.plan.qual,
662  rtoffset, NUM_EXEC_QUAL(plan));
663  splan->indexqual =
664  fix_scan_list(root, splan->indexqual,
665  rtoffset, 1);
666  splan->indexqualorig =
667  fix_scan_list(root, splan->indexqualorig,
668  rtoffset, NUM_EXEC_QUAL(plan));
669  splan->indexorderby =
670  fix_scan_list(root, splan->indexorderby,
671  rtoffset, 1);
672  splan->indexorderbyorig =
673  fix_scan_list(root, splan->indexorderbyorig,
674  rtoffset, NUM_EXEC_QUAL(plan));
675  }
676  break;
677  case T_IndexOnlyScan:
678  {
680 
681  return set_indexonlyscan_references(root, splan, rtoffset);
682  }
683  break;
684  case T_BitmapIndexScan:
685  {
687 
688  splan->scan.scanrelid += rtoffset;
689  /* no need to fix targetlist and qual */
690  Assert(splan->scan.plan.targetlist == NIL);
691  Assert(splan->scan.plan.qual == NIL);
692  splan->indexqual =
693  fix_scan_list(root, splan->indexqual, rtoffset, 1);
694  splan->indexqualorig =
695  fix_scan_list(root, splan->indexqualorig,
696  rtoffset, NUM_EXEC_QUAL(plan));
697  }
698  break;
699  case T_BitmapHeapScan:
700  {
702 
703  splan->scan.scanrelid += rtoffset;
704  splan->scan.plan.targetlist =
705  fix_scan_list(root, splan->scan.plan.targetlist,
706  rtoffset, NUM_EXEC_TLIST(plan));
707  splan->scan.plan.qual =
708  fix_scan_list(root, splan->scan.plan.qual,
709  rtoffset, NUM_EXEC_QUAL(plan));
710  splan->bitmapqualorig =
711  fix_scan_list(root, splan->bitmapqualorig,
712  rtoffset, NUM_EXEC_QUAL(plan));
713  }
714  break;
715  case T_TidScan:
716  {
717  TidScan *splan = (TidScan *) plan;
718 
719  splan->scan.scanrelid += rtoffset;
720  splan->scan.plan.targetlist =
721  fix_scan_list(root, splan->scan.plan.targetlist,
722  rtoffset, NUM_EXEC_TLIST(plan));
723  splan->scan.plan.qual =
724  fix_scan_list(root, splan->scan.plan.qual,
725  rtoffset, NUM_EXEC_QUAL(plan));
726  splan->tidquals =
727  fix_scan_list(root, splan->tidquals,
728  rtoffset, 1);
729  }
730  break;
731  case T_TidRangeScan:
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  splan->tidrangequals =
743  fix_scan_list(root, splan->tidrangequals,
744  rtoffset, 1);
745  }
746  break;
747  case T_SubqueryScan:
748  /* Needs special treatment, see comments below */
750  (SubqueryScan *) plan,
751  rtoffset);
752  case T_FunctionScan:
753  {
755 
756  splan->scan.scanrelid += rtoffset;
757  splan->scan.plan.targetlist =
758  fix_scan_list(root, splan->scan.plan.targetlist,
759  rtoffset, NUM_EXEC_TLIST(plan));
760  splan->scan.plan.qual =
761  fix_scan_list(root, splan->scan.plan.qual,
762  rtoffset, NUM_EXEC_QUAL(plan));
763  splan->functions =
764  fix_scan_list(root, splan->functions, rtoffset, 1);
765  }
766  break;
767  case T_TableFuncScan:
768  {
770 
771  splan->scan.scanrelid += rtoffset;
772  splan->scan.plan.targetlist =
773  fix_scan_list(root, splan->scan.plan.targetlist,
774  rtoffset, NUM_EXEC_TLIST(plan));
775  splan->scan.plan.qual =
776  fix_scan_list(root, splan->scan.plan.qual,
777  rtoffset, NUM_EXEC_QUAL(plan));
778  splan->tablefunc = (TableFunc *)
779  fix_scan_expr(root, (Node *) splan->tablefunc,
780  rtoffset, 1);
781  }
782  break;
783  case T_ValuesScan:
784  {
786 
787  splan->scan.scanrelid += rtoffset;
788  splan->scan.plan.targetlist =
789  fix_scan_list(root, splan->scan.plan.targetlist,
790  rtoffset, NUM_EXEC_TLIST(plan));
791  splan->scan.plan.qual =
792  fix_scan_list(root, splan->scan.plan.qual,
793  rtoffset, NUM_EXEC_QUAL(plan));
794  splan->values_lists =
795  fix_scan_list(root, splan->values_lists,
796  rtoffset, 1);
797  }
798  break;
799  case T_CteScan:
800  {
801  CteScan *splan = (CteScan *) plan;
802 
803  splan->scan.scanrelid += rtoffset;
804  splan->scan.plan.targetlist =
805  fix_scan_list(root, splan->scan.plan.targetlist,
806  rtoffset, NUM_EXEC_TLIST(plan));
807  splan->scan.plan.qual =
808  fix_scan_list(root, splan->scan.plan.qual,
809  rtoffset, NUM_EXEC_QUAL(plan));
810  }
811  break;
812  case T_NamedTuplestoreScan:
813  {
815 
816  splan->scan.scanrelid += rtoffset;
817  splan->scan.plan.targetlist =
818  fix_scan_list(root, splan->scan.plan.targetlist,
819  rtoffset, NUM_EXEC_TLIST(plan));
820  splan->scan.plan.qual =
821  fix_scan_list(root, splan->scan.plan.qual,
822  rtoffset, NUM_EXEC_QUAL(plan));
823  }
824  break;
825  case T_WorkTableScan:
826  {
828 
829  splan->scan.scanrelid += rtoffset;
830  splan->scan.plan.targetlist =
831  fix_scan_list(root, splan->scan.plan.targetlist,
832  rtoffset, NUM_EXEC_TLIST(plan));
833  splan->scan.plan.qual =
834  fix_scan_list(root, splan->scan.plan.qual,
835  rtoffset, NUM_EXEC_QUAL(plan));
836  }
837  break;
838  case T_ForeignScan:
840  break;
841  case T_CustomScan:
843  break;
844 
845  case T_NestLoop:
846  case T_MergeJoin:
847  case T_HashJoin:
848  set_join_references(root, (Join *) plan, rtoffset);
849  break;
850 
851  case T_Gather:
852  case T_GatherMerge:
853  {
854  set_upper_references(root, plan, rtoffset);
856  }
857  break;
858 
859  case T_Hash:
860  set_hash_references(root, plan, rtoffset);
861  break;
862 
863  case T_Memoize:
864  {
865  Memoize *mplan = (Memoize *) plan;
866 
867  /*
868  * Memoize does not evaluate its targetlist. It just uses the
869  * same targetlist from its outer subnode.
870  */
871  set_dummy_tlist_references(plan, rtoffset);
872 
873  mplan->param_exprs = fix_scan_list(root, mplan->param_exprs,
874  rtoffset,
876  break;
877  }
878 
879  case T_Material:
880  case T_Sort:
881  case T_IncrementalSort:
882  case T_Unique:
883  case T_SetOp:
884 
885  /*
886  * These plan types don't actually bother to evaluate their
887  * targetlists, because they just return their unmodified input
888  * tuples. Even though the targetlist won't be used by the
889  * executor, we fix it up for possible use by EXPLAIN (not to
890  * mention ease of debugging --- wrong varnos are very confusing).
891  */
892  set_dummy_tlist_references(plan, rtoffset);
893 
894  /*
895  * Since these plan types don't check quals either, we should not
896  * find any qual expression attached to them.
897  */
898  Assert(plan->qual == NIL);
899  break;
900  case T_LockRows:
901  {
902  LockRows *splan = (LockRows *) plan;
903 
904  /*
905  * Like the plan types above, LockRows doesn't evaluate its
906  * tlist or quals. But we have to fix up the RT indexes in
907  * its rowmarks.
908  */
909  set_dummy_tlist_references(plan, rtoffset);
910  Assert(splan->plan.qual == NIL);
911 
912  foreach(l, splan->rowMarks)
913  {
914  PlanRowMark *rc = (PlanRowMark *) lfirst(l);
915 
916  rc->rti += rtoffset;
917  rc->prti += rtoffset;
918  }
919  }
920  break;
921  case T_Limit:
922  {
923  Limit *splan = (Limit *) plan;
924 
925  /*
926  * Like the plan types above, Limit doesn't evaluate its tlist
927  * or quals. It does have live expressions for limit/offset,
928  * however; and those cannot contain subplan variable refs, so
929  * fix_scan_expr works for them.
930  */
931  set_dummy_tlist_references(plan, rtoffset);
932  Assert(splan->plan.qual == NIL);
933 
934  splan->limitOffset =
935  fix_scan_expr(root, splan->limitOffset, rtoffset, 1);
936  splan->limitCount =
937  fix_scan_expr(root, splan->limitCount, rtoffset, 1);
938  }
939  break;
940  case T_Agg:
941  {
942  Agg *agg = (Agg *) plan;
943 
944  /*
945  * If this node is combining partial-aggregation results, we
946  * must convert its Aggrefs to contain references to the
947  * partial-aggregate subexpressions that will be available
948  * from the child plan node.
949  */
950  if (DO_AGGSPLIT_COMBINE(agg->aggsplit))
951  {
952  plan->targetlist = (List *)
953  convert_combining_aggrefs((Node *) plan->targetlist,
954  NULL);
955  plan->qual = (List *)
957  NULL);
958  }
959 
960  set_upper_references(root, plan, rtoffset);
961  }
962  break;
963  case T_Group:
964  set_upper_references(root, plan, rtoffset);
965  break;
966  case T_WindowAgg:
967  {
968  WindowAgg *wplan = (WindowAgg *) plan;
969 
970  /*
971  * Adjust the WindowAgg's run conditions by swapping the
972  * WindowFuncs references out to instead reference the Var in
973  * the scan slot so that when the executor evaluates the
974  * runCondition, it receives the WindowFunc's value from the
975  * slot that the result has just been stored into rather than
976  * evaluating the WindowFunc all over again.
977  */
979  wplan->runCondition,
980  (Plan *) wplan);
981 
982  set_upper_references(root, plan, rtoffset);
983 
984  /*
985  * Like Limit node limit/offset expressions, WindowAgg has
986  * frame offset expressions, which cannot contain subplan
987  * variable refs, so fix_scan_expr works for them.
988  */
989  wplan->startOffset =
990  fix_scan_expr(root, wplan->startOffset, rtoffset, 1);
991  wplan->endOffset =
992  fix_scan_expr(root, wplan->endOffset, rtoffset, 1);
994  wplan->runCondition,
995  rtoffset,
998  wplan->runConditionOrig,
999  rtoffset,
1000  NUM_EXEC_TLIST(plan));
1001  }
1002  break;
1003  case T_Result:
1004  {
1005  Result *splan = (Result *) plan;
1006 
1007  /*
1008  * Result may or may not have a subplan; if not, it's more
1009  * like a scan node than an upper node.
1010  */
1011  if (splan->plan.lefttree != NULL)
1012  set_upper_references(root, plan, rtoffset);
1013  else
1014  {
1015  /*
1016  * The tlist of a childless Result could contain
1017  * unresolved ROWID_VAR Vars, in case it's representing a
1018  * target relation which is completely empty because of
1019  * constraint exclusion. Replace any such Vars by null
1020  * constants, as though they'd been resolved for a leaf
1021  * scan node that doesn't support them. We could have
1022  * fix_scan_expr do this, but since the case is only
1023  * expected to occur here, it seems safer to special-case
1024  * it here and keep the assertions that ROWID_VARs
1025  * shouldn't be seen by fix_scan_expr.
1026  */
1027  foreach(l, splan->plan.targetlist)
1028  {
1029  TargetEntry *tle = (TargetEntry *) lfirst(l);
1030  Var *var = (Var *) tle->expr;
1031 
1032  if (var && IsA(var, Var) && var->varno == ROWID_VAR)
1033  tle->expr = (Expr *) makeNullConst(var->vartype,
1034  var->vartypmod,
1035  var->varcollid);
1036  }
1037 
1038  splan->plan.targetlist =
1039  fix_scan_list(root, splan->plan.targetlist,
1040  rtoffset, NUM_EXEC_TLIST(plan));
1041  splan->plan.qual =
1042  fix_scan_list(root, splan->plan.qual,
1043  rtoffset, NUM_EXEC_QUAL(plan));
1044  }
1045  /* resconstantqual can't contain any subplan variable refs */
1046  splan->resconstantqual =
1047  fix_scan_expr(root, splan->resconstantqual, rtoffset, 1);
1048  }
1049  break;
1050  case T_ProjectSet:
1051  set_upper_references(root, plan, rtoffset);
1052  break;
1053  case T_ModifyTable:
1054  {
1056  Plan *subplan = outerPlan(splan);
1057 
1058  Assert(splan->plan.targetlist == NIL);
1059  Assert(splan->plan.qual == NIL);
1060 
1061  splan->withCheckOptionLists =
1062  fix_scan_list(root, splan->withCheckOptionLists,
1063  rtoffset, 1);
1064 
1065  if (splan->returningLists)
1066  {
1067  List *newRL = NIL;
1068  ListCell *lcrl,
1069  *lcrr;
1070 
1071  /*
1072  * Pass each per-resultrel returningList through
1073  * set_returning_clause_references().
1074  */
1075  Assert(list_length(splan->returningLists) == list_length(splan->resultRelations));
1076  forboth(lcrl, splan->returningLists,
1077  lcrr, splan->resultRelations)
1078  {
1079  List *rlist = (List *) lfirst(lcrl);
1080  Index resultrel = lfirst_int(lcrr);
1081 
1083  rlist,
1084  subplan,
1085  resultrel,
1086  rtoffset);
1087  newRL = lappend(newRL, rlist);
1088  }
1089  splan->returningLists = newRL;
1090 
1091  /*
1092  * Set up the visible plan targetlist as being the same as
1093  * the first RETURNING list. This is for the use of
1094  * EXPLAIN; the executor won't pay any attention to the
1095  * targetlist. We postpone this step until here so that
1096  * we don't have to do set_returning_clause_references()
1097  * twice on identical targetlists.
1098  */
1099  splan->plan.targetlist = copyObject(linitial(newRL));
1100  }
1101 
1102  /*
1103  * We treat ModifyTable with ON CONFLICT as a form of 'pseudo
1104  * join', where the inner side is the EXCLUDED tuple.
1105  * Therefore use fix_join_expr to setup the relevant variables
1106  * to INNER_VAR. We explicitly don't create any OUTER_VARs as
1107  * those are already used by RETURNING and it seems better to
1108  * be non-conflicting.
1109  */
1110  if (splan->onConflictSet)
1111  {
1112  indexed_tlist *itlist;
1113 
1114  itlist = build_tlist_index(splan->exclRelTlist);
1115 
1116  splan->onConflictSet =
1117  fix_join_expr(root, splan->onConflictSet,
1118  NULL, itlist,
1119  linitial_int(splan->resultRelations),
1120  rtoffset, NRM_EQUAL, NUM_EXEC_QUAL(plan));
1121 
1122  splan->onConflictWhere = (Node *)
1123  fix_join_expr(root, (List *) splan->onConflictWhere,
1124  NULL, itlist,
1125  linitial_int(splan->resultRelations),
1126  rtoffset, NRM_EQUAL, NUM_EXEC_QUAL(plan));
1127 
1128  pfree(itlist);
1129 
1130  splan->exclRelTlist =
1131  fix_scan_list(root, splan->exclRelTlist, rtoffset, 1);
1132  }
1133 
1134  /*
1135  * The MERGE statement produces the target rows by performing
1136  * a right join between the target relation and the source
1137  * relation (which could be a plain relation or a subquery).
1138  * The INSERT and UPDATE actions of the MERGE statement
1139  * require access to the columns from the source relation. We
1140  * arrange things so that the source relation attributes are
1141  * available as INNER_VAR and the target relation attributes
1142  * are available from the scan tuple.
1143  */
1144  if (splan->mergeActionLists != NIL)
1145  {
1146  List *newMJC = NIL;
1147  ListCell *lca,
1148  *lcj,
1149  *lcr;
1150 
1151  /*
1152  * Fix the targetList of individual action nodes so that
1153  * the so-called "source relation" Vars are referenced as
1154  * INNER_VAR. Note that for this to work correctly during
1155  * execution, the ecxt_innertuple must be set to the tuple
1156  * obtained by executing the subplan, which is what
1157  * constitutes the "source relation".
1158  *
1159  * We leave the Vars from the result relation (i.e. the
1160  * target relation) unchanged i.e. those Vars would be
1161  * picked from the scan slot. So during execution, we must
1162  * ensure that ecxt_scantuple is setup correctly to refer
1163  * to the tuple from the target relation.
1164  */
1165  indexed_tlist *itlist;
1166 
1167  itlist = build_tlist_index(subplan->targetlist);
1168 
1169  forthree(lca, splan->mergeActionLists,
1170  lcj, splan->mergeJoinConditions,
1171  lcr, splan->resultRelations)
1172  {
1173  List *mergeActionList = lfirst(lca);
1174  Node *mergeJoinCondition = lfirst(lcj);
1175  Index resultrel = lfirst_int(lcr);
1176 
1177  foreach(l, mergeActionList)
1178  {
1180 
1181  /* Fix targetList of each action. */
1182  action->targetList = fix_join_expr(root,
1183  action->targetList,
1184  NULL, itlist,
1185  resultrel,
1186  rtoffset,
1187  NRM_EQUAL,
1188  NUM_EXEC_TLIST(plan));
1189 
1190  /* Fix quals too. */
1191  action->qual = (Node *) fix_join_expr(root,
1192  (List *) action->qual,
1193  NULL, itlist,
1194  resultrel,
1195  rtoffset,
1196  NRM_EQUAL,
1197  NUM_EXEC_QUAL(plan));
1198  }
1199 
1200  /* Fix join condition too. */
1201  mergeJoinCondition = (Node *)
1203  (List *) mergeJoinCondition,
1204  NULL, itlist,
1205  resultrel,
1206  rtoffset,
1207  NRM_EQUAL,
1208  NUM_EXEC_QUAL(plan));
1209  newMJC = lappend(newMJC, mergeJoinCondition);
1210  }
1211  splan->mergeJoinConditions = newMJC;
1212  }
1213 
1214  splan->nominalRelation += rtoffset;
1215  if (splan->rootRelation)
1216  splan->rootRelation += rtoffset;
1217  splan->exclRelRTI += rtoffset;
1218 
1219  foreach(l, splan->resultRelations)
1220  {
1221  lfirst_int(l) += rtoffset;
1222  }
1223  foreach(l, splan->rowMarks)
1224  {
1225  PlanRowMark *rc = (PlanRowMark *) lfirst(l);
1226 
1227  rc->rti += rtoffset;
1228  rc->prti += rtoffset;
1229  }
1230 
1231  /*
1232  * Append this ModifyTable node's final result relation RT
1233  * index(es) to the global list for the plan.
1234  */
1235  root->glob->resultRelations =
1236  list_concat(root->glob->resultRelations,
1237  splan->resultRelations);
1238  if (splan->rootRelation)
1239  {
1240  root->glob->resultRelations =
1241  lappend_int(root->glob->resultRelations,
1242  splan->rootRelation);
1243  }
1244  }
1245  break;
1246  case T_Append:
1247  /* Needs special treatment, see comments below */
1248  return set_append_references(root,
1249  (Append *) plan,
1250  rtoffset);
1251  case T_MergeAppend:
1252  /* Needs special treatment, see comments below */
1254  (MergeAppend *) plan,
1255  rtoffset);
1256  case T_RecursiveUnion:
1257  /* This doesn't evaluate targetlist or check quals either */
1258  set_dummy_tlist_references(plan, rtoffset);
1259  Assert(plan->qual == NIL);
1260  break;
1261  case T_BitmapAnd:
1262  {
1263  BitmapAnd *splan = (BitmapAnd *) plan;
1264 
1265  /* BitmapAnd works like Append, but has no tlist */
1266  Assert(splan->plan.targetlist == NIL);
1267  Assert(splan->plan.qual == NIL);
1268  foreach(l, splan->bitmapplans)
1269  {
1270  lfirst(l) = set_plan_refs(root,
1271  (Plan *) lfirst(l),
1272  rtoffset);
1273  }
1274  }
1275  break;
1276  case T_BitmapOr:
1277  {
1278  BitmapOr *splan = (BitmapOr *) plan;
1279 
1280  /* BitmapOr works like Append, but has no tlist */
1281  Assert(splan->plan.targetlist == NIL);
1282  Assert(splan->plan.qual == NIL);
1283  foreach(l, splan->bitmapplans)
1284  {
1285  lfirst(l) = set_plan_refs(root,
1286  (Plan *) lfirst(l),
1287  rtoffset);
1288  }
1289  }
1290  break;
1291  default:
1292  elog(ERROR, "unrecognized node type: %d",
1293  (int) nodeTag(plan));
1294  break;
1295  }
1296 
1297  /*
1298  * Now recurse into child plans, if any
1299  *
1300  * NOTE: it is essential that we recurse into child plans AFTER we set
1301  * subplan references in this plan's tlist and quals. If we did the
1302  * reference-adjustments bottom-up, then we would fail to match this
1303  * plan's var nodes against the already-modified nodes of the children.
1304  */
1305  plan->lefttree = set_plan_refs(root, plan->lefttree, rtoffset);
1306  plan->righttree = set_plan_refs(root, plan->righttree, rtoffset);
1307 
1308  return plan;
1309 }
Datum lca(PG_FUNCTION_ARGS)
Definition: ltree_op.c:570
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:339
#define nodeTag(nodeptr)
Definition: nodes.h:133
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:384
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
#define linitial_int(l)
Definition: pg_list.h:179
#define forthree(cell1, list1, cell2, list2, cell3, list3)
Definition: pg_list.h:563
#define outerPlan(node)
Definition: plannodes.h:182
static SPIPlanPtr splan
Definition: regress.c:269
static void set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:1889
static Plan * set_append_references(PlannerInfo *root, Append *aplan, int rtoffset)
Definition: setrefs.c:1741
static Plan * set_mergeappend_references(PlannerInfo *root, MergeAppend *mplan, int rtoffset)
Definition: setrefs.c:1816
static List * set_returning_clause_references(PlannerInfo *root, List *rlist, Plan *topplan, Index resultRelation, int rtoffset)
Definition: setrefs.c:3305
static List * set_windowagg_runcondition_references(PlannerInfo *root, List *runcondition, Plan *plan)
Definition: setrefs.c:3400
static void set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:2419
static void set_param_references(PlannerInfo *root, Plan *plan)
Definition: setrefs.c:2485
static void set_foreignscan_references(PlannerInfo *root, ForeignScan *fscan, int rtoffset)
Definition: setrefs.c:1578
static Plan * set_subqueryscan_references(PlannerInfo *root, SubqueryScan *plan, int rtoffset)
Definition: setrefs.c:1395
static Plan * set_indexonlyscan_references(PlannerInfo *root, IndexOnlyScan *plan, int rtoffset)
Definition: setrefs.c:1321
static void set_customscan_references(PlannerInfo *root, CustomScan *cscan, int rtoffset)
Definition: setrefs.c:1665
static void set_join_references(PlannerInfo *root, Join *join, int rtoffset)
Definition: setrefs.c:2270
static Node * fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset, double num_exec)
Definition: setrefs.c:2148
Definition: plannodes.h:997
AggSplit aggsplit
Definition: plannodes.h:1004
List * param_exprs
Definition: plannodes.h:903
Node * endOffset
Definition: plannodes.h:1076
List * runConditionOrig
Definition: plannodes.h:1082
Node * startOffset
Definition: plannodes.h:1073
List * runCondition
Definition: plannodes.h:1079

References generate_unaccent_rules::action, Agg::aggsplit, Assert, build_tlist_index(), convert_combining_aggrefs(), copyObject, DO_AGGSPLIT_COMBINE, elog, WindowAgg::endOffset, ERROR, TargetEntry::expr, fix_join_expr(), fix_scan_expr(), fix_scan_list, forboth, forthree, if(), IsA, lappend(), lappend_int(), lca(), lfirst, lfirst_int, linitial, linitial_int, list_concat(), list_length(), makeNullConst(), NIL, nodeTag, NRM_EQUAL, NUM_EXEC_QUAL, NUM_EXEC_TLIST, outerPlan, Memoize::param_exprs, pfree(), plan, PlanRowMark::prti, root, ROWID_VAR, PlanRowMark::rti, WindowAgg::runCondition, WindowAgg::runConditionOrig, set_append_references(), set_customscan_references(), set_dummy_tlist_references(), set_foreignscan_references(), set_hash_references(), set_indexonlyscan_references(), set_join_references(), set_mergeappend_references(), set_param_references(), set_returning_clause_references(), set_subqueryscan_references(), set_upper_references(), set_windowagg_runcondition_references(), splan, WindowAgg::startOffset, Plan::targetlist, and Var::varno.

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

3310 {
3311  indexed_tlist *itlist;
3312 
3313  /*
3314  * We can perform the desired Var fixup by abusing the fix_join_expr
3315  * machinery that formerly handled inner indexscan fixup. We search the
3316  * top plan's targetlist for Vars of non-result relations, and use
3317  * fix_join_expr to convert RETURNING Vars into references to those tlist
3318  * entries, while leaving result-rel Vars as-is.
3319  *
3320  * PlaceHolderVars will also be sought in the targetlist, but no
3321  * more-complex expressions will be. Note that it is not possible for a
3322  * PlaceHolderVar to refer to the result relation, since the result is
3323  * never below an outer join. If that case could happen, we'd have to be
3324  * prepared to pick apart the PlaceHolderVar and evaluate its contained
3325  * expression instead.
3326  */
3327  itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
3328 
3329  rlist = fix_join_expr(root,
3330  rlist,
3331  itlist,
3332  NULL,
3333  resultRelation,
3334  rtoffset,
3335  NRM_EQUAL,
3336  NUM_EXEC_TLIST(topplan));
3337 
3338  pfree(itlist);
3339 
3340  return rlist;
3341 }
static indexed_tlist * build_tlist_index_other_vars(List *tlist, int ignore_rel)
Definition: setrefs.c:2727

References build_tlist_index_other_vars(), fix_join_expr(), NRM_EQUAL, NUM_EXEC_TLIST, pfree(), root, 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 1395 of file setrefs.c.

1398 {
1399  RelOptInfo *rel;
1400  Plan *result;
1401 
1402  /* Need to look up the subquery's RelOptInfo, since we need its subroot */
1403  rel = find_base_rel(root, plan->scan.scanrelid);
1404 
1405  /* Recursively process the subplan */
1406  plan->subplan = set_plan_references(rel->subroot, plan->subplan);
1407 
1409  {
1410  /*
1411  * We can omit the SubqueryScan node and just pull up the subplan.
1412  */
1413  result = clean_up_removed_plan_level((Plan *) plan, plan->subplan);
1414  }
1415  else
1416  {
1417  /*
1418  * Keep the SubqueryScan node. We have to do the processing that
1419  * set_plan_references would otherwise have done on it. Notice we do
1420  * not do set_upper_references() here, because a SubqueryScan will
1421  * always have been created with correct references to its subplan's
1422  * outputs to begin with.
1423  */
1424  plan->scan.scanrelid += rtoffset;
1425  plan->scan.plan.targetlist =
1426  fix_scan_list(root, plan->scan.plan.targetlist,
1427  rtoffset, NUM_EXEC_TLIST((Plan *) plan));
1428  plan->scan.plan.qual =
1429  fix_scan_list(root, plan->scan.plan.qual,
1430  rtoffset, NUM_EXEC_QUAL((Plan *) plan));
1431 
1432  result = (Plan *) plan;
1433  }
1434 
1435  return result;
1436 }
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:414
bool trivial_subqueryscan(SubqueryScan *plan)
Definition: setrefs.c:1464
Plan * set_plan_references(PlannerInfo *root, Plan *plan)
Definition: setrefs.c:287

References clean_up_removed_plan_level(), find_base_rel(), fix_scan_list, NUM_EXEC_QUAL, NUM_EXEC_TLIST, plan, root, set_plan_references(), RelOptInfo::subroot, and trivial_subqueryscan().

Referenced by set_plan_refs().

◆ set_upper_references()

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

Definition at line 2419 of file setrefs.c.

2420 {
2421  Plan *subplan = plan->lefttree;
2422  indexed_tlist *subplan_itlist;
2423  List *output_targetlist;
2424  ListCell *l;
2425 
2426  subplan_itlist = build_tlist_index(subplan->targetlist);
2427 
2428  output_targetlist = NIL;
2429  foreach(l, plan->targetlist)
2430  {
2431  TargetEntry *tle = (TargetEntry *) lfirst(l);
2432  Node *newexpr;
2433 
2434  /* If it's a sort/group item, first try to match by sortref */
2435  if (tle->ressortgroupref != 0)
2436  {
2437  newexpr = (Node *)
2439  tle->ressortgroupref,
2440  subplan_itlist,
2441  OUTER_VAR);
2442  if (!newexpr)
2443  newexpr = fix_upper_expr(root,
2444  (Node *) tle->expr,
2445  subplan_itlist,
2446  OUTER_VAR,
2447  rtoffset,
2448  NRM_EQUAL,
2449  NUM_EXEC_TLIST(plan));
2450  }
2451  else
2452  newexpr = fix_upper_expr(root,
2453  (Node *) tle->expr,
2454  subplan_itlist,
2455  OUTER_VAR,
2456  rtoffset,
2457  NRM_EQUAL,
2458  NUM_EXEC_TLIST(plan));
2459  tle = flatCopyTargetEntry(tle);
2460  tle->expr = (Expr *) newexpr;
2461  output_targetlist = lappend(output_targetlist, tle);
2462  }
2463  plan->targetlist = output_targetlist;
2464 
2465  plan->qual = (List *)
2467  (Node *) plan->qual,
2468  subplan_itlist,
2469  OUTER_VAR,
2470  rtoffset,
2471  NRM_EQUAL,
2472  NUM_EXEC_QUAL(plan));
2473 
2474  pfree(subplan_itlist);
2475 }
static Var * search_indexed_tlist_for_sortgroupref(Expr *node, Index sortgroupref, indexed_tlist *itlist, int newvarno)
Definition: setrefs.c:2943

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

Referenced by set_plan_refs().

◆ set_windowagg_runcondition_references()

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

Definition at line 3400 of file setrefs.c.

3403 {
3404  List *newlist;
3405  indexed_tlist *itlist;
3406 
3407  itlist = build_tlist_index(plan->targetlist);
3408 
3409  newlist = fix_windowagg_condition_expr(root, runcondition, itlist);
3410 
3411  pfree(itlist);
3412 
3413  return newlist;
3414 }
static List * fix_windowagg_condition_expr(PlannerInfo *root, List *runcondition, indexed_tlist *subplan_itlist)
Definition: setrefs.c:3379

References build_tlist_index(), fix_windowagg_condition_expr(), pfree(), plan, and root.

Referenced by set_plan_refs().

◆ trivial_subqueryscan()

bool trivial_subqueryscan ( SubqueryScan plan)

Definition at line 1464 of file setrefs.c.

1465 {
1466  int attrno;
1467  ListCell *lp,
1468  *lc;
1469 
1470  /* We might have detected this already; in which case reuse the result */
1471  if (plan->scanstatus == SUBQUERY_SCAN_TRIVIAL)
1472  return true;
1473  if (plan->scanstatus == SUBQUERY_SCAN_NONTRIVIAL)
1474  return false;
1475  Assert(plan->scanstatus == SUBQUERY_SCAN_UNKNOWN);
1476  /* Initially, mark the SubqueryScan as non-deletable from the plan tree */
1477  plan->scanstatus = SUBQUERY_SCAN_NONTRIVIAL;
1478 
1479  if (plan->scan.plan.qual != NIL)
1480  return false;
1481 
1482  if (list_length(plan->scan.plan.targetlist) !=
1483  list_length(plan->subplan->targetlist))
1484  return false; /* tlists not same length */
1485 
1486  attrno = 1;
1487  forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
1488  {
1489  TargetEntry *ptle = (TargetEntry *) lfirst(lp);
1490  TargetEntry *ctle = (TargetEntry *) lfirst(lc);
1491 
1492  if (ptle->resjunk != ctle->resjunk)
1493  return false; /* tlist doesn't match junk status */
1494 
1495  /*
1496  * We accept either a Var referencing the corresponding element of the
1497  * subplan tlist, or a Const equaling the subplan element. See
1498  * generate_setop_tlist() for motivation.
1499  */
1500  if (ptle->expr && IsA(ptle->expr, Var))
1501  {
1502  Var *var = (Var *) ptle->expr;
1503 
1504  Assert(var->varno == plan->scan.scanrelid);
1505  Assert(var->varlevelsup == 0);
1506  if (var->varattno != attrno)
1507  return false; /* out of order */
1508  }
1509  else if (ptle->expr && IsA(ptle->expr, Const))
1510  {
1511  if (!equal(ptle->expr, ctle->expr))
1512  return false;
1513  }
1514  else
1515  return false;
1516 
1517  attrno++;
1518  }
1519 
1520  /* Re-mark the SubqueryScan as deletable from the plan tree */
1521  plan->scanstatus = SUBQUERY_SCAN_TRIVIAL;
1522 
1523  return true;
1524 }
@ SUBQUERY_SCAN_NONTRIVIAL
Definition: plannodes.h:595
@ SUBQUERY_SCAN_UNKNOWN
Definition: plannodes.h:593
@ SUBQUERY_SCAN_TRIVIAL
Definition: plannodes.h:594

References Assert, equal(), TargetEntry::expr, forboth, IsA, lfirst, list_length(), NIL, plan, SUBQUERY_SCAN_NONTRIVIAL, SUBQUERY_SCAN_TRIVIAL, SUBQUERY_SCAN_UNKNOWN, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by mark_async_capable_plan(), and set_subqueryscan_references().