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

Go to the source code of this file.

Typedefs

typedef PlannedStmt *(* planner_hook_type) (Query *parse, int cursorOptions, ParamListInfo boundParams)
 
typedef void(* create_upper_paths_hook_type) (PlannerInfo *root, UpperRelationKind stage, RelOptInfo *input_rel, RelOptInfo *output_rel)
 

Functions

PlannedStmtplanner (Query *parse, int cursorOptions, ParamListInfo boundParams)
 
PlannedStmtstandard_planner (Query *parse, int cursorOptions, ParamListInfo boundParams)
 
PlannerInfosubquery_planner (PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, bool hasRecursion, double tuple_fraction)
 
bool is_dummy_plan (Plan *plan)
 
RowMarkType select_rowmark_type (RangeTblEntry *rte, LockClauseStrength strength)
 
void mark_partial_aggref (Aggref *agg, AggSplit aggsplit)
 
Pathget_cheapest_fractional_path (RelOptInfo *rel, double tuple_fraction)
 
Exprexpression_planner (Expr *expr)
 
Exprpreprocess_phv_expression (PlannerInfo *root, Expr *expr)
 
bool plan_cluster_use_sort (Oid tableOid, Oid indexOid)
 
Listget_partitioned_child_rels (PlannerInfo *root, Index rti)
 
Listget_partitioned_child_rels_for_join (PlannerInfo *root, Relids join_relids)
 

Variables

PGDLLIMPORT planner_hook_type planner_hook
 
PGDLLIMPORT create_upper_paths_hook_type create_upper_paths_hook
 

Typedef Documentation

◆ create_upper_paths_hook_type

typedef void(* create_upper_paths_hook_type) (PlannerInfo *root, UpperRelationKind stage, RelOptInfo *input_rel, RelOptInfo *output_rel)

Definition at line 28 of file planner.h.

◆ planner_hook_type

typedef PlannedStmt*(* planner_hook_type) (Query *parse, int cursorOptions, ParamListInfo boundParams)

Definition at line 22 of file planner.h.

Function Documentation

◆ expression_planner()

Expr* expression_planner ( Expr expr)

Definition at line 6026 of file planner.c.

References eval_const_expressions(), and fix_opfuncids().

Referenced by ATExecAddColumn(), ATPrepAlterColumnType(), BeginCopyFrom(), CheckMutability(), ComputePartitionAttrs(), ExecPrepareCheck(), ExecPrepareExpr(), ExecPrepareQual(), get_cast_hashentry(), load_domaintype_info(), slot_fill_defaults(), and transformPartitionBoundValue().

6027 {
6028  Node *result;
6029 
6030  /*
6031  * Convert named-argument function calls, insert default arguments and
6032  * simplify constant subexprs
6033  */
6034  result = eval_const_expressions(NULL, (Node *) expr);
6035 
6036  /* Fill in opfuncid values if missing */
6037  fix_opfuncids(result);
6038 
6039  return (Expr *) result;
6040 }
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1582
Definition: nodes.h:512
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2459

◆ get_cheapest_fractional_path()

Path* get_cheapest_fractional_path ( RelOptInfo rel,
double  tuple_fraction 
)

Definition at line 5873 of file planner.c.

References RelOptInfo::cheapest_total_path, compare_fractional_path_costs(), lfirst, RelOptInfo::pathlist, and Path::rows.

Referenced by make_subplan(), recurse_set_operations(), and standard_planner().

5874 {
5875  Path *best_path = rel->cheapest_total_path;
5876  ListCell *l;
5877 
5878  /* If all tuples will be retrieved, just return the cheapest-total path */
5879  if (tuple_fraction <= 0.0)
5880  return best_path;
5881 
5882  /* Convert absolute # of tuples to a fraction; no need to clamp to 0..1 */
5883  if (tuple_fraction >= 1.0 && best_path->rows > 0)
5884  tuple_fraction /= best_path->rows;
5885 
5886  foreach(l, rel->pathlist)
5887  {
5888  Path *path = (Path *) lfirst(l);
5889 
5890  if (path == rel->cheapest_total_path ||
5891  compare_fractional_path_costs(best_path, path, tuple_fraction) <= 0)
5892  continue;
5893 
5894  best_path = path;
5895  }
5896 
5897  return best_path;
5898 }
struct Path * cheapest_total_path
Definition: relation.h:603
#define lfirst(lc)
Definition: pg_list.h:106
double rows
Definition: relation.h:1052
int compare_fractional_path_costs(Path *path1, Path *path2, double fraction)
Definition: pathnode.c:117
List * pathlist
Definition: relation.h:599

◆ get_partitioned_child_rels()

List* get_partitioned_child_rels ( PlannerInfo root,
Index  rti 
)

Definition at line 6164 of file planner.c.

References PartitionedChildRelInfo::child_rels, lfirst_node, NIL, PartitionedChildRelInfo::parent_relid, and PlannerInfo::pcinfo_list.

Referenced by add_paths_to_append_rel(), and inheritance_planner().

6165 {
6166  List *result = NIL;
6167  ListCell *l;
6168 
6169  foreach(l, root->pcinfo_list)
6170  {
6172 
6173  if (pc->parent_relid == rti)
6174  {
6175  result = pc->child_rels;
6176  break;
6177  }
6178  }
6179 
6180  return result;
6181 }
#define NIL
Definition: pg_list.h:69
#define lfirst_node(type, lc)
Definition: pg_list.h:109
List * pcinfo_list
Definition: relation.h:254
Definition: pg_list.h:45

◆ get_partitioned_child_rels_for_join()

List* get_partitioned_child_rels_for_join ( PlannerInfo root,
Relids  join_relids 
)

Definition at line 6189 of file planner.c.

References bms_is_member(), PartitionedChildRelInfo::child_rels, lfirst, list_concat(), list_copy(), NIL, PartitionedChildRelInfo::parent_relid, and PlannerInfo::pcinfo_list.

Referenced by add_paths_to_append_rel().

6190 {
6191  List *result = NIL;
6192  ListCell *l;
6193 
6194  foreach(l, root->pcinfo_list)
6195  {
6197 
6198  if (bms_is_member(pc->parent_relid, join_relids))
6199  result = list_concat(result, list_copy(pc->child_rels));
6200  }
6201 
6202  return result;
6203 }
#define NIL
Definition: pg_list.h:69
List * list_copy(const List *oldlist)
Definition: list.c:1160
List * list_concat(List *list1, List *list2)
Definition: list.c:321
#define lfirst(lc)
Definition: pg_list.h:106
List * pcinfo_list
Definition: relation.h:254
Definition: pg_list.h:45
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420

◆ is_dummy_plan()

bool is_dummy_plan ( Plan plan)

Definition at line 2383 of file planner.c.

References Const::constisnull, Const::constvalue, DatumGetBool, IsA, linitial, and list_length().

2384 {
2385  if (IsA(plan, Result))
2386  {
2387  List *rcqual = (List *) ((Result *) plan)->resconstantqual;
2388 
2389  if (list_length(rcqual) == 1)
2390  {
2391  Const *constqual = (Const *) linitial(rcqual);
2392 
2393  if (constqual && IsA(constqual, Const))
2394  {
2395  if (!constqual->constisnull &&
2396  !DatumGetBool(constqual->constvalue))
2397  return true;
2398  }
2399  }
2400  }
2401  return false;
2402 }
Datum constvalue
Definition: primnodes.h:196
#define IsA(nodeptr, _type_)
Definition: nodes.h:563
#define linitial(l)
Definition: pg_list.h:111
#define DatumGetBool(X)
Definition: postgres.h:399
static int list_length(const List *l)
Definition: pg_list.h:89
Definition: pg_list.h:45
bool constisnull
Definition: primnodes.h:197

◆ mark_partial_aggref()

void mark_partial_aggref ( Aggref agg,
AggSplit  aggsplit 
)

Definition at line 5322 of file planner.c.

References Aggref::aggsplit, AGGSPLIT_SIMPLE, Aggref::aggtranstype, Aggref::aggtype, Assert, BYTEAOID, DO_AGGSPLIT_SERIALIZE, DO_AGGSPLIT_SKIPFINAL, INTERNALOID, and OidIsValid.

