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)
 
Listpreprocess_targetlist (PlannerInfo *root)
 
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

◆ flatten_simple_union_all()

void flatten_simple_union_all ( PlannerInfo root)

Definition at line 2453 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().

2454 {
2455  Query *parse = root->parse;
2456  SetOperationStmt *topop;
2457  Node *leftmostjtnode;
2458  int leftmostRTI;
2459  RangeTblEntry *leftmostRTE;
2460  int childRTI;
2461  RangeTblEntry *childRTE;
2462  RangeTblRef *rtr;
2463 
2464  /* Shouldn't be called unless query has setops */
2465  topop = castNode(SetOperationStmt, parse->setOperations);
2466  Assert(topop);
2467 
2468  /* Can't optimize away a recursive UNION */
2469  if (root->hasRecursion)
2470  return;
2471 
2472  /*
2473  * Recursively check the tree of set operations. If not all UNION ALL
2474  * with identical column types, punt.
2475  */
2476  if (!is_simple_union_all_recurse((Node *) topop, parse, topop->colTypes))
2477  return;
2478 
2479  /*
2480  * Locate the leftmost leaf query in the setops tree. The upper query's
2481  * Vars all refer to this RTE (see transformSetOperationStmt).
2482  */
2483  leftmostjtnode = topop->larg;
2484  while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt))
2485  leftmostjtnode = ((SetOperationStmt *) leftmostjtnode)->larg;
2486  Assert(leftmostjtnode && IsA(leftmostjtnode, RangeTblRef));
2487  leftmostRTI = ((RangeTblRef *) leftmostjtnode)->rtindex;
2488  leftmostRTE = rt_fetch(leftmostRTI, parse->rtable);
2489  Assert(leftmostRTE->rtekind == RTE_SUBQUERY);
2490 
2491  /*
2492  * Make a copy of the leftmost RTE and add it to the rtable. This copy
2493  * will represent the leftmost leaf query in its capacity as a member of
2494  * the appendrel. The original will represent the appendrel as a whole.
2495  * (We must do things this way because the upper query's Vars have to be
2496  * seen as referring to the whole appendrel.)
2497  */
2498  childRTE = copyObject(leftmostRTE);
2499  parse->rtable = lappend(parse->rtable, childRTE);
2500  childRTI = list_length(parse->rtable);
2501 
2502  /* Modify the setops tree to reference the child copy */
2503  ((RangeTblRef *) leftmostjtnode)->rtindex = childRTI;
2504 
2505  /* Modify the formerly-leftmost RTE to mark it as an appendrel parent */
2506  leftmostRTE->inh = true;
2507 
2508  /*
2509  * Form a RangeTblRef for the appendrel, and insert it into FROM. The top
2510  * Query of a setops tree should have had an empty FromClause initially.
2511  */
2512  rtr = makeNode(RangeTblRef);
2513  rtr->rtindex = leftmostRTI;
2514  Assert(parse->jointree->fromlist == NIL);
2515  parse->jointree->fromlist = list_make1(rtr);
2516 
2517  /*
2518  * Now pretend the query has no setops. We must do this before trying to
2519  * do subquery pullup, because of Assert in pull_up_simple_subquery.
2520  */
2521  parse->setOperations = NULL;
2522 
2523  /*
2524  * Build AppendRelInfo information, and apply pull_up_subqueries to the
2525  * leaf queries of the UNION ALL. (We must do that now because they
2526  * weren't previously referenced by the jointree, and so were missed by
2527  * the main invocation of pull_up_subqueries.)
2528  */
2529  pull_up_union_leaf_queries((Node *) topop, root, leftmostRTI, parse, 0);
2530 }
#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:584
Query * parse
Definition: pathnodes.h:173
FromExpr * jointree
Definition: parsenodes.h:138
#define castNode(_type_, nodeptr)
Definition: nodes.h:602
Definition: nodes.h:533
static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
List * fromlist
Definition: primnodes.h:1534
bool hasRecursion
Definition: pathnodes.h:345
#define list_make1(x1)
Definition: pg_list.h:206
List * rtable
Definition: parsenodes.h:137
#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:581
#define Assert(condition)
Definition: c.h:804
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:981
Node * setOperations
Definition: parsenodes.h:166
#define copyObject(obj)
Definition: nodes.h:649
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:666

