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)
 

Function Documentation

◆ extract_update_targetlist_colnos()

List* extract_update_targetlist_colnos ( List tlist)

Definition at line 321 of file preptlist.c.

322 {
323  List *update_colnos = NIL;
324  AttrNumber nextresno = 1;
325  ListCell *lc;
326 
327  foreach(lc, tlist)
328  {
329  TargetEntry *tle = (TargetEntry *) lfirst(lc);
330 
331  if (!tle->resjunk)
332  update_colnos = lappend_int(update_colnos, tle->resno);
333  tle->resno = nextresno++;
334  }
335  return update_colnos;
336 }
int16 AttrNumber
Definition: attnum.h:21
List * lappend_int(List *list, int datum)
Definition: list.c:356
#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:1888

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 2534 of file prepjointree.c.

2535 {
2536  Query *parse = root->parse;
2537  SetOperationStmt *topop;
2538  Node *leftmostjtnode;
2539  int leftmostRTI;
2540  RangeTblEntry *leftmostRTE;
2541  int childRTI;
2542  RangeTblEntry *childRTE;
2543  RangeTblRef *rtr;
2544 
2545  /* Shouldn't be called unless query has setops */
2546  topop = castNode(SetOperationStmt, parse->setOperations);
2547  Assert(topop);
2548 
2549  /* Can't optimize away a recursive UNION */
2550  if (root->hasRecursion)
2551  return;
2552 
2553  /*
2554  * Recursively check the tree of set operations. If not all UNION ALL
2555  * with identical column types, punt.
2556  */
2557  if (!is_simple_union_all_recurse((Node *) topop, parse, topop->colTypes))
2558  return;
2559 
2560  /*
2561  * Locate the leftmost leaf query in the setops tree. The upper query's
2562  * Vars all refer to this RTE (see transformSetOperationStmt).
2563  */
2564  leftmostjtnode = topop->larg;
2565  while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt))
2566  leftmostjtnode = ((SetOperationStmt *) leftmostjtnode)->larg;
2567  Assert(leftmostjtnode && IsA(leftmostjtnode, RangeTblRef));
2568  leftmostRTI = ((RangeTblRef *) leftmostjtnode)->rtindex;
2569  leftmostRTE = rt_fetch(leftmostRTI, parse->rtable);
2570  Assert(leftmostRTE->rtekind == RTE_SUBQUERY);
2571 
2572  /*
2573  * Make a copy of the leftmost RTE and add it to the rtable. This copy
2574  * will represent the leftmost leaf query in its capacity as a member of
2575  * the appendrel. The original will represent the appendrel as a whole.
2576  * (We must do things this way because the upper query's Vars have to be
2577  * seen as referring to the whole appendrel.)
2578  */
2579  childRTE = copyObject(leftmostRTE);
2580  parse->rtable = lappend(parse->rtable, childRTE);
2581  childRTI = list_length(parse->rtable);
2582 
2583  /* Modify the setops tree to reference the child copy */
2584  ((RangeTblRef *) leftmostjtnode)->rtindex = childRTI;
2585 
2586  /* Modify the formerly-leftmost RTE to mark it as an appendrel parent */
2587  leftmostRTE->inh = true;
2588 
2589  /*
2590  * Form a RangeTblRef for the appendrel, and insert it into FROM. The top
2591  * Query of a setops tree should have had an empty FromClause initially.
2592  */
2593  rtr = makeNode(RangeTblRef);
2594  rtr->rtindex = leftmostRTI;
2595  Assert(parse->jointree->fromlist == NIL);
2596  parse->jointree->fromlist = list_make1(rtr);
2597 
2598  /*
2599  * Now pretend the query has no setops. We must do this before trying to
2600  * do subquery pullup, because of Assert in pull_up_simple_subquery.
2601  */
2602  parse->setOperations = NULL;
2603 
2604  /*
2605  * Build AppendRelInfo information, and apply pull_up_subqueries to the
2606  * leaf queries of the UNION ALL. (We must do that now because they
2607  * weren't previously referenced by the jointree, and so were missed by
2608  * the main invocation of pull_up_subqueries.)
2609  */
2610  pull_up_union_leaf_queries((Node *) topop, root, leftmostRTI, parse, 0);
2611 }
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:338
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
#define copyObject(obj)
Definition: nodes.h:244
#define makeNode(_type_)
Definition: nodes.h:176
#define castNode(_type_, nodeptr)
Definition: nodes.h:197
@ RTE_SUBQUERY
Definition: parsenodes.h:1015
#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)
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
bool hasRecursion
Definition: pathnodes.h:501
Query * parse
Definition: pathnodes.h:199
RTEKind rtekind
Definition: parsenodes.h:1033

