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 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_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 *agg_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 261 of file preptlist.c.

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

Referenced by make_modifytable(), and preprocess_targetlist().

262 {
263  List *update_colnos = NIL;
264  AttrNumber nextresno = 1;
265  ListCell *lc;
266 
267  foreach(lc, tlist)
268  {
269  TargetEntry *tle = (TargetEntry *) lfirst(lc);
270 
271  if (!tle->resjunk)
272  update_colnos = lappend_int(update_colnos, tle->resno);
273  tle->resno = nextresno++;
274  }
275  return update_colnos;
276 }
#define NIL
Definition: pg_list.h:65
bool resjunk
Definition: primnodes.h:1462
AttrNumber resno
Definition: primnodes.h:1456
List * lappend_int(List *list, int datum)
Definition: list.c:354
#define lfirst(lc)
Definition: pg_list.h:169
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21

◆ flatten_simple_union_all()

void flatten_simple_union_all ( PlannerInfo root)

Definition at line 2466 of file prepjointree.c.

References Assert, castNode, copyObject, FromExpr::fromlist, PlannerInfo::hasRecursion, RangeTblEntry::inh, is_simple_union_all_recurse(), IsA, Query::jointree, lappend(), list_length(), list_make1, makeNode, NIL, parse(), PlannerInfo::parse, pull_up_union_leaf_queries(), rt_fetch, Query::rtable, RTE_SUBQUERY, RangeTblEntry::rtekind, RangeTblRef::rtindex, and Query::setOperations.

Referenced by subquery_planner().

2467 {
2468  Query *parse = root->parse;
2469  SetOperationStmt *topop;
2470  Node *leftmostjtnode;
2471  int leftmostRTI;
2472  RangeTblEntry *leftmostRTE;
2473  int childRTI;
2474  RangeTblEntry *childRTE;
2475  RangeTblRef *rtr;
2476 
2477  /* Shouldn't be called unless query has setops */
2478  topop = castNode(SetOperationStmt, parse->setOperations);
2479  Assert(topop);
2480 
2481  /* Can't optimize away a recursive UNION */
2482  if (root->hasRecursion)
2483  return;
2484 
2485  /*
2486  * Recursively check the tree of set operations. If not all UNION ALL
2487  * with identical column types, punt.
2488  */
2489  if (!is_simple_union_all_recurse((Node *) topop, parse, topop->colTypes))
2490  return;
2491 
2492  /*
2493  * Locate the leftmost leaf query in the setops tree. The upper query's
2494  * Vars all refer to this RTE (see transformSetOperationStmt).
2495  */
2496  leftmostjtnode = topop->larg;
2497  while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt))
2498  leftmostjtnode = ((SetOperationStmt *) leftmostjtnode)->larg;
2499  Assert(leftmostjtnode && IsA(leftmostjtnode, RangeTblRef));
2500  leftmostRTI = ((RangeTblRef *) leftmostjtnode)->rtindex;
2501  leftmostRTE = rt_fetch(leftmostRTI, parse->rtable);
2502  Assert(leftmostRTE->rtekind == RTE_SUBQUERY);
2503 
2504  /*
2505  * Make a copy of the leftmost RTE and add it to the rtable. This copy
2506  * will represent the leftmost leaf query in its capacity as a member of
2507  * the appendrel. The original will represent the appendrel as a whole.
2508  * (We must do things this way because the upper query's Vars have to be
2509  * seen as referring to the whole appendrel.)
2510  */
2511  childRTE = copyObject(leftmostRTE);
2512  parse->rtable = lappend(parse->rtable, childRTE);
2513  childRTI = list_length(parse->rtable);
2514 
2515  /* Modify the setops tree to reference the child copy */
2516  ((RangeTblRef *) leftmostjtnode)->rtindex = childRTI;
2517 
2518  /* Modify the formerly-leftmost RTE to mark it as an appendrel parent */
2519  leftmostRTE->inh = true;
2520 
2521  /*
2522  * Form a RangeTblRef for the appendrel, and insert it into FROM. The top
2523  * Query of a setops tree should have had an empty FromClause initially.
2524  */
2525  rtr = makeNode(RangeTblRef);
2526  rtr->rtindex = leftmostRTI;
2527  Assert(parse->jointree->fromlist == NIL);
2528  parse->jointree->fromlist = list_make1(rtr);
2529 
2530  /*
2531  * Now pretend the query has no setops. We must do this before trying to
2532  * do subquery pullup, because of Assert in pull_up_simple_subquery.
2533  */
2534  parse->setOperations = NULL;
2535 
2536  /*
2537  * Build AppendRelInfo information, and apply pull_up_subqueries to the
2538  * leaf queries of the UNION ALL. (We must do that now because they
2539  * weren't previously referenced by the jointree, and so were missed by
2540  * the main invocation of pull_up_subqueries.)
2541  */
2542  pull_up_union_leaf_queries((Node *) topop, root, leftmostRTI, parse, 0);
2543 }
#define NIL
Definition: pg_list.h:65
static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex, Query *setOpQuery, int childRToffset)
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
Query * parse
Definition: pathnodes.h:162
FromExpr * jointree
Definition: parsenodes.h:148
#define castNode(_type_, nodeptr)
Definition: nodes.h:605
Definition: nodes.h:536
static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
List * fromlist
Definition: primnodes.h:1564
bool hasRecursion
Definition: pathnodes.h:352
#define list_make1(x1)
Definition: pg_list.h:206
List * rtable
Definition: parsenodes.h:147
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * lappend(List *list, void *datum)
Definition: list.c:336
#define makeNode(_type_)
Definition: nodes.h:584
#define Assert(condition)
Definition: c.h:804
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:1007
Node * setOperations
Definition: parsenodes.h:177
#define copyObject(obj)
Definition: nodes.h:652
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:673

