PostgreSQL Source Code  git master
prep.h File Reference
#include "nodes/pathnodes.h"
#include "nodes/plannodes.h"
Include dependency graph for prep.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void transform_MERGE_to_join (Query *parse)
 
void replace_empty_jointree (Query *parse)
 
void pull_up_sublinks (PlannerInfo *root)
 
void preprocess_function_rtes (PlannerInfo *root)
 
void pull_up_subqueries (PlannerInfo *root)
 
void flatten_simple_union_all (PlannerInfo *root)
 
void reduce_outer_joins (PlannerInfo *root)
 
void remove_useless_result_rtes (PlannerInfo *root)
 
Relids get_relids_in_jointree (Node *jtnode, bool include_outer_joins, bool include_inner_joins)
 
Relids get_relids_for_join (Query *query, int joinrelid)
 
void preprocess_targetlist (PlannerInfo *root)
 
Listextract_update_targetlist_colnos (List *tlist)
 
PlanRowMarkget_plan_rowmark (List *rowmarks, Index rtindex)
 
void get_agg_clause_costs (PlannerInfo *root, AggSplit aggsplit, AggClauseCosts *costs)
 
void preprocess_aggrefs (PlannerInfo *root, Node *clause)
 
RelOptInfoplan_set_operations (PlannerInfo *root)
 
bool set_operation_ordered_results_useful (SetOperationStmt *setop)
 

Function Documentation

◆ extract_update_targetlist_colnos()

List* extract_update_targetlist_colnos ( List tlist)

Definition at line 345 of file preptlist.c.

346 {
347  List *update_colnos = NIL;
348  AttrNumber nextresno = 1;
349  ListCell *lc;
350 
351  foreach(lc, tlist)
352  {
353  TargetEntry *tle = (TargetEntry *) lfirst(lc);
354 
355  if (!tle->resjunk)
356  update_colnos = lappend_int(update_colnos, tle->resno);
357  tle->resno = nextresno++;
358  }
359  return update_colnos;
360 }
int16 AttrNumber
Definition: attnum.h:21
List * lappend_int(List *list, int datum)
Definition: list.c:357
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
Definition: pg_list.h:54
AttrNumber resno
Definition: primnodes.h:2164

References lappend_int(), lfirst, NIL, and TargetEntry::resno.

Referenced by make_modifytable(), and preprocess_targetlist().

◆ flatten_simple_union_all()

void flatten_simple_union_all ( PlannerInfo root)

Definition at line 2594 of file prepjointree.c.

2595 {
2596  Query *parse = root->parse;
2597  SetOperationStmt *topop;
2598  Node *leftmostjtnode;
2599  int leftmostRTI;
2600  RangeTblEntry *leftmostRTE;
2601  int childRTI;
2602  RangeTblEntry *childRTE;
2603  RangeTblRef *rtr;
2604 
2605  /* Shouldn't be called unless query has setops */
2606  topop = castNode(SetOperationStmt, parse->setOperations);
2607  Assert(topop);
2608 
2609  /* Can't optimize away a recursive UNION */
2610  if (root->hasRecursion)
2611  return;
2612 
2613  /*
2614  * Recursively check the tree of set operations. If not all UNION ALL
2615  * with identical column types, punt.
2616  */
2617  if (!is_simple_union_all_recurse((Node *) topop, parse, topop->colTypes))
2618  return;
2619 
2620  /*
2621  * Locate the leftmost leaf query in the setops tree. The upper query's
2622  * Vars all refer to this RTE (see transformSetOperationStmt).
2623  */
2624  leftmostjtnode = topop->larg;
2625  while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt))
2626  leftmostjtnode = ((SetOperationStmt *) leftmostjtnode)->larg;
2627  Assert(leftmostjtnode && IsA(leftmostjtnode, RangeTblRef));
2628  leftmostRTI = ((RangeTblRef *) leftmostjtnode)->rtindex;
2629  leftmostRTE = rt_fetch(leftmostRTI, parse->rtable);
2630  Assert(leftmostRTE->rtekind == RTE_SUBQUERY);
2631 
2632  /*
2633  * Make a copy of the leftmost RTE and add it to the rtable. This copy
2634  * will represent the leftmost leaf query in its capacity as a member of
2635  * the appendrel. The original will represent the appendrel as a whole.
2636  * (We must do things this way because the upper query's Vars have to be
2637  * seen as referring to the whole appendrel.)
2638  */
2639  childRTE = copyObject(leftmostRTE);
2640  parse->rtable = lappend(parse->rtable, childRTE);
2641  childRTI = list_length(parse->rtable);
2642 
2643  /* Modify the setops tree to reference the child copy */
2644  ((RangeTblRef *) leftmostjtnode)->rtindex = childRTI;
2645 
2646  /* Modify the formerly-leftmost RTE to mark it as an appendrel parent */
2647  leftmostRTE->inh = true;
2648 
2649  /*
2650  * Form a RangeTblRef for the appendrel, and insert it into FROM. The top
2651  * Query of a setops tree should have had an empty FromClause initially.
2652  */
2653  rtr = makeNode(RangeTblRef);
2654  rtr->rtindex = leftmostRTI;
2655  Assert(parse->jointree->fromlist == NIL);
2656  parse->jointree->fromlist = list_make1(rtr);
2657 
2658  /*
2659  * Now pretend the query has no setops. We must do this before trying to
2660  * do subquery pullup, because of Assert in pull_up_simple_subquery.
2661  */
2662  parse->setOperations = NULL;
2663 
2664  /*
2665  * Build AppendRelInfo information, and apply pull_up_subqueries to the
2666  * leaf queries of the UNION ALL. (We must do that now because they
2667  * weren't previously referenced by the jointree, and so were missed by
2668  * the main invocation of pull_up_subqueries.)
2669  */
2670  pull_up_union_leaf_queries((Node *) topop, root, leftmostRTI, parse, 0);
2671 }
#define Assert(condition)
Definition: c.h:858
List * lappend(List *list, void *datum)
Definition: list.c:339
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define copyObject(obj)
Definition: nodes.h:224
#define makeNode(_type_)
Definition: nodes.h:155
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
@ RTE_SUBQUERY
Definition: parsenodes.h:1029
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
static int list_length(const List *l)
Definition: pg_list.h:152
#define list_make1(x1)
Definition: pg_list.h:212
static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex, Query *setOpQuery, int childRToffset)
static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
tree ctl root
Definition: radixtree.h:1884
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:715
Definition: nodes.h:129
RTEKind rtekind
Definition: parsenodes.h:1057

References Assert, castNode, copyObject, RangeTblEntry::inh, is_simple_union_all_recurse(), IsA, lappend(), SetOperationStmt::larg, list_length(), list_make1, makeNode, NIL, parse(), pull_up_union_leaf_queries(), root, rt_fetch, RTE_SUBQUERY, RangeTblEntry::rtekind, and RangeTblRef::rtindex.

