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 323 of file preptlist.c.

324 {
325  List *update_colnos = NIL;
326  AttrNumber nextresno = 1;
327  ListCell *lc;
328 
329  foreach(lc, tlist)
330  {
331  TargetEntry *tle = (TargetEntry *) lfirst(lc);
332 
333  if (!tle->resjunk)
334  update_colnos = lappend_int(update_colnos, tle->resno);
335  tle->resno = nextresno++;
336  }
337  return update_colnos;
338 }
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:1724

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:1014
#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:717
Definition: nodes.h:129
bool hasRecursion
Definition: pathnodes.h:504
Query * parse
Definition: pathnodes.h:202
RTEKind rtekind
Definition: parsenodes.h:1032

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:4393
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:394
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition: nodes.h:396
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:393
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:395
#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:3309
Oid finalfn_oid
Definition: pathnodes.h:3321
List * args
Definition: pathnodes.h:3338
int32 aggtransspace
Definition: pathnodes.h:3362
bool transtypeByVal
Definition: pathnodes.h:3359
Oid combinefn_oid
Definition: pathnodes.h:3351
Oid deserialfn_oid
Definition: pathnodes.h:3348
int32 aggtranstypmod
Definition: pathnodes.h:3357
Oid serialfn_oid
Definition: pathnodes.h:3345
Oid aggtranstype
Definition: pathnodes.h:3354
Expr * aggfilter
Definition: pathnodes.h:3339
List * aggdirectargs
Definition: primnodes.h:440
List * aggtransinfos
Definition: pathnodes.h:512
List * agginfos
Definition: pathnodes.h:510
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 487 of file preptlist.c.

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

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