References Assert(), castNode, copyObject, PlannerInfo::hasRecursion, RangeTblEntry::inh, is_simple_union_all_recurse(), IsA, lappend(), SetOperationStmt::larg, list_length(), list_make1, makeNode, NIL, parse(), PlannerInfo::parse, pull_up_union_leaf_queries(), 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 561 of file prepagg.c.

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

References add_function_cost(), Aggref::aggdirectargs, AggTransInfo::aggfilter, PlannerInfo::agginfos, AggInfo::aggrefs, PlannerInfo::aggtransinfos, 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, 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 485 of file preptlist.c.

486 {
487  ListCell *l;
488 
489  foreach(l, rowmarks)
490  {
491  PlanRowMark *rc = (PlanRowMark *) lfirst(l);
492 
493  if (rc->rti == rtindex)
494  return rc;
495  }
496  return NULL;
497 }

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 3851 of file prepjointree.c.

3852 {
3853  Node *jtnode;
3854 
3855  jtnode = find_jointree_node_for_rel((Node *) query->jointree,
3856  joinrelid);
3857  if (!jtnode)
3858  elog(ERROR, "could not find join node %d", joinrelid);
3859  return get_relids_in_jointree(jtnode, true, false);
3860 }
#define ERROR
Definition: elog.h:39
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:182

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 3790 of file prepjointree.c.

3792 {
3793  Relids result = NULL;
3794 
3795  if (jtnode == NULL)
3796  return result;
3797  if (IsA(jtnode, RangeTblRef))
3798  {
3799  int varno = ((RangeTblRef *) jtnode)->rtindex;
3800 
3801  result = bms_make_singleton(varno);
3802  }
3803  else if (IsA(jtnode, FromExpr))
3804  {
3805  FromExpr *f = (FromExpr *) jtnode;
3806  ListCell *l;
3807 
3808  foreach(l, f->fromlist)
3809  {
3810  result = bms_join(result,
3812  include_outer_joins,
3813  include_inner_joins));
3814  }
3815  }
3816  else if (IsA(jtnode, JoinExpr))
3817  {
3818  JoinExpr *j = (JoinExpr *) jtnode;
3819 
3820  result = get_relids_in_jointree(j->larg,
3821  include_outer_joins,
3822  include_inner_joins);
3823  result = bms_join(result,
3824  get_relids_in_jointree(j->rarg,
3825  include_outer_joins,
3826  include_inner_joins));
3827  if (j->rtindex)
3828  {
3829  if (j->jointype == JOIN_INNER)
3830  {
3831  if (include_inner_joins)
3832  result = bms_add_member(result, j->rtindex);
3833  }
3834  else
3835  {
3836  if (include_outer_joins)
3837  result = bms_add_member(result, j->rtindex);
3838  }
3839  }
3840  }
3841  else
3842  elog(ERROR, "unrecognized node type: %d",
3843  (int) nodeTag(jtnode));
3844  return result;
3845 }
Bitmapset * bms_join(Bitmapset *a, Bitmapset *b)
Definition: bitmapset.c:987
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:755
int j
Definition: isn.c:74
#define nodeTag(nodeptr)
Definition: nodes.h:133
@ JOIN_INNER
Definition: nodes.h:304
List * fromlist
Definition: primnodes.h:2004

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 104 of file prepunion.c.

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

References Assert(), castNode, PlannerInfo::ec_merging_done, PlannerInfo::eq_classes, generate_recursion_path(), PlannerInfo::hasRecursion, IsA, SetOperationStmt::larg, NIL, parse(), PlannerInfo::parse, PlannerInfo::processed_tlist, recurse_set_operations(), 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 111 of file prepagg.c.

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

