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

Go to the source code of this file.

Macros

#define DEFAULT_CURSOR_TUPLE_FRACTION   0.1
 

Typedefs

typedef void(* query_pathkeys_callback) (PlannerInfo *root, void *extra)
 

Functions

RelOptInfoquery_planner (PlannerInfo *root, query_pathkeys_callback qp_callback, void *qp_extra)
 
void preprocess_minmax_aggregates (PlannerInfo *root)
 
Plancreate_plan (PlannerInfo *root, Path *best_path)
 
ForeignScanmake_foreignscan (List *qptlist, List *qpqual, Index scanrelid, List *fdw_exprs, List *fdw_private, List *fdw_scan_tlist, List *fdw_recheck_quals, Plan *outer_plan)
 
Planchange_plan_targetlist (Plan *subplan, List *tlist, bool tlist_parallel_safe)
 
Planmaterialize_finished_plan (Plan *subplan)
 
bool is_projection_capable_path (Path *path)
 
bool is_projection_capable_plan (Plan *plan)
 
Sortmake_sort_from_sortclauses (List *sortcls, Plan *lefttree)
 
Aggmake_agg (List *tlist, List *qual, AggStrategy aggstrategy, AggSplit aggsplit, int numGroupCols, AttrNumber *grpColIdx, Oid *grpOperators, Oid *grpCollations, List *groupingSets, List *chain, double dNumGroups, Size transitionSpace, Plan *lefttree)
 
Limitmake_limit (Plan *lefttree, Node *limitOffset, Node *limitCount, LimitOption limitOption, int uniqNumCols, AttrNumber *uniqColIdx, Oid *uniqOperators, Oid *uniqCollations)
 
void add_base_rels_to_query (PlannerInfo *root, Node *jtnode)
 
void add_other_rels_to_query (PlannerInfo *root)
 
void build_base_rel_tlists (PlannerInfo *root, List *final_tlist)
 
void add_vars_to_targetlist (PlannerInfo *root, List *vars, Relids where_needed, bool create_new_ph)
 
void find_lateral_references (PlannerInfo *root)
 
void create_lateral_join_info (PlannerInfo *root)
 
Listdeconstruct_jointree (PlannerInfo *root)
 
void distribute_restrictinfo_to_rels (PlannerInfo *root, RestrictInfo *restrictinfo)
 
RestrictInfoprocess_implied_equality (PlannerInfo *root, Oid opno, Oid collation, Expr *item1, Expr *item2, Relids qualscope, Relids nullable_relids, Index security_level, bool below_outer_join, bool both_const)
 
RestrictInfobuild_implied_join_equality (PlannerInfo *root, Oid opno, Oid collation, Expr *item1, Expr *item2, Relids qualscope, Relids nullable_relids, Index security_level)
 
void match_foreign_keys_to_quals (PlannerInfo *root)
 
Listremove_useless_joins (PlannerInfo *root, List *joinlist)
 
void reduce_unique_semijoins (PlannerInfo *root)
 
bool query_supports_distinctness (Query *query)
 
bool query_is_distinct_for (Query *query, List *colnos, List *opids)
 
bool innerrel_is_unique (PlannerInfo *root, Relids joinrelids, Relids outerrelids, RelOptInfo *innerrel, JoinType jointype, List *restrictlist, bool force_cache)
 
Planset_plan_references (PlannerInfo *root, Plan *plan)
 
void record_plan_function_dependency (PlannerInfo *root, Oid funcid)
 
void record_plan_type_dependency (PlannerInfo *root, Oid typid)
 
bool extract_query_dependencies_walker (Node *node, PlannerInfo *root)
 

Variables

double cursor_tuple_fraction
 
int from_collapse_limit
 
int join_collapse_limit
 

Macro Definition Documentation

◆ DEFAULT_CURSOR_TUPLE_FRACTION

#define DEFAULT_CURSOR_TUPLE_FRACTION   0.1

Definition at line 21 of file planmain.h.

Typedef Documentation

◆ query_pathkeys_callback

typedef void(* query_pathkeys_callback) (PlannerInfo *root, void *extra)

Definition at line 25 of file planmain.h.

Function Documentation

◆ add_base_rels_to_query()

void add_base_rels_to_query ( PlannerInfo root,
Node jtnode 
)

Definition at line 106 of file initsplan.c.

References add_base_rels_to_query(), build_simple_rel(), elog, ERROR, FromExpr::fromlist, IsA, JoinExpr::larg, lfirst, nodeTag, and JoinExpr::rarg.

Referenced by add_base_rels_to_query(), and query_planner().

107 {
108  if (jtnode == NULL)
109  return;
110  if (IsA(jtnode, RangeTblRef))
111  {
112  int varno = ((RangeTblRef *) jtnode)->rtindex;
113 
114  (void) build_simple_rel(root, varno, NULL);
115  }
116  else if (IsA(jtnode, FromExpr))
117  {
118  FromExpr *f = (FromExpr *) jtnode;
119  ListCell *l;
120 
121  foreach(l, f->fromlist)
122  add_base_rels_to_query(root, lfirst(l));
123  }
124  else if (IsA(jtnode, JoinExpr))
125  {
126  JoinExpr *j = (JoinExpr *) jtnode;
127 
128  add_base_rels_to_query(root, j->larg);
129  add_base_rels_to_query(root, j->rarg);
130  }
131  else
132  elog(ERROR, "unrecognized node type: %d",
133  (int) nodeTag(jtnode));
134 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
void add_base_rels_to_query(PlannerInfo *root, Node *jtnode)
Definition: initsplan.c:106
List * fromlist
Definition: primnodes.h:1563
Node * larg
Definition: primnodes.h:1542
#define ERROR
Definition: elog.h:46
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition: relnode.c:194
Node * rarg
Definition: primnodes.h:1543
#define lfirst(lc)
Definition: pg_list.h:169
#define nodeTag(nodeptr)
Definition: nodes.h:544
#define elog(elevel,...)
Definition: elog.h:232

◆ add_other_rels_to_query()

void add_other_rels_to_query ( PlannerInfo root)

Definition at line 144 of file initsplan.c.

References expand_inherited_rtentry(), RangeTblEntry::inh, RELOPT_BASEREL, RelOptInfo::reloptkind, PlannerInfo::simple_rel_array, PlannerInfo::simple_rel_array_size, and PlannerInfo::simple_rte_array.

Referenced by query_planner().

145 {
146  int rti;
147 
148  for (rti = 1; rti < root->simple_rel_array_size; rti++)
149  {
150  RelOptInfo *rel = root->simple_rel_array[rti];
151  RangeTblEntry *rte = root->simple_rte_array[rti];
152 
153  /* there may be empty slots corresponding to non-baserel RTEs */
154  if (rel == NULL)
155  continue;
156 
157  /* Ignore any "otherrels" that were already added. */
158  if (rel->reloptkind != RELOPT_BASEREL)
159  continue;
160 
161  /* If it's marked as inheritable, look for children. */
162  if (rte->inh)
163  expand_inherited_rtentry(root, rel, rte, rti);
164  }
165 }
RelOptKind reloptkind
Definition: pathnodes.h:673
struct RelOptInfo ** simple_rel_array
Definition: pathnodes.h:185
int simple_rel_array_size
Definition: pathnodes.h:186
RangeTblEntry ** simple_rte_array
Definition: pathnodes.h:193
void expand_inherited_rtentry(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte, Index rti)
Definition: inherit.c:79

◆ add_vars_to_targetlist()

void add_vars_to_targetlist ( PlannerInfo root,
List vars,
Relids  where_needed,
bool  create_new_ph 
)

Definition at line 230 of file initsplan.c.

References Assert, RelOptInfo::attr_needed, bms_add_members(), bms_is_empty(), bms_is_subset(), copyObject, elog, ERROR, PathTarget::exprs, find_base_rel(), find_placeholder_info(), IsA, lappend(), lfirst, RelOptInfo::min_attr, nodeTag, PlaceHolderInfo::ph_needed, RelOptInfo::relids, RelOptInfo::reltarget, Var::varattno, and Var::varno.

Referenced by build_base_rel_tlists(), distribute_qual_to_rels(), expand_inherited_rtentry(), extract_lateral_references(), fix_placeholder_input_needed_levels(), generate_base_implied_equalities_no_const(), and process_implied_equality().

232 {
233  ListCell *temp;
234 
235  Assert(!bms_is_empty(where_needed));
236 
237  foreach(temp, vars)
238  {
239  Node *node = (Node *) lfirst(temp);
240 
241  if (IsA(node, Var))
242  {
243  Var *var = (Var *) node;
244  RelOptInfo *rel = find_base_rel(root, var->varno);
245  int attno = var->varattno;
246 
247  if (bms_is_subset(where_needed, rel->relids))
248  continue;
249  Assert(attno >= rel->min_attr && attno <= rel->max_attr);
250  attno -= rel->min_attr;
251  if (rel->attr_needed[attno] == NULL)
252  {
253  /* Variable not yet requested, so add to rel's targetlist */
254  /* XXX is copyObject necessary here? */
255  rel->reltarget->exprs = lappend(rel->reltarget->exprs,
256  copyObject(var));
257  /* reltarget cost and width will be computed later */
258  }
259  rel->attr_needed[attno] = bms_add_members(rel->attr_needed[attno],
260  where_needed);
261  }
262  else if (IsA(node, PlaceHolderVar))
263  {
264  PlaceHolderVar *phv = (PlaceHolderVar *) node;
265  PlaceHolderInfo *phinfo = find_placeholder_info(root, phv,
266  create_new_ph);
267 
268  phinfo->ph_needed = bms_add_members(phinfo->ph_needed,
269  where_needed);
270  }
271  else
272  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
273  }
274 }
Relids ph_needed
Definition: pathnodes.h:2404
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Relids * attr_needed
Definition: pathnodes.h:709
Definition: nodes.h:539
AttrNumber varattno
Definition: primnodes.h:191
Definition: primnodes.h:186
#define ERROR
Definition: elog.h:46
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:315
PlaceHolderInfo * find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv, bool create_new_ph)
Definition: placeholder.c:69
Relids relids
Definition: pathnodes.h:676
List * lappend(List *list, void *datum)
Definition: list.c:336
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
Index varno
Definition: primnodes.h:189
List * exprs
Definition: pathnodes.h:1102
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
#define nodeTag(nodeptr)
Definition: nodes.h:544
#define elog(elevel,...)
Definition: elog.h:232
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:374
#define copyObject(obj)
Definition: nodes.h:655
struct PathTarget * reltarget
Definition: pathnodes.h:687
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793
AttrNumber min_attr
Definition: pathnodes.h:707

◆ build_base_rel_tlists()

void build_base_rel_tlists ( PlannerInfo root,
List final_tlist 
)

Definition at line 183 of file initsplan.c.

References add_vars_to_targetlist(), bms_make_singleton(), Query::havingQual, list_free(), NIL, PlannerInfo::parse, pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, and PVC_RECURSE_WINDOWFUNCS.

Referenced by query_planner().