◆ get_agg_clause_costs()

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

Definition at line 538 of file prepagg.c.

References add_function_cost(), Aggref::aggdirectargs, AggTransInfo::aggfilter, PlannerInfo::agginfos, 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, MAXALIGN, OidIsValid, QualCost::per_tuple, AggInfo::representative_aggref, 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().

539 {
540  ListCell *lc;
541 
542  foreach(lc, root->aggtransinfos)
543  {
544  AggTransInfo *transinfo = (AggTransInfo *) lfirst(lc);
545 
546  /*
547  * Add the appropriate component function execution costs to
548  * appropriate totals.
549  */
550  if (DO_AGGSPLIT_COMBINE(aggsplit))
551  {
552  /* charge for combining previously aggregated states */
553  add_function_cost(root, transinfo->combinefn_oid, NULL,
554  &costs->transCost);
555  }
556  else
557  add_function_cost(root, transinfo->transfn_oid, NULL,
558  &costs->transCost);
559  if (DO_AGGSPLIT_DESERIALIZE(aggsplit) &&
560  OidIsValid(transinfo->deserialfn_oid))
561  add_function_cost(root, transinfo->deserialfn_oid, NULL,
562  &costs->transCost);
563  if (DO_AGGSPLIT_SERIALIZE(aggsplit) &&
564  OidIsValid(transinfo->serialfn_oid))
565  add_function_cost(root, transinfo->serialfn_oid, NULL,
566  &costs->finalCost);
567 
568  /*
569  * These costs are incurred only by the initial aggregate node, so we
570  * mustn't include them again at upper levels.
571  */
572  if (!DO_AGGSPLIT_COMBINE(aggsplit))
573  {
574  /* add the input expressions' cost to per-input-row costs */
575  QualCost argcosts;
576 
577  cost_qual_eval_node(&argcosts, (Node *) transinfo->args, root);
578  costs->transCost.startup += argcosts.startup;
579  costs->transCost.per_tuple += argcosts.per_tuple;
580 
581  /*
582  * Add any filter's cost to per-input-row costs.
583  *
584  * XXX Ideally we should reduce input expression costs according
585  * to filter selectivity, but it's not clear it's worth the
586  * trouble.
587  */
588  if (transinfo->aggfilter)
589  {
590  cost_qual_eval_node(&argcosts, (Node *) transinfo->aggfilter,
591  root);
592  costs->transCost.startup += argcosts.startup;
593  costs->transCost.per_tuple += argcosts.per_tuple;
594  }
595  }
596 
597  /*
598  * If the transition type is pass-by-value then it doesn't add
599  * anything to the required size of the hashtable. If it is
600  * pass-by-reference then we have to add the estimated size of the
601  * value itself, plus palloc overhead.
602  */
603  if (!transinfo->transtypeByVal)
604  {
605  int32 avgwidth;
606 
607  /* Use average width if aggregate definition gave one */
608  if (transinfo->aggtransspace > 0)
609  avgwidth = transinfo->aggtransspace;
610  else if (transinfo->transfn_oid == F_ARRAY_APPEND)
611  {
612  /*
613  * If the transition function is array_append(), it'll use an
614  * expanded array as transvalue, which will occupy at least
615  * ALLOCSET_SMALL_INITSIZE and possibly more. Use that as the
616  * estimate for lack of a better idea.
617  */
618  avgwidth = ALLOCSET_SMALL_INITSIZE;
619  }
620  else
621  {
622  avgwidth = get_typavgwidth(transinfo->aggtranstype, transinfo->aggtranstypmod);
623  }
624 
625  avgwidth = MAXALIGN(avgwidth);
626  costs->transitionSpace += avgwidth + 2 * sizeof(void *);
627  }
628  else if (transinfo->aggtranstype == INTERNALOID)
629  {
630  /*
631  * INTERNAL transition type is a special case: although INTERNAL
632  * is pass-by-value, it's almost certainly being used as a pointer
633  * to some large data structure. The aggregate definition can
634  * provide an estimate of the size. If it doesn't, then we assume
635  * ALLOCSET_DEFAULT_INITSIZE, which is a good guess if the data is
636  * being kept in a private memory context, as is done by
637  * array_agg() for instance.
638  */
639  if (transinfo->aggtransspace > 0)
640  costs->transitionSpace += transinfo->aggtransspace;
641  else
642  costs->transitionSpace += ALLOCSET_DEFAULT_INITSIZE;
643  }
644  }
645 
646  foreach(lc, root->agginfos)
647  {
648  AggInfo *agginfo = (AggInfo *) lfirst(lc);
649  Aggref *aggref = agginfo->representative_aggref;
650 
651  /*
652  * Add the appropriate component function execution costs to
653  * appropriate totals.
654  */
655  if (!DO_AGGSPLIT_SKIPFINAL(aggsplit) &&
656  OidIsValid(agginfo->finalfn_oid))
657  add_function_cost(root, agginfo->finalfn_oid, NULL,
658  &costs->finalCost);
659 
660  /*
661  * If there are direct arguments, treat their evaluation cost like the
662  * cost of the finalfn.
663  */
664  if (aggref->aggdirectargs)
665  {
666  QualCost argcosts;
667 
668  cost_qual_eval_node(&argcosts, (Node *) aggref->aggdirectargs,
669  root);
670  costs->finalCost.startup += argcosts.startup;
671  costs->finalCost.per_tuple += argcosts.per_tuple;
672  }
673  }
674 }
Oid serialfn_oid
Definition: pathnodes.h:2701
void cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root)
Definition: costsize.c:4334
Oid finalfn_oid
Definition: pathnodes.h:2681
Definition: nodes.h:536
void add_function_cost(PlannerInfo *root, Oid funcid, Node *node, QualCost *cost)
Definition: plancat.c:1967
bool transtypeByVal
Definition: pathnodes.h:2713
Expr * aggfilter
Definition: pathnodes.h:2695
List * agginfos
Definition: pathnodes.h:357
Oid combinefn_oid
Definition: pathnodes.h:2707
#define OidIsValid(objectId)
Definition: c.h:710
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:799
Cost startup
Definition: pathnodes.h:45
signed int int32
Definition: c.h:429
Cost per_tuple
Definition: pathnodes.h:46
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:801
List * aggtransinfos
Definition: pathnodes.h:358
int32 aggtransspace
Definition: pathnodes.h:2714
List * aggdirectargs
Definition: primnodes.h:329
Oid aggtranstype
Definition: pathnodes.h:2710
int32 aggtranstypmod
Definition: pathnodes.h:2711
#define ALLOCSET_SMALL_INITSIZE
Definition: memutils.h:203
int32 get_typavgwidth(Oid typid, int32 typmod)
Definition: lsyscache.c:2525
List * args
Definition: pathnodes.h:2694
#define lfirst(lc)
Definition: pg_list.h:169
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:800
#define MAXALIGN(LEN)
Definition: c.h:757
Oid deserialfn_oid
Definition: pathnodes.h:2704
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition: nodes.h:802
#define ALLOCSET_DEFAULT_INITSIZE
Definition: memutils.h:193
Aggref * representative_aggref
Definition: pathnodes.h:2670