References preprocess_aggrefs_walker().

Referenced by grouping_planner().

◆ preprocess_function_rtes()

void preprocess_function_rtes ( PlannerInfo root)

Definition at line 727 of file prepjointree.c.

728 {
729  ListCell *rt;
730 
731  foreach(rt, root->parse->rtable)
732  {
733  RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
734 
735  if (rte->rtekind == RTE_FUNCTION)
736  {
737  Query *funcquery;
738 
739  /* Apply const-simplification */
740  rte->functions = (List *)
741  eval_const_expressions(root, (Node *) rte->functions);
742 
743  /* Check safety of expansion, and expand if possible */
744  funcquery = inline_set_returning_function(root, rte);
745  if (funcquery)
746  {
747  /* Successful expansion, convert the RTE to a subquery */
748  rte->rtekind = RTE_SUBQUERY;
749  rte->subquery = funcquery;
750  rte->security_barrier = false;
751  /* Clear fields that should not be set in a subquery RTE */
752  rte->functions = NIL;
753  rte->funcordinality = false;
754  }
755  }
756  }
757 }
Query * inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
Definition: clauses.c:4971
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2171
@ RTE_FUNCTION
Definition: parsenodes.h:1017
List * rtable
Definition: parsenodes.h:175
bool security_barrier
Definition: parsenodes.h:1082
bool funcordinality
Definition: parsenodes.h:1149
List * functions
Definition: parsenodes.h:1148