184 {
185  List *tlist_vars = pull_var_clause((Node *) final_tlist,
189 
190  if (tlist_vars != NIL)
191  {
192  add_vars_to_targetlist(root, tlist_vars, bms_make_singleton(0), true);
193  list_free(tlist_vars);
194  }
195 
196  /*
197  * If there's a HAVING clause, we'll need the Vars it uses, too. Note
198  * that HAVING can contain Aggrefs but not WindowFuncs.
199  */
200  if (root->parse->havingQual)
201  {
202  List *having_vars = pull_var_clause(root->parse->havingQual,
205 
206  if (having_vars != NIL)
207  {
208  add_vars_to_targetlist(root, having_vars,
209  bms_make_singleton(0), true);
210  list_free(having_vars);
211  }
212  }
213 }
#define NIL
Definition: pg_list.h:65
Query * parse
Definition: pathnodes.h:161
Definition: nodes.h:539
List * pull_var_clause(Node *node, int flags)
Definition: var.c:562
void add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed, bool create_new_ph)
Definition: initsplan.c:230
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:190
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:189
void list_free(List *list)
Definition: list.c:1391
Node * havingQual
Definition: parsenodes.h:163
Definition: pg_list.h:50
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:187

◆ build_implied_join_equality()

RestrictInfo* build_implied_join_equality ( PlannerInfo root,
Oid  opno,
Oid  collation,
Expr item1,
Expr item2,
Relids  qualscope,
Relids  nullable_relids,
Index  security_level 
)

Definition at line 2422 of file initsplan.c.

References check_hashjoinable(), check_memoizable(), check_mergejoinable(), copyObject, InvalidOid, make_opclause(), and make_restrictinfo().

Referenced by create_join_clause(), reconsider_full_join_clause(), and reconsider_outer_join_clause().

2430 {
2431  RestrictInfo *restrictinfo;
2432  Expr *clause;
2433 
2434  /*
2435  * Build the new clause. Copy to ensure it shares no substructure with
2436  * original (this is necessary in case there are subselects in there...)
2437  */
2438  clause = make_opclause(opno,
2439  BOOLOID, /* opresulttype */
2440  false, /* opretset */
2441  copyObject(item1),
2442  copyObject(item2),
2443  InvalidOid,
2444  collation);
2445 
2446  /*
2447  * Build the RestrictInfo node itself.
2448  */
2449  restrictinfo = make_restrictinfo(root,
2450  clause,
2451  true, /* is_pushed_down */
2452  false, /* outerjoin_delayed */
2453  false, /* pseudoconstant */
2454  security_level, /* security_level */
2455  qualscope, /* required_relids */
2456  NULL, /* outer_relids */
2457  nullable_relids); /* nullable_relids */
2458 
2459  /* Set mergejoinability/hashjoinability flags */
2460  check_mergejoinable(restrictinfo);
2461  check_hashjoinable(restrictinfo);
2462  check_memoizable(restrictinfo);
2463 
2464  return restrictinfo;
2465 }
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: makefuncs.c:610
RestrictInfo * make_restrictinfo(PlannerInfo *root, Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids)
Definition: restrictinfo.c:61
#define InvalidOid
Definition: postgres_ext.h:36
static void check_mergejoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:2653
static void check_hashjoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:2690
#define copyObject(obj)
Definition: nodes.h:655
static void check_memoizable(RestrictInfo *restrictinfo)
Definition: initsplan.c:2718

◆ change_plan_targetlist()

Plan* change_plan_targetlist ( Plan subplan,
List tlist,
bool  tlist_parallel_safe 
)

Definition at line 2067 of file createplan.c.

References inject_projection_plan(), is_projection_capable_plan(), Plan::parallel_safe, Plan::targetlist, and tlist_same_exprs().

Referenced by create_unique_plan(), and postgresGetForeignPlan().

2068 {
2069  /*
2070  * If the top plan node can't do projections and its existing target list
2071  * isn't already what we need, we need to add a Result node to help it
2072  * along.
2073  */
2074  if (!is_projection_capable_plan(subplan) &&
2075  !tlist_same_exprs(tlist, subplan->targetlist))
2076  subplan = inject_projection_plan(subplan, tlist,
2077  subplan->parallel_safe &&
2078  tlist_parallel_safe);
2079  else
2080  {
2081  /* Else we can just replace the plan node's tlist */
2082  subplan->targetlist = tlist;
2083  subplan->parallel_safe &= tlist_parallel_safe;
2084  }
2085  return subplan;
2086 }
bool is_projection_capable_plan(Plan *plan)
Definition: createplan.c:7078
static Plan * inject_projection_plan(Plan *subplan, List *tlist, bool parallel_safe)
Definition: createplan.c:2035
bool tlist_same_exprs(List *tlist1, List *tlist2)
Definition: tlist.c:207
List * targetlist
Definition: plannodes.h:141
bool parallel_safe
Definition: plannodes.h:130

◆ create_lateral_join_info()

void create_lateral_join_info ( PlannerInfo root)

Definition at line 450 of file initsplan.c.

References Assert, bms_add_member(), bms_add_members(), bms_copy(), bms_get_singleton_member(), bms_is_empty(), bms_is_member(), bms_next_member(), RelOptInfo::direct_lateral_relids, find_base_rel(), find_placeholder_info(), PlannerInfo::hasLateralRTEs, IsA, RelOptInfo::lateral_referencers, RelOptInfo::lateral_relids, RelOptInfo::lateral_vars, lfirst, PlaceHolderInfo::ph_eval_at, PlaceHolderInfo::ph_lateral, PlannerInfo::placeholder_list, RelOptInfo::relid, RELOPT_BASEREL, RelOptInfo::reloptkind, PlannerInfo::simple_rel_array, PlannerInfo::simple_rel_array_size, and Var::varno.

Referenced by query_planner().

451 {
452  bool found_laterals = false;
453  Index rti;
454  ListCell *lc;
455 
456  /* We need do nothing if the query contains no LATERAL RTEs */
457  if (!root->hasLateralRTEs)
458  return;
459 
460  /*
461  * Examine all baserels (the rel array has been set up by now).
462  */
463  for (rti = 1; rti < root->simple_rel_array_size; rti++)
464  {
465  RelOptInfo *brel = root->simple_rel_array[rti];
466  Relids lateral_relids;
467 
468  /* there may be empty slots corresponding to non-baserel RTEs */
469  if (brel == NULL)
470  continue;
471 
472  Assert(brel->relid == rti); /* sanity check on array */
473 
474  /* ignore RTEs that are "other rels" */
475  if (brel->reloptkind != RELOPT_BASEREL)
476  continue;
477 
478  lateral_relids = NULL;
479 
480  /* consider each laterally-referenced Var or PHV */
481  foreach(lc, brel->lateral_vars)
482  {
483  Node *node = (Node *) lfirst(lc);
484 
485  if (IsA(node, Var))
486  {
487  Var *var = (Var *) node;
488 
489  found_laterals = true;
490  lateral_relids = bms_add_member(lateral_relids,
491  var->varno);
492  }
493  else if (IsA(node, PlaceHolderVar))
494  {
495  PlaceHolderVar *phv = (PlaceHolderVar *) node;
496  PlaceHolderInfo *phinfo = find_placeholder_info(root, phv,
497  false);
498 
499  found_laterals = true;
500  lateral_relids = bms_add_members(lateral_relids,
501  phinfo->ph_eval_at);
502  }
503  else
504  Assert(false);
505  }
506 
507  /* We now have all the simple lateral refs from this rel */
508  brel->direct_lateral_relids = lateral_relids;
509  brel->lateral_relids = bms_copy(lateral_relids);
510  }
511 
512  /*
513  * Now check for lateral references within PlaceHolderVars, and mark their
514  * eval_at rels as having lateral references to the source rels.
515  *
516  * For a PHV that is due to be evaluated at a baserel, mark its source(s)
517  * as direct lateral dependencies of the baserel (adding onto the ones
518  * recorded above). If it's due to be evaluated at a join, mark its
519  * source(s) as indirect lateral dependencies of each baserel in the join,
520  * ie put them into lateral_relids but not direct_lateral_relids. This is
521  * appropriate because we can't put any such baserel on the outside of a
522  * join to one of the PHV's lateral dependencies, but on the other hand we
523  * also can't yet join it directly to the dependency.
524  */
525  foreach(lc, root->placeholder_list)
526  {
527  PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc);
528  Relids eval_at = phinfo->ph_eval_at;
529  int varno;
530 
531  if (phinfo->ph_lateral == NULL)
532  continue; /* PHV is uninteresting if no lateral refs */
533 
534  found_laterals = true;
535 
536  if (bms_get_singleton_member(eval_at, &varno))
537  {
538  /* Evaluation site is a baserel */
539  RelOptInfo *brel = find_base_rel(root, varno);
540 
541  brel->direct_lateral_relids =
543  phinfo->ph_lateral);
544  brel->lateral_relids =
546  phinfo->ph_lateral);
547  }
548  else
549  {
550  /* Evaluation site is a join */
551  varno = -1;
552  while ((varno = bms_next_member(eval_at, varno)) >= 0)
553  {
554  RelOptInfo *brel = find_base_rel(root, varno);
555 
557  phinfo->ph_lateral);
558  }
559  }
560  }
561 
562  /*
563  * If we found no actual lateral references, we're done; but reset the
564  * hasLateralRTEs flag to avoid useless work later.
565  */
566  if (!found_laterals)
567  {
568  root->hasLateralRTEs = false;
569  return;
570  }
571 
572  /*
573  * Calculate the transitive closure of the lateral_relids sets, so that
574  * they describe both direct and indirect lateral references. If relation
575  * X references Y laterally, and Y references Z laterally, then we will
576  * have to scan X on the inside of a nestloop with Z, so for all intents
577  * and purposes X is laterally dependent on Z too.
578  *
579  * This code is essentially Warshall's algorithm for transitive closure.
580  * The outer loop considers each baserel, and propagates its lateral
581  * dependencies to those baserels that have a lateral dependency on it.
582  */
583  for (rti = 1; rti < root->simple_rel_array_size; rti++)
584  {
585  RelOptInfo *brel = root->simple_rel_array[rti];
586  Relids outer_lateral_relids;
587  Index rti2;
588 
589  if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
590  continue;
591 
592  /* need not consider baserel further if it has no lateral refs */
593  outer_lateral_relids = brel->lateral_relids;
594  if (outer_lateral_relids == NULL)
595  continue;
596 
597  /* else scan all baserels */
598  for (rti2 = 1; rti2 < root->simple_rel_array_size; rti2++)
599  {
600  RelOptInfo *brel2 = root->simple_rel_array[rti2];
601 
602  if (brel2 == NULL || brel2->reloptkind != RELOPT_BASEREL)
603  continue;
604 
605  /* if brel2 has lateral ref to brel, propagate brel's refs */
606  if (bms_is_member(rti, brel2->lateral_relids))
608  outer_lateral_relids);
609  }
610  }
611 
612  /*
613  * Now that we've identified all lateral references, mark each baserel
614  * with the set of relids of rels that reference it laterally (possibly
615  * indirectly) --- that is, the inverse mapping of lateral_relids.
616  */
617  for (rti = 1; rti < root->simple_rel_array_size; rti++)
618  {
619  RelOptInfo *brel = root->simple_rel_array[rti];
620  Relids lateral_relids;
621  int rti2;
622 
623  if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
624  continue;
625 
626  /* Nothing to do at rels with no lateral refs */
627  lateral_relids = brel->lateral_relids;
628  if (lateral_relids == NULL)
629  continue;
630 
631  /*
632  * We should not have broken the invariant that lateral_relids is
633  * exactly NULL if empty.
634  */
635  Assert(!bms_is_empty(lateral_relids));
636 
637  /* Also, no rel should have a lateral dependency on itself */
638  Assert(!bms_is_member(rti, lateral_relids));
639 
640  /* Mark this rel's referencees */
641  rti2 = -1;
642  while ((rti2 = bms_next_member(lateral_relids, rti2)) >= 0)
643  {
644  RelOptInfo *brel2 = root->simple_rel_array[rti2];
645 
646  Assert(brel2 != NULL && brel2->reloptkind == RELOPT_BASEREL);
647  brel2->lateral_referencers =
648  bms_add_member(brel2->lateral_referencers, rti);
649  }
650  }
651 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
Relids ph_eval_at
Definition: pathnodes.h:2402
RelOptKind reloptkind
Definition: pathnodes.h:673
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
Definition: nodes.h:539
bool bms_get_singleton_member(const Bitmapset *a, int *member)
Definition: bitmapset.c:615
Definition: primnodes.h:186
struct RelOptInfo ** simple_rel_array
Definition: pathnodes.h:185
Relids lateral_relids
Definition: pathnodes.h:701
bool hasLateralRTEs
Definition: pathnodes.h:346
PlaceHolderInfo * find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv, bool create_new_ph)
Definition: placeholder.c:69
int simple_rel_array_size
Definition: pathnodes.h:186
Index relid
Definition: pathnodes.h:704
Relids lateral_referencers
Definition: pathnodes.h:712
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
Index varno
Definition: primnodes.h:189
Relids direct_lateral_relids
Definition: pathnodes.h:700
Relids ph_lateral
Definition: pathnodes.h:2403
unsigned int Index
Definition: c.h:549
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
List * lateral_vars
Definition: pathnodes.h:711
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
List * placeholder_list
Definition: pathnodes.h:289
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:374
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793

◆ create_plan()

Plan* create_plan ( PlannerInfo root,
Path best_path 
)

Definition at line 332 of file createplan.c.

References apply_tlist_labeling(), Assert, CP_EXACT_TLIST, create_plan_recurse(), PlannerInfo::curOuterParams, PlannerInfo::curOuterRels, elog, ERROR, IsA, NIL, PlannerInfo::plan_params, PlannerInfo::processed_tlist, SS_attach_initplans(), and Plan::targetlist.

Referenced by create_minmaxagg_plan(), create_subqueryscan_plan(), make_subplan(), SS_process_ctes(), and standard_planner().

333 {
334  Plan *plan;
335 
336  /* plan_params should not be in use in current query level */
337  Assert(root->plan_params == NIL);
338 
339  /* Initialize this module's workspace in PlannerInfo */
340  root->curOuterRels = NULL;
341  root->curOuterParams = NIL;
342 
343  /* Recursively process the path tree, demanding the correct tlist result */
344  plan = create_plan_recurse(root, best_path, CP_EXACT_TLIST);
345 
346  /*
347  * Make sure the topmost plan node's targetlist exposes the original
348  * column names and other decorative info. Targetlists generated within
349  * the planner don't bother with that stuff, but we must have it on the
350  * top-level tlist seen at execution time. However, ModifyTable plan
351  * nodes don't have a tlist matching the querytree targetlist.
352  */
353  if (!IsA(plan, ModifyTable))
355 
356  /*
357  * Attach any initPlans created in this query level to the topmost plan
358  * node. (In principle the initplans could go in any plan node at or
359  * above where they're referenced, but there seems no reason to put them
360  * any lower than the topmost node for the query level. Also, see
361  * comments for SS_finalize_plan before you try to change this.)
362  */
363  SS_attach_initplans(root, plan);
364 
365  /* Check we successfully assigned all NestLoopParams to plan nodes */
366  if (root->curOuterParams != NIL)
367  elog(ERROR, "failed to assign all NestLoopParams to plan nodes");
368 
369  /*
370  * Reset plan_params to ensure param IDs used for nestloop params are not
371  * re-used later
372  */
373  root->plan_params = NIL;
374 
375  return plan;
376 }
#define NIL
Definition: pg_list.h:65
void apply_tlist_labeling(List *dest_tlist, List *src_tlist)
Definition: tlist.c:307
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
List * plan_params
Definition: pathnodes.h:175
Relids curOuterRels
Definition: pathnodes.h:367
static Plan * create_plan_recurse(PlannerInfo *root, Path *best_path, int flags)
Definition: createplan.c:383
#define ERROR
Definition: elog.h:46
List * curOuterParams
Definition: pathnodes.h:368
#define Assert(condition)
Definition: c.h:804
void SS_attach_initplans(PlannerInfo *root, Plan *plan)
Definition: subselect.c:2186
List * targetlist
Definition: plannodes.h:141
#define elog(elevel,...)
Definition: elog.h:232
List * processed_tlist
Definition: pathnodes.h:320
#define CP_EXACT_TLIST
Definition: createplan.c:69

◆ deconstruct_jointree()

List* deconstruct_jointree ( PlannerInfo root)

Definition at line 687 of file initsplan.c.

References Assert, deconstruct_recurse(), IsA, Query::jointree, NIL, PlannerInfo::nullable_baserels, and PlannerInfo::parse.

Referenced by query_planner().

688 {
689  List *result;
690  Relids qualscope;
691  Relids inner_join_rels;
692  List *postponed_qual_list = NIL;
693 
694  /* Start recursion at top of jointree */
695  Assert(root->parse->jointree != NULL &&
696  IsA(root->parse->jointree, FromExpr));
697 
698  /* this is filled as we scan the jointree */
699  root->nullable_baserels = NULL;
700 
701  result = deconstruct_recurse(root, (Node *) root->parse->jointree, false,
702  &qualscope, &inner_join_rels,
703  &postponed_qual_list);
704 
705  /* Shouldn't be any leftover quals */
706  Assert(postponed_qual_list == NIL);
707 
708  return result;
709 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Query * parse
Definition: pathnodes.h:161
FromExpr * jointree
Definition: parsenodes.h:148
Definition: nodes.h:539
#define Assert(condition)
Definition: c.h:804
static List * deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join, Relids *qualscope, Relids *inner_join_rels, List **postponed_qual_list)
Definition: initsplan.c:733
Relids nullable_baserels
Definition: pathnodes.h:217
Definition: pg_list.h:50

◆ distribute_restrictinfo_to_rels()

void distribute_restrictinfo_to_rels ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 2177 of file initsplan.c.

References add_join_clause_to_rels(), RelOptInfo::baserestrict_min_security, RelOptInfo::baserestrictinfo, bms_membership(), BMS_MULTIPLE, BMS_SINGLETON, bms_singleton_member(), check_hashjoinable(), check_memoizable(), elog, ERROR, find_base_rel(), lappend(), Min, PostponedQual::relids, RestrictInfo::required_relids, and RestrictInfo::security_level.

Referenced by distribute_qual_to_rels(), generate_base_implied_equalities_broken(), generate_base_implied_equalities_const(), process_implied_equality(), reconsider_outer_join_clauses(), and remove_rel_from_query().