Referenced by convert_combining_aggrefs(), and make_partial_grouping_target().

5323 {
5324  /* aggtranstype should be computed by this point */
5326  /* ... but aggsplit should still be as the parser left it */
5327  Assert(agg->aggsplit == AGGSPLIT_SIMPLE);
5328 
5329  /* Mark the Aggref with the intended partial-aggregation mode */
5330  agg->aggsplit = aggsplit;
5331 
5332  /*
5333  * Adjust result type if needed. Normally, a partial aggregate returns
5334  * the aggregate's transition type; but if that's INTERNAL and we're
5335  * serializing, it returns BYTEA instead.
5336  */
5337  if (DO_AGGSPLIT_SKIPFINAL(aggsplit))
5338  {
5339  if (agg->aggtranstype == INTERNALOID && DO_AGGSPLIT_SERIALIZE(aggsplit))
5340  agg->aggtype = BYTEAOID;
5341  else
5342  agg->aggtype = agg->aggtranstype;
5343  }
5344 }
#define OidIsValid(objectId)
Definition: c.h:586
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:773
#define INTERNALOID
Definition: pg_type.h:698
#define Assert(condition)
Definition: c.h:680
AggSplit aggsplit
Definition: primnodes.h:310
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:772
#define BYTEAOID
Definition: pg_type.h:292
Oid aggtranstype
Definition: primnodes.h:298
Oid aggtype
Definition: primnodes.h:295

◆ plan_cluster_use_sort()

bool plan_cluster_use_sort ( Oid  tableOid,
Oid  indexOid 
)

Definition at line 6055 of file planner.c.

References build_simple_rel(), CMD_SELECT, Query::commandType, cost_qual_eval(), cost_sort(), create_index_path(), create_seqscan_path(), CurrentMemoryContext, enable_indexscan, ForwardScanDirection, get_relation_data_width(), PlannerInfo::glob, RelOptInfo::indexlist, IndexOptInfo::indexoid, IndexOptInfo::indexprs, RangeTblEntry::inFromCl, RangeTblEntry::inh, RangeTblEntry::lateral, lfirst_node, list_make1, maintenance_work_mem, makeNode, NIL, RelOptInfo::pages, PlannerInfo::parse, IndexPath::path, QualCost::per_tuple, PlannerInfo::planner_cxt, PlannerInfo::query_level, RangeTblEntry::relid, RangeTblEntry::relkind, RELKIND_RELATION, RelOptInfo::reltarget, RelOptInfo::rows, Query::rtable, RTE_RELATION, RangeTblEntry::rtekind, setup_simple_rel_arrays(), QualCost::startup, Path::total_cost, PlannerInfo::total_table_pages, RelOptInfo::tuples, PathTarget::width, and PlannerInfo::wt_param_id.

Referenced by copy_heap_data().

6056 {
6057  PlannerInfo *root;
6058  Query *query;
6059  PlannerGlobal *glob;
6060  RangeTblEntry *rte;
6061  RelOptInfo *rel;
6062  IndexOptInfo *indexInfo;
6063  QualCost indexExprCost;
6064  Cost comparisonCost;
6065  Path *seqScanPath;
6066  Path seqScanAndSortPath;
6067  IndexPath *indexScanPath;
6068  ListCell *lc;
6069 
6070  /* We can short-circuit the cost comparison if indexscans are disabled */
6071  if (!enable_indexscan)
6072  return true; /* use sort */
6073 
6074  /* Set up mostly-dummy planner state */
6075  query = makeNode(Query);
6076  query->commandType = CMD_SELECT;
6077 
6078  glob = makeNode(PlannerGlobal);
6079 
6080  root = makeNode(PlannerInfo);
6081  root->parse = query;
6082  root->glob = glob;
6083  root->query_level = 1;
6085  root->wt_param_id = -1;
6086 
6087  /* Build a minimal RTE for the rel */
6088  rte = makeNode(RangeTblEntry);
6089  rte->rtekind = RTE_RELATION;
6090  rte->relid = tableOid;
6091  rte->relkind = RELKIND_RELATION; /* Don't be too picky. */
6092  rte->lateral = false;
6093  rte->inh = false;
6094  rte->inFromCl = true;
6095  query->rtable = list_make1(rte);
6096 
6097  /* Set up RTE/RelOptInfo arrays */
6099 
6100  /* Build RelOptInfo */
6101  rel = build_simple_rel(root, 1, NULL);
6102 
6103  /* Locate IndexOptInfo for the target index */
6104  indexInfo = NULL;
6105  foreach(lc, rel->indexlist)
6106  {
6107  indexInfo = lfirst_node(IndexOptInfo, lc);
6108  if (indexInfo->indexoid == indexOid)
6109  break;
6110  }
6111 
6112  /*
6113  * It's possible that get_relation_info did not generate an IndexOptInfo
6114  * for the desired index; this could happen if it's not yet reached its
6115  * indcheckxmin usability horizon, or if it's a system index and we're
6116  * ignoring system indexes. In such cases we should tell CLUSTER to not
6117  * trust the index contents but use seqscan-and-sort.
6118  */
6119  if (lc == NULL) /* not in the list? */
6120  return true; /* use sort */
6121 
6122  /*
6123  * Rather than doing all the pushups that would be needed to use
6124  * set_baserel_size_estimates, just do a quick hack for rows and width.
6125  */
6126  rel->rows = rel->tuples;
6127  rel->reltarget->width = get_relation_data_width(tableOid, NULL);
6128 
6129  root->total_table_pages = rel->pages;
6130 
6131  /*
6132  * Determine eval cost of the index expressions, if any. We need to
6133  * charge twice that amount for each tuple comparison that happens during
6134  * the sort, since tuplesort.c will have to re-evaluate the index
6135  * expressions each time. (XXX that's pretty inefficient...)
6136  */
6137  cost_qual_eval(&indexExprCost, indexInfo->indexprs, root);
6138  comparisonCost = 2.0 * (indexExprCost.startup + indexExprCost.per_tuple);
6139 
6140  /* Estimate the cost of seq scan + sort */
6141  seqScanPath = create_seqscan_path(root, rel, NULL, 0);
6142  cost_sort(&seqScanAndSortPath, root, NIL,
6143  seqScanPath->total_cost, rel->tuples, rel->reltarget->width,
6144  comparisonCost, maintenance_work_mem, -1.0);
6145 
6146  /* Estimate the cost of index scan */
6147  indexScanPath = create_index_path(root, indexInfo,
6148  NIL, NIL, NIL, NIL, NIL,
6149  ForwardScanDirection, false,
6150  NULL, 1.0, false);
6151 
6152  return (seqScanAndSortPath.total_cost < indexScanPath->path.total_cost);
6153 }
#define NIL
Definition: pg_list.h:69
Query * parse
Definition: relation.h:155
Path path
Definition: relation.h:1118
double tuples
Definition: relation.h:625
IndexPath * create_index_path(PlannerInfo *root, IndexOptInfo *index, List *indexclauses, List *indexclausecols, List *indexorderbys, List *indexorderbycols, List *pathkeys, ScanDirection indexscandir, bool indexonly, Relids required_outer, double loop_count, bool partial_path)
Definition: pathnode.c:1018
Cost startup
Definition: relation.h:45
#define list_make1(x1)
Definition: pg_list.h:139
Cost per_tuple
Definition: relation.h:46
int wt_param_id
Definition: relation.h:311
List * rtable
Definition: parsenodes.h:135
void cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root)
Definition: costsize.c:3672
#define lfirst_node(type, lc)
Definition: pg_list.h:109
PlannerGlobal * glob
Definition: relation.h:157
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition: relnode.c:96
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
double total_table_pages
Definition: relation.h:292
int32 get_relation_data_width(Oid relid, int32 *attr_widths)
Definition: plancat.c:1122
void cost_sort(Path *path, PlannerInfo *root, List *pathkeys, Cost input_cost, double tuples, int width, Cost comparison_cost, int sort_mem, double limit_tuples)
Definition: costsize.c:1648
List * indexlist
Definition: relation.h:622
double rows
Definition: relation.h:588
int maintenance_work_mem
Definition: globals.c:114
Cost total_cost
Definition: relation.h:1054
CmdType commandType
Definition: parsenodes.h:110
#define makeNode(_type_)
Definition: nodes.h:560
BlockNumber pages
Definition: relation.h:624
void setup_simple_rel_arrays(PlannerInfo *root)
Definition: relnode.c:67
Index query_level
Definition: relation.h:159
RTEKind rtekind
Definition: parsenodes.h:951
int width
Definition: relation.h:975
MemoryContext planner_cxt
Definition: relation.h:290
Oid indexoid
Definition: relation.h:719
#define RELKIND_RELATION
Definition: pg_class.h:160
struct PathTarget * reltarget
Definition: relation.h:596
bool enable_indexscan
Definition: costsize.c:119
Path * create_seqscan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer, int parallel_workers)
Definition: pathnode.c:948
double Cost
Definition: nodes.h:643
List * indexprs
Definition: relation.h:741