References eval_const_expressions(), RangeTblEntry::funcordinality, RangeTblEntry::functions, inline_set_returning_function(), lfirst, NIL, PlannerInfo::parse, Query::rtable, RTE_FUNCTION, RTE_SUBQUERY, RangeTblEntry::rtekind, RangeTblEntry::security_barrier, 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)
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 
138  /*
139  * For MERGE, handle targetlist of each MergeAction separately. Give
140  * the same treatment to MergeAction->targetList as we would have
141  * given to a regular INSERT. For UPDATE, collect the column numbers
142  * being modified.
143  */
144  foreach(l, parse->mergeActionList)
145  {
147  List *vars;
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  /*
188  * Add necessary junk columns for rowmarked rels. These values are needed
189  * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
190  * rechecking. See comments for PlanRowMark in plannodes.h. If you
191  * change this stanza, see also expand_inherited_rtentry(), which has to
192  * be able to add on junk columns equivalent to these.
193  *
194  * (Someday it might be useful to fold these resjunk columns into the
195  * row-identity-column management used for UPDATE/DELETE. Today is not
196  * that day, however. One notable issue is that it seems important that
197  * the whole-row Vars made here use the real table rowtype, not RECORD, so
198  * that conversion to/from child relations' rowtypes will happen. Also,
199  * since these entries don't potentially bloat with more and more child
200  * relations, there's not really much need for column sharing.)
201  */
202  foreach(lc, root->rowMarks)
203  {
204  PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
205  Var *var;
206  char resname[32];
207  TargetEntry *tle;
208 
209  /* child rels use the same junk attrs as their parents */
210  if (rc->rti != rc->prti)
211  continue;
212 
213  if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
214  {
215  /* Need to fetch TID */
216  var = makeVar(rc->rti,
218  TIDOID,
219  -1,
220  InvalidOid,
221  0);
222  snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
223  tle = makeTargetEntry((Expr *) var,
224  list_length(tlist) + 1,
225  pstrdup(resname),
226  true);
227  tlist = lappend(tlist, tle);
228  }
229  if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
230  {
231  /* Need the whole row as a junk var */
232  var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
233  rc->rti,
234  0,
235  false);
236  snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
237  tle = makeTargetEntry((Expr *) var,
238  list_length(tlist) + 1,
239  pstrdup(resname),
240  true);
241  tlist = lappend(tlist, tle);
242  }
243 
244  /* If parent of inheritance tree, always fetch the tableoid too. */
245  if (rc->isParent)
246  {
247  var = makeVar(rc->rti,
249  OIDOID,
250  -1,
251  InvalidOid,
252  0);
253  snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
254  tle = makeTargetEntry((Expr *) var,
255  list_length(tlist) + 1,
256  pstrdup(resname),
257  true);
258  tlist = lappend(tlist, tle);
259  }
260  }
261 
262  /*
263  * If the query has a RETURNING list, add resjunk entries for any Vars
264  * used in RETURNING that belong to other relations. We need to do this
265  * to make these Vars available for the RETURNING calculation. Vars that
266  * belong to the result rel don't need to be added, because they will be
267  * made to refer to the actual heap tuple.
268  */
269  if (parse->returningList && list_length(parse->rtable) > 1)
270  {
271  List *vars;
272  ListCell *l;
273 
274  vars = pull_var_clause((Node *) parse->returningList,
278  foreach(l, vars)
279  {
280  Var *var = (Var *) lfirst(l);
281  TargetEntry *tle;
282 
283  if (IsA(var, Var) &&
284  var->varno == result_relation)
285  continue; /* don't need it */
286 
287  if (tlist_member((Expr *) var, tlist))
288  continue; /* already got it */
289 
290  tle = makeTargetEntry((Expr *) var,
291  list_length(tlist) + 1,
292  NULL,
293  true);
294 
295  tlist = lappend(tlist, tle);
296  }
297  list_free(vars);
298  }
299 
300  root->processed_tlist = tlist;
301 
302  if (target_relation)
303  table_close(target_relation, NoLock);
304 }
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:1545
List * list_concat_copy(const List *list1, const List *list2)
Definition: list.c:597
#define NoLock
Definition: lockdefs.h:34
Var * makeWholeRowVar(RangeTblEntry *rte, int varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:136
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:241
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
char * pstrdup(const char *in)
Definition: mcxt.c:1644
CmdType
Definition: nodes.h:274
@ CMD_MERGE
Definition: nodes.h:280
@ CMD_INSERT
Definition: nodes.h:278
@ CMD_DELETE
Definition: nodes.h:279
@ CMD_UPDATE
Definition: nodes.h:277
@ CMD_SELECT
Definition: nodes.h:276
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:184
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:186
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:187
@ RTE_RELATION
Definition: parsenodes.h:1014
@ ROW_MARK_COPY
Definition: plannodes.h:1332
#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:355
List * extract_update_targetlist_colnos(List *tlist)
Definition: preptlist.c:321
Index prti
Definition: plannodes.h:1381
bool isParent
Definition: plannodes.h:1387
Index rowmarkId
Definition: plannodes.h:1382
int allMarkTypes
Definition: plannodes.h:1384
List * rowMarks
Definition: pathnodes.h:368
List * update_colnos
Definition: pathnodes.h:461
Definition: primnodes.h:226
int varno
Definition: primnodes.h:233
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(), PlannerInfo::parse, PlannerInfo::processed_tlist, PlanRowMark::prti, pstrdup(), pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, RangeTblEntry::relid, ROW_MARK_COPY, PlanRowMark::rowmarkId, PlannerInfo::rowMarks, rt_fetch, RTE_RELATION, RangeTblEntry::rtekind, PlanRowMark::rti, SelfItemPointerAttributeNumber, snprintf, table_close(), table_open(), TableOidAttributeNumber, tlist_member(), PlannerInfo::update_colnos, and Var::varno.

Referenced by grouping_planner().

◆ pull_up_sublinks()

void pull_up_sublinks ( PlannerInfo root)

Definition at line 293 of file prepjointree.c.

294 {
295  Node *jtnode;
296  Relids relids;
297 
298  /* Begin recursion through the jointree */
299  jtnode = pull_up_sublinks_jointree_recurse(root,
300  (Node *) root->parse->jointree,
301  &relids);
302 
303  /*
304  * root->parse->jointree must always be a FromExpr, so insert a dummy one
305  * if we got a bare RangeTblRef or JoinExpr out of the recursion.
306  */
307  if (IsA(jtnode, FromExpr))
308  root->parse->jointree = (FromExpr *) jtnode;
309  else
310  root->parse->jointree = makeFromExpr(list_make1(jtnode), NULL);
311 }
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:288
static Node * pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode, Relids *relids)
Definition: prepjointree.c:320