◆ get_plan_rowmark()

PlanRowMark* get_plan_rowmark ( List rowmarks,
Index  rtindex 
)

Definition at line 425 of file preptlist.c.

References lfirst, and PlanRowMark::rti.

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

426 {
427  ListCell *l;
428 
429  foreach(l, rowmarks)
430  {
431  PlanRowMark *rc = (PlanRowMark *) lfirst(l);
432 
433  if (rc->rti == rtindex)
434  return rc;
435  }
436  return NULL;
437 }
#define lfirst(lc)
Definition: pg_list.h:169

◆ get_relids_for_join()

Relids get_relids_for_join ( Query query,
int  joinrelid 
)

Definition at line 3583 of file prepjointree.c.

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

Referenced by alias_relid_set().

3584 {
3585  Node *jtnode;
3586 
3587  jtnode = find_jointree_node_for_rel((Node *) query->jointree,
3588  joinrelid);
3589  if (!jtnode)
3590  elog(ERROR, "could not find join node %d", joinrelid);
3591  return get_relids_in_jointree(jtnode, false);
3592 }
FromExpr * jointree
Definition: parsenodes.h:148
Definition: nodes.h:536
static Node * find_jointree_node_for_rel(Node *jtnode, int relid)
#define ERROR
Definition: elog.h:46
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
#define elog(elevel,...)
Definition: elog.h:232