Referenced by subquery_planner().

◆ get_agg_clause_costs()

void get_agg_clause_costs ( PlannerInfo root,
AggSplit  aggsplit,
AggClauseCosts costs 
)

Definition at line 560 of file prepagg.c.

561 {
562  ListCell *lc;
563 
564  foreach(lc, root->aggtransinfos)
565  {
566  AggTransInfo *transinfo = lfirst_node(AggTransInfo, lc);
567 
568  /*
569  * Add the appropriate component function execution costs to
570  * appropriate totals.
571  */
572  if (DO_AGGSPLIT_COMBINE(aggsplit))
573  {
574  /* charge for combining previously aggregated states */
575  add_function_cost(root, transinfo->combinefn_oid, NULL,
576  &costs->transCost);
577  }
578  else
579  add_function_cost(root, transinfo->transfn_oid, NULL,
580  &costs->transCost);
581  if (DO_AGGSPLIT_DESERIALIZE(aggsplit) &&
582  OidIsValid(transinfo->deserialfn_oid))
583  add_function_cost(root, transinfo->deserialfn_oid, NULL,
584  &costs->transCost);
585  if (DO_AGGSPLIT_SERIALIZE(aggsplit) &&
586  OidIsValid(transinfo->serialfn_oid))
587  add_function_cost(root, transinfo->serialfn_oid, NULL,
588  &costs->finalCost);
589 
590  /*
591  * These costs are incurred only by the initial aggregate node, so we
592  * mustn't include them again at upper levels.
593  */
594  if (!DO_AGGSPLIT_COMBINE(aggsplit))
595  {
596  /* add the input expressions' cost to per-input-row costs */
597  QualCost argcosts;
598 
599  cost_qual_eval_node(&argcosts, (Node *) transinfo->args, root);
600  costs->transCost.startup += argcosts.startup;
601  costs->transCost.per_tuple += argcosts.per_tuple;
602 
603  /*
604  * Add any filter's cost to per-input-row costs.
605  *
606  * XXX Ideally we should reduce input expression costs according
607  * to filter selectivity, but it's not clear it's worth the
608  * trouble.
609  */
610  if (transinfo->aggfilter)
611  {
612  cost_qual_eval_node(&argcosts, (Node *) transinfo->aggfilter,
613  root);
614  costs->transCost.startup += argcosts.startup;
615  costs->transCost.per_tuple += argcosts.per_tuple;
616  }
617  }
618 
619  /*
620  * If the transition type is pass-by-value then it doesn't add
621  * anything to the required size of the hashtable. If it is
622  * pass-by-reference then we have to add the estimated size of the
623  * value itself, plus palloc overhead.
624  */
625  if (!transinfo->transtypeByVal)
626  {
627  int32 avgwidth;
628 
629  /* Use average width if aggregate definition gave one */
630  if (transinfo->aggtransspace > 0)
631  avgwidth = transinfo->aggtransspace;
632  else if (transinfo->transfn_oid == F_ARRAY_APPEND)
633  {
634  /*
635  * If the transition function is array_append(), it'll use an
636  * expanded array as transvalue, which will occupy at least
637  * ALLOCSET_SMALL_INITSIZE and possibly more. Use that as the
638  * estimate for lack of a better idea.
639  */
640  avgwidth = ALLOCSET_SMALL_INITSIZE;
641  }
642  else
643  {
644  avgwidth = get_typavgwidth(transinfo->aggtranstype, transinfo->aggtranstypmod);
645  }
646 
647  avgwidth = MAXALIGN(avgwidth);
648  costs->transitionSpace += avgwidth + 2 * sizeof(void *);
649  }
650  else if (transinfo->aggtranstype == INTERNALOID)
651  {
652  /*
653  * INTERNAL transition type is a special case: although INTERNAL
654  * is pass-by-value, it's almost certainly being used as a pointer
655  * to some large data structure. The aggregate definition can
656  * provide an estimate of the size. If it doesn't, then we assume
657  * ALLOCSET_DEFAULT_INITSIZE, which is a good guess if the data is
658  * being kept in a private memory context, as is done by
659  * array_agg() for instance.
660  */
661  if (transinfo->aggtransspace > 0)
662  costs->transitionSpace += transinfo->aggtransspace;
663  else
665  }
666  }
667 
668  foreach(lc, root->agginfos)
669  {
670  AggInfo *agginfo = lfirst_node(AggInfo, lc);
671  Aggref *aggref = linitial_node(Aggref, agginfo->aggrefs);
672 
673  /*
674  * Add the appropriate component function execution costs to
675  * appropriate totals.
676  */
677  if (!DO_AGGSPLIT_SKIPFINAL(aggsplit) &&
678  OidIsValid(agginfo->finalfn_oid))
679  add_function_cost(root, agginfo->finalfn_oid, NULL,
680  &costs->finalCost);
681 
682  /*
683  * If there are direct arguments, treat their evaluation cost like the
684  * cost of the finalfn.
685  */
686  if (aggref->aggdirectargs)
687  {
688  QualCost argcosts;
689 
690  cost_qual_eval_node(&argcosts, (Node *) aggref->aggdirectargs,
691  root);
692  costs->finalCost.startup += argcosts.startup;
693  costs->finalCost.per_tuple += argcosts.per_tuple;
694  }
695  }
696 }
#define MAXALIGN(LEN)
Definition: c.h:811
signed int int32
Definition: c.h:494
#define OidIsValid(objectId)
Definition: c.h:775
void cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root)
Definition: costsize.c:4666
int32 get_typavgwidth(Oid typid, int32 typmod)
Definition: lsyscache.c:2578
#define ALLOCSET_SMALL_INITSIZE
Definition: memutils.h:168
#define ALLOCSET_DEFAULT_INITSIZE
Definition: memutils.h:158
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:385
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition: nodes.h:387
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:384
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:386
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define linitial_node(type, l)
Definition: pg_list.h:181
void add_function_cost(PlannerInfo *root, Oid funcid, Node *node, QualCost *cost)
Definition: plancat.c:2072
QualCost finalCost
Definition: pathnodes.h:61
Size transitionSpace
Definition: pathnodes.h:62
QualCost transCost
Definition: pathnodes.h:60
List * aggrefs
Definition: pathnodes.h:3363
Oid finalfn_oid
Definition: pathnodes.h:3375
List * args
Definition: pathnodes.h:3392
int32 aggtransspace
Definition: pathnodes.h:3416
bool transtypeByVal
Definition: pathnodes.h:3413
Oid combinefn_oid
Definition: pathnodes.h:3405
Oid deserialfn_oid
Definition: pathnodes.h:3402
int32 aggtranstypmod
Definition: pathnodes.h:3411
Oid serialfn_oid
Definition: pathnodes.h:3399
Oid aggtranstype
Definition: pathnodes.h:3408
Expr * aggfilter
Definition: pathnodes.h:3393
List * aggdirectargs
Definition: primnodes.h:465
Cost per_tuple
Definition: pathnodes.h:48
Cost startup
Definition: pathnodes.h:47