2179 {
2180  Relids relids = restrictinfo->required_relids;
2181  RelOptInfo *rel;
2182 
2183  switch (bms_membership(relids))
2184  {
2185  case BMS_SINGLETON:
2186 
2187  /*
2188  * There is only one relation participating in the clause, so it
2189  * is a restriction clause for that relation.
2190  */
2191  rel = find_base_rel(root, bms_singleton_member(relids));
2192 
2193  /* Add clause to rel's restriction list */
2195  restrictinfo);
2196  /* Update security level info */
2198  restrictinfo->security_level);
2199  break;
2200  case BMS_MULTIPLE:
2201 
2202  /*
2203  * The clause is a join clause, since there is more than one rel
2204  * in its relid set.
2205  */
2206 
2207  /*
2208  * Check for hashjoinable operators. (We don't bother setting the
2209  * hashjoin info except in true join clauses.)
2210  */
2211  check_hashjoinable(restrictinfo);
2212 
2213  /*
2214  * Likewise, check if the clause is suitable to be used with a
2215  * Memoize node to cache inner tuples during a parameterized
2216  * nested loop.
2217  */
2218  check_memoizable(restrictinfo);
2219 
2220  /*
2221  * Add clause to the join lists of all the relevant relations.
2222  */
2223  add_join_clause_to_rels(root, restrictinfo, relids);
2224  break;
2225  default:
2226 
2227  /*
2228  * clause references no rels, and therefore we have no place to
2229  * attach it. Shouldn't get here if callers are working properly.
2230  */
2231  elog(ERROR, "cannot cope with variable-free clause");
2232  break;
2233  }
2234 }
Index security_level
Definition: pathnodes.h:2060
Relids required_relids
Definition: pathnodes.h:2066
List * baserestrictinfo
Definition: pathnodes.h:740
#define Min(x, y)
Definition: c.h:986
Index baserestrict_min_security
Definition: pathnodes.h:742
#define ERROR
Definition: elog.h:46
List * lappend(List *list, void *datum)
Definition: list.c:336
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:672
int bms_singleton_member(const Bitmapset *a)
Definition: bitmapset.c:577
void add_join_clause_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo, Relids join_relids)
Definition: joininfo.c:95
static void check_hashjoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:2690
#define elog(elevel,...)
Definition: elog.h:232
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:374
static void check_memoizable(RestrictInfo *restrictinfo)
Definition: initsplan.c:2718

◆ extract_query_dependencies_walker()

bool extract_query_dependencies_walker ( Node node,
PlannerInfo root 
)

Definition at line 3069 of file setrefs.c.

References Assert, CMD_UTILITY, Query::commandType, PlannerGlobal::dependsOnRole, expression_tree_walker(), extract_query_dependencies_walker(), fix_expr_common(), PlannerInfo::glob, Query::hasRowSecurity, IsA, lappend_oid(), lfirst, OidIsValid, query_tree_walker(), PlannerGlobal::relationOids, RangeTblEntry::relid, Query::rtable, RTE_NAMEDTUPLESTORE, RTE_RELATION, RangeTblEntry::rtekind, UtilityContainsQuery(), and Query::utilityStmt.

Referenced by expression_planner_with_deps(), extract_query_dependencies(), and extract_query_dependencies_walker().

3070 {
3071  if (node == NULL)
3072  return false;
3073  Assert(!IsA(node, PlaceHolderVar));
3074  if (IsA(node, Query))
3075  {
3076  Query *query = (Query *) node;
3077  ListCell *lc;
3078 
3079  if (query->commandType == CMD_UTILITY)
3080  {
3081  /*
3082  * Ignore utility statements, except those (such as EXPLAIN) that
3083  * contain a parsed-but-not-planned query.
3084  */
3085  query = UtilityContainsQuery(query->utilityStmt);
3086  if (query == NULL)
3087  return false;
3088  }
3089 
3090  /* Remember if any Query has RLS quals applied by rewriter */
3091  if (query->hasRowSecurity)
3092  context->glob->dependsOnRole = true;
3093 
3094  /* Collect relation OIDs in this Query's rtable */
3095  foreach(lc, query->rtable)
3096  {
3097  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3098 
3099  if (rte->rtekind == RTE_RELATION)
3100  context->glob->relationOids =
3101  lappend_oid(context->glob->relationOids, rte->relid);
3102  else if (rte->rtekind == RTE_NAMEDTUPLESTORE &&
3103  OidIsValid(rte->relid))
3104  context->glob->relationOids =
3105  lappend_oid(context->glob->relationOids,
3106  rte->relid);
3107  }
3108 
3109  /* And recurse into the query's subexpressions */
3111  (void *) context, 0);
3112  }
3113  /* Extract function dependencies and check for regclass Consts */
3114  fix_expr_common(context, node);
3116  (void *) context);
3117 }
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2355
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Node * utilityStmt
Definition: parsenodes.h:128
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
#define OidIsValid(objectId)
Definition: c.h:710
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2137
List * rtable
Definition: parsenodes.h:147
bool extract_query_dependencies_walker(Node *node, PlannerInfo *context)
Definition: setrefs.c:3069
static void fix_expr_common(PlannerInfo *root, Node *node)
Definition: setrefs.c:1645
CmdType commandType
Definition: parsenodes.h:120
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1904
RTEKind rtekind
Definition: parsenodes.h:995
bool hasRowSecurity
Definition: parsenodes.h:141

◆ find_lateral_references()

void find_lateral_references ( PlannerInfo root)

Definition at line 304 of file initsplan.c.

References Assert, extract_lateral_references(), PlannerInfo::hasLateralRTEs, RelOptInfo::relid, RELOPT_BASEREL, RelOptInfo::reloptkind, PlannerInfo::simple_rel_array, and PlannerInfo::simple_rel_array_size.

Referenced by query_planner().

305 {
306  Index rti;
307 
308  /* We need do nothing if the query contains no LATERAL RTEs */
309  if (!root->hasLateralRTEs)
310  return;
311 
312  /*
313  * Examine all baserels (the rel array has been set up by now).
314  */
315  for (rti = 1; rti < root->simple_rel_array_size; rti++)
316  {
317  RelOptInfo *brel = root->simple_rel_array[rti];
318 
319  /* there may be empty slots corresponding to non-baserel RTEs */
320  if (brel == NULL)
321  continue;
322 
323  Assert(brel->relid == rti); /* sanity check on array */
324 
325  /*
326  * This bit is less obvious than it might look. We ignore appendrel
327  * otherrels and consider only their parent baserels. In a case where
328  * a LATERAL-containing UNION ALL subquery was pulled up, it is the
329  * otherrel that is actually going to be in the plan. However, we
330  * want to mark all its lateral references as needed by the parent,
331  * because it is the parent's relid that will be used for join
332  * planning purposes. And the parent's RTE will contain all the
333  * lateral references we need to know, since the pulled-up member is
334  * nothing but a copy of parts of the original RTE's subquery. We
335  * could visit the parent's children instead and transform their
336  * references back to the parent's relid, but it would be much more
337  * complicated for no real gain. (Important here is that the child
338  * members have not yet received any processing beyond being pulled
339  * up.) Similarly, in appendrels created by inheritance expansion,
340  * it's sufficient to look at the parent relation.
341  */
342 
343  /* ignore RTEs that are "other rels" */
344  if (brel->reloptkind != RELOPT_BASEREL)
345  continue;
346 
347  extract_lateral_references(root, brel, rti);
348  }
349 }
RelOptKind reloptkind
Definition: pathnodes.h:673
struct RelOptInfo ** simple_rel_array
Definition: pathnodes.h:185
bool hasLateralRTEs
Definition: pathnodes.h:346
int simple_rel_array_size
Definition: pathnodes.h:186
Index relid
Definition: pathnodes.h:704
unsigned int Index
Definition: c.h:549
#define Assert(condition)
Definition: c.h:804
static void extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex)
Definition: initsplan.c:352

◆ innerrel_is_unique()

bool innerrel_is_unique ( PlannerInfo root,
Relids  joinrelids,
Relids  outerrelids,
RelOptInfo innerrel,
JoinType  jointype,
List restrictlist,
bool  force_cache 
)

Definition at line 964 of file analyzejoins.c.

References bms_copy(), bms_is_subset(), is_innerrel_unique_for(), PlannerInfo::join_search_private, lappend(), lfirst, MemoryContextSwitchTo(), NIL, RelOptInfo::non_unique_for_rels, PlannerInfo::planner_cxt, rel_supports_distinctness(), and RelOptInfo::unique_for_rels.

Referenced by add_paths_to_joinrel(), and reduce_unique_semijoins().

971 {
972  MemoryContext old_context;
973  ListCell *lc;
974 
975  /* Certainly can't prove uniqueness when there are no joinclauses */
976  if (restrictlist == NIL)
977  return false;
978 
979  /*
980  * Make a quick check to eliminate cases in which we will surely be unable
981  * to prove uniqueness of the innerrel.
982  */
983  if (!rel_supports_distinctness(root, innerrel))
984  return false;
985 
986  /*
987  * Query the cache to see if we've managed to prove that innerrel is
988  * unique for any subset of this outerrel. We don't need an exact match,
989  * as extra outerrels can't make the innerrel any less unique (or more
990  * formally, the restrictlist for a join to a superset outerrel must be a
991  * superset of the conditions we successfully used before).
992  */
993  foreach(lc, innerrel->unique_for_rels)
994  {
995  Relids unique_for_rels = (Relids) lfirst(lc);
996 
997  if (bms_is_subset(unique_for_rels, outerrelids))
998  return true; /* Success! */
999  }
1000 
1001  /*
1002  * Conversely, we may have already determined that this outerrel, or some
1003  * superset thereof, cannot prove this innerrel to be unique.
1004  */
1005  foreach(lc, innerrel->non_unique_for_rels)
1006  {
1007  Relids unique_for_rels = (Relids) lfirst(lc);
1008 
1009  if (bms_is_subset(outerrelids, unique_for_rels))
1010  return false;
1011  }
1012 
1013  /* No cached information, so try to make the proof. */
1014  if (is_innerrel_unique_for(root, joinrelids, outerrelids, innerrel,
1015  jointype, restrictlist))
1016  {
1017  /*
1018  * Cache the positive result for future probes, being sure to keep it
1019  * in the planner_cxt even if we are working in GEQO.
1020  *
1021  * Note: one might consider trying to isolate the minimal subset of
1022  * the outerrels that proved the innerrel unique. But it's not worth
1023  * the trouble, because the planner builds up joinrels incrementally
1024  * and so we'll see the minimally sufficient outerrels before any
1025  * supersets of them anyway.
1026  */
1027  old_context = MemoryContextSwitchTo(root->planner_cxt);
1028  innerrel->unique_for_rels = lappend(innerrel->unique_for_rels,
1029  bms_copy(outerrelids));
1030  MemoryContextSwitchTo(old_context);
1031 
1032  return true; /* Success! */
1033  }
1034  else
1035  {
1036  /*
1037  * None of the join conditions for outerrel proved innerrel unique, so
1038  * we can safely reject this outerrel or any subset of it in future
1039  * checks.
1040  *
1041  * However, in normal planning mode, caching this knowledge is totally
1042  * pointless; it won't be queried again, because we build up joinrels
1043  * from smaller to larger. It is useful in GEQO mode, where the
1044  * knowledge can be carried across successive planning attempts; and
1045  * it's likely to be useful when using join-search plugins, too. Hence
1046  * cache when join_search_private is non-NULL. (Yeah, that's a hack,
1047  * but it seems reasonable.)
1048  *
1049  * Also, allow callers to override that heuristic and force caching;
1050  * that's useful for reduce_unique_semijoins, which calls here before
1051  * the normal join search starts.
1052  */
1053  if (force_cache || root->join_search_private)
1054  {
1055  old_context = MemoryContextSwitchTo(root->planner_cxt);
1056  innerrel->non_unique_for_rels =
1057  lappend(innerrel->non_unique_for_rels,
1058  bms_copy(outerrelids));
1059  MemoryContextSwitchTo(old_context);
1060  }
1061 
1062  return false;
1063  }
1064 }
static bool is_innerrel_unique_for(PlannerInfo *root, Relids joinrelids, Relids outerrelids, RelOptInfo *innerrel, JoinType jointype, List *restrictlist)
#define NIL
Definition: pg_list.h:65
List * unique_for_rels
Definition: pathnodes.h:735
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
void * join_search_private
Definition: pathnodes.h:371
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:315
List * non_unique_for_rels
Definition: pathnodes.h:737
List * lappend(List *list, void *datum)
Definition: list.c:336
#define lfirst(lc)
Definition: pg_list.h:169
Bitmapset * Relids
Definition: pathnodes.h:28
MemoryContext planner_cxt
Definition: pathnodes.h:334
static bool rel_supports_distinctness(PlannerInfo *root, RelOptInfo *rel)
Definition: analyzejoins.c:585

◆ is_projection_capable_path()

bool is_projection_capable_path ( Path path)

Definition at line 7028 of file createplan.c.

References castNode, CUSTOMPATH_SUPPORT_PROJECTION, IS_DUMMY_APPEND, Path::pathtype, T_Append, T_CustomScan, T_Hash, T_IncrementalSort, T_Limit, T_LockRows, T_Material, T_Memoize, T_MergeAppend, T_ModifyTable, T_ProjectSet, T_RecursiveUnion, T_SetOp, T_Sort, and T_Unique.

Referenced by apply_projection_to_path(), create_projection_path(), and create_projection_plan().

7029 {
7030  /* Most plan types can project, so just list the ones that can't */
7031  switch (path->pathtype)
7032  {
7033  case T_Hash:
7034  case T_Material:
7035  case T_Memoize:
7036  case T_Sort:
7037  case T_IncrementalSort:
7038  case T_Unique:
7039  case T_SetOp:
7040  case T_LockRows:
7041  case T_Limit:
7042  case T_ModifyTable:
7043  case T_MergeAppend:
7044  case T_RecursiveUnion:
7045  return false;
7046  case T_CustomScan:
7048  return true;
7049  return false;
7050  case T_Append:
7051 
7052  /*
7053  * Append can't project, but if an AppendPath is being used to
7054  * represent a dummy path, what will actually be generated is a
7055  * Result which can project.
7056  */
7057  return IS_DUMMY_APPEND(path);
7058  case T_ProjectSet:
7059 
7060  /*
7061  * Although ProjectSet certainly projects, say "no" because we
7062  * don't want the planner to randomly replace its tlist with
7063  * something else; the SRFs have to stay at top level. This might
7064  * get relaxed later.
7065  */
7066  return false;
7067  default:
7068  break;
7069  }
7070  return true;
7071 }
Definition: nodes.h:83
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
Definition: nodes.h:49
Definition: nodes.h:78
NodeTag pathtype
Definition: pathnodes.h:1172
#define CUSTOMPATH_SUPPORT_PROJECTION
Definition: extensible.h:84
Definition: nodes.h:86
#define IS_DUMMY_APPEND(p)
Definition: pathnodes.h:1450
Definition: nodes.h:87
Definition: nodes.h:89