◆ get_relids_in_jointree()

Relids get_relids_in_jointree ( Node jtnode,
bool  include_joins 
)

Definition at line 3539 of file prepjointree.c.

References bms_add_member(), bms_join(), bms_make_singleton(), elog, ERROR, FromExpr::fromlist, get_relids_in_jointree(), IsA, JoinExpr::larg, lfirst, nodeTag, JoinExpr::rarg, JoinExpr::rtindex, and pullup_replace_vars_context::varno.

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

3540 {
3541  Relids result = NULL;
3542 
3543  if (jtnode == NULL)
3544  return result;
3545  if (IsA(jtnode, RangeTblRef))
3546  {
3547  int varno = ((RangeTblRef *) jtnode)->rtindex;
3548 
3549  result = bms_make_singleton(varno);
3550  }
3551  else if (IsA(jtnode, FromExpr))
3552  {
3553  FromExpr *f = (FromExpr *) jtnode;
3554  ListCell *l;
3555 
3556  foreach(l, f->fromlist)
3557  {
3558  result = bms_join(result,
3560  include_joins));
3561  }
3562  }
3563  else if (IsA(jtnode, JoinExpr))
3564  {
3565  JoinExpr *j = (JoinExpr *) jtnode;
3566 
3567  result = get_relids_in_jointree(j->larg, include_joins);
3568  result = bms_join(result,
3569  get_relids_in_jointree(j->rarg, include_joins));
3570  if (include_joins && j->rtindex)
3571  result = bms_add_member(result, j->rtindex);
3572  }
3573  else
3574  elog(ERROR, "unrecognized node type: %d",
3575  (int) nodeTag(jtnode));
3576  return result;
3577 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
List * fromlist
Definition: primnodes.h:1564
Node * larg
Definition: primnodes.h:1543
#define ERROR
Definition: elog.h:46
Bitmapset * bms_join(Bitmapset *a, Bitmapset *b)
Definition: bitmapset.c:949
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
Node * rarg
Definition: primnodes.h:1544
#define lfirst(lc)
Definition: pg_list.h:169
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define nodeTag(nodeptr)
Definition: nodes.h:541
#define elog(elevel,...)
Definition: elog.h:232
int rtindex
Definition: primnodes.h:1549

◆ plan_set_operations()

RelOptInfo* plan_set_operations ( PlannerInfo root)

Definition at line 103 of file prepunion.c.