References add_function_cost(), Aggref::aggdirectargs, AggTransInfo::aggfilter, AggInfo::aggrefs, AggTransInfo::aggtransspace, AggTransInfo::aggtranstype, AggTransInfo::aggtranstypmod, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_SMALL_INITSIZE, AggTransInfo::args, AggTransInfo::combinefn_oid, cost_qual_eval_node(), AggTransInfo::deserialfn_oid, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_DESERIALIZE, DO_AGGSPLIT_SERIALIZE, DO_AGGSPLIT_SKIPFINAL, AggClauseCosts::finalCost, AggInfo::finalfn_oid, get_typavgwidth(), lfirst_node, linitial_node, MAXALIGN, OidIsValid, QualCost::per_tuple, root, AggTransInfo::serialfn_oid, QualCost::startup, AggClauseCosts::transCost, AggTransInfo::transfn_oid, AggClauseCosts::transitionSpace, and AggTransInfo::transtypeByVal.

Referenced by create_grouping_paths(), create_partial_grouping_paths(), and estimate_path_cost_size().

◆ get_plan_rowmark()

PlanRowMark* get_plan_rowmark ( List rowmarks,
Index  rtindex 
)

Definition at line 509 of file preptlist.c.

510 {
511  ListCell *l;
512 
513  foreach(l, rowmarks)
514  {
515  PlanRowMark *rc = (PlanRowMark *) lfirst(l);
516 
517  if (rc->rti == rtindex)
518  return rc;
519  }
520  return NULL;
521 }

References lfirst, and PlanRowMark::rti.

Referenced by check_index_predicates(), deparseLockingClause(), and expand_inherited_rtentry().

◆ get_relids_for_join()

Relids get_relids_for_join ( Query query,
int  joinrelid 
)

Definition at line 3922 of file prepjointree.c.

3923 {
3924  Node *jtnode;
3925 
3926  jtnode = find_jointree_node_for_rel((Node *) query->jointree,
3927  joinrelid);
3928  if (!jtnode)
3929  elog(ERROR, "could not find join node %d", joinrelid);
3930  return get_relids_in_jointree(jtnode, true, false);
3931 }
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
static Node * find_jointree_node_for_rel(Node *jtnode, int relid)
Relids get_relids_in_jointree(Node *jtnode, bool include_outer_joins, bool include_inner_joins)
FromExpr * jointree
Definition: parsenodes.h:175

References elog, ERROR, find_jointree_node_for_rel(), get_relids_in_jointree(), and Query::jointree.

Referenced by add_nullingrels_if_needed(), and alias_relid_set().

◆ get_relids_in_jointree()

Relids get_relids_in_jointree ( Node jtnode,
bool  include_outer_joins,
bool  include_inner_joins 
)

Definition at line 3861 of file prepjointree.c.

3863 {
3864  Relids result = NULL;
3865 
3866  if (jtnode == NULL)
3867  return result;
3868  if (IsA(jtnode, RangeTblRef))
3869  {
3870  int varno = ((RangeTblRef *) jtnode)->rtindex;
3871 
3872  result = bms_make_singleton(varno);
3873  }
3874  else if (IsA(jtnode, FromExpr))
3875  {
3876  FromExpr *f = (FromExpr *) jtnode;
3877  ListCell *l;
3878 
3879  foreach(l, f->fromlist)
3880  {
3881  result = bms_join(result,
3883  include_outer_joins,
3884  include_inner_joins));
3885  }
3886  }
3887  else if (IsA(jtnode, JoinExpr))
3888  {
3889  JoinExpr *j = (JoinExpr *) jtnode;
3890 
3891  result = get_relids_in_jointree(j->larg,
3892  include_outer_joins,
3893  include_inner_joins);
3894  result = bms_join(result,
3895  get_relids_in_jointree(j->rarg,
3896  include_outer_joins,
3897  include_inner_joins));
3898  if (j->rtindex)
3899  {
3900  if (j->jointype == JOIN_INNER)
3901  {
3902  if (include_inner_joins)
3903  result = bms_add_member(result, j->rtindex);
3904  }
3905  else
3906  {
3907  if (include_outer_joins)
3908  result = bms_add_member(result, j->rtindex);
3909  }
3910  }
3911  }
3912  else
3913  elog(ERROR, "unrecognized node type: %d",
3914  (int) nodeTag(jtnode));
3915  return result;
3916 }
Bitmapset * bms_join(Bitmapset *a, Bitmapset *b)
Definition: bitmapset.c:1230
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:216
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
int j
Definition: isn.c:74
#define nodeTag(nodeptr)
Definition: nodes.h:133
@ JOIN_INNER
Definition: nodes.h:293
List * fromlist
Definition: primnodes.h:2280

References bms_add_member(), bms_join(), bms_make_singleton(), elog, ERROR, FromExpr::fromlist, IsA, j, JOIN_INNER, lfirst, and nodeTag.

Referenced by find_dependent_phvs_in_jointree(), get_relids_for_join(), is_simple_subquery(), preprocess_rowmarks(), pull_up_simple_subquery(), and remove_result_refs().

◆ plan_set_operations()

RelOptInfo* plan_set_operations ( PlannerInfo root)

Definition at line 99 of file prepunion.c.