◆ planner()

PlannedStmt* planner ( Query parse,
int  cursorOptions,
ParamListInfo  boundParams 
)

Definition at line 204 of file planner.c.

References parse(), planner_hook, and standard_planner().

Referenced by pg_plan_query().

205 {
206  PlannedStmt *result;
207 
208  if (planner_hook)
209  result = (*planner_hook) (parse, cursorOptions, boundParams);
210  else
211  result = standard_planner(parse, cursorOptions, boundParams);
212  return result;
213 }
PlannedStmt * standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
Definition: planner.c:216
planner_hook_type planner_hook
Definition: planner.c:67
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:649

◆ preprocess_phv_expression()

Expr* preprocess_phv_expression ( PlannerInfo root,
Expr expr 
)

Definition at line 1054 of file planner.c.

References EXPRKIND_PHV, and preprocess_expression().

Referenced by extract_lateral_references().

1055 {
1056  return (Expr *) preprocess_expression(root, (Node *) expr, EXPRKIND_PHV);
1057 }
Definition: nodes.h:512
static Node * preprocess_expression(PlannerInfo *root, Node *expr, int kind)
Definition: planner.c:923
#define EXPRKIND_PHV
Definition: planner.c:82

◆ select_rowmark_type()

RowMarkType select_rowmark_type ( RangeTblEntry rte,
LockClauseStrength  strength 
)

Definition at line 2519 of file planner.c.

References elog, ERROR, GetFdwRoutineByRelId(), FdwRoutine::GetForeignRowMarkType, LCS_FORKEYSHARE, LCS_FORNOKEYUPDATE, LCS_FORSHARE, LCS_FORUPDATE, LCS_NONE, RangeTblEntry::relid, RangeTblEntry::relkind, RELKIND_FOREIGN_TABLE, ROW_MARK_COPY, ROW_MARK_EXCLUSIVE, ROW_MARK_KEYSHARE, ROW_MARK_NOKEYEXCLUSIVE, ROW_MARK_REFERENCE, ROW_MARK_SHARE, RTE_RELATION, and RangeTblEntry::rtekind.

Referenced by expand_single_inheritance_child(), and preprocess_rowmarks().

2520 {
2521  if (rte->rtekind != RTE_RELATION)
2522  {
2523  /* If it's not a table at all, use ROW_MARK_COPY */
2524  return ROW_MARK_COPY;
2525  }
2526  else if (rte->relkind == RELKIND_FOREIGN_TABLE)
2527  {
2528  /* Let the FDW select the rowmark type, if it wants to */
2529  FdwRoutine *fdwroutine = GetFdwRoutineByRelId(rte->relid);
2530 
2531  if (fdwroutine->GetForeignRowMarkType != NULL)
2532  return fdwroutine->GetForeignRowMarkType(rte, strength);
2533  /* Otherwise, use ROW_MARK_COPY by default */
2534  return ROW_MARK_COPY;
2535  }
2536  else
2537  {
2538  /* Regular table, apply the appropriate lock type */
2539  switch (strength)
2540  {
2541  case LCS_NONE:
2542 
2543  /*
2544  * We don't need a tuple lock, only the ability to re-fetch
2545  * the row.
2546  */
2547  return ROW_MARK_REFERENCE;
2548  break;
2549  case LCS_FORKEYSHARE:
2550  return ROW_MARK_KEYSHARE;
2551  break;
2552  case LCS_FORSHARE:
2553  return ROW_MARK_SHARE;
2554  break;
2555  case LCS_FORNOKEYUPDATE:
2556  return ROW_MARK_NOKEYEXCLUSIVE;
2557  break;
2558  case LCS_FORUPDATE:
2559  return ROW_MARK_EXCLUSIVE;
2560  break;
2561  }
2562  elog(ERROR, "unrecognized LockClauseStrength %d", (int) strength);
2563  return ROW_MARK_EXCLUSIVE; /* keep compiler quiet */
2564  }
2565 }
#define ERROR
Definition: elog.h:43
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
FdwRoutine * GetFdwRoutineByRelId(Oid relid)
Definition: foreign.c:372
GetForeignRowMarkType_function GetForeignRowMarkType
Definition: fdwapi.h:214
RTEKind rtekind
Definition: parsenodes.h:951
#define elog
Definition: elog.h:219

◆ standard_planner()

PlannedStmt* standard_planner ( Query parse,
int  cursorOptions,
ParamListInfo  boundParams 
)

Definition at line 216 of file planner.c.

References Assert, PlannerGlobal::boundParams, PlannedStmt::canSetTag, Query::canSetTag, CMD_SELECT, PlannedStmt::commandType, Query::commandType, create_plan(), CURSOR_OPT_FAST_PLAN, CURSOR_OPT_PARALLEL_OK, CURSOR_OPT_SCROLL, cursor_tuple_fraction, PlannedStmt::dependsOnRole, PlannerGlobal::dependsOnRole, DSM_IMPL_NONE, dynamic_shared_memory_type, ExecSupportsBackwardScan(), fetch_upper_rel(), PlannerGlobal::finalrowmarks, PlannerGlobal::finalrtable, forboth, force_parallel_mode, FORCE_PARALLEL_OFF, FORCE_PARALLEL_REGRESS, get_cheapest_fractional_path(), PlannerInfo::glob, PlannedStmt::hasModifyingCTE, Query::hasModifyingCTE, PlannedStmt::hasReturning, Plan::initPlan, PlannedStmt::invalItems, PlannerGlobal::invalItems, Gather::invisible, IsolationIsSerializable, IsParallelWorker, IsUnderPostmaster, PlannerGlobal::lastPHId, PlannerGlobal::lastPlanNodeId, PlannerGlobal::lastRowMarkId, Plan::lefttree, lfirst, lfirst_node, list_length(), makeNode, materialize_finished_plan(), max_parallel_hazard(), max_parallel_workers_per_gather, PlannerGlobal::maxParallelHazard, NIL, PlannedStmt::nonleafResultRelations, PlannerGlobal::nonleafResultRelations, Gather::num_workers, Plan::parallel_aware, Plan::parallel_safe, parallel_setup_cost, parallel_tuple_cost, PlannedStmt::parallelModeNeeded, PlannerGlobal::parallelModeNeeded, PlannerGlobal::parallelModeOK, PlannedStmt::paramExecTypes, PlannerGlobal::paramExecTypes, Gather::plan, Plan::plan_rows, Plan::plan_width, PlannedStmt::planTree, PROPARALLEL_UNSAFE, Plan::qual, PlannedStmt::queryId, Query::queryId, PlannedStmt::relationOids, PlannerGlobal::relationOids, Gather::rescan_param, PlannedStmt::resultRelations, PlannerGlobal::resultRelations, Query::returningList, PlannedStmt::rewindPlanIDs, PlannerGlobal::rewindPlanIDs, Plan::righttree, PlannedStmt::rootResultRelations, PlannerGlobal::rootResultRelations, PlannedStmt::rowMarks, PlannedStmt::rtable, set_plan_references(), Gather::single_copy, SS_finalize_plan(), Plan::startup_cost, PlannedStmt::stmt_len, Query::stmt_len, PlannedStmt::stmt_location, Query::stmt_location, PlannedStmt::subplans, PlannerGlobal::subplans, subquery_planner(), PlannerGlobal::subroots, Plan::targetlist, Plan::total_cost, PlannedStmt::transientPlan, PlannerGlobal::transientPlan, UPPERREL_FINAL, PlannedStmt::utilityStmt, and Query::utilityStmt.