◆ get_agg_clause_costs()

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

Definition at line 542 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().

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

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

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

Referenced by alias_relid_set().

3571 {
3572  Node *jtnode;
3573 
3574  jtnode = find_jointree_node_for_rel((Node *) query->jointree,
3575  joinrelid);
3576  if (!jtnode)
3577  elog(ERROR, "could not find join node %d", joinrelid);
3578  return get_relids_in_jointree(jtnode, false);
3579 }
FromExpr * jointree
Definition: parsenodes.h:138
Definition: nodes.h:533
static Node * find_jointree_node_for_rel(Node *jtnode, int relid)
#define ERROR
Definition: elog.h:45
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
#define elog(elevel,...)
Definition: elog.h:227

◆ get_relids_in_jointree()

Relids get_relids_in_jointree ( Node jtnode,
bool  include_joins 
)

Definition at line 3526 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().

3527 {
3528  Relids result = NULL;
3529 
3530  if (jtnode == NULL)
3531  return result;
3532  if (IsA(jtnode, RangeTblRef))
3533  {
3534  int varno = ((RangeTblRef *) jtnode)->rtindex;
3535 
3536  result = bms_make_singleton(varno);
3537  }
3538  else if (IsA(jtnode, FromExpr))
3539  {
3540  FromExpr *f = (FromExpr *) jtnode;
3541  ListCell *l;
3542 
3543  foreach(l, f->fromlist)
3544  {
3545  result = bms_join(result,
3547  include_joins));
3548  }
3549  }
3550  else if (IsA(jtnode, JoinExpr))
3551  {
3552  JoinExpr *j = (JoinExpr *) jtnode;
3553 
3554  result = get_relids_in_jointree(j->larg, include_joins);
3555  result = bms_join(result,
3556  get_relids_in_jointree(j->rarg, include_joins));
3557  if (include_joins && j->rtindex)
3558  result = bms_add_member(result, j->rtindex);
3559  }
3560  else
3561  elog(ERROR, "unrecognized node type: %d",
3562  (int) nodeTag(jtnode));
3563  return result;
3564 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:584
List * fromlist
Definition: primnodes.h:1534
Node * larg
Definition: primnodes.h:1514
#define ERROR
Definition: elog.h:45
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:1515
#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:538
#define elog(elevel,...)
Definition: elog.h:227
int rtindex
Definition: primnodes.h:1519

◆ 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:433
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:584
Query * parse
Definition: pathnodes.h:173
bool ec_merging_done
Definition: pathnodes.h:262
FromExpr * jointree
Definition: parsenodes.h:138
#define castNode(_type_, nodeptr)
Definition: nodes.h:602
Definition: nodes.h:533
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:1534
bool hasRecursion
Definition: pathnodes.h:345
Node * quals
Definition: primnodes.h:1535
List * windowClause
Definition: parsenodes.h:154
List * targetList
Definition: parsenodes.h:140
List * distinctClause
Definition: parsenodes.h:156
RangeTblEntry ** simple_rte_array
Definition: pathnodes.h:205
#define Assert(condition)
Definition: c.h:804
List * eq_classes
Definition: pathnodes.h:260
void setup_simple_rel_arrays(PlannerInfo *root)
Definition: relnode.c:83
Node * setOperations
Definition: parsenodes.h:166
Query * subquery
Definition: parsenodes.h:1016
List * groupClause
Definition: parsenodes.h:148
Node * havingQual
Definition: parsenodes.h:152
List * processed_tlist
Definition: pathnodes.h:319
Definition: pg_list.h:50
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:666