100 {
101  Query *parse = root->parse;
102  SetOperationStmt *topop = castNode(SetOperationStmt, parse->setOperations);
103  Node *node;
104  RangeTblEntry *leftmostRTE;
105  Query *leftmostQuery;
106  RelOptInfo *setop_rel;
107  List *top_tlist;
108 
109  Assert(topop);
110 
111  /* check for unsupported stuff */
112  Assert(parse->jointree->fromlist == NIL);
113  Assert(parse->jointree->quals == NULL);
114  Assert(parse->groupClause == NIL);
115  Assert(parse->havingQual == NULL);
116  Assert(parse->windowClause == NIL);
117  Assert(parse->distinctClause == NIL);
118 
119  /*
120  * In the outer query level, equivalence classes are limited to classes
121  * which define that the top-level target entry is equivalent to the
122  * corresponding child target entry. There won't be any equivalence class
123  * merging. Mark that merging is complete to allow us to make pathkeys.
124  */
125  Assert(root->eq_classes == NIL);
126  root->ec_merging_done = true;
127 
128  /*
129  * We'll need to build RelOptInfos for each of the leaf subqueries, which
130  * are RTE_SUBQUERY rangetable entries in this Query. Prepare the index
131  * arrays for those, and for AppendRelInfos in case they're needed.
132  */
134 
135  /*
136  * Find the leftmost component Query. We need to use its column names for
137  * all generated tlists (else SELECT INTO won't work right).
138  */
139  node = topop->larg;
140  while (node && IsA(node, SetOperationStmt))
141  node = ((SetOperationStmt *) node)->larg;
142  Assert(node && IsA(node, RangeTblRef));
143  leftmostRTE = root->simple_rte_array[((RangeTblRef *) node)->rtindex];
144  leftmostQuery = leftmostRTE->subquery;
145  Assert(leftmostQuery != NULL);
146 
147  /*
148  * If the topmost node is a recursive union, it needs special processing.
149  */
150  if (root->hasRecursion)
151  {
152  setop_rel = generate_recursion_path(topop, root,
153  leftmostQuery->targetList,
154  &top_tlist);
155  }
156  else
157  {
158  bool trivial_tlist;
159 
160  /*
161  * Recurse on setOperations tree to generate paths for set ops. The
162  * final output paths should have just the column types shown as the
163  * output from the top-level node, plus possibly resjunk working
164  * columns (we can rely on upper-level nodes to deal with that).
165  */
166  setop_rel = recurse_set_operations((Node *) topop, root,
167  topop->colTypes, topop->colCollations,
168  true, -1,
169  leftmostQuery->targetList,
170  &top_tlist,
171  &trivial_tlist);
172  }
173 
174  /* Must return the built tlist into root->processed_tlist. */
175  root->processed_tlist = top_tlist;
176 
177  return setop_rel;
178 }
static RelOptInfo * recurse_set_operations(Node *setOp, PlannerInfo *root, List *colTypes, List *colCollations, bool junkOK, int flag, List *refnames_tlist, List **pTargetList, bool *istrivial_tlist)
Definition: prepunion.c:230
static RelOptInfo * generate_recursion_path(SetOperationStmt *setOp, PlannerInfo *root, List *refnames_tlist, List **pTargetList)
Definition: prepunion.c:384
void setup_simple_rel_arrays(PlannerInfo *root)
Definition: relnode.c:94
List * targetList
Definition: parsenodes.h:191
Query * subquery
Definition: parsenodes.h:1114

References Assert, castNode, generate_recursion_path(), IsA, SetOperationStmt::larg, NIL, parse(), recurse_set_operations(), root, setup_simple_rel_arrays(), RangeTblEntry::subquery, and Query::targetList.

Referenced by grouping_planner().

◆ preprocess_aggrefs()

void preprocess_aggrefs ( PlannerInfo root,
Node clause 
)

Definition at line 110 of file prepagg.c.

111 {
112  (void) preprocess_aggrefs_walker(clause, root);
113 }
static bool preprocess_aggrefs_walker(Node *node, PlannerInfo *root)
Definition: prepagg.c:344

References preprocess_aggrefs_walker(), and root.

Referenced by grouping_planner().

◆ preprocess_function_rtes()

void preprocess_function_rtes ( PlannerInfo root)

Definition at line 776 of file prepjointree.c.

777 {
778  ListCell *rt;
779 
780  foreach(rt, root->parse->rtable)
781  {
782  RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
783 
784  if (rte->rtekind == RTE_FUNCTION)
785  {
786  Query *funcquery;
787 
788  /* Apply const-simplification */
789  rte->functions = (List *)
791 
792  /* Check safety of expansion, and expand if possible */
793  funcquery = inline_set_returning_function(root, rte);
794  if (funcquery)
795  {
796  /* Successful expansion, convert the RTE to a subquery */
797  rte->rtekind = RTE_SUBQUERY;
798  rte->subquery = funcquery;
799  rte->security_barrier = false;
800  /* Clear fields that should not be set in a subquery RTE */
801  rte->functions = NIL;
802  rte->funcordinality = false;
803  }
804  }
805  }
806 }
Query * inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
Definition: clauses.c:5052
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2254
@ RTE_FUNCTION
Definition: parsenodes.h:1031
bool funcordinality
Definition: parsenodes.h:1189
List * functions
Definition: parsenodes.h:1187

References eval_const_expressions(), RangeTblEntry::funcordinality, RangeTblEntry::functions, inline_set_returning_function(), lfirst, NIL, root, RTE_FUNCTION, RTE_SUBQUERY, RangeTblEntry::rtekind, and RangeTblEntry::subquery.

Referenced by pull_up_simple_subquery(), and subquery_planner().

◆ preprocess_targetlist()

void preprocess_targetlist ( PlannerInfo root)

Definition at line 62 of file preptlist.c.