References Assert, castNode, Query::distinctClause, PlannerInfo::ec_merging_done, PlannerInfo::eq_classes, FromExpr::fromlist, generate_recursion_path(), Query::groupClause, PlannerInfo::hasRecursion, Query::havingQual, IsA, Query::jointree, SetOperationStmt::larg, NIL, parse(), PlannerInfo::parse, PlannerInfo::processed_tlist, FromExpr::quals, recurse_set_operations(), Query::setOperations, setup_simple_rel_arrays(), PlannerInfo::simple_rte_array, RangeTblEntry::subquery, Query::targetList, and Query::windowClause.

Referenced by grouping_planner().

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

◆ preprocess_aggrefs()

void preprocess_aggrefs ( PlannerInfo root,
Node clause 
)

Definition at line 111 of file prepagg.c.

References preprocess_aggrefs_walker().

Referenced by grouping_planner().

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

◆ preprocess_function_rtes()

void preprocess_function_rtes ( PlannerInfo root)

Definition at line 639 of file prepjointree.c.

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

640 {
641  ListCell *rt;
642 
643  foreach(rt, root->parse->rtable)
644  {
645  RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
646 
647  if (rte->rtekind == RTE_FUNCTION)
648  {
649  Query *funcquery;
650 
651  /* Apply const-simplification */
652  rte->functions = (List *)
653  eval_const_expressions(root, (Node *) rte->functions);
654 
655  /* Check safety of expansion, and expand if possible */
656  funcquery = inline_set_returning_function(root, rte);
657  if (funcquery)
658  {
659  /* Successful expansion, convert the RTE to a subquery */
660  rte->rtekind = RTE_SUBQUERY;
661  rte->subquery = funcquery;
662  rte->security_barrier = false;
663  /* Clear fields that should not be set in a subquery RTE */
664  rte->functions = NIL;
665  rte->funcordinality = false;
666  }
667  }
668  }
669 }
#define NIL
Definition: pg_list.h:65
Query * parse
Definition: pathnodes.h:162
Definition: nodes.h:536
Query * inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
Definition: clauses.c:4877
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2094
bool funcordinality
Definition: parsenodes.h:1102
List * rtable
Definition: parsenodes.h:147
bool security_barrier
Definition: parsenodes.h:1043
#define lfirst(lc)
Definition: pg_list.h:169
List * functions
Definition: parsenodes.h:1101
RTEKind rtekind
Definition: parsenodes.h:1007
Query * subquery
Definition: parsenodes.h:1042
Definition: pg_list.h:50

◆ preprocess_targetlist()

void preprocess_targetlist ( PlannerInfo root)

Definition at line 62 of file preptlist.c.

References add_row_identity_columns(), PlanRowMark::allMarkTypes, Assert, CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, Query::commandType, elog, ERROR, expand_insert_targetlist(), extract_update_targetlist_colnos(), RangeTblEntry::inh, InvalidOid, IsA, PlanRowMark::isParent, lappend(), lfirst, 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, Query::resultRelation, Query::returningList, ROW_MARK_COPY, PlanRowMark::rowmarkId, PlannerInfo::rowMarks, rt_fetch, Query::rtable, RTE_RELATION, RangeTblEntry::rtekind, PlanRowMark::rti, SelfItemPointerAttributeNumber, snprintf, table_close(), table_open(), TableOidAttributeNumber, Query::targetList, tlist_member(), PlannerInfo::update_colnos, and Var::varno.