◆ is_projection_capable_plan()

bool is_projection_capable_plan ( Plan plan)

Definition at line 7078 of file createplan.c.

References CUSTOMPATH_SUPPORT_PROJECTION, nodeTag, T_Append, T_CustomScan, T_Hash, T_Limit, T_LockRows, T_Material, T_Memoize, T_MergeAppend, T_ModifyTable, T_ProjectSet, T_RecursiveUnion, T_SetOp, T_Sort, and T_Unique.

Referenced by change_plan_targetlist(), create_projection_plan(), and prepare_sort_from_pathkeys().

7079 {
7080  /* Most plan types can project, so just list the ones that can't */
7081  switch (nodeTag(plan))
7082  {
7083  case T_Hash:
7084  case T_Material:
7085  case T_Memoize:
7086  case T_Sort:
7087  case T_Unique:
7088  case T_SetOp:
7089  case T_LockRows:
7090  case T_Limit:
7091  case T_ModifyTable:
7092  case T_Append:
7093  case T_MergeAppend:
7094  case T_RecursiveUnion:
7095  return false;
7096  case T_CustomScan:
7097  if (((CustomScan *) plan)->flags & CUSTOMPATH_SUPPORT_PROJECTION)
7098  return true;
7099  return false;
7100  case T_ProjectSet:
7101 
7102  /*
7103  * Although ProjectSet certainly projects, say "no" because we
7104  * don't want the planner to randomly replace its tlist with
7105  * something else; the SRFs have to stay at top level. This might
7106  * get relaxed later.
7107  */
7108  return false;
7109  default:
7110  break;
7111  }
7112  return true;
7113 }
Definition: nodes.h:83
Definition: nodes.h:49
Definition: nodes.h:78
#define CUSTOMPATH_SUPPORT_PROJECTION
Definition: extensible.h:84
Definition: nodes.h:86
#define nodeTag(nodeptr)
Definition: nodes.h:544
Definition: nodes.h:87
Definition: nodes.h:89

◆ make_agg()

Agg* make_agg ( List tlist,
List qual,
AggStrategy  aggstrategy,
AggSplit  aggsplit,
int  numGroupCols,
AttrNumber grpColIdx,
Oid grpOperators,
Oid grpCollations,
List groupingSets,
List chain,
double  dNumGroups,
Size  transitionSpace,
Plan lefttree 
)

Definition at line 6440 of file createplan.c.

References Agg::aggParams, Agg::aggsplit, Agg::aggstrategy, Agg::chain, Agg::groupingSets, Agg::grpColIdx, Agg::grpCollations, Agg::grpOperators, Plan::lefttree, makeNode, Min, Agg::numCols, Agg::numGroups, Agg::plan, Plan::qual, Plan::righttree, Plan::targetlist, and Agg::transitionSpace.

Referenced by create_agg_plan(), create_groupingsets_plan(), and create_unique_plan().

6445 {
6446  Agg *node = makeNode(Agg);
6447  Plan *plan = &node->plan;
6448  long numGroups;
6449 
6450  /* Reduce to long, but 'ware overflow! */
6451  numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
6452 
6453  node->aggstrategy = aggstrategy;
6454  node->aggsplit = aggsplit;
6455  node->numCols = numGroupCols;
6456  node->grpColIdx = grpColIdx;
6457  node->grpOperators = grpOperators;
6458  node->grpCollations = grpCollations;
6459  node->numGroups = numGroups;
6460  node->transitionSpace = transitionSpace;
6461  node->aggParams = NULL; /* SS_finalize_plan() will fill this */
6462  node->groupingSets = groupingSets;
6463  node->chain = chain;
6464 
6465  plan->qual = qual;
6466  plan->targetlist = tlist;
6467  plan->lefttree = lefttree;
6468  plan->righttree = NULL;
6469 
6470  return node;
6471 }
int numCols
Definition: plannodes.h:862
List * qual
Definition: plannodes.h:142
AttrNumber * grpColIdx
Definition: plannodes.h:863
uint64 transitionSpace
Definition: plannodes.h:867
Oid * grpCollations
Definition: plannodes.h:865
#define Min(x, y)
Definition: c.h:986
struct Plan * righttree
Definition: plannodes.h:144
AggStrategy aggstrategy
Definition: plannodes.h:860
Bitmapset * aggParams
Definition: plannodes.h:868
Plan plan
Definition: plannodes.h:859
List * groupingSets
Definition: plannodes.h:870
#define makeNode(_type_)
Definition: nodes.h:587
AggSplit aggsplit
Definition: plannodes.h:861
long numGroups
Definition: plannodes.h:866
struct Plan * lefttree
Definition: plannodes.h:143
List * targetlist
Definition: plannodes.h:141
Oid * grpOperators
Definition: plannodes.h:864
List * chain
Definition: plannodes.h:871
Definition: plannodes.h:857

◆ make_foreignscan()

ForeignScan* make_foreignscan ( List qptlist,
List qpqual,
Index  scanrelid,
List fdw_exprs,
List fdw_private,
List fdw_scan_tlist,
List fdw_recheck_quals,
Plan outer_plan 
)

Definition at line 5678 of file createplan.c.

References CMD_SELECT, ForeignScan::fdw_exprs, ForeignScan::fdw_private, ForeignScan::fdw_recheck_quals, ForeignScan::fdw_scan_tlist, ForeignScan::fs_relids, ForeignScan::fs_server, ForeignScan::fsSystemCol, InvalidOid, Plan::lefttree, makeNode, ForeignScan::operation, Scan::plan, Plan::qual, ForeignScan::resultRelation, Plan::righttree, ForeignScan::scan, Scan::scanrelid, and Plan::targetlist.

Referenced by fileGetForeignPlan(), and postgresGetForeignPlan().

5686 {
5687  ForeignScan *node = makeNode(ForeignScan);
5688  Plan *plan = &node->scan.plan;
5689 
5690  /* cost will be filled in by create_foreignscan_plan */
5691  plan->targetlist = qptlist;
5692  plan->qual = qpqual;
5693  plan->lefttree = outer_plan;
5694  plan->righttree = NULL;
5695  node->scan.scanrelid = scanrelid;
5696 
5697  /* these may be overridden by the FDW's PlanDirectModify callback. */
5698  node->operation = CMD_SELECT;
5699  node->resultRelation = 0;
5700 
5701  /* fs_server will be filled in by create_foreignscan_plan */
5702  node->fs_server = InvalidOid;
5703  node->fdw_exprs = fdw_exprs;
5704  node->fdw_private = fdw_private;
5705  node->fdw_scan_tlist = fdw_scan_tlist;
5706  node->fdw_recheck_quals = fdw_recheck_quals;
5707  /* fs_relids will be filled in by create_foreignscan_plan */
5708  node->fs_relids = NULL;
5709  /* fsSystemCol will be filled in by create_foreignscan_plan */
5710  node->fsSystemCol = false;
5711 
5712  return node;
5713 }
List * qual
Definition: plannodes.h:142
Plan plan
Definition: plannodes.h:343
Index scanrelid
Definition: plannodes.h:344
Oid fs_server
Definition: plannodes.h:636
List * fdw_exprs
Definition: plannodes.h:637
List * fdw_private
Definition: plannodes.h:638
List * fdw_scan_tlist
Definition: plannodes.h:639
CmdType operation
Definition: plannodes.h:634
struct Plan * righttree
Definition: plannodes.h:144
List * fdw_recheck_quals
Definition: plannodes.h:640
Index resultRelation
Definition: plannodes.h:635
#define InvalidOid
Definition: postgres_ext.h:36
#define makeNode(_type_)
Definition: nodes.h:587
struct Plan * lefttree
Definition: plannodes.h:143
List * targetlist
Definition: plannodes.h:141
bool fsSystemCol
Definition: plannodes.h:642
Bitmapset * fs_relids
Definition: plannodes.h:641

◆ make_limit()

Limit* make_limit ( Plan lefttree,
Node limitOffset,
Node limitCount,
LimitOption  limitOption,
int  uniqNumCols,
AttrNumber uniqColIdx,
Oid uniqOperators,
Oid uniqCollations 
)

Definition at line 6804 of file createplan.c.

References Plan::lefttree, Limit::limitCount, Limit::limitOffset, Limit::limitOption, makeNode, NIL, Limit::plan, Plan::qual, Plan::righttree, Plan::targetlist, Limit::uniqColIdx, Limit::uniqCollations, Limit::uniqNumCols, and Limit::uniqOperators.

Referenced by create_limit_plan(), and create_minmaxagg_plan().

6807 {
6808  Limit *node = makeNode(Limit);
6809  Plan *plan = &node->plan;
6810 
6811  plan->targetlist = lefttree->targetlist;
6812  plan->qual = NIL;
6813  plan->lefttree = lefttree;
6814  plan->righttree = NULL;
6815 
6816  node->limitOffset = limitOffset;
6817  node->limitCount = limitCount;
6818  node->limitOption = limitOption;
6819  node->uniqNumCols = uniqNumCols;
6820  node->uniqColIdx = uniqColIdx;
6821  node->uniqOperators = uniqOperators;
6822  node->uniqCollations = uniqCollations;
6823 
6824  return node;
6825 }
#define NIL
Definition: pg_list.h:65
List * qual
Definition: plannodes.h:142
Plan plan
Definition: plannodes.h:1023
Oid * uniqOperators
Definition: plannodes.h:1029
Node * limitOffset
Definition: plannodes.h:1024
Oid * uniqCollations
Definition: plannodes.h:1030
struct Plan * righttree
Definition: plannodes.h:144
LimitOption limitOption
Definition: plannodes.h:1026
Node * limitCount
Definition: plannodes.h:1025
int uniqNumCols
Definition: plannodes.h:1027
#define makeNode(_type_)
Definition: nodes.h:587
struct Plan * lefttree
Definition: plannodes.h:143
List * targetlist
Definition: plannodes.h:141
AttrNumber * uniqColIdx
Definition: plannodes.h:1028

◆ make_sort_from_sortclauses()

Sort* make_sort_from_sortclauses ( List sortcls,
Plan lefttree 
)

Definition at line 6272 of file createplan.c.

References TargetEntry::expr, exprCollation(), get_sortgroupclause_tle(), lfirst, list_length(), make_sort(), SortGroupClause::nulls_first, palloc(), TargetEntry::resno, SortGroupClause::sortop, and Plan::targetlist.

Referenced by create_unique_plan().

6273 {
6274  List *sub_tlist = lefttree->targetlist;
6275  ListCell *l;
6276  int numsortkeys;
6277  AttrNumber *sortColIdx;
6278  Oid *sortOperators;
6279  Oid *collations;
6280  bool *nullsFirst;
6281 
6282  /* Convert list-ish representation to arrays wanted by executor */
6283  numsortkeys = list_length(sortcls);
6284  sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
6285  sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
6286  collations = (Oid *) palloc(numsortkeys * sizeof(Oid));
6287  nullsFirst = (bool *) palloc(numsortkeys * sizeof(bool));
6288 
6289  numsortkeys = 0;
6290  foreach(l, sortcls)
6291  {
6292  SortGroupClause *sortcl = (SortGroupClause *) lfirst(l);
6293  TargetEntry *tle = get_sortgroupclause_tle(sortcl, sub_tlist);
6294 
6295  sortColIdx[numsortkeys] = tle->resno;
6296  sortOperators[numsortkeys] = sortcl->sortop;
6297  collations[numsortkeys] = exprCollation((Node *) tle->expr);
6298  nullsFirst[numsortkeys] = sortcl->nulls_first;
6299  numsortkeys++;
6300  }
6301 
6302  return make_sort(lefttree, numsortkeys,
6303  sortColIdx, sortOperators,
6304  collations, nullsFirst);
6305 }
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition: tlist.c:356
Definition: nodes.h:539
unsigned int Oid
Definition: postgres_ext.h:31
AttrNumber resno
Definition: primnodes.h:1455
static Sort * make_sort(Plan *lefttree, int numCols, AttrNumber *sortColIdx, Oid *sortOperators, Oid *collations, bool *nullsFirst)
Definition: createplan.c:5922
#define lfirst(lc)
Definition: pg_list.h:169
Expr * expr
Definition: primnodes.h:1454
static int list_length(const List *l)
Definition: pg_list.h:149
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:759
List * targetlist
Definition: plannodes.h:141
void * palloc(Size size)
Definition: mcxt.c:1062
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21

◆ match_foreign_keys_to_quals()

void match_foreign_keys_to_quals ( PlannerInfo root)

Definition at line 2483 of file initsplan.c.

References OpExpr::args, RestrictInfo::clause, ForeignKeyOptInfo::con_relid, ForeignKeyOptInfo::confkey, ForeignKeyOptInfo::conkey, ForeignKeyOptInfo::conpfeqop, EquivalenceClass::ec_has_const, PlannerInfo::fkey_list, get_commutator(), get_leftop(), get_rightop(), InvalidOid, IsA, RelOptInfo::joininfo, lappend(), lfirst, list_length(), match_eclasses_to_foreign_key_col(), ForeignKeyOptInfo::nconst_ec, NIL, ForeignKeyOptInfo::nkeys, ForeignKeyOptInfo::nmatched_ec, ForeignKeyOptInfo::nmatched_rcols, ForeignKeyOptInfo::nmatched_ri, OidIsValid, OpExpr::opno, RestrictInfo::outerjoin_delayed, ForeignKeyOptInfo::ref_relid, RELOPT_BASEREL, RelOptInfo::reloptkind, ForeignKeyOptInfo::rinfos, PlannerInfo::simple_rel_array, and PlannerInfo::simple_rel_array_size.

Referenced by query_planner().