References IsA, Query::jointree, list_make1, makeFromExpr(), PlannerInfo::parse, and pull_up_sublinks_jointree_recurse().

Referenced by pull_up_simple_subquery(), and subquery_planner().

◆ pull_up_subqueries()

void pull_up_subqueries ( PlannerInfo root)

Definition at line 768 of file prepjointree.c.

769 {
770  /* Top level of jointree must always be a FromExpr */
771  Assert(IsA(root->parse->jointree, FromExpr));
772  /* Recursion starts with no containing join nor appendrel */
773  root->parse->jointree = (FromExpr *)
775  NULL, NULL);
776  /* We should still have a FromExpr */
777  Assert(IsA(root->parse->jointree, FromExpr));
778 }
static Node * pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode, JoinExpr *lowest_outer_join, AppendRelInfo *containing_appendrel)
Definition: prepjointree.c:812

References Assert(), IsA, Query::jointree, PlannerInfo::parse, and pull_up_subqueries_recurse().

Referenced by pull_up_simple_subquery(), and subquery_planner().

◆ reduce_outer_joins()

void reduce_outer_joins ( PlannerInfo root)

Definition at line 2653 of file prepjointree.c.

2654 {
2657  ListCell *lc;
2658 
2659  /*
2660  * To avoid doing strictness checks on more quals than necessary, we want
2661  * to stop descending the jointree as soon as there are no outer joins
2662  * below our current point. This consideration forces a two-pass process.
2663  * The first pass gathers information about which base rels appear below
2664  * each side of each join clause, and about whether there are outer
2665  * join(s) below each side of each join clause. The second pass examines
2666  * qual clauses and changes join types as it descends the tree.
2667  */
2668  state1 = reduce_outer_joins_pass1((Node *) root->parse->jointree);
2669 
2670  /* planner.c shouldn't have called me if no outer joins */
2671  if (state1 == NULL || !state1->contains_outer)
2672  elog(ERROR, "so where are the outer joins?");
2673 
2674  state2.inner_reduced = NULL;
2675  state2.partial_reduced = NIL;
2676 
2678  state1, &state2,
2679  root, NULL, NIL);
2680 
2681  /*
2682  * If we successfully reduced the strength of any outer joins, we must
2683  * remove references to those joins as nulling rels. This is handled as
2684  * an additional pass, for simplicity and because we can handle all
2685  * fully-reduced joins in a single pass over the parse tree.
2686  */
2687  if (!bms_is_empty(state2.inner_reduced))
2688  {
2689  root->parse = (Query *)
2690  remove_nulling_relids((Node *) root->parse,
2691  state2.inner_reduced,
2692  NULL);
2693  /* There could be references in the append_rel_list, too */
2694  root->append_rel_list = (List *)
2696  state2.inner_reduced,
2697  NULL);
2698  }
2699 
2700  /*
2701  * Partially-reduced full joins have to be done one at a time, since
2702  * they'll each need a different setting of except_relids.
2703  */
2704  foreach(lc, state2.partial_reduced)
2705  {
2707  Relids full_join_relids = bms_make_singleton(statep->full_join_rti);
2708 
2709  root->parse = (Query *)
2710  remove_nulling_relids((Node *) root->parse,
2711  full_join_relids,
2712  statep->unreduced_side);
2713  root->append_rel_list = (List *)
2715  full_join_relids,
2716  statep->unreduced_side);
2717  }
2718 }
#define bms_is_empty(a)
Definition: bitmapset.h:105
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)
List * append_rel_list
Definition: pathnodes.h:362

References PlannerInfo::append_rel_list, 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, Query::jointree, lfirst, NIL, PlannerInfo::parse, reduce_outer_joins_pass2_state::partial_reduced, reduce_outer_joins_pass1(), reduce_outer_joins_pass2(), remove_nulling_relids(), 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 3147 of file prepjointree.c.