Referenced by grouping_planner().

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, register any junk column(s) needed to
111  * allow the executor to identify the rows to be updated or deleted. In
112  * the inheritance case, we do nothing now, leaving this to be dealt with
113  * when expand_inherited_rtentry() makes the leaf target relations. (But
114  * there might not be any leaf target relations, in which case we must do
115  * this in distribute_row_identity_vars().)
116  */
117  if ((command_type == CMD_UPDATE || command_type == CMD_DELETE) &&
118  !target_rte->inh)
119  {
120  /* row-identity logic expects to add stuff to processed_tlist */
121  root->processed_tlist = tlist;
122  add_row_identity_columns(root, result_relation,
123  target_rte, target_relation);
124  tlist = root->processed_tlist;
125  }
126 
127  /*
128  * Add necessary junk columns for rowmarked rels. These values are needed
129  * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
130  * rechecking. See comments for PlanRowMark in plannodes.h. If you
131  * change this stanza, see also expand_inherited_rtentry(), which has to
132  * be able to add on junk columns equivalent to these.
133  *
134  * (Someday it might be useful to fold these resjunk columns into the
135  * row-identity-column management used for UPDATE/DELETE. Today is not
136  * that day, however. One notable issue is that it seems important that
137  * the whole-row Vars made here use the real table rowtype, not RECORD, so
138  * that conversion to/from child relations' rowtypes will happen. Also,
139  * since these entries don't potentially bloat with more and more child
140  * relations, there's not really much need for column sharing.)
141  */
142  foreach(lc, root->rowMarks)
143  {
144  PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
145  Var *var;
146  char resname[32];
147  TargetEntry *tle;
148 
149  /* child rels use the same junk attrs as their parents */
150  if (rc->rti != rc->prti)
151  continue;
152 
153  if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
154  {
155  /* Need to fetch TID */
156  var = makeVar(rc->rti,
158  TIDOID,
159  -1,
160  InvalidOid,
161  0);
162  snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
163  tle = makeTargetEntry((Expr *) var,
164  list_length(tlist) + 1,
165  pstrdup(resname),
166  true);
167  tlist = lappend(tlist, tle);
168  }
169  if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
170  {
171  /* Need the whole row as a junk var */
172  var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
173  rc->rti,
174  0,
175  false);
176  snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
177  tle = makeTargetEntry((Expr *) var,
178  list_length(tlist) + 1,
179  pstrdup(resname),
180  true);
181  tlist = lappend(tlist, tle);
182  }
183 
184  /* If parent of inheritance tree, always fetch the tableoid too. */
185  if (rc->isParent)
186  {
187  var = makeVar(rc->rti,
189  OIDOID,
190  -1,
191  InvalidOid,
192  0);
193  snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
194  tle = makeTargetEntry((Expr *) var,
195  list_length(tlist) + 1,
196  pstrdup(resname),
197  true);
198  tlist = lappend(tlist, tle);
199  }
200  }
201 
202  /*
203  * If the query has a RETURNING list, add resjunk entries for any Vars
204  * used in RETURNING that belong to other relations. We need to do this
205  * to make these Vars available for the RETURNING calculation. Vars that
206  * belong to the result rel don't need to be added, because they will be
207  * made to refer to the actual heap tuple.
208  */
209  if (parse->returningList && list_length(parse->rtable) > 1)
210  {
211  List *vars;
212  ListCell *l;
213 
214  vars = pull_var_clause((Node *) parse->returningList,
218  foreach(l, vars)
219  {
220  Var *var = (Var *) lfirst(l);
221  TargetEntry *tle;
222 
223  if (IsA(var, Var) &&
224  var->varno == result_relation)
225  continue; /* don't need it */
226 
227  if (tlist_member((Expr *) var, tlist))
228  continue; /* already got it */
229 
230  tle = makeTargetEntry((Expr *) var,
231  list_length(tlist) + 1,
232  NULL,
233  true);
234 
235  tlist = lappend(tlist, tle);
236  }
237  list_free(vars);
238  }
239 
240  root->processed_tlist = tlist;
241 
242  if (target_relation)
243  table_close(target_relation, NoLock);
244 }
int varno
Definition: primnodes.h:189
List * rowMarks
Definition: pathnodes.h:288
List * extract_update_targetlist_colnos(List *tlist)
Definition: preptlist.c:261
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
Query * parse
Definition: pathnodes.h:162
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
char * pstrdup(const char *in)
Definition: mcxt.c:1299
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
int resultRelation
Definition: parsenodes.h:130
Definition: nodes.h:536
Index prti
Definition: plannodes.h:1121
List * pull_var_clause(Node *node, int flags)
Definition: var.c:597
Definition: primnodes.h:186
Index rowmarkId
Definition: plannodes.h:1122
List * targetList
Definition: parsenodes.h:150
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
static List * expand_insert_targetlist(List *tlist, Relation rel)
Definition: preptlist.c:295
#define NoLock
Definition: lockdefs.h:34
Var * makeWholeRowVar(RangeTblEntry *rte, int varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:133
#define TableOidAttributeNumber
Definition: sysattr.h:26
int allMarkTypes
Definition: plannodes.h:1124
List * returningList
Definition: parsenodes.h:156
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
List * lappend(List *list, void *datum)
Definition: list.c:336
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:190
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:68
#define InvalidOid
Definition: postgres_ext.h:36
CmdType commandType
Definition: parsenodes.h:120
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:1007
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:189
void list_free(List *list)
Definition: list.c:1391
#define elog(elevel,...)
Definition: elog.h:232
bool isParent
Definition: plannodes.h:1127
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
List * processed_tlist
Definition: pathnodes.h:321
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: regcomp.c:237
Definition: pg_list.h:50
#define snprintf
Definition: port.h:217
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:187
CmdType
Definition: nodes.h:680
void add_row_identity_columns(PlannerInfo *root, Index rtindex, RangeTblEntry *target_rte, Relation target_relation)
Definition: appendinfo.c:857
List * update_colnos
Definition: pathnodes.h:329
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:673

◆ pull_up_sublinks()

void pull_up_sublinks ( PlannerInfo root)

Definition at line 208 of file prepjointree.c.

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

Referenced by pull_up_simple_subquery(), and subquery_planner().

209 {
210  Node *jtnode;
211  Relids relids;
212 
213  /* Begin recursion through the jointree */
214  jtnode = pull_up_sublinks_jointree_recurse(root,
215  (Node *) root->parse->jointree,
216  &relids);
217 
218  /*
219  * root->parse->jointree must always be a FromExpr, so insert a dummy one
220  * if we got a bare RangeTblRef or JoinExpr out of the recursion.
221  */
222  if (IsA(jtnode, FromExpr))
223  root->parse->jointree = (FromExpr *) jtnode;
224  else
225  root->parse->jointree = makeFromExpr(list_make1(jtnode), NULL);
226 }
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:285
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
Query * parse
Definition: pathnodes.h:162
FromExpr * jointree
Definition: parsenodes.h:148
Definition: nodes.h:536
#define list_make1(x1)
Definition: pg_list.h:206
static Node * pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode, Relids *relids)
Definition: prepjointree.c:235