2484 {
2485  List *newlist = NIL;
2486  ListCell *lc;
2487 
2488  foreach(lc, root->fkey_list)
2489  {
2490  ForeignKeyOptInfo *fkinfo = (ForeignKeyOptInfo *) lfirst(lc);
2491  RelOptInfo *con_rel;
2492  RelOptInfo *ref_rel;
2493  int colno;
2494 
2495  /*
2496  * Either relid might identify a rel that is in the query's rtable but
2497  * isn't referenced by the jointree so won't have a RelOptInfo. Hence
2498  * don't use find_base_rel() here. We can ignore such FKs.
2499  */
2500  if (fkinfo->con_relid >= root->simple_rel_array_size ||
2501  fkinfo->ref_relid >= root->simple_rel_array_size)
2502  continue; /* just paranoia */
2503  con_rel = root->simple_rel_array[fkinfo->con_relid];
2504  if (con_rel == NULL)
2505  continue;
2506  ref_rel = root->simple_rel_array[fkinfo->ref_relid];
2507  if (ref_rel == NULL)
2508  continue;
2509 
2510  /*
2511  * Ignore FK unless both rels are baserels. This gets rid of FKs that
2512  * link to inheritance child rels (otherrels) and those that link to
2513  * rels removed by join removal (dead rels).
2514  */
2515  if (con_rel->reloptkind != RELOPT_BASEREL ||
2516  ref_rel->reloptkind != RELOPT_BASEREL)
2517  continue;
2518 
2519  /*
2520  * Scan the columns and try to match them to eclasses and quals.
2521  *
2522  * Note: for simple inner joins, any match should be in an eclass.
2523  * "Loose" quals that syntactically match an FK equality must have
2524  * been rejected for EC status because they are outer-join quals or
2525  * similar. We can still consider them to match the FK if they are
2526  * not outerjoin_delayed.
2527  */
2528  for (colno = 0; colno < fkinfo->nkeys; colno++)
2529  {
2530  EquivalenceClass *ec;
2531  AttrNumber con_attno,
2532  ref_attno;
2533  Oid fpeqop;
2534  ListCell *lc2;
2535 
2536  ec = match_eclasses_to_foreign_key_col(root, fkinfo, colno);
2537  /* Don't bother looking for loose quals if we got an EC match */
2538  if (ec != NULL)
2539  {
2540  fkinfo->nmatched_ec++;
2541  if (ec->ec_has_const)
2542  fkinfo->nconst_ec++;
2543  continue;
2544  }
2545 
2546  /*
2547  * Scan joininfo list for relevant clauses. Either rel's joininfo
2548  * list would do equally well; we use con_rel's.
2549  */
2550  con_attno = fkinfo->conkey[colno];
2551  ref_attno = fkinfo->confkey[colno];
2552  fpeqop = InvalidOid; /* we'll look this up only if needed */
2553 
2554  foreach(lc2, con_rel->joininfo)
2555  {
2556  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc2);
2557  OpExpr *clause = (OpExpr *) rinfo->clause;
2558  Var *leftvar;
2559  Var *rightvar;
2560 
2561  /* Ignore outerjoin-delayed clauses */
2562  if (rinfo->outerjoin_delayed)
2563  continue;
2564 
2565  /* Only binary OpExprs are useful for consideration */
2566  if (!IsA(clause, OpExpr) ||
2567  list_length(clause->args) != 2)
2568  continue;
2569  leftvar = (Var *) get_leftop((Expr *) clause);
2570  rightvar = (Var *) get_rightop((Expr *) clause);
2571 
2572  /* Operands must be Vars, possibly with RelabelType */
2573  while (leftvar && IsA(leftvar, RelabelType))
2574  leftvar = (Var *) ((RelabelType *) leftvar)->arg;
2575  if (!(leftvar && IsA(leftvar, Var)))
2576  continue;
2577  while (rightvar && IsA(rightvar, RelabelType))
2578  rightvar = (Var *) ((RelabelType *) rightvar)->arg;
2579  if (!(rightvar && IsA(rightvar, Var)))
2580  continue;
2581 
2582  /* Now try to match the vars to the current foreign key cols */
2583  if (fkinfo->ref_relid == leftvar->varno &&
2584  ref_attno == leftvar->varattno &&
2585  fkinfo->con_relid == rightvar->varno &&
2586  con_attno == rightvar->varattno)
2587  {
2588  /* Vars match, but is it the right operator? */
2589  if (clause->opno == fkinfo->conpfeqop[colno])
2590  {
2591  fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
2592  rinfo);
2593  fkinfo->nmatched_ri++;
2594  }
2595  }
2596  else if (fkinfo->ref_relid == rightvar->varno &&
2597  ref_attno == rightvar->varattno &&
2598  fkinfo->con_relid == leftvar->varno &&
2599  con_attno == leftvar->varattno)
2600  {
2601  /*
2602  * Reverse match, must check commutator operator. Look it
2603  * up if we didn't already. (In the worst case we might
2604  * do multiple lookups here, but that would require an FK
2605  * equality operator without commutator, which is
2606  * unlikely.)
2607  */
2608  if (!OidIsValid(fpeqop))
2609  fpeqop = get_commutator(fkinfo->conpfeqop[colno]);
2610  if (clause->opno == fpeqop)
2611  {
2612  fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
2613  rinfo);
2614  fkinfo->nmatched_ri++;
2615  }
2616  }
2617  }
2618  /* If we found any matching loose quals, count col as matched */
2619  if (fkinfo->rinfos[colno])
2620  fkinfo->nmatched_rcols++;
2621  }
2622 
2623  /*
2624  * Currently, we drop multicolumn FKs that aren't fully matched to the
2625  * query. Later we might figure out how to derive some sort of
2626  * estimate from them, in which case this test should be weakened to
2627  * "if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) > 0)".
2628  */
2629  if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) == fkinfo->nkeys)
2630  newlist = lappend(newlist, fkinfo);
2631  }
2632  /* Replace fkey_list, thereby discarding any useless entries */
2633  root->fkey_list = newlist;
2634 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Oid get_commutator(Oid opno)
Definition: lsyscache.c:1480
RelOptKind reloptkind
Definition: pathnodes.h:673
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:186
List * fkey_list
Definition: pathnodes.h:291
#define OidIsValid(objectId)
Definition: c.h:710
struct RelOptInfo ** simple_rel_array
Definition: pathnodes.h:185
Oid conpfeqop[INDEX_MAX_KEYS]
Definition: pathnodes.h:902
bool outerjoin_delayed
Definition: pathnodes.h:2049
List * joininfo
Definition: pathnodes.h:744
static Node * get_leftop(const void *clause)
Definition: nodeFuncs.h:73
int simple_rel_array_size
Definition: pathnodes.h:186
List * lappend(List *list, void *datum)
Definition: list.c:336
Expr * clause
Definition: pathnodes.h:2045
AttrNumber conkey[INDEX_MAX_KEYS]
Definition: pathnodes.h:900
EquivalenceClass * match_eclasses_to_foreign_key_col(PlannerInfo *root, ForeignKeyOptInfo *fkinfo, int colno)
Definition: equivclass.c:2437
static Node * get_rightop(const void *clause)
Definition: nodeFuncs.h:85
#define InvalidOid
Definition: postgres_ext.h:36
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
Oid opno
Definition: primnodes.h:542
List * args
Definition: primnodes.h:548
Definition: pg_list.h:50
AttrNumber confkey[INDEX_MAX_KEYS]
Definition: pathnodes.h:901
int16 AttrNumber
Definition: attnum.h:21
List * rinfos[INDEX_MAX_KEYS]
Definition: pathnodes.h:914

◆ materialize_finished_plan()

Plan* materialize_finished_plan ( Plan subplan)

Definition at line 6384 of file createplan.c.

References cost_material(), Plan::initPlan, make_material(), NIL, Plan::parallel_aware, Plan::parallel_safe, Plan::plan_rows, Plan::plan_width, Plan::startup_cost, Path::startup_cost, Plan::total_cost, and Path::total_cost.

Referenced by build_subplan(), and standard_planner().

6385 {
6386  Plan *matplan;
6387  Path matpath; /* dummy for result of cost_material */
6388 
6389  matplan = (Plan *) make_material(subplan);
6390 
6391  /*
6392  * XXX horrid kluge: if there are any initPlans attached to the subplan,
6393  * move them up to the Material node, which is now effectively the top
6394  * plan node in its query level. This prevents failure in
6395  * SS_finalize_plan(), which see for comments. We don't bother adjusting
6396  * the subplan's cost estimate for this.
6397  */
6398  matplan->initPlan = subplan->initPlan;
6399  subplan->initPlan = NIL;
6400 
6401  /* Set cost data */
6402  cost_material(&matpath,
6403  subplan->startup_cost,
6404  subplan->total_cost,
6405  subplan->plan_rows,
6406  subplan->plan_width);
6407  matplan->startup_cost = matpath.startup_cost;
6408  matplan->total_cost = matpath.total_cost;
6409  matplan->plan_rows = subplan->plan_rows;
6410  matplan->plan_width = subplan->plan_width;
6411  matplan->parallel_aware = false;
6412  matplan->parallel_safe = subplan->parallel_safe;
6413 
6414  return matplan;
6415 }
#define NIL
Definition: pg_list.h:65
double plan_rows
Definition: plannodes.h:123
static Material * make_material(Plan *lefttree)
Definition: createplan.c:6362
Cost startup_cost
Definition: pathnodes.h:1185
Cost startup_cost
Definition: plannodes.h:117
bool parallel_aware
Definition: plannodes.h:129
Cost total_cost
Definition: pathnodes.h:1186
void cost_material(Path *path, Cost input_startup_cost, Cost input_total_cost, double tuples, int width)
Definition: costsize.c:2365
int plan_width
Definition: plannodes.h:124
List * initPlan
Definition: plannodes.h:145
Cost total_cost
Definition: plannodes.h:118
bool parallel_safe
Definition: plannodes.h:130

◆ preprocess_minmax_aggregates()

void preprocess_minmax_aggregates ( PlannerInfo root)

Definition at line 73 of file planagg.c.

References add_path(), MinMaxAggInfo::aggsortop, Assert, build_minmax_path(), can_minmax_aggs(), create_minmaxagg_path(), create_pathtarget, Query::cteList, elog, ERROR, exprCollation(), exprType(), fetch_upper_rel(), FromExpr::fromlist, get_equality_op_for_ordering_op(), Query::groupClause, Query::groupingSets, Query::hasAggs, Query::hasWindowFuncs, Query::havingQual, RangeTblEntry::inh, IsA, Query::jointree, lfirst, linitial, list_length(), PlannerInfo::minmax_aggs, NIL, OidIsValid, MinMaxAggInfo::param, parse(), PlannerInfo::parse, planner_rt_fetch, PlannerInfo::processed_tlist, Query::rowMarks, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, RangeTblRef::rtindex, Query::setOperations, SS_make_initplan_output_param(), MinMaxAggInfo::target, and UPPERREL_GROUP_AGG.

Referenced by grouping_planner().

74 {
75  Query *parse = root->parse;
76  FromExpr *jtnode;
77  RangeTblRef *rtr;
78  RangeTblEntry *rte;
79  List *aggs_list;
80  RelOptInfo *grouped_rel;
81  ListCell *lc;
82 
83  /* minmax_aggs list should be empty at this point */
84  Assert(root->minmax_aggs == NIL);
85 
86  /* Nothing to do if query has no aggregates */
87  if (!parse->hasAggs)
88  return;
89 
90  Assert(!parse->setOperations); /* shouldn't get here if a setop */
91  Assert(parse->rowMarks == NIL); /* nor if FOR UPDATE */
92 
93  /*
94  * Reject unoptimizable cases.
95  *
96  * We don't handle GROUP BY or windowing, because our current
97  * implementations of grouping require looking at all the rows anyway, and
98  * so there's not much point in optimizing MIN/MAX.
99  */
100  if (parse->groupClause || list_length(parse->groupingSets) > 1 ||
101  parse->hasWindowFuncs)
102  return;
103 
104  /*
105  * Reject if query contains any CTEs; there's no way to build an indexscan
106  * on one so we couldn't succeed here. (If the CTEs are unreferenced,
107  * that's not true, but it doesn't seem worth expending cycles to check.)
108  */
109  if (parse->cteList)
110  return;
111 
112  /*
113  * We also restrict the query to reference exactly one table, since join
114  * conditions can't be handled reasonably. (We could perhaps handle a
115  * query containing cartesian-product joins, but it hardly seems worth the
116  * trouble.) However, the single table could be buried in several levels
117  * of FromExpr due to subqueries. Note the "single" table could be an
118  * inheritance parent, too, including the case of a UNION ALL subquery
119  * that's been flattened to an appendrel.
120  */
121  jtnode = parse->jointree;
122  while (IsA(jtnode, FromExpr))
123  {
124  if (list_length(jtnode->fromlist) != 1)
125  return;
126  jtnode = linitial(jtnode->fromlist);
127  }
128  if (!IsA(jtnode, RangeTblRef))
129  return;
130  rtr = (RangeTblRef *) jtnode;
131  rte = planner_rt_fetch(rtr->rtindex, root);
132  if (rte->rtekind == RTE_RELATION)
133  /* ordinary relation, ok */ ;
134  else if (rte->rtekind == RTE_SUBQUERY && rte->inh)
135  /* flattened UNION ALL subquery, ok */ ;
136  else
137  return;
138 
139  /*
140  * Scan the tlist and HAVING qual to find all the aggregates and verify
141  * all are MIN/MAX aggregates. Stop as soon as we find one that isn't.
142  */
143  aggs_list = NIL;
144  if (!can_minmax_aggs(root, &aggs_list))
145  return;
146 
147  /*
148  * OK, there is at least the possibility of performing the optimization.
149  * Build an access path for each aggregate. If any of the aggregates
150  * prove to be non-indexable, give up; there is no point in optimizing
151  * just some of them.
152  */
153  foreach(lc, aggs_list)
154  {
155  MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
156  Oid eqop;
157  bool reverse;
158 
159  /*
160  * We'll need the equality operator that goes with the aggregate's
161  * ordering operator.
162  */
163  eqop = get_equality_op_for_ordering_op(mminfo->aggsortop, &reverse);
164  if (!OidIsValid(eqop)) /* shouldn't happen */
165  elog(ERROR, "could not find equality operator for ordering operator %u",
166  mminfo->aggsortop);
167 
168  /*
169  * We can use either an ordering that gives NULLS FIRST or one that
170  * gives NULLS LAST; furthermore there's unlikely to be much
171  * performance difference between them, so it doesn't seem worth
172  * costing out both ways if we get a hit on the first one. NULLS
173  * FIRST is more likely to be available if the operator is a
174  * reverse-sort operator, so try that first if reverse.
175  */
176  if (build_minmax_path(root, mminfo, eqop, mminfo->aggsortop, reverse))
177  continue;
178  if (build_minmax_path(root, mminfo, eqop, mminfo->aggsortop, !reverse))
179  continue;
180 
181  /* No indexable path for this aggregate, so fail */
182  return;
183  }
184 
185  /*
186  * OK, we can do the query this way. Prepare to create a MinMaxAggPath
187  * node.
188  *
189  * First, create an output Param node for each agg. (If we end up not
190  * using the MinMaxAggPath, we'll waste a PARAM_EXEC slot for each agg,
191  * which is not worth worrying about. We can't wait till create_plan time
192  * to decide whether to make the Param, unfortunately.)
193  */
194  foreach(lc, aggs_list)
195  {
196  MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
197 
198  mminfo->param =
200  exprType((Node *) mminfo->target),
201  -1,
202  exprCollation((Node *) mminfo->target));
203  }
204 
205  /*
206  * Create a MinMaxAggPath node with the appropriate estimated costs and
207  * other needed data, and add it to the UPPERREL_GROUP_AGG upperrel, where
208  * it will compete against the standard aggregate implementation. (It
209  * will likely always win, but we need not assume that here.)
210  *
211  * Note: grouping_planner won't have created this upperrel yet, but it's
212  * fine for us to create it first. We will not have inserted the correct
213  * consider_parallel value in it, but MinMaxAggPath paths are currently
214  * never parallel-safe anyway, so that doesn't matter. Likewise, it
215  * doesn't matter that we haven't filled FDW-related fields in the rel.
216  * Also, because there are no rowmarks, we know that the processed_tlist
217  * doesn't need to change anymore, so making the pathtarget now is safe.
218  */
219  grouped_rel = fetch_upper_rel(root, UPPERREL_GROUP_AGG, NULL);
220  add_path(grouped_rel, (Path *)
221  create_minmaxagg_path(root, grouped_rel,
222  create_pathtarget(root,
223  root->processed_tlist),
224  aggs_list,
225  (List *) parse->havingQual));
226 }
#define NIL
Definition: pg_list.h:65
MinMaxAggPath * create_minmaxagg_path(PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *mmaggregates, List *quals)
Definition: pathnode.c:3325
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Query * parse
Definition: pathnodes.h:161
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:422
FromExpr * jointree
Definition: parsenodes.h:148
bool hasAggs
Definition: parsenodes.h:133
Oid get_equality_op_for_ordering_op(Oid opno, bool *reverse)
Definition: lsyscache.c:265
Param * param
Definition: pathnodes.h:2423
List * groupingSets
Definition: parsenodes.h:161
Definition: nodes.h:539
List * minmax_aggs
Definition: pathnodes.h:332
List * fromlist
Definition: primnodes.h:1563
unsigned int Oid
Definition: postgres_ext.h:31
List * rowMarks
Definition: parsenodes.h:175
#define OidIsValid(objectId)
Definition: c.h:710
static bool can_minmax_aggs(PlannerInfo *root, List **context)
Definition: planagg.c:241
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:46
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:383
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1207
#define create_pathtarget(root, tlist)
Definition: tlist.h:53
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
Expr * target
Definition: pathnodes.h:2419
bool hasWindowFuncs
Definition: parsenodes.h:134
Param * SS_make_initplan_output_param(PlannerInfo *root, Oid resulttype, int32 resulttypmod, Oid resultcollation)
Definition: subselect.c:2942
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
static int list_length(const List *l)
Definition: pg_list.h:149
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:759
static bool build_minmax_path(PlannerInfo *root, MinMaxAggInfo *mminfo, Oid eqop, Oid sortop, bool nulls_first)
Definition: planagg.c:317
RTEKind rtekind
Definition: parsenodes.h:995
List * cteList
Definition: parsenodes.h:145
Node * setOperations
Definition: parsenodes.h:177
List * groupClause
Definition: parsenodes.h:158
#define elog(elevel,...)
Definition: elog.h:232
Node * havingQual
Definition: parsenodes.h:163
List * processed_tlist
Definition: pathnodes.h:320
Definition: pg_list.h:50
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:665