63 {
64  Query *parse = root->parse;
65  int result_relation = parse->resultRelation;
66  List *range_table = parse->rtable;
67  CmdType command_type = parse->commandType;
68  RangeTblEntry *target_rte = NULL;
69  Relation target_relation = NULL;
70  List *tlist;
71  ListCell *lc;
72 
73  /*
74  * If there is a result relation, open it so we can look for missing
75  * columns and so on. We assume that previous code already acquired at
76  * least AccessShareLock on the relation, so we need no lock here.
77  */
78  if (result_relation)
79  {
80  target_rte = rt_fetch(result_relation, range_table);
81 
82  /*
83  * Sanity check: it'd better be a real relation not, say, a subquery.
84  * Else parser or rewriter messed up.
85  */
86  if (target_rte->rtekind != RTE_RELATION)
87  elog(ERROR, "result relation must be a regular relation");
88 
89  target_relation = table_open(target_rte->relid, NoLock);
90  }
91  else
92  Assert(command_type == CMD_SELECT);
93 
94  /*
95  * In an INSERT, the executor expects the targetlist to match the exact
96  * order of the target table's attributes, including entries for
97  * attributes not mentioned in the source query.
98  *
99  * In an UPDATE, we don't rearrange the tlist order, but we need to make a
100  * separate list of the target attribute numbers, in tlist order, and then
101  * renumber the processed_tlist entries to be consecutive.
102  */
103  tlist = parse->targetList;
104  if (command_type == CMD_INSERT)
105  tlist = expand_insert_targetlist(tlist, target_relation);
106  else if (command_type == CMD_UPDATE)
107  root->update_colnos = extract_update_targetlist_colnos(tlist);
108 
109  /*
110  * For non-inherited UPDATE/DELETE/MERGE, register any junk column(s)
111  * needed to allow the executor to identify the rows to be updated or
112  * deleted. In the inheritance case, we do nothing now, leaving this to
113  * be dealt with when expand_inherited_rtentry() makes the leaf target
114  * relations. (But there might not be any leaf target relations, in which
115  * case we must do this in distribute_row_identity_vars().)
116  */
117  if ((command_type == CMD_UPDATE || command_type == CMD_DELETE ||
118  command_type == CMD_MERGE) &&
119  !target_rte->inh)
120  {
121  /* row-identity logic expects to add stuff to processed_tlist */
122  root->processed_tlist = tlist;
123  add_row_identity_columns(root, result_relation,
124  target_rte, target_relation);
125  tlist = root->processed_tlist;
126  }
127 
128  /*
129  * For MERGE we also need to handle the target list for each INSERT and
130  * UPDATE action separately. In addition, we examine the qual of each
131  * action and add any Vars there (other than those of the target rel) to
132  * the subplan targetlist.
133  */
134  if (command_type == CMD_MERGE)
135  {
136  ListCell *l;
137  List *vars;
138 
139  /*
140  * For MERGE, handle targetlist of each MergeAction separately. Give
141  * the same treatment to MergeAction->targetList as we would have
142  * given to a regular INSERT. For UPDATE, collect the column numbers
143  * being modified.
144  */
145  foreach(l, parse->mergeActionList)
146  {
148  ListCell *l2;
149 
150  if (action->commandType == CMD_INSERT)
151  action->targetList = expand_insert_targetlist(action->targetList,
152  target_relation);
153  else if (action->commandType == CMD_UPDATE)
154  action->updateColnos =
156 
157  /*
158  * Add resjunk entries for any Vars and PlaceHolderVars used in
159  * each action's targetlist and WHEN condition that belong to
160  * relations other than the target. We don't expect to see any
161  * aggregates or window functions here.
162  */
164  list_concat_copy((List *) action->qual,
165  action->targetList),
167  foreach(l2, vars)
168  {
169  Var *var = (Var *) lfirst(l2);
170  TargetEntry *tle;
171 
172  if (IsA(var, Var) && var->varno == result_relation)
173  continue; /* don't need it */
174 
175  if (tlist_member((Expr *) var, tlist))
176  continue; /* already got it */
177 
178  tle = makeTargetEntry((Expr *) var,
179  list_length(tlist) + 1,
180  NULL, true);
181  tlist = lappend(tlist, tle);
182  }
183  list_free(vars);
184  }
185 
186  /*
187  * Add resjunk entries for any Vars and PlaceHolderVars used in the
188  * join condition that belong to relations other than the target. We
189  * don't expect to see any aggregates or window functions here.
190  */
191  vars = pull_var_clause(parse->mergeJoinCondition,
193  foreach(l, vars)
194  {
195  Var *var = (Var *) lfirst(l);
196  TargetEntry *tle;
197 
198  if (IsA(var, Var) && var->varno == result_relation)
199  continue; /* don't need it */
200 
201  if (tlist_member((Expr *) var, tlist))
202  continue; /* already got it */
203 
204  tle = makeTargetEntry((Expr *) var,
205  list_length(tlist) + 1,
206  NULL, true);
207  tlist = lappend(tlist, tle);
208  }
209  }
210 
211  /*
212  * Add necessary junk columns for rowmarked rels. These values are needed
213  * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
214  * rechecking. See comments for PlanRowMark in plannodes.h. If you
215  * change this stanza, see also expand_inherited_rtentry(), which has to
216  * be able to add on junk columns equivalent to these.
217  *
218  * (Someday it might be useful to fold these resjunk columns into the
219  * row-identity-column management used for UPDATE/DELETE. Today is not
220  * that day, however. One notable issue is that it seems important that
221  * the whole-row Vars made here use the real table rowtype, not RECORD, so
222  * that conversion to/from child relations' rowtypes will happen. Also,
223  * since these entries don't potentially bloat with more and more child
224  * relations, there's not really much need for column sharing.)
225  */
226  foreach(lc, root->rowMarks)
227  {
228  PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
229  Var *var;
230  char resname[32];
231  TargetEntry *tle;
232 
233  /* child rels use the same junk attrs as their parents */
234  if (rc->rti != rc->prti)
235  continue;
236 
237  if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
238  {
239  /* Need to fetch TID */
240  var = makeVar(rc->rti,
242  TIDOID,
243  -1,
244  InvalidOid,
245  0);
246  snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
247  tle = makeTargetEntry((Expr *) var,
248  list_length(tlist) + 1,
249  pstrdup(resname),
250  true);
251  tlist = lappend(tlist, tle);
252  }
253  if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
254  {
255  /* Need the whole row as a junk var */
256  var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
257  rc->rti,
258  0,
259  false);
260  snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
261  tle = makeTargetEntry((Expr *) var,
262  list_length(tlist) + 1,
263  pstrdup(resname),
264  true);
265  tlist = lappend(tlist, tle);
266  }
267 
268  /* If parent of inheritance tree, always fetch the tableoid too. */
269  if (rc->isParent)
270  {
271  var = makeVar(rc->rti,
273  OIDOID,
274  -1,
275  InvalidOid,
276  0);
277  snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
278  tle = makeTargetEntry((Expr *) var,
279  list_length(tlist) + 1,
280  pstrdup(resname),
281  true);
282  tlist = lappend(tlist, tle);
283  }
284  }
285 
286  /*
287  * If the query has a RETURNING list, add resjunk entries for any Vars
288  * used in RETURNING that belong to other relations. We need to do this
289  * to make these Vars available for the RETURNING calculation. Vars that
290  * belong to the result rel don't need to be added, because they will be
291  * made to refer to the actual heap tuple.
292  */
293  if (parse->returningList && list_length(parse->rtable) > 1)
294  {
295  List *vars;
296  ListCell *l;
297 
298  vars = pull_var_clause((Node *) parse->returningList,
302  foreach(l, vars)
303  {
304  Var *var = (Var *) lfirst(l);
305  TargetEntry *tle;
306 
307  if (IsA(var, Var) &&
308  var->varno == result_relation)
309  continue; /* don't need it */
310 
311  if (tlist_member((Expr *) var, tlist))
312  continue; /* already got it */
313 
314  tle = makeTargetEntry((Expr *) var,
315  list_length(tlist) + 1,
316  NULL,
317  true);
318 
319  tlist = lappend(tlist, tle);
320  }
321  list_free(vars);
322  }
323 
324  root->processed_tlist = tlist;
325 
326  if (target_relation)
327  table_close(target_relation, NoLock);
328 }
void add_row_identity_columns(PlannerInfo *root, Index rtindex, RangeTblEntry *target_rte, Relation target_relation)
Definition: appendinfo.c:884
void list_free(List *list)
Definition: list.c:1546
List * list_concat_copy(const List *list1, const List *list2)
Definition: list.c:598
#define NoLock
Definition: lockdefs.h:34
Var * makeWholeRowVar(RangeTblEntry *rte, int varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:135
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:240
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
char * pstrdup(const char *in)
Definition: mcxt.c:1695
CmdType
Definition: nodes.h:263
@ CMD_MERGE
Definition: nodes.h:269
@ CMD_INSERT
Definition: nodes.h:267
@ CMD_DELETE
Definition: nodes.h:268
@ CMD_UPDATE
Definition: nodes.h:266
@ CMD_SELECT
Definition: nodes.h:265
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:187
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:189
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:190
@ RTE_RELATION
Definition: parsenodes.h:1028
@ ROW_MARK_COPY
Definition: plannodes.h:1334
#define snprintf
Definition: port.h:238
#define InvalidOid
Definition: postgres_ext.h:36
static List * expand_insert_targetlist(List *tlist, Relation rel)
Definition: preptlist.c:379
List * extract_update_targetlist_colnos(List *tlist)
Definition: preptlist.c:345
Index prti
Definition: plannodes.h:1383
bool isParent
Definition: plannodes.h:1389
Index rowmarkId
Definition: plannodes.h:1384
int allMarkTypes
Definition: plannodes.h:1386
Definition: primnodes.h:248
int varno
Definition: primnodes.h:255
Definition: regcomp.c:281
#define TableOidAttributeNumber
Definition: sysattr.h:26
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:79
List * pull_var_clause(Node *node, int flags)
Definition: var.c:607

References generate_unaccent_rules::action, add_row_identity_columns(), PlanRowMark::allMarkTypes, Assert, CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_SELECT, CMD_UPDATE, elog, ERROR, expand_insert_targetlist(), extract_update_targetlist_colnos(), RangeTblEntry::inh, InvalidOid, IsA, PlanRowMark::isParent, lappend(), lfirst, list_concat_copy(), list_free(), list_length(), makeTargetEntry(), makeVar(), makeWholeRowVar(), NoLock, parse(), PlanRowMark::prti, pstrdup(), pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, RangeTblEntry::relid, root, ROW_MARK_COPY, PlanRowMark::rowmarkId, rt_fetch, RTE_RELATION, RangeTblEntry::rtekind, PlanRowMark::rti, SelfItemPointerAttributeNumber, snprintf, table_close(), table_open(), TableOidAttributeNumber, tlist_member(), and Var::varno.

Referenced by grouping_planner().

◆ pull_up_sublinks()

void pull_up_sublinks ( PlannerInfo root)

Definition at line 342 of file prepjointree.c.

343 {
344  Node *jtnode;
345  Relids relids;
346 
347  /* Begin recursion through the jointree */
349  (Node *) root->parse->jointree,
350  &relids);
351 
352  /*
353  * root->parse->jointree must always be a FromExpr, so insert a dummy one
354  * if we got a bare RangeTblRef or JoinExpr out of the recursion.
355  */
356  if (IsA(jtnode, FromExpr))
357  root->parse->jointree = (FromExpr *) jtnode;
358  else
359  root->parse->jointree = makeFromExpr(list_make1(jtnode), NULL);
360 }
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:287
static Node * pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode, Relids *relids)
Definition: prepjointree.c:369