3148 {
3149  Relids dropped_outer_joins = NULL;
3150  ListCell *cell;
3151 
3152  /* Top level of jointree must always be a FromExpr */
3153  Assert(IsA(root->parse->jointree, FromExpr));
3154  /* Recurse ... */
3155  root->parse->jointree = (FromExpr *)
3157  (Node *) root->parse->jointree,
3158  NULL,
3159  &dropped_outer_joins);
3160  /* We should still have a FromExpr */
3161  Assert(IsA(root->parse->jointree, FromExpr));
3162 
3163  /*
3164  * If we removed any outer-join nodes from the jointree, run around and
3165  * remove references to those joins as nulling rels. (There could be such
3166  * references in PHVs that we pulled up out of the original subquery that
3167  * the RESULT rel replaced. This is kosher on the grounds that we now
3168  * know that such an outer join wouldn't really have nulled anything.) We
3169  * don't do this during the main recursion, for simplicity and because we
3170  * can handle all such joins in a single pass over the parse tree.
3171  */
3172  if (!bms_is_empty(dropped_outer_joins))
3173  {
3174  root->parse = (Query *)
3175  remove_nulling_relids((Node *) root->parse,
3176  dropped_outer_joins,
3177  NULL);
3178  /* There could be references in the append_rel_list, too */
3179  root->append_rel_list = (List *)
3181  dropped_outer_joins,
3182  NULL);
3183  }
3184 
3185  /*
3186  * Remove any PlanRowMark referencing an RTE_RESULT RTE. We obviously
3187  * must do that for any RTE_RESULT that we just removed. But one for a
3188  * RTE that we did not remove can be dropped anyway: since the RTE has
3189  * only one possible output row, there is no need for EPQ to mark and
3190  * restore that row.
3191  *
3192  * It's necessary, not optional, to remove the PlanRowMark for a surviving
3193  * RTE_RESULT RTE; otherwise we'll generate a whole-row Var for the
3194  * RTE_RESULT, which the executor has no support for.
3195  */
3196  foreach(cell, root->rowMarks)
3197  {
3198  PlanRowMark *rc = (PlanRowMark *) lfirst(cell);
3199 
3200  if (rt_fetch(rc->rti, root->parse->rtable)->rtekind == RTE_RESULT)
3201  root->rowMarks = foreach_delete_current(root->rowMarks, cell);
3202  }
3203 }
@ RTE_RESULT
Definition: parsenodes.h:1022
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:390
static Node * remove_useless_results_recurse(PlannerInfo *root, Node *jtnode, Node **parent_quals, Relids *dropped_outer_joins)

References PlannerInfo::append_rel_list, Assert(), bms_is_empty, foreach_delete_current, IsA, Query::jointree, lfirst, PlannerInfo::parse, remove_nulling_relids(), remove_useless_results_recurse(), PlannerInfo::rowMarks, rt_fetch, Query::rtable, RTE_RESULT, and PlanRowMark::rti.

Referenced by subquery_planner().

◆ replace_empty_jointree()

void replace_empty_jointree ( Query parse)

Definition at line 235 of file prepjointree.c.

236 {
237  RangeTblEntry *rte;
238  Index rti;
239  RangeTblRef *rtr;
240 
241  /* Nothing to do if jointree is already nonempty */
242  if (parse->jointree->fromlist != NIL)
243  return;
244 
245  /* We mustn't change it in the top level of a setop tree, either */
246  if (parse->setOperations)
247  return;
248 
249  /* Create suitable RTE */
250  rte = makeNode(RangeTblEntry);
251  rte->rtekind = RTE_RESULT;
252  rte->eref = makeAlias("*RESULT*", NIL);
253 
254  /* Add it to rangetable */
255  parse->rtable = lappend(parse->rtable, rte);
256  rti = list_length(parse->rtable);
257 
258  /* And jam a reference into the jointree */
259  rtr = makeNode(RangeTblRef);
260  rtr->rtindex = rti;
261  parse->jointree->fromlist = list_make1(rtr);
262 }
unsigned int Index
Definition: c.h:598
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:390
Alias * eref
Definition: parsenodes.h:1200

References RangeTblEntry::eref, 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().