3850 {
3851  Node *jtnode;
3852 
3853  jtnode = find_jointree_node_for_rel((Node *) query->jointree,
3854  joinrelid);
3855  if (!jtnode)
3856  elog(ERROR, "could not find join node %d", joinrelid);
3857  return get_relids_in_jointree(jtnode, true, false);
3858 }
#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 3788 of file prepjointree.c.

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

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:91
List * processed_tlist
Definition: pathnodes.h:456
bool ec_merging_done
Definition: pathnodes.h:317
List * eq_classes
Definition: pathnodes.h:314
List * targetList
Definition: parsenodes.h:189
Query * subquery
Definition: parsenodes.h:1080

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:4901
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2134
@ RTE_FUNCTION
Definition: parsenodes.h:1016
List * rtable
Definition: parsenodes.h:175
bool security_barrier
Definition: parsenodes.h:1081
bool funcordinality
Definition: parsenodes.h:1148
List * functions
Definition: parsenodes.h:1147

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 used in each action's
159  * targetlist and WHEN condition that belong to relations other
160  * than target. Note that aggregates, window functions and
161  * placeholder vars are not possible anywhere in MERGE's WHEN
162  * clauses. (PHVs may be added later, but they don't concern us
163  * here.)
164  */
166  list_concat_copy((List *) action->qual,
167  action->targetList),
168  0);
169  foreach(l2, vars)
170  {
171  Var *var = (Var *) lfirst(l2);
172  TargetEntry *tle;
173 
174  if (IsA(var, Var) && var->varno == result_relation)
175  continue; /* don't need it */
176 
177  if (tlist_member((Expr *) var, tlist))
178  continue; /* already got it */
179 
180  tle = makeTargetEntry((Expr *) var,
181  list_length(tlist) + 1,
182  NULL, true);
183  tlist = lappend(tlist, tle);
184  }
185  list_free(vars);
186  }
187  }
188 
189  /*
190  * Add necessary junk columns for rowmarked rels. These values are needed
191  * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
192  * rechecking. See comments for PlanRowMark in plannodes.h. If you
193  * change this stanza, see also expand_inherited_rtentry(), which has to
194  * be able to add on junk columns equivalent to these.
195  *
196  * (Someday it might be useful to fold these resjunk columns into the
197  * row-identity-column management used for UPDATE/DELETE. Today is not
198  * that day, however. One notable issue is that it seems important that
199  * the whole-row Vars made here use the real table rowtype, not RECORD, so
200  * that conversion to/from child relations' rowtypes will happen. Also,
201  * since these entries don't potentially bloat with more and more child
202  * relations, there's not really much need for column sharing.)
203  */
204  foreach(lc, root->rowMarks)
205  {
206  PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
207  Var *var;
208  char resname[32];
209  TargetEntry *tle;
210 
211  /* child rels use the same junk attrs as their parents */
212  if (rc->rti != rc->prti)
213  continue;
214 
215  if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
216  {
217  /* Need to fetch TID */
218  var = makeVar(rc->rti,
220  TIDOID,
221  -1,
222  InvalidOid,
223  0);
224  snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
225  tle = makeTargetEntry((Expr *) var,
226  list_length(tlist) + 1,
227  pstrdup(resname),
228  true);
229  tlist = lappend(tlist, tle);
230  }
231  if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
232  {
233  /* Need the whole row as a junk var */
234  var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
235  rc->rti,
236  0,
237  false);
238  snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
239  tle = makeTargetEntry((Expr *) var,
240  list_length(tlist) + 1,
241  pstrdup(resname),
242  true);
243  tlist = lappend(tlist, tle);
244  }
245 
246  /* If parent of inheritance tree, always fetch the tableoid too. */
247  if (rc->isParent)
248  {
249  var = makeVar(rc->rti,
251  OIDOID,
252  -1,
253  InvalidOid,
254  0);
255  snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
256  tle = makeTargetEntry((Expr *) var,
257  list_length(tlist) + 1,
258  pstrdup(resname),
259  true);
260  tlist = lappend(tlist, tle);
261  }
262  }
263 
264  /*
265  * If the query has a RETURNING list, add resjunk entries for any Vars
266  * used in RETURNING that belong to other relations. We need to do this
267  * to make these Vars available for the RETURNING calculation. Vars that
268  * belong to the result rel don't need to be added, because they will be
269  * made to refer to the actual heap tuple.
270  */
271  if (parse->returningList && list_length(parse->rtable) > 1)
272  {
273  List *vars;
274  ListCell *l;
275 
276  vars = pull_var_clause((Node *) parse->returningList,
280  foreach(l, vars)
281  {
282  Var *var = (Var *) lfirst(l);
283  TargetEntry *tle;
284 
285  if (IsA(var, Var) &&
286  var->varno == result_relation)
287  continue; /* don't need it */
288 
289  if (tlist_member((Expr *) var, tlist))
290  continue; /* already got it */
291 
292  tle = makeTargetEntry((Expr *) var,
293  list_length(tlist) + 1,
294  NULL,
295  true);
296 
297  tlist = lappend(tlist, tle);
298  }
299  list_free(vars);
300  }
301 
302  root->processed_tlist = tlist;
303 
304  if (target_relation)
305  table_close(target_relation, NoLock);
306 }
void add_row_identity_columns(PlannerInfo *root, Index rtindex, RangeTblEntry *target_rte, Relation target_relation)
Definition: appendinfo.c:883
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: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:1624
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:1013
@ ROW_MARK_COPY
Definition: plannodes.h:1335
#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:357
List * extract_update_targetlist_colnos(List *tlist)
Definition: preptlist.c:323
Index prti
Definition: plannodes.h:1384
bool isParent
Definition: plannodes.h:1390
Index rowmarkId
Definition: plannodes.h:1385
int allMarkTypes
Definition: plannodes.h:1387
List * rowMarks
Definition: pathnodes.h:371
List * update_colnos
Definition: pathnodes.h:464
Definition: primnodes.h:223
int varno
Definition: primnodes.h:230
Definition: regcomp.c:282
#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:287
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 2652 of file prepjointree.c.

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

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

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

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:1015
#define linitial(l)
Definition: pg_list.h:178
Node * quals
Definition: primnodes.h:1821
JoinType jointype
Definition: primnodes.h:1812
int rtindex
Definition: primnodes.h:1825
Node * larg
Definition: primnodes.h:1814
bool isNatural
Definition: primnodes.h:1813
Node * rarg
Definition: primnodes.h:1815
Alias * join_using_alias
Definition: parsenodes.h:1137
List * joinrightcols
Definition: parsenodes.h:1130
List * joinaliasvars
Definition: parsenodes.h:1128
JoinType jointype
Definition: parsenodes.h:1126
Alias * alias
Definition: parsenodes.h:1198
List * joinleftcols
Definition: parsenodes.h:1129

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