◆ pull_up_subqueries()

void pull_up_subqueries ( PlannerInfo root)

Definition at line 680 of file prepjointree.c.

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

Referenced by pull_up_simple_subquery(), and subquery_planner().

681 {
682  /* Top level of jointree must always be a FromExpr */
683  Assert(IsA(root->parse->jointree, FromExpr));
684  /* Recursion starts with no containing join nor appendrel */
685  root->parse->jointree = (FromExpr *)
687  NULL, NULL, NULL);
688  /* We should still have a FromExpr */
689  Assert(IsA(root->parse->jointree, FromExpr));
690 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
Query * parse
Definition: pathnodes.h:162
FromExpr * jointree
Definition: parsenodes.h:148
static Node * pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode, JoinExpr *lowest_outer_join, JoinExpr *lowest_nulling_outer_join, AppendRelInfo *containing_appendrel)
Definition: prepjointree.c:730
Definition: nodes.h:536
#define Assert(condition)
Definition: c.h:804

◆ reduce_outer_joins()

void reduce_outer_joins ( PlannerInfo root)

Definition at line 2584 of file prepjointree.c.

References reduce_outer_joins_state::contains_outer, elog, ERROR, Query::jointree, NIL, PlannerInfo::parse, reduce_outer_joins_pass1(), and reduce_outer_joins_pass2().

Referenced by subquery_planner().

2585 {
2587 
2588  /*
2589  * To avoid doing strictness checks on more quals than necessary, we want
2590  * to stop descending the jointree as soon as there are no outer joins
2591  * below our current point. This consideration forces a two-pass process.
2592  * The first pass gathers information about which base rels appear below
2593  * each side of each join clause, and about whether there are outer
2594  * join(s) below each side of each join clause. The second pass examines
2595  * qual clauses and changes join types as it descends the tree.
2596  */
2597  state = reduce_outer_joins_pass1((Node *) root->parse->jointree);
2598 
2599  /* planner.c shouldn't have called me if no outer joins */
2600  if (state == NULL || !state->contains_outer)
2601  elog(ERROR, "so where are the outer joins?");
2602 
2604  state, root, NULL, NIL, NIL);
2605 }
#define NIL
Definition: pg_list.h:65
Query * parse
Definition: pathnodes.h:162
FromExpr * jointree
Definition: parsenodes.h:148
Definition: nodes.h:536
#define ERROR
Definition: elog.h:46
static reduce_outer_joins_state * reduce_outer_joins_pass1(Node *jtnode)
Definition: regguts.h:317
#define elog(elevel,...)
Definition: elog.h:232
static void reduce_outer_joins_pass2(Node *jtnode, reduce_outer_joins_state *state, PlannerInfo *root, Relids nonnullable_rels, List *nonnullable_vars, List *forced_null_vars)