◆ 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  JoinType jointype;
157  int joinrti;
158  List *vars;
159 
160  if (parse->commandType != CMD_MERGE)
161  return;
162 
163  /* XXX probably bogus */
164  vars = NIL;
165 
166  /*
167  * When any WHEN NOT MATCHED THEN INSERT clauses exist, we need to use an
168  * outer join so that we process all unmatched tuples from the source
169  * relation. If none exist, we can use an inner join.
170  */
171  if (parse->mergeUseOuterJoin)
172  jointype = JOIN_RIGHT;
173  else
174  jointype = JOIN_INNER;
175 
176  /* Manufacture a join RTE to use. */
177  joinrte = makeNode(RangeTblEntry);
178  joinrte->rtekind = RTE_JOIN;
179  joinrte->jointype = jointype;
180  joinrte->joinmergedcols = 0;
181  joinrte->joinaliasvars = vars;
182  joinrte->joinleftcols = NIL; /* MERGE does not allow JOIN USING */
183  joinrte->joinrightcols = NIL; /* ditto */
184  joinrte->join_using_alias = NULL;
185 
186  joinrte->alias = NULL;
187  joinrte->eref = makeAlias("*MERGE*", NIL);
188  joinrte->lateral = false;
189  joinrte->inh = false;
190  joinrte->inFromCl = true;
191 
192  /*
193  * Add completed RTE to pstate's range table list, so that we know its
194  * index.
195  */
196  parse->rtable = lappend(parse->rtable, joinrte);
197  joinrti = list_length(parse->rtable);
198 
199  /*
200  * Create a JOIN between the target and the source relation.
201  */
202  joinexpr = makeNode(JoinExpr);
203  joinexpr->jointype = jointype;
204  joinexpr->isNatural = false;
205  joinexpr->larg = (Node *) makeNode(RangeTblRef);
206  ((RangeTblRef *) joinexpr->larg)->rtindex = parse->resultRelation;
207  joinexpr->rarg = linitial(parse->jointree->fromlist); /* original join */
208  joinexpr->usingClause = NIL;
209  joinexpr->join_using_alias = NULL;
210  /* The quals are removed from the jointree and into this specific join */
211  joinexpr->quals = parse->jointree->quals;
212  joinexpr->alias = NULL;
213  joinexpr->rtindex = joinrti;
214 
215  /* Make the new join be the sole entry in the query's jointree */
216  parse->jointree->fromlist = list_make1(joinexpr);
217  parse->jointree->quals = NULL;
218 }
JoinType
Definition: nodes.h:299
@ JOIN_RIGHT
Definition: nodes.h:307
@ RTE_JOIN
Definition: parsenodes.h:1016
#define linitial(l)
Definition: pg_list.h:178
Node * quals
Definition: primnodes.h:1985
JoinType jointype
Definition: primnodes.h:1976
int rtindex
Definition: primnodes.h:1989
Node * larg
Definition: primnodes.h:1978
bool isNatural
Definition: primnodes.h:1977
Node * rarg
Definition: primnodes.h:1979
Alias * join_using_alias
Definition: parsenodes.h:1138
List * joinrightcols
Definition: parsenodes.h:1131
List * joinaliasvars
Definition: parsenodes.h:1129
JoinType jointype
Definition: parsenodes.h:1127
Alias * alias
Definition: parsenodes.h:1199
List * joinleftcols
Definition: parsenodes.h:1130

References RangeTblEntry::alias, CMD_MERGE, RangeTblEntry::eref, RangeTblEntry::inFromCl, RangeTblEntry::inh, JoinExpr::isNatural, JOIN_INNER, JOIN_RIGHT, RangeTblEntry::join_using_alias, RangeTblEntry::joinaliasvars, RangeTblEntry::joinleftcols, RangeTblEntry::joinmergedcols, RangeTblEntry::joinrightcols, RangeTblEntry::jointype, JoinExpr::jointype, lappend(), JoinExpr::larg, RangeTblEntry::lateral, linitial, list_length(), list_make1, makeAlias(), makeNode, NIL, parse(), JoinExpr::quals, JoinExpr::rarg, RTE_JOIN, RangeTblEntry::rtekind, and JoinExpr::rtindex.

Referenced by subquery_planner().