◆ 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:173
Definition: nodes.h:533
Query * inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
Definition: clauses.c:4589
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2022
bool funcordinality
Definition: parsenodes.h:1069
List * rtable
Definition: parsenodes.h:137
bool security_barrier
Definition: parsenodes.h:1017
#define lfirst(lc)
Definition: pg_list.h:169
List * functions
Definition: parsenodes.h:1068
RTEKind rtekind
Definition: parsenodes.h:981
Query * subquery
Definition: parsenodes.h:1016
Definition: pg_list.h:50

◆ preprocess_targetlist()

List* preprocess_targetlist ( PlannerInfo root)

Definition at line 69 of file preptlist.c.

References PlanRowMark::allMarkTypes, Assert, CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, Query::commandType, elog, ERROR, expand_targetlist(), InvalidOid, IsA, PlanRowMark::isParent, lappend(), lfirst, list_free(), list_length(), makeTargetEntry(), makeVar(), makeWholeRowVar(), NoLock, Query::onConflict, OnConflictExpr::onConflictSet, parse(), PlannerInfo::parse, PlanRowMark::prti, pstrdup(), pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, RangeTblEntry::relid, Query::resultRelation, Query::returningList, rewriteTargetListUD(), 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(), and Var::varno.

Referenced by grouping_planner(), and inheritance_planner().