References IsA, list_make1, makeFromExpr(), pull_up_sublinks_jointree_recurse(), and root.

Referenced by pull_up_simple_subquery(), and subquery_planner().

◆ pull_up_subqueries()

void pull_up_subqueries ( PlannerInfo root)

Definition at line 817 of file prepjointree.c.

818 {
819  /* Top level of jointree must always be a FromExpr */
820  Assert(IsA(root->parse->jointree, FromExpr));
821  /* Recursion starts with no containing join nor appendrel */
822  root->parse->jointree = (FromExpr *)
823  pull_up_subqueries_recurse(root, (Node *) root->parse->jointree,
824  NULL, NULL);
825  /* We should still have a FromExpr */
826  Assert(IsA(root->parse->jointree, FromExpr));
827 }
static Node * pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode, JoinExpr *lowest_outer_join, AppendRelInfo *containing_appendrel)
Definition: prepjointree.c:861

References Assert, IsA, pull_up_subqueries_recurse(), and root.

Referenced by pull_up_simple_subquery(), and subquery_planner().

◆ reduce_outer_joins()

void reduce_outer_joins ( PlannerInfo root)

Definition at line 2713 of file prepjointree.c.

2714 {
2717  ListCell *lc;
2718 
2719  /*
2720  * To avoid doing strictness checks on more quals than necessary, we want
2721  * to stop descending the jointree as soon as there are no outer joins
2722  * below our current point. This consideration forces a two-pass process.
2723  * The first pass gathers information about which base rels appear below
2724  * each side of each join clause, and about whether there are outer
2725  * join(s) below each side of each join clause. The second pass examines
2726  * qual clauses and changes join types as it descends the tree.
2727  */
2728  state1 = reduce_outer_joins_pass1((Node *) root->parse->jointree);
2729 
2730  /* planner.c shouldn't have called me if no outer joins */
2731  if (state1 == NULL || !state1->contains_outer)
2732  elog(ERROR, "so where are the outer joins?");
2733 
2734  state2.inner_reduced = NULL;
2735  state2.partial_reduced = NIL;
2736 
2737  reduce_outer_joins_pass2((Node *) root->parse->jointree,
2738  state1, &state2,
2739  root, NULL, NIL);
2740 
2741  /*
2742  * If we successfully reduced the strength of any outer joins, we must
2743  * remove references to those joins as nulling rels. This is handled as
2744  * an additional pass, for simplicity and because we can handle all
2745  * fully-reduced joins in a single pass over the parse tree.
2746  */
2747  if (!bms_is_empty(state2.inner_reduced))
2748  {
2749  root->parse = (Query *)
2750  remove_nulling_relids((Node *) root->parse,
2751  state2.inner_reduced,
2752  NULL);
2753  /* There could be references in the append_rel_list, too */
2754  root->append_rel_list = (List *)
2755  remove_nulling_relids((Node *) root->append_rel_list,
2756  state2.inner_reduced,
2757  NULL);
2758  }
2759 
2760  /*
2761  * Partially-reduced full joins have to be done one at a time, since
2762  * they'll each need a different setting of except_relids.
2763  */
2764  foreach(lc, state2.partial_reduced)
2765  {
2767  Relids full_join_relids = bms_make_singleton(statep->full_join_rti);
2768 
2769  root->parse = (Query *)
2770  remove_nulling_relids((Node *) root->parse,
2771  full_join_relids,
2772  statep->unreduced_side);
2773  root->append_rel_list = (List *)
2774  remove_nulling_relids((Node *) root->append_rel_list,
2775  full_join_relids,
2776  statep->unreduced_side);
2777  }
2778 }
#define bms_is_empty(a)
Definition: bitmapset.h:118
static void reduce_outer_joins_pass2(Node *jtnode, reduce_outer_joins_pass1_state *state1, reduce_outer_joins_pass2_state *state2, PlannerInfo *root, Relids nonnullable_rels, List *forced_null_vars)
static reduce_outer_joins_pass1_state * reduce_outer_joins_pass1(Node *jtnode)
Node * remove_nulling_relids(Node *node, const Bitmapset *removable_relids, const Bitmapset *except_relids)