Referenced by planner().

217 {
218  PlannedStmt *result;
219  PlannerGlobal *glob;
220  double tuple_fraction;
221  PlannerInfo *root;
222  RelOptInfo *final_rel;
223  Path *best_path;
224  Plan *top_plan;
225  ListCell *lp,
226  *lr;
227 
228  /*
229  * Set up global state for this planner invocation. This data is needed
230  * across all levels of sub-Query that might exist in the given command,
231  * so we keep it in a separate struct that's linked to by each per-Query
232  * PlannerInfo.
233  */
234  glob = makeNode(PlannerGlobal);
235 
236  glob->boundParams = boundParams;
237  glob->subplans = NIL;
238  glob->subroots = NIL;
239  glob->rewindPlanIDs = NULL;
240  glob->finalrtable = NIL;
241  glob->finalrowmarks = NIL;
242  glob->resultRelations = NIL;
243  glob->nonleafResultRelations = NIL;
244  glob->rootResultRelations = NIL;
245  glob->relationOids = NIL;
246  glob->invalItems = NIL;
247  glob->paramExecTypes = NIL;
248  glob->lastPHId = 0;
249  glob->lastRowMarkId = 0;
250  glob->lastPlanNodeId = 0;
251  glob->transientPlan = false;
252  glob->dependsOnRole = false;
253 
254  /*
255  * Assess whether it's feasible to use parallel mode for this query. We
256  * can't do this in a standalone backend, or if the command will try to
257  * modify any data, or if this is a cursor operation, or if GUCs are set
258  * to values that don't permit parallelism, or if parallel-unsafe
259  * functions are present in the query tree.
260  *
261  * (Note that we do allow CREATE TABLE AS, SELECT INTO, and CREATE
262  * MATERIALIZED VIEW to use parallel plans, but this is safe only because
263  * the command is writing into a completely new table which workers won't
264  * be able to see. If the workers could see the table, the fact that
265  * group locking would cause them to ignore the leader's heavyweight
266  * relation extension lock and GIN page locks would make this unsafe.
267  * We'll have to fix that somehow if we want to allow parallel inserts in
268  * general; updates and deletes have additional problems especially around
269  * combo CIDs.)
270  *
271  * For now, we don't try to use parallel mode if we're running inside a
272  * parallel worker. We might eventually be able to relax this
273  * restriction, but for now it seems best not to have parallel workers
274  * trying to create their own parallel workers.
275  *
276  * We can't use parallelism in serializable mode because the predicate
277  * locking code is not parallel-aware. It's not catastrophic if someone
278  * tries to run a parallel plan in serializable mode; it just won't get
279  * any workers and will run serially. But it seems like a good heuristic
280  * to assume that the same serialization level will be in effect at plan
281  * time and execution time, so don't generate a parallel plan if we're in
282  * serializable mode.
283  */
284  if ((cursorOptions & CURSOR_OPT_PARALLEL_OK) != 0 &&
287  parse->commandType == CMD_SELECT &&
288  !parse->hasModifyingCTE &&
290  !IsParallelWorker() &&
292  {
293  /* all the cheap tests pass, so scan the query tree */
294  glob->maxParallelHazard = max_parallel_hazard(parse);
296  }
297  else
298  {
299  /* skip the query tree scan, just assume it's unsafe */
301  glob->parallelModeOK = false;
302  }
303 
304  /*
305  * glob->parallelModeNeeded is normally set to false here and changed to
306  * true during plan creation if a Gather or Gather Merge plan is actually
307  * created (cf. create_gather_plan, create_gather_merge_plan).
308  *
309  * However, if force_parallel_mode = on or force_parallel_mode = regress,
310  * then we impose parallel mode whenever it's safe to do so, even if the
311  * final plan doesn't use parallelism. It's not safe to do so if the
312  * query contains anything parallel-unsafe; parallelModeOK will be false
313  * in that case. Note that parallelModeOK can't change after this point.
314  * Otherwise, everything in the query is either parallel-safe or
315  * parallel-restricted, and in either case it should be OK to impose
316  * parallel-mode restrictions. If that ends up breaking something, then
317  * either some function the user included in the query is incorrectly
318  * labelled as parallel-safe or parallel-restricted when in reality it's
319  * parallel-unsafe, or else the query planner itself has a bug.
320  */
321  glob->parallelModeNeeded = glob->parallelModeOK &&
323 
324  /* Determine what fraction of the plan is likely to be scanned */
325  if (cursorOptions & CURSOR_OPT_FAST_PLAN)
326  {
327  /*
328  * We have no real idea how many tuples the user will ultimately FETCH
329  * from a cursor, but it is often the case that he doesn't want 'em
330  * all, or would prefer a fast-start plan anyway so that he can
331  * process some of the tuples sooner. Use a GUC parameter to decide
332  * what fraction to optimize for.
333  */
334  tuple_fraction = cursor_tuple_fraction;
335 
336  /*
337  * We document cursor_tuple_fraction as simply being a fraction, which
338  * means the edge cases 0 and 1 have to be treated specially here. We
339  * convert 1 to 0 ("all the tuples") and 0 to a very small fraction.
340  */
341  if (tuple_fraction >= 1.0)
342  tuple_fraction = 0.0;
343  else if (tuple_fraction <= 0.0)
344  tuple_fraction = 1e-10;
345  }
346  else
347  {
348  /* Default assumption is we need all the tuples */
349  tuple_fraction = 0.0;
350  }
351 
352  /* primary planning entry point (may recurse for subqueries) */
353  root = subquery_planner(glob, parse, NULL,
354  false, tuple_fraction);
355 
356  /* Select best Path and turn it into a Plan */
357  final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
358  best_path = get_cheapest_fractional_path(final_rel, tuple_fraction);
359 
360  top_plan = create_plan(root, best_path);
361 
362  /*
363  * If creating a plan for a scrollable cursor, make sure it can run
364  * backwards on demand. Add a Material node at the top at need.
365  */
366  if (cursorOptions & CURSOR_OPT_SCROLL)
367  {
368  if (!ExecSupportsBackwardScan(top_plan))
369  top_plan = materialize_finished_plan(top_plan);
370  }
371 
372  /*
373  * Optionally add a Gather node for testing purposes, provided this is
374  * actually a safe thing to do.
375  */
377  {
378  Gather *gather = makeNode(Gather);
379 
380  /*
381  * If there are any initPlans attached to the formerly-top plan node,
382  * move them up to the Gather node; same as we do for Material node in
383  * materialize_finished_plan.
384  */
385  gather->plan.initPlan = top_plan->initPlan;
386  top_plan->initPlan = NIL;
387 
388  gather->plan.targetlist = top_plan->targetlist;
389  gather->plan.qual = NIL;
390  gather->plan.lefttree = top_plan;
391  gather->plan.righttree = NULL;
392  gather->num_workers = 1;
393  gather->single_copy = true;
395 
396  /*
397  * Since this Gather has no parallel-aware descendants to signal to,
398  * we don't need a rescan Param.
399  */
400  gather->rescan_param = -1;
401 
402  /*
403  * Ideally we'd use cost_gather here, but setting up dummy path data
404  * to satisfy it doesn't seem much cleaner than knowing what it does.
405  */
406  gather->plan.startup_cost = top_plan->startup_cost +
408  gather->plan.total_cost = top_plan->total_cost +
410  gather->plan.plan_rows = top_plan->plan_rows;
411  gather->plan.plan_width = top_plan->plan_width;
412  gather->plan.parallel_aware = false;
413  gather->plan.parallel_safe = false;
414 
415  /* use parallel mode for parallel plans. */
416  root->glob->parallelModeNeeded = true;
417 
418  top_plan = &gather->plan;
419  }
420 
421  /*
422  * If any Params were generated, run through the plan tree and compute
423  * each plan node's extParam/allParam sets. Ideally we'd merge this into
424  * set_plan_references' tree traversal, but for now it has to be separate
425  * because we need to visit subplans before not after main plan.
426  */
427  if (glob->paramExecTypes != NIL)
428  {
429  Assert(list_length(glob->subplans) == list_length(glob->subroots));
430  forboth(lp, glob->subplans, lr, glob->subroots)
431  {
432  Plan *subplan = (Plan *) lfirst(lp);
433  PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
434 
435  SS_finalize_plan(subroot, subplan);
436  }
437  SS_finalize_plan(root, top_plan);
438  }
439 
440  /* final cleanup of the plan */
441  Assert(glob->finalrtable == NIL);
442  Assert(glob->finalrowmarks == NIL);
443  Assert(glob->resultRelations == NIL);
445  Assert(glob->rootResultRelations == NIL);
446  top_plan = set_plan_references(root, top_plan);
447  /* ... and the subplans (both regular subplans and initplans) */
448  Assert(list_length(glob->subplans) == list_length(glob->subroots));
449  forboth(lp, glob->subplans, lr, glob->subroots)
450  {
451  Plan *subplan = (Plan *) lfirst(lp);
452  PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
453 
454  lfirst(lp) = set_plan_references(subroot, subplan);
455  }
456 
457  /* build the PlannedStmt result */
458  result = makeNode(PlannedStmt);
459 
460  result->commandType = parse->commandType;
461  result->queryId = parse->queryId;
462  result->hasReturning = (parse->returningList != NIL);
463  result->hasModifyingCTE = parse->hasModifyingCTE;
464  result->canSetTag = parse->canSetTag;
465  result->transientPlan = glob->transientPlan;
466  result->dependsOnRole = glob->dependsOnRole;
467  result->parallelModeNeeded = glob->parallelModeNeeded;
468  result->planTree = top_plan;
469  result->rtable = glob->finalrtable;
470  result->resultRelations = glob->resultRelations;
473  result->subplans = glob->subplans;
474  result->rewindPlanIDs = glob->rewindPlanIDs;
475  result->rowMarks = glob->finalrowmarks;
476  result->relationOids = glob->relationOids;
477  result->invalItems = glob->invalItems;
478  result->paramExecTypes = glob->paramExecTypes;
479  /* utilityStmt should be null, but we might as well copy it */
480  result->utilityStmt = parse->utilityStmt;
481  result->stmt_location = parse->stmt_location;
482  result->stmt_len = parse->stmt_len;
483 
484  return result;
485 }
char maxParallelHazard
Definition: relation.h:133
bool dependsOnRole
Definition: plannodes.h:57
List * paramExecTypes
Definition: plannodes.h:92
#define NIL
Definition: pg_list.h:69
List * qual
Definition: plannodes.h:145
double plan_rows
Definition: plannodes.h:131
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:180
int stmt_location
Definition: parsenodes.h:179
List * nonleafResultRelations
Definition: plannodes.h:72
List * relationOids
Definition: plannodes.h:88
int lastPlanNodeId
Definition: relation.h:123
List * resultRelations
Definition: relation.h:108
double parallel_setup_cost
Definition: costsize.c:110
Node * utilityStmt
Definition: parsenodes.h:118
bool transientPlan
Definition: plannodes.h:55
int stmt_len
Definition: plannodes.h:98
char max_parallel_hazard(Query *parse)
Definition: clauses.c:1068
struct Plan * planTree
Definition: plannodes.h:61
List * invalItems
Definition: plannodes.h:90
List * rootResultRelations
Definition: relation.h:111
Plan * create_plan(PlannerInfo *root, Path *best_path)
Definition: createplan.c:305
bool dependsOnRole
Definition: relation.h:127
struct Plan * righttree
Definition: plannodes.h:147
bool parallelModeNeeded
Definition: relation.h:131
List * paramExecTypes
Definition: relation.h:117
Plan plan
Definition: plannodes.h:840
bool single_copy
Definition: plannodes.h:843
bool parallelModeOK
Definition: relation.h:129
Bitmapset * rewindPlanIDs
Definition: relation.h:102
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1137
#define lfirst_node(type, lc)
Definition: pg_list.h:109
int stmt_location
Definition: plannodes.h:97
List * subplans
Definition: relation.h:98
Cost startup_cost
Definition: plannodes.h:125
PlannerGlobal * glob
Definition: relation.h:157
bool IsUnderPostmaster
Definition: globals.c:101
bool hasReturning
Definition: plannodes.h:49
Plan * materialize_finished_plan(Plan *subplan)
Definition: createplan.c:5997
List * rootResultRelations
Definition: plannodes.h:79
Node * utilityStmt
Definition: plannodes.h:94
int dynamic_shared_memory_type
Definition: dsm_impl.c:113
bool parallel_aware
Definition: plannodes.h:137
double cursor_tuple_fraction
Definition: planner.c:62
List * returningList
Definition: parsenodes.h:144
#define IsParallelWorker()
Definition: parallel.h:58
#define PROPARALLEL_UNSAFE
Definition: pg_proc.h:5548
uint64 queryId
Definition: parsenodes.h:114
List * invalItems
Definition: relation.h:115
bool canSetTag
Definition: plannodes.h:53
CmdType commandType
Definition: plannodes.h:45
#define CURSOR_OPT_FAST_PLAN
Definition: parsenodes.h:2647
bool ExecSupportsBackwardScan(Plan *node)
Definition: execAmi.c:462
Index lastPHId
Definition: relation.h:119
List * rowMarks
Definition: plannodes.h:86
int num_workers
Definition: plannodes.h:841
CmdType commandType
Definition: parsenodes.h:110
#define makeNode(_type_)
Definition: nodes.h:560
List * subplans
Definition: plannodes.h:81
List * nonleafResultRelations
Definition: relation.h:110
int plan_width
Definition: plannodes.h:132
int force_parallel_mode
Definition: planner.c:63
ParamListInfo boundParams
Definition: relation.h:96
#define Assert(condition)
Definition: c.h:680
#define lfirst(lc)
Definition: pg_list.h:106
Bitmapset * rewindPlanIDs
Definition: plannodes.h:84
bool hasModifyingCTE
Definition: plannodes.h:51
bool canSetTag
Definition: parsenodes.h:116
#define DSM_IMPL_NONE
Definition: dsm_impl.h:17
int rescan_param
Definition: plannodes.h:842
static int list_length(const List *l)
Definition: pg_list.h:89
List * relationOids
Definition: relation.h:113
List * subroots
Definition: relation.h:100
List * rtable
Definition: plannodes.h:63
struct Plan * lefttree
Definition: plannodes.h:146
List * targetlist
Definition: plannodes.h:144
bool invisible
Definition: plannodes.h:844
e
Definition: preproc-init.c:82
List * finalrtable
Definition: relation.h:104
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2650
Index lastRowMarkId
Definition: relation.h:121
uint64 queryId
Definition: plannodes.h:47
#define IsolationIsSerializable()
Definition: xact.h:44
List * resultRelations
Definition: plannodes.h:66
bool parallelModeNeeded
Definition: plannodes.h:59
List * initPlan
Definition: plannodes.h:148
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:2642
Cost total_cost
Definition: plannodes.h:126
bool hasModifyingCTE
Definition: parsenodes.h:129
bool parallel_safe
Definition: plannodes.h:138
Plan * set_plan_references(PlannerInfo *root, Plan *plan)
Definition: setrefs.c:214
void SS_finalize_plan(PlannerInfo *root, Plan *plan)
Definition: subselect.c:2235
int max_parallel_workers_per_gather
Definition: costsize.c:116
List * finalrowmarks
Definition: relation.h:106
int stmt_len
Definition: parsenodes.h:180
PlannerInfo * subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, bool hasRecursion, double tuple_fraction)
Definition: planner.c:517
Path * get_cheapest_fractional_path(RelOptInfo *rel, double tuple_fraction)
Definition: planner.c:5873
bool transientPlan
Definition: relation.h:125
double parallel_tuple_cost
Definition: costsize.c:109