◆ process_implied_equality()

RestrictInfo* process_implied_equality ( PlannerInfo root,
Oid  opno,
Oid  collation,
Expr item1,
Expr item2,
Relids  qualscope,
Relids  nullable_relids,
Index  security_level,
bool  below_outer_join,
bool  both_const 
)

Definition at line 2272 of file initsplan.c.

References add_vars_to_targetlist(), Assert, bms_copy(), bms_is_empty(), bms_is_subset(), bms_membership(), BMS_MULTIPLE, check_mergejoinable(), Const::constisnull, Const::consttype, Const::constvalue, contain_volatile_functions(), copyObject, DatumGetBool, distribute_restrictinfo_to_rels(), eval_const_expressions(), get_relids_in_jointree(), PlannerInfo::hasPseudoConstantQuals, InvalidOid, IsA, Query::jointree, list_free(), make_opclause(), make_restrictinfo(), PlannerInfo::parse, pull_var_clause(), pull_varnos(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, and PostponedQual::relids.

Referenced by generate_base_implied_equalities_const(), and generate_base_implied_equalities_no_const().

2282 {
2283  RestrictInfo *restrictinfo;
2284  Node *clause;
2285  Relids relids;
2286  bool pseudoconstant = false;
2287 
2288  /*
2289  * Build the new clause. Copy to ensure it shares no substructure with
2290  * original (this is necessary in case there are subselects in there...)
2291  */
2292  clause = (Node *) make_opclause(opno,
2293  BOOLOID, /* opresulttype */
2294  false, /* opretset */
2295  copyObject(item1),
2296  copyObject(item2),
2297  InvalidOid,
2298  collation);
2299 
2300  /* If both constant, try to reduce to a boolean constant. */
2301  if (both_const)
2302  {
2303  clause = eval_const_expressions(root, clause);
2304 
2305  /* If we produced const TRUE, just drop the clause */
2306  if (clause && IsA(clause, Const))
2307  {
2308  Const *cclause = (Const *) clause;
2309 
2310  Assert(cclause->consttype == BOOLOID);
2311  if (!cclause->constisnull && DatumGetBool(cclause->constvalue))
2312  return NULL;
2313  }
2314  }
2315 
2316  /*
2317  * The rest of this is a very cut-down version of distribute_qual_to_rels.
2318  * We can skip most of the work therein, but there are a couple of special
2319  * cases we still have to handle.
2320  *
2321  * Retrieve all relids mentioned within the possibly-simplified clause.
2322  */
2323  relids = pull_varnos(root, clause);
2324  Assert(bms_is_subset(relids, qualscope));
2325 
2326  /*
2327  * If the clause is variable-free, our normal heuristic for pushing it
2328  * down to just the mentioned rels doesn't work, because there are none.
2329  * Apply at the given qualscope, or at the top of tree if it's nonvolatile
2330  * (which it very likely is, but we'll check, just to be sure).
2331  */
2332  if (bms_is_empty(relids))
2333  {
2334  /* eval at original syntactic level */
2335  relids = bms_copy(qualscope);
2336  if (!contain_volatile_functions(clause))
2337  {
2338  /* mark as gating qual */
2339  pseudoconstant = true;
2340  /* tell createplan.c to check for gating quals */
2341  root->hasPseudoConstantQuals = true;
2342  /* if not below outer join, push it to top of tree */
2343  if (!below_outer_join)
2344  {
2345  relids =
2347  false);
2348  }
2349  }
2350  }
2351 
2352  /*
2353  * Build the RestrictInfo node itself.
2354  */
2355  restrictinfo = make_restrictinfo(root,
2356  (Expr *) clause,
2357  true, /* is_pushed_down */
2358  false, /* outerjoin_delayed */
2359  pseudoconstant,
2360  security_level,
2361  relids,
2362  NULL, /* outer_relids */
2363  nullable_relids);
2364 
2365  /*
2366  * If it's a join clause, add vars used in the clause to targetlists of
2367  * their relations, so that they will be emitted by the plan nodes that
2368  * scan those relations (else they won't be available at the join node!).
2369  *
2370  * Typically, we'd have already done this when the component expressions
2371  * were first seen by distribute_qual_to_rels; but it is possible that
2372  * some of the Vars could have missed having that done because they only
2373  * appeared in single-relation clauses originally. So do it here for
2374  * safety.
2375  */
2376  if (bms_membership(relids) == BMS_MULTIPLE)
2377  {
2378  List *vars = pull_var_clause(clause,
2382 
2383  add_vars_to_targetlist(root, vars, relids, false);
2384  list_free(vars);
2385  }
2386 
2387  /*
2388  * Check mergejoinability. This will usually succeed, since the op came
2389  * from an EquivalenceClass; but we could have reduced the original clause
2390  * to a constant.
2391  */
2392  check_mergejoinable(restrictinfo);
2393 
2394  /*
2395  * Note we don't do initialize_mergeclause_eclasses(); the caller can
2396  * handle that much more cheaply than we can. It's okay to call
2397  * distribute_restrictinfo_to_rels() before that happens.
2398  */
2399 
2400  /*
2401  * Push the new clause into all the appropriate restrictinfo lists.
2402  */
2403  distribute_restrictinfo_to_rels(root, restrictinfo);
2404 
2405  return restrictinfo;
2406 }
Datum constvalue
Definition: primnodes.h:219
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:97
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Query * parse
Definition: pathnodes.h:161
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
FromExpr * jointree
Definition: parsenodes.h:148
Definition: nodes.h:539
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2093
List * pull_var_clause(Node *node, int flags)
Definition: var.c:562
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:451
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: makefuncs.c:610
void add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed, bool create_new_ph)
Definition: initsplan.c:230
Oid consttype
Definition: primnodes.h:215
void distribute_restrictinfo_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2177
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:315
Relids get_relids_in_jointree(Node *jtnode, bool include_joins)
#define DatumGetBool(X)
Definition: postgres.h:437
RestrictInfo * make_restrictinfo(PlannerInfo *root, Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids)
Definition: restrictinfo.c:61
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:190
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:672
bool hasPseudoConstantQuals
Definition: pathnodes.h:348
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:804
static void check_mergejoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:2653
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:189
void list_free(List *list)
Definition: list.c:1391
#define copyObject(obj)
Definition: nodes.h:655
Definition: regcomp.c:237
Definition: pg_list.h:50
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:187
bool constisnull
Definition: primnodes.h:220

◆ query_is_distinct_for()

bool query_is_distinct_for ( Query query,
List colnos,
List opids 
)

Definition at line 775 of file analyzejoins.c.

References SetOperationStmt::all, Assert, castNode, distinct_col_search(), Query::distinctClause, SortGroupClause::eqop, equality_ops_are_compatible(), get_sortgroupclause_tle(), Query::groupClause, SetOperationStmt::groupClauses, GROUPING_SET_EMPTY, Query::groupingSets, Query::hasAggs, Query::hasTargetSRFs, Query::havingQual, lfirst, linitial, list_head(), list_length(), lnext(), OidIsValid, SetOperationStmt::op, TargetEntry::resjunk, TargetEntry::resno, SETOP_NONE, Query::setOperations, and Query::targetList.

Referenced by create_unique_path(), and rel_is_distinct_for().

776 {
777  ListCell *l;
778  Oid opid;
779 
780  Assert(list_length(colnos) == list_length(opids));
781 
782  /*
783  * DISTINCT (including DISTINCT ON) guarantees uniqueness if all the
784  * columns in the DISTINCT clause appear in colnos and operator semantics
785  * match. This is true even if there are SRFs in the DISTINCT columns or
786  * elsewhere in the tlist.
787  */
788  if (query->distinctClause)
789  {
790  foreach(l, query->distinctClause)
791  {
792  SortGroupClause *sgc = (SortGroupClause *) lfirst(l);
794  query->targetList);
795 
796  opid = distinct_col_search(tle->resno, colnos, opids);
797  if (!OidIsValid(opid) ||
798  !equality_ops_are_compatible(opid, sgc->eqop))
799  break; /* exit early if no match */
800  }
801  if (l == NULL) /* had matches for all? */
802  return true;
803  }
804 
805  /*
806  * Otherwise, a set-returning function in the query's targetlist can
807  * result in returning duplicate rows, despite any grouping that might
808  * occur before tlist evaluation. (If all tlist SRFs are within GROUP BY
809  * columns, it would be safe because they'd be expanded before grouping.
810  * But it doesn't currently seem worth the effort to check for that.)
811  */
812  if (query->hasTargetSRFs)
813  return false;
814 
815  /*
816  * Similarly, GROUP BY without GROUPING SETS guarantees uniqueness if all
817  * the grouped columns appear in colnos and operator semantics match.
818  */
819  if (query->groupClause && !query->groupingSets)
820  {
821  foreach(l, query->groupClause)
822  {
823  SortGroupClause *sgc = (SortGroupClause *) lfirst(l);
825  query->targetList);
826 
827  opid = distinct_col_search(tle->resno, colnos, opids);
828  if (!OidIsValid(opid) ||
829  !equality_ops_are_compatible(opid, sgc->eqop))
830  break; /* exit early if no match */
831  }
832  if (l == NULL) /* had matches for all? */
833  return true;
834  }
835  else if (query->groupingSets)
836  {
837  /*
838  * If we have grouping sets with expressions, we probably don't have
839  * uniqueness and analysis would be hard. Punt.
840  */
841  if (query->groupClause)
842  return false;
843 
844  /*
845  * If we have no groupClause (therefore no grouping expressions), we
846  * might have one or many empty grouping sets. If there's just one,
847  * then we're returning only one row and are certainly unique. But
848  * otherwise, we know we're certainly not unique.
849  */
850  if (list_length(query->groupingSets) == 1 &&
851  ((GroupingSet *) linitial(query->groupingSets))->kind == GROUPING_SET_EMPTY)
852  return true;
853  else
854  return false;
855  }
856  else
857  {
858  /*
859  * If we have no GROUP BY, but do have aggregates or HAVING, then the
860  * result is at most one row so it's surely unique, for any operators.
861  */
862  if (query->hasAggs || query->havingQual)
863  return true;
864  }
865 
866  /*
867  * UNION, INTERSECT, EXCEPT guarantee uniqueness of the whole output row,
868  * except with ALL.
869  */
870  if (query->setOperations)
871  {
873 
874  Assert(topop->op != SETOP_NONE);
875 
876  if (!topop->all)
877  {
878  ListCell *lg;
879 
880  /* We're good if all the nonjunk output columns are in colnos */
881  lg = list_head(topop->groupClauses);
882  foreach(l, query->targetList)
883  {
884  TargetEntry *tle = (TargetEntry *) lfirst(l);
885  SortGroupClause *sgc;
886 
887  if (tle->resjunk)
888  continue; /* ignore resjunk columns */
889 
890  /* non-resjunk columns should have grouping clauses */
891  Assert(lg != NULL);
892  sgc = (SortGroupClause *) lfirst(lg);
893  lg = lnext(topop->groupClauses, lg);
894 
895  opid = distinct_col_search(tle->resno, colnos, opids);
896  if (!OidIsValid(opid) ||
897  !equality_ops_are_compatible(opid, sgc->eqop))
898  break; /* exit early if no match */
899  }
900  if (l == NULL) /* had matches for all? */
901  return true;
902  }
903  }
904 
905  /*
906  * XXX Are there any other cases in which we can easily see the result
907  * must be distinct?
908  *
909  * If you do add more smarts to this function, be sure to update
910  * query_supports_distinctness() to match.
911  */
912 
913  return false;
914 }
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition: tlist.c:356
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:322
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
static Oid distinct_col_search(int colno, List *colnos, List *opids)
Definition: analyzejoins.c:924
bool hasAggs
Definition: parsenodes.h:133
List * groupingSets
Definition: parsenodes.h:161
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
List * targetList
Definition: parsenodes.h:150
bool resjunk
Definition: primnodes.h:1461
#define linitial(l)
Definition: pg_list.h:174
List * distinctClause
Definition: parsenodes.h:167
AttrNumber resno
Definition: primnodes.h:1455
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
bool hasTargetSRFs
Definition: parsenodes.h:135
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
bool equality_ops_are_compatible(Oid opno1, Oid opno2)
Definition: lsyscache.c:696
static int list_length(const List *l)
Definition: pg_list.h:149
SetOperation op
Definition: parsenodes.h:1711
Node * setOperations
Definition: parsenodes.h:177
List * groupClause
Definition: parsenodes.h:158
Node * havingQual
Definition: parsenodes.h:163