◆ remove_useless_result_rtes()

void remove_useless_result_rtes ( PlannerInfo root)

Definition at line 2997 of file prepjointree.c.

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

Referenced by subquery_planner().

2998 {
2999  ListCell *cell;
3000 
3001  /* Top level of jointree must always be a FromExpr */
3002  Assert(IsA(root->parse->jointree, FromExpr));
3003  /* Recurse ... */
3004  root->parse->jointree = (FromExpr *)
3006  /* We should still have a FromExpr */
3007  Assert(IsA(root->parse->jointree, FromExpr));
3008 
3009  /*
3010  * Remove any PlanRowMark referencing an RTE_RESULT RTE. We obviously
3011  * must do that for any RTE_RESULT that we just removed. But one for a
3012  * RTE that we did not remove can be dropped anyway: since the RTE has
3013  * only one possible output row, there is no need for EPQ to mark and
3014  * restore that row.
3015  *
3016  * It's necessary, not optional, to remove the PlanRowMark for a surviving
3017  * RTE_RESULT RTE; otherwise we'll generate a whole-row Var for the
3018  * RTE_RESULT, which the executor has no support for.
3019  */
3020  foreach(cell, root->rowMarks)
3021  {
3022  PlanRowMark *rc = (PlanRowMark *) lfirst(cell);
3023 
3024  if (rt_fetch(rc->rti, root->parse->rtable)->rtekind == RTE_RESULT)
3025  root->rowMarks = foreach_delete_current(root->rowMarks, cell);
3026  }
3027 }
List * rowMarks
Definition: pathnodes.h:288
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
Query * parse
Definition: pathnodes.h:162
FromExpr * jointree
Definition: parsenodes.h:148
Definition: nodes.h:536
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
List * rtable
Definition: parsenodes.h:147
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
static Node * remove_useless_results_recurse(PlannerInfo *root, Node *jtnode)

◆ replace_empty_jointree()

void replace_empty_jointree ( Query parse)

Definition at line 150 of file prepjointree.c.

References RangeTblEntry::eref, FromExpr::fromlist, Query::jointree, lappend(), list_length(), list_make1, makeAlias(), makeNode, NIL, Query::rtable, RTE_RESULT, RangeTblEntry::rtekind, RangeTblRef::rtindex, and Query::setOperations.

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

151 {
152  RangeTblEntry *rte;
153  Index rti;
154  RangeTblRef *rtr;
155 
156  /* Nothing to do if jointree is already nonempty */
157  if (parse->jointree->fromlist != NIL)
158  return;
159 
160  /* We mustn't change it in the top level of a setop tree, either */
161  if (parse->setOperations)
162  return;
163 
164  /* Create suitable RTE */
165  rte = makeNode(RangeTblEntry);
166  rte->rtekind = RTE_RESULT;
167  rte->eref = makeAlias("*RESULT*", NIL);
168 
169  /* Add it to rangetable */
170  parse->rtable = lappend(parse->rtable, rte);
171  rti = list_length(parse->rtable);
172 
173  /* And jam a reference into the jointree */
174  rtr = makeNode(RangeTblRef);
175  rtr->rtindex = rti;
176  parse->jointree->fromlist = list_make1(rtr);
177 }
#define NIL
Definition: pg_list.h:65
FromExpr * jointree
Definition: parsenodes.h:148
List * fromlist
Definition: primnodes.h:1564
#define list_make1(x1)
Definition: pg_list.h:206
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:387
List * rtable
Definition: parsenodes.h:147
List * lappend(List *list, void *datum)
Definition: list.c:336
unsigned int Index
Definition: c.h:549
#define makeNode(_type_)
Definition: nodes.h:584
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:1007
Node * setOperations
Definition: parsenodes.h:177
Alias * eref
Definition: parsenodes.h:1153