◆ subquery_planner()

PlannerInfo* subquery_planner ( PlannerGlobal glob,
Query parse,
PlannerInfo parent_root,
bool  hasRecursion,
double  tuple_fraction 
)

Definition at line 517 of file planner.c.

References PlannerInfo::append_rel_list, OnConflictExpr::arbiterElems, OnConflictExpr::arbiterWhere, contain_agg_clause(), contain_subplans(), contain_volatile_functions(), copyObject, PlannerInfo::cte_plan_ids, Query::cteList, CurrentMemoryContext, WindowClause::endOffset, PlannerInfo::eq_classes, expand_inherited_tables(), expression_returns_set(), EXPRKIND_APPINFO, EXPRKIND_ARBITER_ELEM, EXPRKIND_LIMIT, EXPRKIND_QUAL, EXPRKIND_RTFUNC, EXPRKIND_RTFUNC_LATERAL, EXPRKIND_TABLEFUNC, EXPRKIND_TABLEFUNC_LATERAL, EXPRKIND_TABLESAMPLE, EXPRKIND_TARGET, EXPRKIND_VALUES, EXPRKIND_VALUES_LATERAL, fetch_upper_rel(), flatten_join_alias_vars(), flatten_simple_union_all(), RangeTblEntry::functions, PlannerInfo::glob, Query::groupClause, PlannerInfo::grouping_map, grouping_planner(), Query::groupingSets, PlannerInfo::hasHavingQual, PlannerInfo::hasInheritedTarget, PlannerInfo::hasJoinRTEs, PlannerInfo::hasLateralRTEs, PlannerInfo::hasPseudoConstantQuals, PlannerInfo::hasRecursion, Query::hasSubLinks, Query::hasTargetSRFs, Query::havingQual, inheritance_planner(), PlannerInfo::init_plans, inline_set_returning_functions(), IS_OUTER_JOIN, RangeTblEntry::joinaliasvars, Query::jointree, RangeTblEntry::jointype, lappend(), RangeTblEntry::lateral, lfirst, lfirst_node, Query::limitCount, Query::limitOffset, makeNode, PlannerInfo::minmax_aggs, PlannerInfo::multiexpr_params, NIL, PlannerInfo::non_recursive_path, Query::onConflict, OnConflictExpr::onConflictSet, OnConflictExpr::onConflictWhere, PlannerInfo::outer_params, PlannerInfo::parent_root, parse(), PlannerInfo::parse, PlannerInfo::pcinfo_list, PlannerInfo::plan_params, PlannerInfo::planner_cxt, preprocess_expression(), preprocess_qual_conditions(), preprocess_rowmarks(), PlannerInfo::processed_tlist, pull_up_sublinks(), pull_up_subqueries(), WithCheckOption::qual, PlannerInfo::qual_security_level, FromExpr::quals, PlannerInfo::query_level, reduce_outer_joins(), remove_useless_groupby_columns(), Query::resultRelation, Query::returningList, PlannerInfo::rowMarks, rt_fetch, Query::rtable, RTE_FUNCTION, RTE_JOIN, RTE_RELATION, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, RangeTblEntry::securityQuals, set_cheapest(), Query::setOperations, SS_assign_special_param(), SS_charge_for_initplans(), SS_identify_outer_params(), SS_process_ctes(), WindowClause::startOffset, RangeTblEntry::subquery, RangeTblEntry::tablefunc, RangeTblEntry::tablesample, Query::targetList, PlannerInfo::upper_rels, PlannerInfo::upper_targets, UPPERREL_FINAL, RangeTblEntry::values_lists, Query::windowClause, Query::withCheckOptions, and PlannerInfo::wt_param_id.