References bms_is_empty, bms_make_singleton(), reduce_outer_joins_pass1_state::contains_outer, elog, ERROR, reduce_outer_joins_partial_state::full_join_rti, reduce_outer_joins_pass2_state::inner_reduced, lfirst, NIL, reduce_outer_joins_pass2_state::partial_reduced, reduce_outer_joins_pass1(), reduce_outer_joins_pass2(), remove_nulling_relids(), root, and reduce_outer_joins_partial_state::unreduced_side.

Referenced by subquery_planner().

◆ remove_useless_result_rtes()

void remove_useless_result_rtes ( PlannerInfo root)

Definition at line 3207 of file prepjointree.c.

3208 {
3209  Relids dropped_outer_joins = NULL;
3210  ListCell *cell;
3211 
3212  /* Top level of jointree must always be a FromExpr */
3213  Assert(IsA(root->parse->jointree, FromExpr));
3214  /* Recurse ... */
3215  root->parse->jointree = (FromExpr *)
3217  (Node *) root->parse->jointree,
3218  NULL,
3219  &dropped_outer_joins);
3220  /* We should still have a FromExpr */
3221  Assert(IsA(root->parse->jointree, FromExpr));
3222 
3223  /*
3224  * If we removed any outer-join nodes from the jointree, run around and
3225  * remove references to those joins as nulling rels. (There could be such
3226  * references in PHVs that we pulled up out of the original subquery that
3227  * the RESULT rel replaced. This is kosher on the grounds that we now
3228  * know that such an outer join wouldn't really have nulled anything.) We
3229  * don't do this during the main recursion, for simplicity and because we
3230  * can handle all such joins in a single pass over the parse tree.
3231  */
3232  if (!bms_is_empty(dropped_outer_joins))
3233  {
3234  root->parse = (Query *)
3235  remove_nulling_relids((Node *) root->parse,
3236  dropped_outer_joins,
3237  NULL);
3238  /* There could be references in the append_rel_list, too */
3239  root->append_rel_list = (List *)
3240  remove_nulling_relids((Node *) root->append_rel_list,
3241  dropped_outer_joins,
3242  NULL);
3243  }
3244 
3245  /*
3246  * Remove any PlanRowMark referencing an RTE_RESULT RTE. We obviously
3247  * must do that for any RTE_RESULT that we just removed. But one for a
3248  * RTE that we did not remove can be dropped anyway: since the RTE has
3249  * only one possible output row, there is no need for EPQ to mark and
3250  * restore that row.
3251  *
3252  * It's necessary, not optional, to remove the PlanRowMark for a surviving
3253  * RTE_RESULT RTE; otherwise we'll generate a whole-row Var for the
3254  * RTE_RESULT, which the executor has no support for.
3255  */
3256  foreach(cell, root->rowMarks)
3257  {
3258  PlanRowMark *rc = (PlanRowMark *) lfirst(cell);
3259 
3260  if (rt_fetch(rc->rti, root->parse->rtable)->rtekind == RTE_RESULT)
3261  root->rowMarks = foreach_delete_current(root->rowMarks, cell);
3262  }
3263 }
@ RTE_RESULT
Definition: parsenodes.h:1036
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
static Node * remove_useless_results_recurse(PlannerInfo *root, Node *jtnode, Node **parent_quals, Relids *dropped_outer_joins)

References Assert, bms_is_empty, foreach_delete_current, IsA, lfirst, remove_nulling_relids(), remove_useless_results_recurse(), root, rt_fetch, RTE_RESULT, and PlanRowMark::rti.

Referenced by subquery_planner().

◆ replace_empty_jointree()

void replace_empty_jointree ( Query parse)

Definition at line 284 of file prepjointree.c.

285 {
286  RangeTblEntry *rte;
287  Index rti;
288  RangeTblRef *rtr;
289 
290  /* Nothing to do if jointree is already nonempty */
291  if (parse->jointree->fromlist != NIL)
292  return;
293 
294  /* We mustn't change it in the top level of a setop tree, either */
295  if (parse->setOperations)
296  return;
297 
298  /* Create suitable RTE */
299  rte = makeNode(RangeTblEntry);
300  rte->rtekind = RTE_RESULT;
301  rte->eref = makeAlias("*RESULT*", NIL);
302 
303  /* Add it to rangetable */
304  parse->rtable = lappend(parse->rtable, rte);
305  rti = list_length(parse->rtable);
306 
307  /* And jam a reference into the jointree */
308  rtr = makeNode(RangeTblRef);
309  rtr->rtindex = rti;
310  parse->jointree->fromlist = list_make1(rtr);
311 }
unsigned int Index
Definition: c.h:614
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:389

References lappend(), list_length(), list_make1, makeAlias(), makeNode, NIL, parse(), RTE_RESULT, RangeTblEntry::rtekind, and RangeTblRef::rtindex.

Referenced by convert_EXISTS_sublink_to_join(), pull_up_simple_subquery(), and subquery_planner().

◆ set_operation_ordered_results_useful()

bool set_operation_ordered_results_useful ( SetOperationStmt setop)

Definition at line 188 of file prepunion.c.

189 {
190  /*
191  * Paths sorted by the targetlist are useful for UNION as we can opt to
192  * MergeAppend the sorted paths then Unique them. Ordered paths are no
193  * more useful than unordered ones for UNION ALL.
194  */
195  if (!setop->all && setop->op == SETOP_UNION)
196  return true;
197 
198  /*
199  * EXCEPT / EXCEPT ALL / INTERSECT / INTERSECT ALL cannot yet utilize
200  * correctly sorted input paths.
201  */
202  return false;
203 }
@ SETOP_UNION
Definition: parsenodes.h:2116
SetOperation op
Definition: parsenodes.h:2193

References SetOperationStmt::all, SetOperationStmt::op, and SETOP_UNION.

Referenced by standard_qp_callback().

◆ transform_MERGE_to_join()

void transform_MERGE_to_join ( Query parse)

Definition at line 152 of file prepjointree.c.