◆ query_planner()

RelOptInfo* query_planner ( PlannerInfo root,
query_pathkeys_callback  qp_callback,
void *  qp_extra 
)

Definition at line 55 of file planmain.c.

References add_base_rels_to_query(), add_other_rels_to_query(), add_path(), add_placeholders_to_base_rels(), Assert, build_base_rel_tlists(), build_simple_rel(), PlannerInfo::canon_pathkeys, RelOptInfo::cheapest_total_path, RelOptInfo::consider_parallel, create_group_result_path(), create_lateral_join_info(), deconstruct_jointree(), distribute_row_identity_vars(), PlannerInfo::ec_merging_done, elog, ERROR, extract_restriction_or_clauses(), find_lateral_references(), find_placeholders_in_jointree(), fix_placeholder_input_needed_levels(), PlannerInfo::fkey_list, force_parallel_mode, FORCE_PARALLEL_OFF, FromExpr::fromlist, PlannerInfo::full_join_clauses, generate_base_implied_equalities(), PlannerInfo::glob, PlannerInfo::initial_rels, is_parallel_safe(), IsA, PlannerInfo::join_cur_level, PlannerInfo::join_info_list, PlannerInfo::join_rel_hash, PlannerInfo::join_rel_level, PlannerInfo::join_rel_list, Query::jointree, PlannerInfo::left_join_clauses, linitial, list_length(), make_one_rel(), match_foreign_keys_to_quals(), NIL, PlannerGlobal::parallelModeOK, Path::param_info, parse(), PlannerInfo::parse, PlannerInfo::placeholder_list, PlannerInfo::processed_tlist, FromExpr::quals, reconsider_outer_join_clauses(), reduce_unique_semijoins(), RelOptInfo::reltarget, remove_useless_joins(), PlannerInfo::right_join_clauses, RTE_RESULT, RangeTblEntry::rtekind, set_cheapest(), setup_simple_rel_arrays(), and PlannerInfo::simple_rte_array.

Referenced by build_minmax_path(), and grouping_planner().

57 {
58  Query *parse = root->parse;
59  List *joinlist;
60  RelOptInfo *final_rel;
61 
62  /*
63  * Init planner lists to empty.
64  *
65  * NOTE: append_rel_list was set up by subquery_planner, so do not touch
66  * here.
67  */
68  root->join_rel_list = NIL;
69  root->join_rel_hash = NULL;
70  root->join_rel_level = NULL;
71  root->join_cur_level = 0;
72  root->canon_pathkeys = NIL;
73  root->left_join_clauses = NIL;
74  root->right_join_clauses = NIL;
75  root->full_join_clauses = NIL;
76  root->join_info_list = NIL;
77  root->placeholder_list = NIL;
78  root->fkey_list = NIL;
79  root->initial_rels = NIL;
80 
81  /*
82  * Set up arrays for accessing base relations and AppendRelInfos.
83  */
85 
86  /*
87  * In the trivial case where the jointree is a single RTE_RESULT relation,
88  * bypass all the rest of this function and just make a RelOptInfo and its
89  * one access path. This is worth optimizing because it applies for
90  * common cases like "SELECT expression" and "INSERT ... VALUES()".
91  */
92  Assert(parse->jointree->fromlist != NIL);
93  if (list_length(parse->jointree->fromlist) == 1)
94  {
95  Node *jtnode = (Node *) linitial(parse->jointree->fromlist);
96 
97  if (IsA(jtnode, RangeTblRef))
98  {
99  int varno = ((RangeTblRef *) jtnode)->rtindex;
100  RangeTblEntry *rte = root->simple_rte_array[varno];
101 
102  Assert(rte != NULL);
103  if (rte->rtekind == RTE_RESULT)
104  {
105  /* Make the RelOptInfo for it directly */
106  final_rel = build_simple_rel(root, varno, NULL);
107 
108  /*
109  * If query allows parallelism in general, check whether the
110  * quals are parallel-restricted. (We need not check
111  * final_rel->reltarget because it's empty at this point.
112  * Anything parallel-restricted in the query tlist will be
113  * dealt with later.) This is normally pretty silly, because
114  * a Result-only plan would never be interesting to
115  * parallelize. However, if force_parallel_mode is on, then
116  * we want to execute the Result in a parallel worker if
117  * possible, so we must do this.
118  */
119  if (root->glob->parallelModeOK &&
121  final_rel->consider_parallel =
122  is_parallel_safe(root, parse->jointree->quals);
123 
124  /*
125  * The only path for it is a trivial Result path. We cheat a
126  * bit here by using a GroupResultPath, because that way we
127  * can just jam the quals into it without preprocessing them.
128  * (But, if you hold your head at the right angle, a FROM-less
129  * SELECT is a kind of degenerate-grouping case, so it's not
130  * that much of a cheat.)
131  */
132  add_path(final_rel, (Path *)
133  create_group_result_path(root, final_rel,
134  final_rel->reltarget,
135  (List *) parse->jointree->quals));
136 
137  /* Select cheapest path (pretty easy in this case...) */
138  set_cheapest(final_rel);
139 
140  /*
141  * We don't need to run generate_base_implied_equalities, but
142  * we do need to pretend that EC merging is complete.
143  */
144  root->ec_merging_done = true;
145 
146  /*
147  * We still are required to call qp_callback, in case it's
148  * something like "SELECT 2+2 ORDER BY 1".
149  */
150  (*qp_callback) (root, qp_extra);
151 
152  return final_rel;
153  }
154  }
155  }
156 
157  /*
158  * Construct RelOptInfo nodes for all base relations used in the query.
159  * Appendrel member relations ("other rels") will be added later.
160  *
161  * Note: the reason we find the baserels by searching the jointree, rather
162  * than scanning the rangetable, is that the rangetable may contain RTEs
163  * for rels not actively part of the query, for example views. We don't
164  * want to make RelOptInfos for them.
165  */
166  add_base_rels_to_query(root, (Node *) parse->jointree);
167 
168  /*
169  * Examine the targetlist and join tree, adding entries to baserel
170  * targetlists for all referenced Vars, and generating PlaceHolderInfo
171  * entries for all referenced PlaceHolderVars. Restrict and join clauses
172  * are added to appropriate lists belonging to the mentioned relations. We
173  * also build EquivalenceClasses for provably equivalent expressions. The
174  * SpecialJoinInfo list is also built to hold information about join order
175  * restrictions. Finally, we form a target joinlist for make_one_rel() to
176  * work from.
177  */
179 
181 
183 
184  joinlist = deconstruct_jointree(root);
185 
186  /*
187  * Reconsider any postponed outer-join quals now that we have built up
188  * equivalence classes. (This could result in further additions or
189  * mergings of classes.)
190  */
192 
193  /*
194  * If we formed any equivalence classes, generate additional restriction
195  * clauses as appropriate. (Implied join clauses are formed on-the-fly
196  * later.)
197  */
199 
200  /*
201  * We have completed merging equivalence sets, so it's now possible to
202  * generate pathkeys in canonical form; so compute query_pathkeys and
203  * other pathkeys fields in PlannerInfo.
204  */
205  (*qp_callback) (root, qp_extra);
206 
207  /*
208  * Examine any "placeholder" expressions generated during subquery pullup.
209  * Make sure that the Vars they need are marked as needed at the relevant
210  * join level. This must be done before join removal because it might
211  * cause Vars or placeholders to be needed above a join when they weren't
212  * so marked before.
213  */
215 
216  /*
217  * Remove any useless outer joins. Ideally this would be done during
218  * jointree preprocessing, but the necessary information isn't available
219  * until we've built baserel data structures and classified qual clauses.
220  */
221  joinlist = remove_useless_joins(root, joinlist);
222 
223  /*
224  * Also, reduce any semijoins with unique inner rels to plain inner joins.
225  * Likewise, this can't be done until now for lack of needed info.
226  */
228 
229  /*
230  * Now distribute "placeholders" to base rels as needed. This has to be
231  * done after join removal because removal could change whether a
232  * placeholder is evaluable at a base rel.
233  */
235 
236  /*
237  * Construct the lateral reference sets now that we have finalized
238  * PlaceHolderVar eval levels.
239  */
241 
242  /*
243  * Match foreign keys to equivalence classes and join quals. This must be
244  * done after finalizing equivalence classes, and it's useful to wait till
245  * after join removal so that we can skip processing foreign keys
246  * involving removed relations.
247  */
249 
250  /*
251  * Look for join OR clauses that we can extract single-relation
252  * restriction OR clauses from.
253  */
255 
256  /*
257  * Now expand appendrels by adding "otherrels" for their children. We
258  * delay this to the end so that we have as much information as possible
259  * available for each baserel, including all restriction clauses. That
260  * let us prune away partitions that don't satisfy a restriction clause.
261  * Also note that some information such as lateral_relids is propagated
262  * from baserels to otherrels here, so we must have computed it already.
263  */
265 
266  /*
267  * Distribute any UPDATE/DELETE row identity variables to the target
268  * relations. This can't be done till we've finished expansion of
269  * appendrels.
270  */
272 
273  /*
274  * Ready to do the primary planning.
275  */
276  final_rel = make_one_rel(root, joinlist);
277 
278  /* Check that we got at least one usable path */
279  if (!final_rel || !final_rel->cheapest_total_path ||
280  final_rel->cheapest_total_path->param_info != NULL)
281  elog(ERROR, "failed to construct the join relation");
282 
283  return final_rel;
284 }
#define NIL
Definition: pg_list.h:65
int join_cur_level
Definition: pathnodes.h:239
RelOptInfo * make_one_rel(PlannerInfo *root, List *joinlist)
Definition: allpaths.c:153
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Query * parse
Definition: pathnodes.h:161
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:422
void reduce_unique_semijoins(PlannerInfo *root)
Definition: analyzejoins.c:508
bool ec_merging_done
Definition: pathnodes.h:250
void add_base_rels_to_query(PlannerInfo *root, Node *jtnode)
Definition: initsplan.c:106
List * join_info_list
Definition: pathnodes.h:265
FromExpr * jointree
Definition: parsenodes.h:148
void extract_restriction_or_clauses(PlannerInfo *root)
Definition: orclauses.c:76
List * deconstruct_jointree(PlannerInfo *root)
Definition: initsplan.c:687
ParamPathInfo * param_info
Definition: pathnodes.h:1177
Definition: nodes.h:539
List * join_rel_list
Definition: pathnodes.h:228
List * fromlist
Definition: primnodes.h:1563
List * fkey_list
Definition: pathnodes.h:291
void distribute_row_identity_vars(PlannerInfo *root)
Definition: appendinfo.c:937
void add_placeholders_to_base_rels(PlannerInfo *root)
Definition: placeholder.c:379
Node * quals
Definition: primnodes.h:1564
void add_other_rels_to_query(PlannerInfo *root)
Definition: initsplan.c:144
bool is_parallel_safe(PlannerInfo *root, Node *node)
Definition: clauses.c:638
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:46
bool parallelModeOK
Definition: pathnodes.h:125
struct Path * cheapest_total_path
Definition: pathnodes.h:694
PlannerGlobal * glob
Definition: pathnodes.h:163
List * left_join_clauses
Definition: pathnodes.h:254
List * full_join_clauses
Definition: pathnodes.h:262
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition: relnode.c:194
List * canon_pathkeys
Definition: pathnodes.h:252
RangeTblEntry ** simple_rte_array
Definition: pathnodes.h:193
void fix_placeholder_input_needed_levels(PlannerInfo *root)
Definition: placeholder.c:350
void set_cheapest(RelOptInfo *parent_rel)
Definition: pathnode.c:244
void find_placeholders_in_jointree(PlannerInfo *root)
Definition: placeholder.c:144
void generate_base_implied_equalities(PlannerInfo *root)
Definition: equivclass.c:1088
void reconsider_outer_join_clauses(PlannerInfo *root)
Definition: equivclass.c:1984
int force_parallel_mode
Definition: planner.c:70
#define Assert(condition)
Definition: c.h:804
List ** join_rel_level
Definition: pathnodes.h:238
void setup_simple_rel_arrays(PlannerInfo *root)
Definition: relnode.c:83
List * remove_useless_joins(PlannerInfo *root, List *joinlist)
Definition: analyzejoins.c:61
static int list_length(const List *l)
Definition: pg_list.h:149
struct HTAB * join_rel_hash
Definition: pathnodes.h:229
void build_base_rel_tlists(PlannerInfo *root, List *final_tlist)
Definition: initsplan.c:183
bool consider_parallel
Definition: pathnodes.h:684
RTEKind rtekind
Definition: parsenodes.h:995
void match_foreign_keys_to_quals(PlannerInfo *root)
Definition: initsplan.c:2483
#define elog(elevel,...)
Definition: elog.h:232
List * placeholder_list
Definition: pathnodes.h:289
GroupResultPath * create_group_result_path(PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *havingqual)
Definition: pathnode.c:1504
List * initial_rels
Definition: pathnodes.h:303
List * right_join_clauses
Definition: pathnodes.h:258
List * processed_tlist
Definition: pathnodes.h:320
Definition: pg_list.h:50
struct PathTarget * reltarget
Definition: pathnodes.h:687
void create_lateral_join_info(PlannerInfo *root)
Definition: initsplan.c:450
void find_lateral_references(PlannerInfo *root)
Definition: initsplan.c:304
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:665

◆ query_supports_distinctness()

bool query_supports_distinctness ( Query query)

Definition at line 738 of file analyzejoins.c.

References Query::distinctClause, Query::groupClause, Query::groupingSets, Query::hasAggs, Query::hasTargetSRFs, Query::havingQual, NIL, and Query::setOperations.

Referenced by create_unique_path(), and rel_supports_distinctness().

739 {
740  /* SRFs break distinctness except with DISTINCT, see below */
741  if (query->hasTargetSRFs && query->distinctClause == NIL)
742  return false;
743 
744  /* check for features we can prove distinctness with */
745  if (query->distinctClause != NIL ||
746  query->groupClause != NIL ||
747  query->groupingSets != NIL ||
748  query->hasAggs ||
749  query->havingQual ||
750  query->setOperations)
751  return true;
752 
753  return false;
754 }
#define NIL
Definition: pg_list.h:65
bool hasAggs
Definition: parsenodes.h:133
List * groupingSets
Definition: parsenodes.h:161
List * distinctClause
Definition: parsenodes.h:167
bool hasTargetSRFs
Definition: parsenodes.h:135
Node * setOperations
Definition: parsenodes.h:177
List * groupClause
Definition: parsenodes.h:158
Node * havingQual
Definition: parsenodes.h:163

◆ record_plan_function_dependency()

void record_plan_function_dependency ( PlannerInfo root,
Oid  funcid 
)

Definition at line 2952 of file setrefs.c.

References PlanInvalItem::cacheId, FirstUnpinnedObjectId, GetSysCacheHashValue1, PlannerInfo::glob, PlanInvalItem::hashValue, PlannerGlobal::invalItems, lappend(), makeNode, ObjectIdGetDatum, and PROCOID.

Referenced by fix_expr_common(), inline_function(), and inline_set_returning_function().

2953 {
2954  /*
2955  * For performance reasons, we don't bother to track built-in functions;
2956  * we just assume they'll never change (or at least not in ways that'd
2957  * invalidate plans using them). For this purpose we can consider a
2958  * built-in function to be one with OID less than FirstUnpinnedObjectId.
2959  * Note that the OID generator guarantees never to generate such an OID
2960  * after startup, even at OID wraparound.
2961  */
2962  if (funcid >= (Oid) FirstUnpinnedObjectId)
2963  {
2964  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
2965 
2966  /*
2967  * It would work to use any syscache on pg_proc, but the easiest is
2968  * PROCOID since we already have the function's OID at hand. Note
2969  * that plancache.c knows we use PROCOID.
2970  */
2971  inval_item->cacheId = PROCOID;
2972  inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
2973  ObjectIdGetDatum(funcid));
2974 
2975  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
2976  }
2977 }
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:202
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define FirstUnpinnedObjectId
Definition: transam.h:196
PlannerGlobal * glob
Definition: pathnodes.h:163
List * lappend(List *list, void *datum)
Definition: list.c:336
List * invalItems
Definition: pathnodes.h:111
uint32 hashValue
Definition: plannodes.h:1288
#define makeNode(_type_)
Definition: nodes.h:587