Referenced by make_subplan(), recurse_set_operations(), set_subquery_pathlist(), SS_process_ctes(), and standard_planner().

520 {
521  PlannerInfo *root;
522  List *newWithCheckOptions;
523  List *newHaving;
524  bool hasOuterJoins;
525  RelOptInfo *final_rel;
526  ListCell *l;
527 
528  /* Create a PlannerInfo data structure for this subquery */
529  root = makeNode(PlannerInfo);
530  root->parse = parse;
531  root->glob = glob;
532  root->query_level = parent_root ? parent_root->query_level + 1 : 1;
533  root->parent_root = parent_root;
534  root->plan_params = NIL;
535  root->outer_params = NULL;
537  root->init_plans = NIL;
538  root->cte_plan_ids = NIL;
539  root->multiexpr_params = NIL;
540  root->eq_classes = NIL;
541  root->append_rel_list = NIL;
542  root->pcinfo_list = NIL;
543  root->rowMarks = NIL;
544  memset(root->upper_rels, 0, sizeof(root->upper_rels));
545  memset(root->upper_targets, 0, sizeof(root->upper_targets));
546  root->processed_tlist = NIL;
547  root->grouping_map = NULL;
548  root->minmax_aggs = NIL;
549  root->qual_security_level = 0;
550  root->hasInheritedTarget = false;
551  root->hasRecursion = hasRecursion;
552  if (hasRecursion)
553  root->wt_param_id = SS_assign_special_param(root);
554  else
555  root->wt_param_id = -1;
556  root->non_recursive_path = NULL;
557 
558  /*
559  * If there is a WITH list, process each WITH query and build an initplan
560  * SubPlan structure for it.
561  */
562  if (parse->cteList)
563  SS_process_ctes(root);
564 
565  /*
566  * Look for ANY and EXISTS SubLinks in WHERE and JOIN/ON clauses, and try
567  * to transform them into joins. Note that this step does not descend
568  * into subqueries; if we pull up any subqueries below, their SubLinks are
569  * processed just before pulling them up.
570  */
571  if (parse->hasSubLinks)
572  pull_up_sublinks(root);
573 
574  /*
575  * Scan the rangetable for set-returning functions, and inline them if
576  * possible (producing subqueries that might get pulled up next).
577  * Recursion issues here are handled in the same way as for SubLinks.
578  */
580 
581  /*
582  * Check to see if any subqueries in the jointree can be merged into this
583  * query.
584  */
585  pull_up_subqueries(root);
586 
587  /*
588  * If this is a simple UNION ALL query, flatten it into an appendrel. We
589  * do this now because it requires applying pull_up_subqueries to the leaf
590  * queries of the UNION ALL, which weren't touched above because they
591  * weren't referenced by the jointree (they will be after we do this).
592  */
593  if (parse->setOperations)
595 
596  /*
597  * Detect whether any rangetable entries are RTE_JOIN kind; if not, we can
598  * avoid the expense of doing flatten_join_alias_vars(). Also check for
599  * outer joins --- if none, we can skip reduce_outer_joins(). And check
600  * for LATERAL RTEs, too. This must be done after we have done
601  * pull_up_subqueries(), of course.
602  */
603  root->hasJoinRTEs = false;
604  root->hasLateralRTEs = false;
605  hasOuterJoins = false;
606  foreach(l, parse->rtable)
607  {
609 
610  if (rte->rtekind == RTE_JOIN)
611  {
612  root->hasJoinRTEs = true;
613  if (IS_OUTER_JOIN(rte->jointype))
614  hasOuterJoins = true;
615  }
616  if (rte->lateral)
617  root->hasLateralRTEs = true;
618  }
619 
620  /*
621  * Preprocess RowMark information. We need to do this after subquery
622  * pullup (so that all non-inherited RTEs are present) and before
623  * inheritance expansion (so that the info is available for
624  * expand_inherited_tables to examine and modify).
625  */
626  preprocess_rowmarks(root);
627 
628  /*
629  * Expand any rangetable entries that are inheritance sets into "append
630  * relations". This can add entries to the rangetable, but they must be
631  * plain base relations not joins, so it's OK (and marginally more
632  * efficient) to do it after checking for join RTEs. We must do it after
633  * pulling up subqueries, else we'd fail to handle inherited tables in
634  * subqueries.
635  */
637 
638  /*
639  * Set hasHavingQual to remember if HAVING clause is present. Needed
640  * because preprocess_expression will reduce a constant-true condition to
641  * an empty qual list ... but "HAVING TRUE" is not a semantic no-op.
642  */
643  root->hasHavingQual = (parse->havingQual != NULL);
644 
645  /* Clear this flag; might get set in distribute_qual_to_rels */
646  root->hasPseudoConstantQuals = false;
647 
648  /*
649  * Do expression preprocessing on targetlist and quals, as well as other
650  * random expressions in the querytree. Note that we do not need to
651  * handle sort/group expressions explicitly, because they are actually
652  * part of the targetlist.
653  */
654  parse->targetList = (List *)
655  preprocess_expression(root, (Node *) parse->targetList,
657 
658  /* Constant-folding might have removed all set-returning functions */
659  if (parse->hasTargetSRFs)
661 
662  newWithCheckOptions = NIL;
663  foreach(l, parse->withCheckOptions)
664  {
666 
667  wco->qual = preprocess_expression(root, wco->qual,
668  EXPRKIND_QUAL);
669  if (wco->qual != NULL)
670  newWithCheckOptions = lappend(newWithCheckOptions, wco);
671  }
672  parse->withCheckOptions = newWithCheckOptions;
673 
674  parse->returningList = (List *)
675  preprocess_expression(root, (Node *) parse->returningList,
677 
678  preprocess_qual_conditions(root, (Node *) parse->jointree);
679 
680  parse->havingQual = preprocess_expression(root, parse->havingQual,
681  EXPRKIND_QUAL);
682 
683  foreach(l, parse->windowClause)
684  {
686 
687  /* partitionClause/orderClause are sort/group expressions */
690  wc->endOffset = preprocess_expression(root, wc->endOffset,
692  }
693 
694  parse->limitOffset = preprocess_expression(root, parse->limitOffset,
696  parse->limitCount = preprocess_expression(root, parse->limitCount,
698 
699  if (parse->onConflict)
700  {
701  parse->onConflict->arbiterElems = (List *)
703  (Node *) parse->onConflict->arbiterElems,
705  parse->onConflict->arbiterWhere =
707  parse->onConflict->arbiterWhere,
708  EXPRKIND_QUAL);
709  parse->onConflict->onConflictSet = (List *)
711  (Node *) parse->onConflict->onConflictSet,
713  parse->onConflict->onConflictWhere =
715  parse->onConflict->onConflictWhere,
716  EXPRKIND_QUAL);
717  /* exclRelTlist contains only Vars, so no preprocessing needed */
718  }
719 
720  root->append_rel_list = (List *)
723 
724  /* Also need to preprocess expressions within RTEs */
725  foreach(l, parse->rtable)
726  {
728  int kind;
729  ListCell *lcsq;
730 
731  if (rte->rtekind == RTE_RELATION)
732  {
733  if (rte->tablesample)
734  rte->tablesample = (TableSampleClause *)
736  (Node *) rte->tablesample,
738  }
739  else if (rte->rtekind == RTE_SUBQUERY)
740  {
741  /*
742  * We don't want to do all preprocessing yet on the subquery's
743  * expressions, since that will happen when we plan it. But if it
744  * contains any join aliases of our level, those have to get
745  * expanded now, because planning of the subquery won't do it.
746  * That's only possible if the subquery is LATERAL.
747  */
748  if (rte->lateral && root->hasJoinRTEs)
749  rte->subquery = (Query *)
750  flatten_join_alias_vars(root, (Node *) rte->subquery);
751  }
752  else if (rte->rtekind == RTE_FUNCTION)
753  {
754  /* Preprocess the function expression(s) fully */
756  rte->functions = (List *)
757  preprocess_expression(root, (Node *) rte->functions, kind);
758  }
759  else if (rte->rtekind == RTE_TABLEFUNC)
760  {
761  /* Preprocess the function expression(s) fully */
763  rte->tablefunc = (TableFunc *)
764  preprocess_expression(root, (Node *) rte->tablefunc, kind);
765  }
766  else if (rte->rtekind == RTE_VALUES)
767  {
768  /* Preprocess the values lists fully */
770  rte->values_lists = (List *)
771  preprocess_expression(root, (Node *) rte->values_lists, kind);
772  }
773 
774  /*
775  * Process each element of the securityQuals list as if it were a
776  * separate qual expression (as indeed it is). We need to do it this
777  * way to get proper canonicalization of AND/OR structure. Note that
778  * this converts each element into an implicit-AND sublist.
779  */
780  foreach(lcsq, rte->securityQuals)
781  {
782  lfirst(lcsq) = preprocess_expression(root,
783  (Node *) lfirst(lcsq),
784  EXPRKIND_QUAL);
785  }
786  }
787 
788  /*
789  * Now that we are done preprocessing expressions, and in particular done
790  * flattening join alias variables, get rid of the joinaliasvars lists.
791  * They no longer match what expressions in the rest of the tree look
792  * like, because we have not preprocessed expressions in those lists (and
793  * do not want to; for example, expanding a SubLink there would result in
794  * a useless unreferenced subplan). Leaving them in place simply creates
795  * a hazard for later scans of the tree. We could try to prevent that by
796  * using QTW_IGNORE_JOINALIASES in every tree scan done after this point,
797  * but that doesn't sound very reliable.
798  */
799  if (root->hasJoinRTEs)
800  {
801  foreach(l, parse->rtable)
802  {
804 
805  rte->joinaliasvars = NIL;
806  }
807  }
808 
809  /*
810  * In some cases we may want to transfer a HAVING clause into WHERE. We
811  * cannot do so if the HAVING clause contains aggregates (obviously) or
812  * volatile functions (since a HAVING clause is supposed to be executed
813  * only once per group). We also can't do this if there are any nonempty
814  * grouping sets; moving such a clause into WHERE would potentially change
815  * the results, if any referenced column isn't present in all the grouping
816  * sets. (If there are only empty grouping sets, then the HAVING clause
817  * must be degenerate as discussed below.)
818  *
819  * Also, it may be that the clause is so expensive to execute that we're
820  * better off doing it only once per group, despite the loss of
821  * selectivity. This is hard to estimate short of doing the entire
822  * planning process twice, so we use a heuristic: clauses containing
823  * subplans are left in HAVING. Otherwise, we move or copy the HAVING
824  * clause into WHERE, in hopes of eliminating tuples before aggregation
825  * instead of after.
826  *
827  * If the query has explicit grouping then we can simply move such a
828  * clause into WHERE; any group that fails the clause will not be in the
829  * output because none of its tuples will reach the grouping or
830  * aggregation stage. Otherwise we must have a degenerate (variable-free)
831  * HAVING clause, which we put in WHERE so that query_planner() can use it
832  * in a gating Result node, but also keep in HAVING to ensure that we
833  * don't emit a bogus aggregated row. (This could be done better, but it
834  * seems not worth optimizing.)
835  *
836  * Note that both havingQual and parse->jointree->quals are in
837  * implicitly-ANDed-list form at this point, even though they are declared
838  * as Node *.
839  */
840  newHaving = NIL;
841  foreach(l, (List *) parse->havingQual)
842  {
843  Node *havingclause = (Node *) lfirst(l);
844 
845  if ((parse->groupClause && parse->groupingSets) ||
846  contain_agg_clause(havingclause) ||
847  contain_volatile_functions(havingclause) ||
848  contain_subplans(havingclause))
849  {
850  /* keep it in HAVING */
851  newHaving = lappend(newHaving, havingclause);
852  }
853  else if (parse->groupClause && !parse->groupingSets)
854  {
855  /* move it to WHERE */
856  parse->jointree->quals = (Node *)
857  lappend((List *) parse->jointree->quals, havingclause);
858  }
859  else
860  {
861  /* put a copy in WHERE, keep it in HAVING */
862  parse->jointree->quals = (Node *)
863  lappend((List *) parse->jointree->quals,
864  copyObject(havingclause));
865  newHaving = lappend(newHaving, havingclause);
866  }
867  }
868  parse->havingQual = (Node *) newHaving;
869 
870  /* Remove any redundant GROUP BY columns */
872 
873  /*
874  * If we have any outer joins, try to reduce them to plain inner joins.
875  * This step is most easily done after we've done expression
876  * preprocessing.
877  */
878  if (hasOuterJoins)
879  reduce_outer_joins(root);
880 
881  /*
882  * Do the main planning. If we have an inherited target relation, that
883  * needs special processing, else go straight to grouping_planner.
884  */
885  if (parse->resultRelation &&
886  rt_fetch(parse->resultRelation, parse->rtable)->inh)
887  inheritance_planner(root);
888  else
889  grouping_planner(root, false, tuple_fraction);
890 
891  /*
892  * Capture the set of outer-level param IDs we have access to, for use in
893  * extParam/allParam calculations later.
894  */
896 
897  /*
898  * If any initPlans were created in this query level, adjust the surviving
899  * Paths' costs and parallel-safety flags to account for them. The
900  * initPlans won't actually get attached to the plan tree till
901  * create_plan() runs, but we must include their effects now.
902  */
903  final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
904  SS_charge_for_initplans(root, final_rel);
905 
906  /*
907  * Make sure we've identified the cheapest Path for the final rel. (By
908  * doing this here not in grouping_planner, we include initPlan costs in
909  * the decision, though it's unlikely that will change anything.)
910  */
911  set_cheapest(final_rel);
912 
913  return root;
914 }
Node * limitOffset
Definition: parsenodes.h:158
#define NIL
Definition: pg_list.h:69
List * rowMarks
Definition: relation.h:256
Query * parse
Definition: relation.h:155
List * joinaliasvars
Definition: parsenodes.h:995
List * plan_params
Definition: relation.h:169
bool hasJoinRTEs
Definition: relation.h:302
#define EXPRKIND_ARBITER_ELEM
Definition: planner.c:84
void reduce_outer_joins(PlannerInfo *root)
FromExpr * jointree
Definition: parsenodes.h:136
int SS_assign_special_param(PlannerInfo *root)
Definition: subselect.c:429
OnConflictExpr * onConflict
Definition: parsenodes.h:142
static void preprocess_rowmarks(PlannerInfo *root)
Definition: planner.c:2408
List * securityQuals
Definition: parsenodes.h:1064
List * withCheckOptions
Definition: parsenodes.h:169
#define EXPRKIND_APPINFO
Definition: planner.c:81
#define EXPRKIND_QUAL
Definition: planner.c:74
#define EXPRKIND_TABLEFUNC_LATERAL
Definition: planner.c:86
bool expression_returns_set(Node *clause)
Definition: nodeFuncs.c:670
int resultRelation
Definition: parsenodes.h:120
void SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel)
Definition: subselect.c:2170
#define IS_OUTER_JOIN(jointype)
Definition: nodes.h:725
#define EXPRKIND_RTFUNC
Definition: planner.c:76
List * groupingSets
Definition: parsenodes.h:148
Definition: nodes.h:512
static Node * preprocess_expression(PlannerInfo *root, Node *expr, int kind)
Definition: planner.c:923
List * minmax_aggs
Definition: relation.h:288
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:957
#define EXPRKIND_VALUES_LATERAL
Definition: planner.c:79
void expand_inherited_tables(PlannerInfo *root)
Definition: prepunion.c:1345
AttrNumber * grouping_map
Definition: relation.h:287
bool hasRecursion
Definition: relation.h:308
void pull_up_subqueries(PlannerInfo *root)
Definition: prepjointree.c:607
#define EXPRKIND_TARGET
Definition: planner.c:75
List * values_lists
Definition: parsenodes.h:1016
Node * quals
Definition: primnodes.h:1479
List * windowClause
Definition: parsenodes.h:152
List * targetList
Definition: parsenodes.h:138
List * arbiterElems
Definition: primnodes.h:1497
List * multiexpr_params
Definition: relation.h:232
bool contain_subplans(Node *clause)
Definition: clauses.c:843
#define EXPRKIND_LIMIT
Definition: planner.c:80
int wt_param_id
Definition: relation.h:311
List * rtable
Definition: parsenodes.h:135
TableFunc * tablefunc
Definition: parsenodes.h:1011
bool hasLateralRTEs
Definition: relation.h:303
void inline_set_returning_functions(PlannerInfo *root)
Definition: prepjointree.c:573
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1137
#define lfirst_node(type, lc)
Definition: pg_list.h:109
static void remove_useless_groupby_columns(PlannerInfo *root)
Definition: planner.c:2827
Node * limitCount
Definition: parsenodes.h:159
PlannerGlobal * glob
Definition: relation.h:157
JoinType jointype
Definition: parsenodes.h:994
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
void SS_process_ctes(PlannerInfo *root)
Definition: subselect.c:1158
List * returningList
Definition: parsenodes.h:144
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * lappend(List *list, void *datum)
Definition: list.c:128
struct PlannerInfo * parent_root
Definition: relation.h:161
void set_cheapest(RelOptInfo *parent_rel)
Definition: pathnode.c:244
Node * startOffset
Definition: parsenodes.h:1292
Node * flatten_join_alias_vars(PlannerInfo *root, Node *node)
Definition: var.c:670
List * append_rel_list
Definition: relation.h:252
List * cte_plan_ids
Definition: relation.h:230
List * init_plans
Definition: relation.h:228
bool hasPseudoConstantQuals
Definition: relation.h:306
static void inheritance_planner(PlannerInfo *root)
Definition: planner.c:1079
bool hasTargetSRFs
Definition: parsenodes.h:125
#define makeNode(_type_)
Definition: nodes.h:560
#define lfirst(lc)
Definition: pg_list.h:106
List * pcinfo_list
Definition: relation.h:254
void SS_identify_outer_params(PlannerInfo *root)
Definition: subselect.c:2108
List * eq_classes
Definition: relation.h:235
List * functions
Definition: parsenodes.h:1005
bool hasInheritedTarget
Definition: relation.h:300
void flatten_simple_union_all(PlannerInfo *root)
Bitmapset * outer_params
Definition: relation.h:170
struct Path * non_recursive_path
Definition: relation.h:312
Node * endOffset
Definition: parsenodes.h:1293
#define EXPRKIND_RTFUNC_LATERAL
Definition: planner.c:77
Index qual_security_level
Definition: relation.h:297
Index query_level
Definition: relation.h:159
void pull_up_sublinks(PlannerInfo *root)
Definition: prepjointree.c:150
RTEKind rtekind
Definition: parsenodes.h:951
Node * arbiterWhere
Definition: primnodes.h:1499
List * cteList
Definition: parsenodes.h:133
Node * setOperations
Definition: parsenodes.h:163
bool contain_agg_clause(Node *clause)
Definition: clauses.c:417
Query * subquery
Definition: parsenodes.h:974
List * groupClause
Definition: parsenodes.h:146
bool hasSubLinks
Definition: parsenodes.h:126
static void grouping_planner(PlannerInfo *root, bool inheritance_update, double tuple_fraction)
Definition: planner.c:1554
static void preprocess_qual_conditions(PlannerInfo *root, Node *jtnode)
Definition: planner.c:1010
List * onConflictSet
Definition: primnodes.h:1503
bool hasHavingQual
Definition: relation.h:305
#define EXPRKIND_TABLESAMPLE
Definition: planner.c:83
MemoryContext planner_cxt
Definition: relation.h:290
#define copyObject(obj)
Definition: nodes.h:625
#define EXPRKIND_VALUES
Definition: planner.c:78
Node * havingQual
Definition: parsenodes.h:150
List * processed_tlist
Definition: relation.h:284
Node * onConflictWhere
Definition: primnodes.h:1504
Definition: pg_list.h:45
struct TableSampleClause * tablesample
Definition: parsenodes.h:969
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:649
struct PathTarget * upper_targets[UPPERREL_FINAL+1]
Definition: relation.h:278
#define EXPRKIND_TABLEFUNC
Definition: planner.c:85
List * upper_rels[UPPERREL_FINAL+1]
Definition: relation.h:275

Variable Documentation

◆ create_upper_paths_hook

◆ planner_hook

Definition at line 67 of file planner.c.

Referenced by planner().