70 {
71  Query *parse = root->parse;
72  int result_relation = parse->resultRelation;
73  List *range_table = parse->rtable;
74  CmdType command_type = parse->commandType;
75  RangeTblEntry *target_rte = NULL;
76  Relation target_relation = NULL;
77  List *tlist;
78  ListCell *lc;
79 
80  /*
81  * If there is a result relation, open it so we can look for missing
82  * columns and so on. We assume that previous code already acquired at
83  * least AccessShareLock on the relation, so we need no lock here.
84  */
85  if (result_relation)
86  {
87  target_rte = rt_fetch(result_relation, range_table);
88 
89  /*
90  * Sanity check: it'd better be a real relation not, say, a subquery.
91  * Else parser or rewriter messed up.
92  */
93  if (target_rte->rtekind != RTE_RELATION)
94  elog(ERROR, "result relation must be a regular relation");
95 
96  target_relation = table_open(target_rte->relid, NoLock);
97  }
98  else
99  Assert(command_type == CMD_SELECT);
100 
101  /*
102  * For UPDATE/DELETE, add any junk column(s) needed to allow the executor
103  * to identify the rows to be updated or deleted. Note that this step
104  * scribbles on parse->targetList, which is not very desirable, but we
105  * keep it that way to avoid changing APIs used by FDWs.
106  */
107  if (command_type == CMD_UPDATE || command_type == CMD_DELETE)
108  rewriteTargetListUD(parse, target_rte, target_relation);
109 
110  /*
111  * for heap_form_tuple to work, the targetlist must match the exact order
112  * of the attributes. We also need to fill in any missing attributes. -ay
113  * 10/94
114  */
115  tlist = parse->targetList;
116  if (command_type == CMD_INSERT || command_type == CMD_UPDATE)
117  tlist = expand_targetlist(tlist, command_type,
118  result_relation, target_relation);
119 
120  /*
121  * Add necessary junk columns for rowmarked rels. These values are needed
122  * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
123  * rechecking. See comments for PlanRowMark in plannodes.h. If you
124  * change this stanza, see also expand_inherited_rtentry(), which has to
125  * be able to add on junk columns equivalent to these.
126  */
127  foreach(lc, root->rowMarks)
128  {
129  PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
130  Var *var;
131  char resname[32];
132  TargetEntry *tle;
133 
134  /* child rels use the same junk attrs as their parents */
135  if (rc->rti != rc->prti)
136  continue;
137 
138  if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
139  {
140  /* Need to fetch TID */
141  var = makeVar(rc->rti,
143  TIDOID,
144  -1,
145  InvalidOid,
146  0);
147  snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
148  tle = makeTargetEntry((Expr *) var,
149  list_length(tlist) + 1,
150  pstrdup(resname),
151  true);
152  tlist = lappend(tlist, tle);
153  }
154  if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
155  {
156  /* Need the whole row as a junk var */
157  var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
158  rc->rti,
159  0,
160  false);
161  snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
162  tle = makeTargetEntry((Expr *) var,
163  list_length(tlist) + 1,
164  pstrdup(resname),
165  true);
166  tlist = lappend(tlist, tle);
167  }
168 
169  /* If parent of inheritance tree, always fetch the tableoid too. */
170  if (rc->isParent)
171  {
172  var = makeVar(rc->rti,
174  OIDOID,
175  -1,
176  InvalidOid,
177  0);
178  snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
179  tle = makeTargetEntry((Expr *) var,
180  list_length(tlist) + 1,
181  pstrdup(resname),
182  true);
183  tlist = lappend(tlist, tle);
184  }
185  }
186 
187  /*
188  * If the query has a RETURNING list, add resjunk entries for any Vars
189  * used in RETURNING that belong to other relations. We need to do this
190  * to make these Vars available for the RETURNING calculation. Vars that
191  * belong to the result rel don't need to be added, because they will be
192  * made to refer to the actual heap tuple.
193  */
194  if (parse->returningList && list_length(parse->rtable) > 1)
195  {
196  List *vars;
197  ListCell *l;
198 
199  vars = pull_var_clause((Node *) parse->returningList,
203  foreach(l, vars)
204  {
205  Var *var = (Var *) lfirst(l);
206  TargetEntry *tle;
207 
208  if (IsA(var, Var) &&
209  var->varno == result_relation)
210  continue; /* don't need it */
211 
212  if (tlist_member((Expr *) var, tlist))
213  continue; /* already got it */
214 
215  tle = makeTargetEntry((Expr *) var,
216  list_length(tlist) + 1,
217  NULL,
218  true);
219 
220  tlist = lappend(tlist, tle);
221  }
222  list_free(vars);
223  }
224 
225  /*
226  * If there's an ON CONFLICT UPDATE clause, preprocess its targetlist too
227  * while we have the relation open.
228  */
229  if (parse->onConflict)
230  parse->onConflict->onConflictSet =
232  CMD_UPDATE,
233  result_relation,
234  target_relation);
235 
236  if (target_relation)
237  table_close(target_relation, NoLock);
238 
239  return tlist;
240 }
List * rowMarks
Definition: pathnodes.h:286
#define IsA(nodeptr, _type_)
Definition: nodes.h:584
Query * parse
Definition: pathnodes.h:173
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
OnConflictExpr * onConflict
Definition: parsenodes.h:144
char * pstrdup(const char *in)
Definition: mcxt.c:1187
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:533
Var * makeWholeRowVar(RangeTblEntry *rte, Index varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:133
Index prti
Definition: plannodes.h:1091
List * pull_var_clause(Node *node, int flags)
Definition: var.c:562
Definition: primnodes.h:181
Index rowmarkId
Definition: plannodes.h:1092
List * targetList
Definition: parsenodes.h:140
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:45
#define NoLock
Definition: lockdefs.h:34
#define TableOidAttributeNumber
Definition: sysattr.h:26
int allMarkTypes
Definition: plannodes.h:1094
List * returningList
Definition: parsenodes.h:146
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
List * lappend(List *list, void *datum)
Definition: list.c:336
Index varno
Definition: primnodes.h:184
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:187
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:68
static List * expand_targetlist(List *tlist, int command_type, Index result_relation, Relation rel)
Definition: preptlist.c:256
#define InvalidOid
Definition: postgres_ext.h:36
CmdType commandType
Definition: parsenodes.h:112
#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:981
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:186
void list_free(List *list)
Definition: list.c:1391
#define elog(elevel,...)
Definition: elog.h:227
List * onConflictSet
Definition: primnodes.h:1559
bool isParent
Definition: plannodes.h:1097
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: regcomp.c:238
Definition: pg_list.h:50
#define snprintf
Definition: port.h:216
void rewriteTargetListUD(Query *parsetree, RangeTblEntry *target_rte, Relation target_relation)
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:184
CmdType
Definition: nodes.h:676
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:666

◆ 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:584
Query * parse
Definition: pathnodes.h:173
FromExpr * jointree
Definition: parsenodes.h:138
Definition: nodes.h:533
#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:584
Query * parse
Definition: pathnodes.h:173
FromExpr * jointree
Definition: parsenodes.h:138
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:533
#define Assert(condition)
Definition: c.h:804

◆ reduce_outer_joins()

void reduce_outer_joins ( PlannerInfo root)

Definition at line 2571 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().

2572 {
2574 
2575  /*
2576  * To avoid doing strictness checks on more quals than necessary, we want
2577  * to stop descending the jointree as soon as there are no outer joins
2578  * below our current point. This consideration forces a two-pass process.
2579  * The first pass gathers information about which base rels appear below
2580  * each side of each join clause, and about whether there are outer
2581  * join(s) below each side of each join clause. The second pass examines
2582  * qual clauses and changes join types as it descends the tree.
2583  */
2584  state = reduce_outer_joins_pass1((Node *) root->parse->jointree);
2585 
2586  /* planner.c shouldn't have called me if no outer joins */
2587  if (state == NULL || !state->contains_outer)
2588  elog(ERROR, "so where are the outer joins?");
2589 
2591  state, root, NULL, NIL, NIL);
2592 }
#define NIL
Definition: pg_list.h:65
Query * parse
Definition: pathnodes.h:173
FromExpr * jointree
Definition: parsenodes.h:138
Definition: nodes.h:533
#define ERROR
Definition: elog.h:45
static reduce_outer_joins_state * reduce_outer_joins_pass1(Node *jtnode)
Definition: regguts.h:317
#define elog(elevel,...)
Definition: elog.h:227
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 2984 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().