153 {
154  RangeTblEntry *joinrte;
155  JoinExpr *joinexpr;
156  bool have_action[NUM_MERGE_MATCH_KINDS];
157  JoinType jointype;
158  int joinrti;
159  List *vars;
160  RangeTblRef *rtr;
161 
162  if (parse->commandType != CMD_MERGE)
163  return;
164 
165  /* XXX probably bogus */
166  vars = NIL;
167 
168  /*
169  * Work out what kind of join is required. If there any WHEN NOT MATCHED
170  * BY SOURCE/TARGET actions, an outer join is required so that we process
171  * all unmatched tuples from the source and/or target relations.
172  * Otherwise, we can use an inner join.
173  */
174  have_action[MERGE_WHEN_MATCHED] = false;
175  have_action[MERGE_WHEN_NOT_MATCHED_BY_SOURCE] = false;
176  have_action[MERGE_WHEN_NOT_MATCHED_BY_TARGET] = false;
177 
178  foreach_node(MergeAction, action, parse->mergeActionList)
179  {
180  if (action->commandType != CMD_NOTHING)
181  have_action[action->matchKind] = true;
182  }
183 
184  if (have_action[MERGE_WHEN_NOT_MATCHED_BY_SOURCE] &&
186  jointype = JOIN_FULL;
187  else if (have_action[MERGE_WHEN_NOT_MATCHED_BY_SOURCE])
188  jointype = JOIN_LEFT;
189  else if (have_action[MERGE_WHEN_NOT_MATCHED_BY_TARGET])
190  jointype = JOIN_RIGHT;
191  else
192  jointype = JOIN_INNER;
193 
194  /* Manufacture a join RTE to use. */
195  joinrte = makeNode(RangeTblEntry);
196  joinrte->rtekind = RTE_JOIN;
197  joinrte->jointype = jointype;
198  joinrte->joinmergedcols = 0;
199  joinrte->joinaliasvars = vars;
200  joinrte->joinleftcols = NIL; /* MERGE does not allow JOIN USING */
201  joinrte->joinrightcols = NIL; /* ditto */
202  joinrte->join_using_alias = NULL;
203 
204  joinrte->alias = NULL;
205  joinrte->eref = makeAlias("*MERGE*", NIL);
206  joinrte->lateral = false;
207  joinrte->inh = false;
208  joinrte->inFromCl = true;
209 
210  /*
211  * Add completed RTE to pstate's range table list, so that we know its
212  * index.
213  */
214  parse->rtable = lappend(parse->rtable, joinrte);
215  joinrti = list_length(parse->rtable);
216 
217  /*
218  * Create a JOIN between the target and the source relation.
219  *
220  * Here the target is identified by parse->mergeTargetRelation. For a
221  * regular table, this will equal parse->resultRelation, but for a
222  * trigger-updatable view, it will be the expanded view subquery that we
223  * need to pull data from.
224  *
225  * The source relation is in parse->jointree->fromlist, but any quals in
226  * parse->jointree->quals are restrictions on the target relation (if the
227  * target relation is an auto-updatable view).
228  */
229  rtr = makeNode(RangeTblRef);
230  rtr->rtindex = parse->mergeTargetRelation;
231  joinexpr = makeNode(JoinExpr);
232  joinexpr->jointype = jointype;
233  joinexpr->isNatural = false;
234  joinexpr->larg = (Node *) makeFromExpr(list_make1(rtr), parse->jointree->quals);
235  joinexpr->rarg = linitial(parse->jointree->fromlist); /* source rel */
236  joinexpr->usingClause = NIL;
237  joinexpr->join_using_alias = NULL;
238  joinexpr->quals = parse->mergeJoinCondition;
239  joinexpr->alias = NULL;
240  joinexpr->rtindex = joinrti;
241 
242  /* Make the new join be the sole entry in the query's jointree */
243  parse->jointree->fromlist = list_make1(joinexpr);
244  parse->jointree->quals = NULL;
245 
246  /*
247  * If necessary, mark parse->targetlist entries that refer to the target
248  * as nullable by the join. Normally the targetlist will be empty for a
249  * MERGE, but if the target is a trigger-updatable view, it will contain a
250  * whole-row Var referring to the expanded view query.
251  */
252  if (parse->targetList != NIL &&
253  (jointype == JOIN_RIGHT || jointype == JOIN_FULL))
254  parse->targetList = (List *)
255  add_nulling_relids((Node *) parse->targetList,
256  bms_make_singleton(parse->mergeTargetRelation),
257  bms_make_singleton(joinrti));
258 
259  /*
260  * If there are any WHEN NOT MATCHED BY SOURCE actions, the executor will
261  * use the join condition to distinguish between MATCHED and NOT MATCHED
262  * BY SOURCE cases. Otherwise, it's no longer needed, and we set it to
263  * NULL, saving cycles during planning and execution.
264  */
265  if (!have_action[MERGE_WHEN_NOT_MATCHED_BY_SOURCE])
266  parse->mergeJoinCondition = NULL;
267 }
@ CMD_NOTHING
Definition: nodes.h:272
JoinType
Definition: nodes.h:288
@ JOIN_FULL
Definition: nodes.h:295
@ JOIN_RIGHT
Definition: nodes.h:296
@ JOIN_LEFT
Definition: nodes.h:294
@ RTE_JOIN
Definition: parsenodes.h:1030
#define linitial(l)
Definition: pg_list.h:178
#define foreach_node(type, var, lst)
Definition: pg_list.h:496
#define NUM_MERGE_MATCH_KINDS
Definition: primnodes.h:1973
@ MERGE_WHEN_NOT_MATCHED_BY_TARGET
Definition: primnodes.h:1970
@ MERGE_WHEN_NOT_MATCHED_BY_SOURCE
Definition: primnodes.h:1969
@ MERGE_WHEN_MATCHED
Definition: primnodes.h:1968
Node * add_nulling_relids(Node *node, const Bitmapset *target_relids, const Bitmapset *added_relids)
Node * quals
Definition: primnodes.h:2261
JoinType jointype
Definition: primnodes.h:2252
int rtindex
Definition: primnodes.h:2265
Node * larg
Definition: primnodes.h:2254
bool isNatural
Definition: primnodes.h:2253
Node * rarg
Definition: primnodes.h:2255
JoinType jointype
Definition: parsenodes.h:1161

References generate_unaccent_rules::action, add_nulling_relids(), bms_make_singleton(), CMD_MERGE, CMD_NOTHING, foreach_node, RangeTblEntry::inh, JoinExpr::isNatural, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, RangeTblEntry::jointype, JoinExpr::jointype, lappend(), JoinExpr::larg, linitial, list_length(), list_make1, makeAlias(), makeFromExpr(), makeNode, MERGE_WHEN_MATCHED, MERGE_WHEN_NOT_MATCHED_BY_SOURCE, MERGE_WHEN_NOT_MATCHED_BY_TARGET, NIL, NUM_MERGE_MATCH_KINDS, parse(), JoinExpr::quals, JoinExpr::rarg, RTE_JOIN, RangeTblEntry::rtekind, RangeTblRef::rtindex, and JoinExpr::rtindex.

Referenced by subquery_planner().