◆ record_plan_type_dependency()

void record_plan_type_dependency ( PlannerInfo root,
Oid  typid 
)

Definition at line 2992 of file setrefs.c.

References PlanInvalItem::cacheId, FirstUnpinnedObjectId, GetSysCacheHashValue1, PlannerInfo::glob, PlanInvalItem::hashValue, PlannerGlobal::invalItems, lappend(), makeNode, ObjectIdGetDatum, and TYPEOID.

Referenced by eval_const_expressions_mutator().

2993 {
2994  /*
2995  * As in record_plan_function_dependency, ignore the possibility that
2996  * someone would change a built-in domain.
2997  */
2998  if (typid >= (Oid) FirstUnpinnedObjectId)
2999  {
3000  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3001 
3002  /*
3003  * It would work to use any syscache on pg_type, but the easiest is
3004  * TYPEOID since we already have the type's OID at hand. Note that
3005  * plancache.c knows we use TYPEOID.
3006  */
3007  inval_item->cacheId = TYPEOID;
3008  inval_item->hashValue = GetSysCacheHashValue1(TYPEOID,
3009  ObjectIdGetDatum(typid));
3010 
3011  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3012  }
3013 }
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:202
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define FirstUnpinnedObjectId
Definition: transam.h:196
PlannerGlobal * glob
Definition: pathnodes.h:163
List * lappend(List *list, void *datum)
Definition: list.c:336
List * invalItems
Definition: pathnodes.h:111
uint32 hashValue
Definition: plannodes.h:1288
#define makeNode(_type_)
Definition: nodes.h:587

◆ reduce_unique_semijoins()

void reduce_unique_semijoins ( PlannerInfo root)

Definition at line 508 of file analyzejoins.c.

References bms_get_singleton_member(), bms_union(), SpecialJoinInfo::delay_upper_joins, find_base_rel(), foreach_delete_current, generate_join_implied_equalities(), innerrel_is_unique(), PlannerInfo::join_info_list, JOIN_SEMI, RelOptInfo::joininfo, SpecialJoinInfo::jointype, lfirst, list_concat(), SpecialJoinInfo::min_lefthand, SpecialJoinInfo::min_righthand, and rel_supports_distinctness().

Referenced by query_planner().

509 {
510  ListCell *lc;
511 
512  /*
513  * Scan the join_info_list to find semijoins.
514  */
515  foreach(lc, root->join_info_list)
516  {
517  SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
518  int innerrelid;
519  RelOptInfo *innerrel;
520  Relids joinrelids;
521  List *restrictlist;
522 
523  /*
524  * Must be a non-delaying semijoin to a single baserel, else we aren't
525  * going to be able to do anything with it. (It's probably not
526  * possible for delay_upper_joins to be set on a semijoin, but we
527  * might as well check.)
528  */
529  if (sjinfo->jointype != JOIN_SEMI ||
530  sjinfo->delay_upper_joins)
531  continue;
532 
533  if (!bms_get_singleton_member(sjinfo->min_righthand, &innerrelid))
534  continue;
535 
536  innerrel = find_base_rel(root, innerrelid);
537 
538  /*
539  * Before we trouble to run generate_join_implied_equalities, make a
540  * quick check to eliminate cases in which we will surely be unable to
541  * prove uniqueness of the innerrel.
542  */
543  if (!rel_supports_distinctness(root, innerrel))
544  continue;
545 
546  /* Compute the relid set for the join we are considering */
547  joinrelids = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
548 
549  /*
550  * Since we're only considering a single-rel RHS, any join clauses it
551  * has must be clauses linking it to the semijoin's min_lefthand. We
552  * can also consider EC-derived join clauses.
553  */
554  restrictlist =
556  joinrelids,
557  sjinfo->min_lefthand,
558  innerrel),
559  innerrel->joininfo);
560 
561  /* Test whether the innerrel is unique for those clauses. */
562  if (!innerrel_is_unique(root,
563  joinrelids, sjinfo->min_lefthand, innerrel,
564  JOIN_SEMI, restrictlist, true))
565  continue;
566 
567  /* OK, remove the SpecialJoinInfo from the list. */
569  }
570 }
List * join_info_list
Definition: pathnodes.h:265
Relids min_righthand
Definition: pathnodes.h:2242
List * list_concat(List *list1, const List *list2)
Definition: list.c:530
bool bms_get_singleton_member(const Bitmapset *a, int *member)
Definition: bitmapset.c:615
bool innerrel_is_unique(PlannerInfo *root, Relids joinrelids, Relids outerrelids, RelOptInfo *innerrel, JoinType jointype, List *restrictlist, bool force_cache)
Definition: analyzejoins.c:964
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
List * generate_join_implied_equalities(PlannerInfo *root, Relids join_relids, Relids outer_relids, RelOptInfo *inner_rel)
Definition: equivclass.c:1421
List * joininfo
Definition: pathnodes.h:744
bool delay_upper_joins
Definition: pathnodes.h:2247
#define lfirst(lc)
Definition: pg_list.h:169
JoinType jointype
Definition: pathnodes.h:2245
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:225
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:374
static bool rel_supports_distinctness(PlannerInfo *root, RelOptInfo *rel)
Definition: analyzejoins.c:585
Definition: pg_list.h:50
Relids min_lefthand
Definition: pathnodes.h:2241

◆ remove_useless_joins()

List* remove_useless_joins ( PlannerInfo root,
List joinlist 
)

Definition at line 61 of file analyzejoins.c.

References bms_singleton_member(), bms_union(), elog, ERROR, PlannerInfo::join_info_list, join_is_removable(), lfirst, list_delete_cell(), SpecialJoinInfo::min_lefthand, SpecialJoinInfo::min_righthand, remove_rel_from_joinlist(), and remove_rel_from_query().

Referenced by query_planner().

62 {
63  ListCell *lc;
64 
65  /*
66  * We are only interested in relations that are left-joined to, so we can
67  * scan the join_info_list to find them easily.
68  */
69 restart:
70  foreach(lc, root->join_info_list)
71  {
72  SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
73  int innerrelid;
74  int nremoved;
75 
76  /* Skip if not removable */
77  if (!join_is_removable(root, sjinfo))
78  continue;
79 
80  /*
81  * Currently, join_is_removable can only succeed when the sjinfo's
82  * righthand is a single baserel. Remove that rel from the query and
83  * joinlist.
84  */
85  innerrelid = bms_singleton_member(sjinfo->min_righthand);
86 
87  remove_rel_from_query(root, innerrelid,
88  bms_union(sjinfo->min_lefthand,
89  sjinfo->min_righthand));
90 
91  /* We verify that exactly one reference gets removed from joinlist */
92  nremoved = 0;
93  joinlist = remove_rel_from_joinlist(joinlist, innerrelid, &nremoved);
94  if (nremoved != 1)
95  elog(ERROR, "failed to find relation %d in joinlist", innerrelid);
96 
97  /*
98  * We can delete this SpecialJoinInfo from the list too, since it's no
99  * longer of interest. (Since we'll restart the foreach loop
100  * immediately, we don't bother with foreach_delete_current.)
101  */
103 
104  /*
105  * Restart the scan. This is necessary to ensure we find all
106  * removable joins independently of ordering of the join_info_list
107  * (note that removal of attr_needed bits may make a join appear
108  * removable that did not before).
109  */
110  goto restart;
111  }
112 
113  return joinlist;
114 }
List * join_info_list
Definition: pathnodes.h:265
Relids min_righthand
Definition: pathnodes.h:2242
static void remove_rel_from_query(PlannerInfo *root, int relid, Relids joinrelids)
Definition: analyzejoins.c:312
#define ERROR
Definition: elog.h:46
static bool join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo)
Definition: analyzejoins.c:159
int bms_singleton_member(const Bitmapset *a)
Definition: bitmapset.c:577
List * list_delete_cell(List *list, ListCell *cell)
Definition: list.c:782
#define lfirst(lc)
Definition: pg_list.h:169
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:225
#define elog(elevel,...)
Definition: elog.h:232
static List * remove_rel_from_joinlist(List *joinlist, int relid, int *nremoved)
Definition: analyzejoins.c:454
Relids min_lefthand
Definition: pathnodes.h:2241

◆ set_plan_references()

Plan* set_plan_references ( PlannerInfo root,
Plan plan 
)

Definition at line 250 of file setrefs.c.

References add_rtes_to_flat_rtable(), PlannerInfo::append_rel_list, PlannerGlobal::appendRelations, AppendRelInfo::child_relid, PlannerGlobal::finalrowmarks, PlannerGlobal::finalrtable, PlannerInfo::glob, lappend(), lfirst_node, list_length(), NIL, palloc(), AppendRelInfo::parent_relid, PlanRowMark::prti, PlannerInfo::rowMarks, PlanRowMark::rti, set_plan_refs(), and AppendRelInfo::translated_vars.

Referenced by set_subqueryscan_references(), and standard_planner().

251 {
252  PlannerGlobal *glob = root->glob;
253  int rtoffset = list_length(glob->finalrtable);
254  ListCell *lc;
255 
256  /*
257  * Add all the query's RTEs to the flattened rangetable. The live ones
258  * will have their rangetable indexes increased by rtoffset. (Additional
259  * RTEs, not referenced by the Plan tree, might get added after those.)
260  */
261  add_rtes_to_flat_rtable(root, false);
262 
263  /*
264  * Adjust RT indexes of PlanRowMarks and add to final rowmarks list
265  */
266  foreach(lc, root->rowMarks)
267  {
269  PlanRowMark *newrc;
270 
271  /* flat copy is enough since all fields are scalars */
272  newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark));
273  memcpy(newrc, rc, sizeof(PlanRowMark));
274 
275  /* adjust indexes ... but *not* the rowmarkId */
276  newrc->rti += rtoffset;
277  newrc->prti += rtoffset;
278 
279  glob->finalrowmarks = lappend(glob->finalrowmarks, newrc);
280  }
281 
282  /*
283  * Adjust RT indexes of AppendRelInfos and add to final appendrels list.
284  * We assume the AppendRelInfos were built during planning and don't need
285  * to be copied.
286  */
287  foreach(lc, root->append_rel_list)
288  {
289  AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
290 
291  /* adjust RT indexes */
292  appinfo->parent_relid += rtoffset;
293  appinfo->child_relid += rtoffset;
294 
295  /*
296  * Rather than adjust the translated_vars entries, just drop 'em.
297  * Neither the executor nor EXPLAIN currently need that data.
298  */
299  appinfo->translated_vars = NIL;
300 
301  glob->appendRelations = lappend(glob->appendRelations, appinfo);
302  }
303 
304  /* Now fix the Plan tree */
305  return set_plan_refs(root, plan, rtoffset);
306 }
#define NIL
Definition: pg_list.h:65
List * rowMarks
Definition: pathnodes.h:287
List * appendRelations
Definition: pathnodes.h:107
Index prti
Definition: plannodes.h:1118
List * translated_vars
Definition: pathnodes.h:2323
static Plan * set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:500
#define lfirst_node(type, lc)
Definition: pg_list.h:172
PlannerGlobal * glob
Definition: pathnodes.h:163
List * lappend(List *list, void *datum)
Definition: list.c:336
List * append_rel_list
Definition: pathnodes.h:283
static void add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
Definition: setrefs.c:314
static int list_length(const List *l)
Definition: pg_list.h:149
List * finalrtable
Definition: pathnodes.h:101
void * palloc(Size size)
Definition: mcxt.c:1062
Index child_relid
Definition: pathnodes.h:2296
Index parent_relid
Definition: pathnodes.h:2295
List * finalrowmarks
Definition: pathnodes.h:103

Variable Documentation

◆ cursor_tuple_fraction

double cursor_tuple_fraction

Definition at line 69 of file planner.c.

Referenced by standard_planner().

◆ from_collapse_limit

int from_collapse_limit

Definition at line 39 of file initsplan.c.

Referenced by deconstruct_recurse().

◆ join_collapse_limit

int join_collapse_limit

Definition at line 40 of file initsplan.c.

Referenced by deconstruct_recurse().