2985 {
2986  ListCell *cell;
2987 
2988  /* Top level of jointree must always be a FromExpr */
2989  Assert(IsA(root->parse->jointree, FromExpr));
2990  /* Recurse ... */
2991  root->parse->jointree = (FromExpr *)
2993  /* We should still have a FromExpr */
2994  Assert(IsA(root->parse->jointree, FromExpr));
2995 
2996  /*
2997  * Remove any PlanRowMark referencing an RTE_RESULT RTE. We obviously
2998  * must do that for any RTE_RESULT that we just removed. But one for a
2999  * RTE that we did not remove can be dropped anyway: since the RTE has
3000  * only one possible output row, there is no need for EPQ to mark and
3001  * restore that row.
3002  *
3003  * It's necessary, not optional, to remove the PlanRowMark for a surviving
3004  * RTE_RESULT RTE; otherwise we'll generate a whole-row Var for the
3005  * RTE_RESULT, which the executor has no support for.
3006  */
3007  foreach(cell, root->rowMarks)
3008  {
3009  PlanRowMark *rc = (PlanRowMark *) lfirst(cell);
3010 
3011  if (rt_fetch(rc->rti, root->parse->rtable)->rtekind == RTE_RESULT)
3012  root->rowMarks = foreach_delete_current(root->rowMarks, cell);
3013  }
3014 }
List * rowMarks
Definition: pathnodes.h:286
#define IsA(nodeptr, _type_)
Definition: nodes.h:584
Query * parse
Definition: pathnodes.h:173
FromExpr * jointree
Definition: parsenodes.h:138
Definition: nodes.h:533
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
List * rtable
Definition: parsenodes.h:137
#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:138
List * fromlist
Definition: primnodes.h:1534
#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:137
List * lappend(List *list, void *datum)
Definition: list.c:336
unsigned int Index
Definition: c.h:549
#define makeNode(_type_)
Definition: nodes.h:581
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:981
Node * setOperations
Definition: parsenodes.h:166
Alias * eref
Definition: parsenodes.h:1120