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)
 
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, Index security_level, bool both_const)
 
RestrictInfobuild_implied_join_equality (PlannerInfo *root, Oid opno, Oid collation, Expr *item1, Expr *item2, Relids qualscope, 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)
 
bool trivial_subqueryscan (SubqueryScan *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 *context)
 

Variables

PGDLLIMPORT double cursor_tuple_fraction
 
PGDLLIMPORT int from_collapse_limit
 
PGDLLIMPORT 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 161 of file initsplan.c.

162 {
163  if (jtnode == NULL)
164  return;
165  if (IsA(jtnode, RangeTblRef))
166  {
167  int varno = ((RangeTblRef *) jtnode)->rtindex;
168 
169  (void) build_simple_rel(root, varno, NULL);
170  }
171  else if (IsA(jtnode, FromExpr))
172  {
173  FromExpr *f = (FromExpr *) jtnode;
174  ListCell *l;
175 
176  foreach(l, f->fromlist)
177  add_base_rels_to_query(root, lfirst(l));
178  }
179  else if (IsA(jtnode, JoinExpr))
180  {
181  JoinExpr *j = (JoinExpr *) jtnode;
182 
183  add_base_rels_to_query(root, j->larg);
184  add_base_rels_to_query(root, j->rarg);
185  }
186  else
187  elog(ERROR, "unrecognized node type: %d",
188  (int) nodeTag(jtnode));
189 }
#define ERROR
Definition: elog.h:39
void add_base_rels_to_query(PlannerInfo *root, Node *jtnode)
Definition: initsplan.c:161
int j
Definition: isn.c:74
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
#define nodeTag(nodeptr)
Definition: nodes.h:133
#define lfirst(lc)
Definition: pg_list.h:172
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition: relnode.c:189
List * fromlist
Definition: primnodes.h:1840

References build_simple_rel(), elog(), ERROR, FromExpr::fromlist, IsA, j, lfirst, and nodeTag.

Referenced by query_planner().

◆ add_other_rels_to_query()

void add_other_rels_to_query ( PlannerInfo root)

Definition at line 199 of file initsplan.c.

200 {
201  int rti;
202 
203  for (rti = 1; rti < root->simple_rel_array_size; rti++)
204  {
205  RelOptInfo *rel = root->simple_rel_array[rti];
206  RangeTblEntry *rte = root->simple_rte_array[rti];
207 
208  /* there may be empty slots corresponding to non-baserel RTEs */
209  if (rel == NULL)
210  continue;
211 
212  /* Ignore any "otherrels" that were already added. */
213  if (rel->reloptkind != RELOPT_BASEREL)
214  continue;
215 
216  /* If it's marked as inheritable, look for children. */
217  if (rte->inh)
218  expand_inherited_rtentry(root, rel, rte, rti);
219  }
220 }
void expand_inherited_rtentry(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte, Index rti)
Definition: inherit.c:86
@ RELOPT_BASEREL
Definition: pathnodes.h:821
int simple_rel_array_size
Definition: pathnodes.h:232
RelOptKind reloptkind
Definition: pathnodes.h:860

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

Referenced by query_planner().

◆ add_vars_to_targetlist()

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

Definition at line 283 of file initsplan.c.

285 {
286  ListCell *temp;
287 
288  Assert(!bms_is_empty(where_needed));
289 
290  foreach(temp, vars)
291  {
292  Node *node = (Node *) lfirst(temp);
293 
294  if (IsA(node, Var))
295  {
296  Var *var = (Var *) node;
297  RelOptInfo *rel = find_base_rel(root, var->varno);
298  int attno = var->varattno;
299 
300  if (bms_is_subset(where_needed, rel->relids))
301  continue;
302  Assert(attno >= rel->min_attr && attno <= rel->max_attr);
303  attno -= rel->min_attr;
304  if (rel->attr_needed[attno] == NULL)
305  {
306  /*
307  * Variable not yet requested, so add to rel's targetlist.
308  *
309  * The value available at the rel's scan level has not been
310  * nulled by any outer join, so drop its varnullingrels.
311  * (We'll put those back as we climb up the join tree.)
312  */
313  var = copyObject(var);
314  var->varnullingrels = NULL;
315  rel->reltarget->exprs = lappend(rel->reltarget->exprs, var);
316  /* reltarget cost and width will be computed later */
317  }
318  rel->attr_needed[attno] = bms_add_members(rel->attr_needed[attno],
319  where_needed);
320  }
321  else if (IsA(node, PlaceHolderVar))
322  {
323  PlaceHolderVar *phv = (PlaceHolderVar *) node;
324  PlaceHolderInfo *phinfo = find_placeholder_info(root, phv);
325 
326  phinfo->ph_needed = bms_add_members(phinfo->ph_needed,
327  where_needed);
328  }
329  else
330  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
331  }
332 }
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:316
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:796
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:704
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:338
#define copyObject(obj)
Definition: nodes.h:244
PlaceHolderInfo * find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv)
Definition: placeholder.c:83
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:393
Definition: nodes.h:129
List * exprs
Definition: pathnodes.h:1511
Relids ph_needed
Definition: pathnodes.h:3028
Relids relids
Definition: pathnodes.h:866
struct PathTarget * reltarget
Definition: pathnodes.h:888
AttrNumber min_attr
Definition: pathnodes.h:919
Definition: primnodes.h:223
AttrNumber varattno
Definition: primnodes.h:235
int varno
Definition: primnodes.h:230
Definition: regcomp.c:282

References Assert(), 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().

◆ build_base_rel_tlists()

void build_base_rel_tlists ( PlannerInfo root,
List final_tlist 
)

Definition at line 238 of file initsplan.c.

239 {
240  List *tlist_vars = pull_var_clause((Node *) final_tlist,
244 
245  if (tlist_vars != NIL)
246  {
247  add_vars_to_targetlist(root, tlist_vars, bms_make_singleton(0));
248  list_free(tlist_vars);
249  }
250 
251  /*
252  * If there's a HAVING clause, we'll need the Vars it uses, too. Note
253  * that HAVING can contain Aggrefs but not WindowFuncs.
254  */
255  if (root->parse->havingQual)
256  {
257  List *having_vars = pull_var_clause(root->parse->havingQual,
260 
261  if (having_vars != NIL)
262  {
263  add_vars_to_targetlist(root, having_vars,
264  bms_make_singleton(0));
265  list_free(having_vars);
266  }
267  }
268 }
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
void add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed)
Definition: initsplan.c:283
void list_free(List *list)
Definition: list.c:1545
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:184
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:186
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:187
#define NIL
Definition: pg_list.h:68
Definition: pg_list.h:54
Query * parse
Definition: pathnodes.h:202
Node * havingQual
Definition: parsenodes.h:203
List * pull_var_clause(Node *node, int flags)
Definition: var.c:617

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

◆ build_implied_join_equality()

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

Definition at line 2809 of file initsplan.c.

2816 {
2817  RestrictInfo *restrictinfo;
2818  Expr *clause;
2819 
2820  /*
2821  * Build the new clause. Copy to ensure it shares no substructure with
2822  * original (this is necessary in case there are subselects in there...)
2823  */
2824  clause = make_opclause(opno,
2825  BOOLOID, /* opresulttype */
2826  false, /* opretset */
2827  copyObject(item1),
2828  copyObject(item2),
2829  InvalidOid,
2830  collation);
2831 
2832  /*
2833  * Build the RestrictInfo node itself.
2834  */
2835  restrictinfo = make_restrictinfo(root,
2836  clause,
2837  true, /* is_pushed_down */
2838  false, /* pseudoconstant */
2839  security_level, /* security_level */
2840  qualscope, /* required_relids */
2841  NULL); /* outer_relids */
2842 
2843  /* Set mergejoinability/hashjoinability flags */
2844  check_mergejoinable(restrictinfo);
2845  check_hashjoinable(restrictinfo);
2846  check_memoizable(restrictinfo);
2847 
2848  return restrictinfo;
2849 }
static void check_hashjoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3069
static void check_mergejoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3032
static void check_memoizable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3097
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: makefuncs.c:612
#define InvalidOid
Definition: postgres_ext.h:36
RestrictInfo * make_restrictinfo(PlannerInfo *root, Expr *clause, bool is_pushed_down, bool pseudoconstant, Index security_level, Relids required_relids, Relids outer_relids)
Definition: restrictinfo.c:61

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

◆ change_plan_targetlist()

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

Definition at line 2141 of file createplan.c.

2142 {
2143  /*
2144  * If the top plan node can't do projections and its existing target list
2145  * isn't already what we need, we need to add a Result node to help it
2146  * along.
2147  */
2148  if (!is_projection_capable_plan(subplan) &&
2149  !tlist_same_exprs(tlist, subplan->targetlist))
2150  subplan = inject_projection_plan(subplan, tlist,
2151  subplan->parallel_safe &&
2152  tlist_parallel_safe);
2153  else
2154  {
2155  /* Else we can just replace the plan node's tlist */
2156  subplan->targetlist = tlist;
2157  subplan->parallel_safe &= tlist_parallel_safe;
2158  }
2159  return subplan;
2160 }
bool is_projection_capable_plan(Plan *plan)
Definition: createplan.c:7218
static Plan * inject_projection_plan(Plan *subplan, List *tlist, bool parallel_safe)
Definition: createplan.c:2109
bool parallel_safe
Definition: plannodes.h:145
List * targetlist
Definition: plannodes.h:156
bool tlist_same_exprs(List *tlist1, List *tlist2)
Definition: tlist.c:218

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

Referenced by create_unique_plan(), and postgresGetForeignPlan().

◆ create_lateral_join_info()

void create_lateral_join_info ( PlannerInfo root)

Definition at line 508 of file initsplan.c.

509 {
510  bool found_laterals = false;
511  Index rti;
512  ListCell *lc;
513 
514  /* We need do nothing if the query contains no LATERAL RTEs */
515  if (!root->hasLateralRTEs)
516  return;
517 
518  /*
519  * Examine all baserels (the rel array has been set up by now).
520  */
521  for (rti = 1; rti < root->simple_rel_array_size; rti++)
522  {
523  RelOptInfo *brel = root->simple_rel_array[rti];
524  Relids lateral_relids;
525 
526  /* there may be empty slots corresponding to non-baserel RTEs */
527  if (brel == NULL)
528  continue;
529 
530  Assert(brel->relid == rti); /* sanity check on array */
531 
532  /* ignore RTEs that are "other rels" */
533  if (brel->reloptkind != RELOPT_BASEREL)
534  continue;
535 
536  lateral_relids = NULL;
537 
538  /* consider each laterally-referenced Var or PHV */
539  foreach(lc, brel->lateral_vars)
540  {
541  Node *node = (Node *) lfirst(lc);
542 
543  if (IsA(node, Var))
544  {
545  Var *var = (Var *) node;
546 
547  found_laterals = true;
548  lateral_relids = bms_add_member(lateral_relids,
549  var->varno);
550  }
551  else if (IsA(node, PlaceHolderVar))
552  {
553  PlaceHolderVar *phv = (PlaceHolderVar *) node;
554  PlaceHolderInfo *phinfo = find_placeholder_info(root, phv);
555 
556  found_laterals = true;
557  lateral_relids = bms_add_members(lateral_relids,
558  phinfo->ph_eval_at);
559  }
560  else
561  Assert(false);
562  }
563 
564  /* We now have all the simple lateral refs from this rel */
565  brel->direct_lateral_relids = lateral_relids;
566  brel->lateral_relids = bms_copy(lateral_relids);
567  }
568 
569  /*
570  * Now check for lateral references within PlaceHolderVars, and mark their
571  * eval_at rels as having lateral references to the source rels.
572  *
573  * For a PHV that is due to be evaluated at a baserel, mark its source(s)
574  * as direct lateral dependencies of the baserel (adding onto the ones
575  * recorded above). If it's due to be evaluated at a join, mark its
576  * source(s) as indirect lateral dependencies of each baserel in the join,
577  * ie put them into lateral_relids but not direct_lateral_relids. This is
578  * appropriate because we can't put any such baserel on the outside of a
579  * join to one of the PHV's lateral dependencies, but on the other hand we
580  * also can't yet join it directly to the dependency.
581  */
582  foreach(lc, root->placeholder_list)
583  {
584  PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc);
585  Relids eval_at = phinfo->ph_eval_at;
586  int varno;
587 
588  if (phinfo->ph_lateral == NULL)
589  continue; /* PHV is uninteresting if no lateral refs */
590 
591  found_laterals = true;
592 
593  if (bms_get_singleton_member(eval_at, &varno))
594  {
595  /* Evaluation site is a baserel */
596  RelOptInfo *brel = find_base_rel(root, varno);
597 
598  brel->direct_lateral_relids =
600  phinfo->ph_lateral);
601  brel->lateral_relids =
603  phinfo->ph_lateral);
604  }
605  else
606  {
607  /* Evaluation site is a join */
608  varno = -1;
609  while ((varno = bms_next_member(eval_at, varno)) >= 0)
610  {
611  RelOptInfo *brel = find_base_rel_ignore_join(root, varno);
612 
613  if (brel == NULL)
614  continue; /* ignore outer joins in eval_at */
616  phinfo->ph_lateral);
617  }
618  }
619  }
620 
621  /*
622  * If we found no actual lateral references, we're done; but reset the
623  * hasLateralRTEs flag to avoid useless work later.
624  */
625  if (!found_laterals)
626  {
627  root->hasLateralRTEs = false;
628  return;
629  }
630 
631  /*
632  * Calculate the transitive closure of the lateral_relids sets, so that
633  * they describe both direct and indirect lateral references. If relation
634  * X references Y laterally, and Y references Z laterally, then we will
635  * have to scan X on the inside of a nestloop with Z, so for all intents
636  * and purposes X is laterally dependent on Z too.
637  *
638  * This code is essentially Warshall's algorithm for transitive closure.
639  * The outer loop considers each baserel, and propagates its lateral
640  * dependencies to those baserels that have a lateral dependency on it.
641  */
642  for (rti = 1; rti < root->simple_rel_array_size; rti++)
643  {
644  RelOptInfo *brel = root->simple_rel_array[rti];
645  Relids outer_lateral_relids;
646  Index rti2;
647 
648  if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
649  continue;
650 
651  /* need not consider baserel further if it has no lateral refs */
652  outer_lateral_relids = brel->lateral_relids;
653  if (outer_lateral_relids == NULL)
654  continue;
655 
656  /* else scan all baserels */
657  for (rti2 = 1; rti2 < root->simple_rel_array_size; rti2++)
658  {
659  RelOptInfo *brel2 = root->simple_rel_array[rti2];
660 
661  if (brel2 == NULL || brel2->reloptkind != RELOPT_BASEREL)
662  continue;
663 
664  /* if brel2 has lateral ref to brel, propagate brel's refs */
665  if (bms_is_member(rti, brel2->lateral_relids))
667  outer_lateral_relids);
668  }
669  }
670 
671  /*
672  * Now that we've identified all lateral references, mark each baserel
673  * with the set of relids of rels that reference it laterally (possibly
674  * indirectly) --- that is, the inverse mapping of lateral_relids.
675  */
676  for (rti = 1; rti < root->simple_rel_array_size; rti++)
677  {
678  RelOptInfo *brel = root->simple_rel_array[rti];
679  Relids lateral_relids;
680  int rti2;
681 
682  if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
683  continue;
684 
685  /* Nothing to do at rels with no lateral refs */
686  lateral_relids = brel->lateral_relids;
687  if (lateral_relids == NULL)
688  continue;
689 
690  /*
691  * We should not have broken the invariant that lateral_relids is
692  * exactly NULL if empty.
693  */
694  Assert(!bms_is_empty(lateral_relids));
695 
696  /* Also, no rel should have a lateral dependency on itself */
697  Assert(!bms_is_member(rti, lateral_relids));
698 
699  /* Mark this rel's referencees */
700  rti2 = -1;
701  while ((rti2 = bms_next_member(lateral_relids, rti2)) >= 0)
702  {
703  RelOptInfo *brel2 = root->simple_rel_array[rti2];
704 
705  if (brel2 == NULL)
706  continue; /* must be an OJ */
707 
708  Assert(brel2->reloptkind == RELOPT_BASEREL);
709  brel2->lateral_referencers =
710  bms_add_member(brel2->lateral_referencers, rti);
711  }
712  }
713 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1047
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:428
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:739
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
bool bms_get_singleton_member(const Bitmapset *a, int *member)
Definition: bitmapset.c:618
unsigned int Index
Definition: c.h:598
RelOptInfo * find_base_rel_ignore_join(PlannerInfo *root, int relid)
Definition: relnode.c:421
Relids ph_lateral
Definition: pathnodes.h:3025
Relids ph_eval_at
Definition: pathnodes.h:3022
bool hasLateralRTEs
Definition: pathnodes.h:494
List * placeholder_list
Definition: pathnodes.h:374
Index relid
Definition: pathnodes.h:913
List * lateral_vars
Definition: pathnodes.h:929
Relids lateral_relids
Definition: pathnodes.h:908
Relids lateral_referencers
Definition: pathnodes.h:931
Relids direct_lateral_relids
Definition: pathnodes.h:906

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_base_rel_ignore_join(), 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_size, and Var::varno.

Referenced by query_planner().

◆ create_plan()

Plan* create_plan ( PlannerInfo root,
Path best_path 
)

Definition at line 335 of file createplan.c.

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

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

◆ deconstruct_jointree()

List* deconstruct_jointree ( PlannerInfo root)

Definition at line 740 of file initsplan.c.

741 {
742  List *result;
743  JoinDomain *top_jdomain;
744  List *item_list = NIL;
745  List *postponed_qual_list = NIL;
746  ListCell *lc;
747 
748  /*
749  * After this point, no more PlaceHolderInfos may be made, because
750  * make_outerjoininfo requires all active placeholders to be present in
751  * root->placeholder_list while we crawl up the join tree.
752  */
753  root->placeholdersFrozen = true;
754 
755  /* Fetch the already-created top-level join domain for the query */
756  top_jdomain = linitial_node(JoinDomain, root->join_domains);
757  top_jdomain->jd_relids = NULL; /* filled during deconstruct_recurse */
758 
759  /* Start recursion at top of jointree */
760  Assert(root->parse->jointree != NULL &&
761  IsA(root->parse->jointree, FromExpr));
762 
763  /* These are filled as we scan the jointree */
764  root->all_baserels = NULL;
765  root->outer_join_rels = NULL;
766 
767  /* Perform the initial scan of the jointree */
768  result = deconstruct_recurse(root, (Node *) root->parse->jointree,
769  top_jdomain,
770  &item_list);
771 
772  /* Now we can form the value of all_query_rels, too */
774 
775  /* ... which should match what we computed for the top join domain */
776  Assert(bms_equal(root->all_query_rels, top_jdomain->jd_relids));
777 
778  /* Now scan all the jointree nodes again, and distribute quals */
779  foreach(lc, item_list)
780  {
781  JoinTreeItem *jtitem = (JoinTreeItem *) lfirst(lc);
782 
783  deconstruct_distribute(root, jtitem,
784  &postponed_qual_list);
785  }
786 
787  /* Shouldn't be any leftover postponed quals */
788  Assert(postponed_qual_list == NIL);
789 
790  /*
791  * However, if there were any special joins then we may have some
792  * postponed LEFT JOIN clauses to deal with.
793  */
794  if (root->join_info_list)
795  {
796  foreach(lc, item_list)
797  {
798  JoinTreeItem *jtitem = (JoinTreeItem *) lfirst(lc);
799 
800  if (jtitem->oj_joinclauses != NIL)
801  deconstruct_distribute_oj_quals(root, item_list, jtitem);
802  }
803  }
804 
805  /* Don't need the JoinTreeItems any more */
806  list_free_deep(item_list);
807 
808  return result;
809 }
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:94
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:226
static void deconstruct_distribute_oj_quals(PlannerInfo *root, List *jtitems, JoinTreeItem *jtitem)
Definition: initsplan.c:1876
static List * deconstruct_recurse(PlannerInfo *root, Node *jtnode, JoinDomain *parent_domain, List **item_list)
Definition: initsplan.c:826
static void deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem, List **postponed_qual_list)
Definition: initsplan.c:1123
void list_free_deep(List *list)
Definition: list.c:1559
#define linitial_node(type, l)
Definition: pg_list.h:181
Relids jd_relids
Definition: pathnodes.h:1316
List * oj_joinclauses
Definition: initsplan.c:76
Relids all_query_rels
Definition: pathnodes.h:269
Relids outer_join_rels
Definition: pathnodes.h:261
List * join_domains
Definition: pathnodes.h:311
bool placeholdersFrozen
Definition: pathnodes.h:502
List * join_info_list
Definition: pathnodes.h:340
Relids all_baserels
Definition: pathnodes.h:255
FromExpr * jointree
Definition: parsenodes.h:182

References PlannerInfo::all_baserels, PlannerInfo::all_query_rels, Assert(), bms_equal(), bms_union(), deconstruct_distribute(), deconstruct_distribute_oj_quals(), deconstruct_recurse(), IsA, JoinDomain::jd_relids, PlannerInfo::join_domains, PlannerInfo::join_info_list, Query::jointree, lfirst, linitial_node, list_free_deep(), NIL, JoinTreeItem::oj_joinclauses, PlannerInfo::outer_join_rels, PlannerInfo::parse, and PlannerInfo::placeholdersFrozen.

Referenced by query_planner().

◆ distribute_restrictinfo_to_rels()

void distribute_restrictinfo_to_rels ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 2583 of file initsplan.c.

2585 {
2586  Relids relids = restrictinfo->required_relids;
2587  RelOptInfo *rel;
2588 
2589  switch (bms_membership(relids))
2590  {
2591  case BMS_SINGLETON:
2592 
2593  /*
2594  * There is only one relation participating in the clause, so it
2595  * is a restriction clause for that relation.
2596  */
2597  rel = find_base_rel(root, bms_singleton_member(relids));
2598 
2599  /* Add clause to rel's restriction list */
2601  restrictinfo);
2602  /* Update security level info */
2604  restrictinfo->security_level);
2605  break;
2606  case BMS_MULTIPLE:
2607 
2608  /*
2609  * The clause is a join clause, since there is more than one rel
2610  * in its relid set.
2611  */
2612 
2613  /*
2614  * Check for hashjoinable operators. (We don't bother setting the
2615  * hashjoin info except in true join clauses.)
2616  */
2617  check_hashjoinable(restrictinfo);
2618 
2619  /*
2620  * Likewise, check if the clause is suitable to be used with a
2621  * Memoize node to cache inner tuples during a parameterized
2622  * nested loop.
2623  */
2624  check_memoizable(restrictinfo);
2625 
2626  /*
2627  * Add clause to the join lists of all the relevant relations.
2628  */
2629  add_join_clause_to_rels(root, restrictinfo, relids);
2630  break;
2631  default:
2632 
2633  /*
2634  * clause references no rels, and therefore we have no place to
2635  * attach it. Shouldn't get here if callers are working properly.
2636  */
2637  elog(ERROR, "cannot cope with variable-free clause");
2638  break;
2639  }
2640 }
int bms_singleton_member(const Bitmapset *a)
Definition: bitmapset.c:580
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:675
@ BMS_SINGLETON
Definition: bitmapset.h:74
@ BMS_MULTIPLE
Definition: bitmapset.h:75
#define Min(x, y)
Definition: c.h:988
void add_join_clause_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo, Relids join_relids)
Definition: joininfo.c:95
List * baserestrictinfo
Definition: pathnodes.h:974
Index baserestrict_min_security
Definition: pathnodes.h:978
Index security_level
Definition: pathnodes.h:2539
Relids required_relids
Definition: pathnodes.h:2548

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

◆ extract_query_dependencies_walker()

bool extract_query_dependencies_walker ( Node node,
PlannerInfo context 
)

Definition at line 3513 of file setrefs.c.

3514 {
3515  if (node == NULL)
3516  return false;
3517  Assert(!IsA(node, PlaceHolderVar));
3518  if (IsA(node, Query))
3519  {
3520  Query *query = (Query *) node;
3521  ListCell *lc;
3522 
3523  if (query->commandType == CMD_UTILITY)
3524  {
3525  /*
3526  * Ignore utility statements, except those (such as EXPLAIN) that
3527  * contain a parsed-but-not-planned query.
3528  */
3529  query = UtilityContainsQuery(query->utilityStmt);
3530  if (query == NULL)
3531  return false;
3532  }
3533 
3534  /* Remember if any Query has RLS quals applied by rewriter */
3535  if (query->hasRowSecurity)
3536  context->glob->dependsOnRole = true;
3537 
3538  /* Collect relation OIDs in this Query's rtable */
3539  foreach(lc, query->rtable)
3540  {
3541  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3542 
3543  if (rte->rtekind == RTE_RELATION ||
3544  (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)) ||
3545  (rte->rtekind == RTE_NAMEDTUPLESTORE && OidIsValid(rte->relid)))
3546  context->glob->relationOids =
3547  lappend_oid(context->glob->relationOids, rte->relid);
3548  }
3549 
3550  /* And recurse into the query's subexpressions */
3552  (void *) context, 0);
3553  }
3554  /* Extract function dependencies and check for regclass Consts */
3555  fix_expr_common(context, node);
3557  (void *) context);
3558 }
#define OidIsValid(objectId)
Definition: c.h:759
List * lappend_oid(List *list, Oid datum)
Definition: list.c:374
#define query_tree_walker(q, w, c, f)
Definition: nodeFuncs.h:156
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:151
@ CMD_UTILITY
Definition: nodes.h:281
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1020
@ RTE_SUBQUERY
Definition: parsenodes.h:1014
@ RTE_RELATION
Definition: parsenodes.h:1013
static void fix_expr_common(PlannerInfo *root, Node *node)
Definition: setrefs.c:1931
bool extract_query_dependencies_walker(Node *node, PlannerInfo *context)
Definition: setrefs.c:3513
bool dependsOnRole
Definition: pathnodes.h:153
List * relationOids
Definition: pathnodes.h:132
PlannerGlobal * glob
Definition: pathnodes.h:205
List * rtable
Definition: parsenodes.h:175
CmdType commandType
Definition: parsenodes.h:128
Node * utilityStmt
Definition: parsenodes.h:143
RTEKind rtekind
Definition: parsenodes.h:1032
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2170

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

Referenced by expression_planner_with_deps(), and extract_query_dependencies().

◆ find_lateral_references()

void find_lateral_references ( PlannerInfo root)

Definition at line 362 of file initsplan.c.

363 {
364  Index rti;
365 
366  /* We need do nothing if the query contains no LATERAL RTEs */
367  if (!root->hasLateralRTEs)
368  return;
369 
370  /*
371  * Examine all baserels (the rel array has been set up by now).
372  */
373  for (rti = 1; rti < root->simple_rel_array_size; rti++)
374  {
375  RelOptInfo *brel = root->simple_rel_array[rti];
376 
377  /* there may be empty slots corresponding to non-baserel RTEs */
378  if (brel == NULL)
379  continue;
380 
381  Assert(brel->relid == rti); /* sanity check on array */
382 
383  /*
384  * This bit is less obvious than it might look. We ignore appendrel
385  * otherrels and consider only their parent baserels. In a case where
386  * a LATERAL-containing UNION ALL subquery was pulled up, it is the
387  * otherrel that is actually going to be in the plan. However, we
388  * want to mark all its lateral references as needed by the parent,
389  * because it is the parent's relid that will be used for join
390  * planning purposes. And the parent's RTE will contain all the
391  * lateral references we need to know, since the pulled-up member is
392  * nothing but a copy of parts of the original RTE's subquery. We
393  * could visit the parent's children instead and transform their
394  * references back to the parent's relid, but it would be much more
395  * complicated for no real gain. (Important here is that the child
396  * members have not yet received any processing beyond being pulled
397  * up.) Similarly, in appendrels created by inheritance expansion,
398  * it's sufficient to look at the parent relation.
399  */
400 
401  /* ignore RTEs that are "other rels" */
402  if (brel->reloptkind != RELOPT_BASEREL)
403  continue;
404 
405  extract_lateral_references(root, brel, rti);
406  }
407 }
static void extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex)
Definition: initsplan.c:410

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

Referenced by query_planner().

◆ 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 1010 of file analyzejoins.c.

1017 {
1018  MemoryContext old_context;
1019  ListCell *lc;
1020 
1021  /* Certainly can't prove uniqueness when there are no joinclauses */
1022  if (restrictlist == NIL)
1023  return false;
1024 
1025  /*
1026  * Make a quick check to eliminate cases in which we will surely be unable
1027  * to prove uniqueness of the innerrel.
1028  */
1029  if (!rel_supports_distinctness(root, innerrel))
1030  return false;
1031 
1032  /*
1033  * Query the cache to see if we've managed to prove that innerrel is
1034  * unique for any subset of this outerrel. We don't need an exact match,
1035  * as extra outerrels can't make the innerrel any less unique (or more
1036  * formally, the restrictlist for a join to a superset outerrel must be a
1037  * superset of the conditions we successfully used before).
1038  */
1039  foreach(lc, innerrel->unique_for_rels)
1040  {
1041  Relids unique_for_rels = (Relids) lfirst(lc);
1042 
1043  if (bms_is_subset(unique_for_rels, outerrelids))
1044  return true; /* Success! */
1045  }
1046 
1047  /*
1048  * Conversely, we may have already determined that this outerrel, or some
1049  * superset thereof, cannot prove this innerrel to be unique.
1050  */
1051  foreach(lc, innerrel->non_unique_for_rels)
1052  {
1053  Relids unique_for_rels = (Relids) lfirst(lc);
1054 
1055  if (bms_is_subset(outerrelids, unique_for_rels))
1056  return false;
1057  }
1058 
1059  /* No cached information, so try to make the proof. */
1060  if (is_innerrel_unique_for(root, joinrelids, outerrelids, innerrel,
1061  jointype, restrictlist))
1062  {
1063  /*
1064  * Cache the positive result for future probes, being sure to keep it
1065  * in the planner_cxt even if we are working in GEQO.
1066  *
1067  * Note: one might consider trying to isolate the minimal subset of
1068  * the outerrels that proved the innerrel unique. But it's not worth
1069  * the trouble, because the planner builds up joinrels incrementally
1070  * and so we'll see the minimally sufficient outerrels before any
1071  * supersets of them anyway.
1072  */
1073  old_context = MemoryContextSwitchTo(root->planner_cxt);
1074  innerrel->unique_for_rels = lappend(innerrel->unique_for_rels,
1075  bms_copy(outerrelids));
1076  MemoryContextSwitchTo(old_context);
1077 
1078  return true; /* Success! */
1079  }
1080  else
1081  {
1082  /*
1083  * None of the join conditions for outerrel proved innerrel unique, so
1084  * we can safely reject this outerrel or any subset of it in future
1085  * checks.
1086  *
1087  * However, in normal planning mode, caching this knowledge is totally
1088  * pointless; it won't be queried again, because we build up joinrels
1089  * from smaller to larger. It is useful in GEQO mode, where the
1090  * knowledge can be carried across successive planning attempts; and
1091  * it's likely to be useful when using join-search plugins, too. Hence
1092  * cache when join_search_private is non-NULL. (Yeah, that's a hack,
1093  * but it seems reasonable.)
1094  *
1095  * Also, allow callers to override that heuristic and force caching;
1096  * that's useful for reduce_unique_semijoins, which calls here before
1097  * the normal join search starts.
1098  */
1099  if (force_cache || root->join_search_private)
1100  {
1101  old_context = MemoryContextSwitchTo(root->planner_cxt);
1102  innerrel->non_unique_for_rels =
1103  lappend(innerrel->non_unique_for_rels,
1104  bms_copy(outerrelids));
1105  MemoryContextSwitchTo(old_context);
1106  }
1107 
1108  return false;
1109  }
1110 }
static bool is_innerrel_unique_for(PlannerInfo *root, Relids joinrelids, Relids outerrelids, RelOptInfo *innerrel, JoinType jointype, List *restrictlist)
static bool rel_supports_distinctness(PlannerInfo *root, RelOptInfo *rel)
Definition: analyzejoins.c:631
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
Bitmapset * Relids
Definition: pathnodes.h:30
List * unique_for_rels
Definition: pathnodes.h:966
List * non_unique_for_rels
Definition: pathnodes.h:968

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

Referenced by add_paths_to_joinrel(), and reduce_unique_semijoins().

◆ is_projection_capable_path()

bool is_projection_capable_path ( Path path)

Definition at line 7168 of file createplan.c.

7169 {
7170  /* Most plan types can project, so just list the ones that can't */
7171  switch (path->pathtype)
7172  {
7173  case T_Hash:
7174  case T_Material:
7175  case T_Memoize:
7176  case T_Sort:
7177  case T_IncrementalSort:
7178  case T_Unique:
7179  case T_SetOp:
7180  case T_LockRows:
7181  case T_Limit:
7182  case T_ModifyTable:
7183  case T_MergeAppend:
7184  case T_RecursiveUnion:
7185  return false;
7186  case T_CustomScan:
7188  return true;
7189  return false;
7190  case T_Append:
7191 
7192  /*
7193  * Append can't project, but if an AppendPath is being used to
7194  * represent a dummy path, what will actually be generated is a
7195  * Result which can project.
7196  */
7197  return IS_DUMMY_APPEND(path);
7198  case T_ProjectSet:
7199 
7200  /*
7201  * Although ProjectSet certainly projects, say "no" because we
7202  * don't want the planner to randomly replace its tlist with
7203  * something else; the SRFs have to stay at top level. This might
7204  * get relaxed later.
7205  */
7206  return false;
7207  default:
7208  break;
7209  }
7210  return true;
7211 }
#define CUSTOMPATH_SUPPORT_PROJECTION
Definition: extensible.h:86
#define castNode(_type_, nodeptr)
Definition: nodes.h:197
#define IS_DUMMY_APPEND(p)
Definition: pathnodes.h:1903
NodeTag pathtype
Definition: pathnodes.h:1604

References castNode, CUSTOMPATH_SUPPORT_PROJECTION, IS_DUMMY_APPEND, and Path::pathtype.

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

◆ is_projection_capable_plan()

bool is_projection_capable_plan ( Plan plan)

Definition at line 7218 of file createplan.c.

7219 {
7220  /* Most plan types can project, so just list the ones that can't */
7221  switch (nodeTag(plan))
7222  {
7223  case T_Hash:
7224  case T_Material:
7225  case T_Memoize:
7226  case T_Sort:
7227  case T_Unique:
7228  case T_SetOp:
7229  case T_LockRows:
7230  case T_Limit:
7231  case T_ModifyTable:
7232  case T_Append:
7233  case T_MergeAppend:
7234  case T_RecursiveUnion:
7235  return false;
7236  case T_CustomScan:
7237  if (((CustomScan *) plan)->flags & CUSTOMPATH_SUPPORT_PROJECTION)
7238  return true;
7239  return false;
7240  case T_ProjectSet:
7241 
7242  /*
7243  * Although ProjectSet certainly projects, say "no" because we
7244  * don't want the planner to randomly replace its tlist with
7245  * something else; the SRFs have to stay at top level. This might
7246  * get relaxed later.
7247  */
7248  return false;
7249  default:
7250  break;
7251  }
7252  return true;
7253 }

References CUSTOMPATH_SUPPORT_PROJECTION, and nodeTag.

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

◆ 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 6554 of file createplan.c.

6559 {
6560  Agg *node = makeNode(Agg);
6561  Plan *plan = &node->plan;
6562  long numGroups;
6563 
6564  /* Reduce to long, but 'ware overflow! */
6565  numGroups = clamp_cardinality_to_long(dNumGroups);
6566 
6567  node->aggstrategy = aggstrategy;
6568  node->aggsplit = aggsplit;
6569  node->numCols = numGroupCols;
6570  node->grpColIdx = grpColIdx;
6571  node->grpOperators = grpOperators;
6572  node->grpCollations = grpCollations;
6573  node->numGroups = numGroups;
6574  node->transitionSpace = transitionSpace;
6575  node->aggParams = NULL; /* SS_finalize_plan() will fill this */
6576  node->groupingSets = groupingSets;
6577  node->chain = chain;
6578 
6579  plan->qual = qual;
6580  plan->targetlist = tlist;
6581  plan->lefttree = lefttree;
6582  plan->righttree = NULL;
6583 
6584  return node;
6585 }
long clamp_cardinality_to_long(Cardinality x)
Definition: costsize.c:225
#define makeNode(_type_)
Definition: nodes.h:176
Definition: plannodes.h:998
AggSplit aggsplit
Definition: plannodes.h:1005
List * chain
Definition: plannodes.h:1032
long numGroups
Definition: plannodes.h:1018
List * groupingSets
Definition: plannodes.h:1029
Bitmapset * aggParams
Definition: plannodes.h:1024
Plan plan
Definition: plannodes.h:999
int numCols
Definition: plannodes.h:1008
uint64 transitionSpace
Definition: plannodes.h:1021
AggStrategy aggstrategy
Definition: plannodes.h:1002
struct Plan * lefttree
Definition: plannodes.h:158
struct Plan * righttree
Definition: plannodes.h:159
List * qual
Definition: plannodes.h:157

References Agg::aggParams, Agg::aggsplit, Agg::aggstrategy, Agg::chain, clamp_cardinality_to_long(), Agg::groupingSets, Plan::lefttree, makeNode, 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().

◆ 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 5790 of file createplan.c.

5798 {
5799  ForeignScan *node = makeNode(ForeignScan);
5800  Plan *plan = &node->scan.plan;
5801 
5802  /* cost will be filled in by create_foreignscan_plan */
5803  plan->targetlist = qptlist;
5804  plan->qual = qpqual;
5805  plan->lefttree = outer_plan;
5806  plan->righttree = NULL;
5807  node->scan.scanrelid = scanrelid;
5808 
5809  /* these may be overridden by the FDW's PlanDirectModify callback. */
5810  node->operation = CMD_SELECT;
5811  node->resultRelation = 0;
5812 
5813  /* checkAsUser, fs_server will be filled in by create_foreignscan_plan */
5814  node->checkAsUser = InvalidOid;
5815  node->fs_server = InvalidOid;
5816  node->fdw_exprs = fdw_exprs;
5817  node->fdw_private = fdw_private;
5818  node->fdw_scan_tlist = fdw_scan_tlist;
5819  node->fdw_recheck_quals = fdw_recheck_quals;
5820  /* fs_relids, fs_base_relids will be filled by create_foreignscan_plan */
5821  node->fs_relids = NULL;
5822  node->fs_base_relids = NULL;
5823  /* fsSystemCol will be filled in by create_foreignscan_plan */
5824  node->fsSystemCol = false;
5825 
5826  return node;
5827 }
@ CMD_SELECT
Definition: nodes.h:276
Oid checkAsUser
Definition: plannodes.h:713
CmdType operation
Definition: plannodes.h:711
Oid fs_server
Definition: plannodes.h:715
List * fdw_exprs
Definition: plannodes.h:716
bool fsSystemCol
Definition: plannodes.h:722
Bitmapset * fs_relids
Definition: plannodes.h:720
List * fdw_private
Definition: plannodes.h:717
Bitmapset * fs_base_relids
Definition: plannodes.h:721
Index resultRelation
Definition: plannodes.h:712
List * fdw_recheck_quals
Definition: plannodes.h:719
List * fdw_scan_tlist
Definition: plannodes.h:718
Index scanrelid
Definition: plannodes.h:390

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

Referenced by fileGetForeignPlan(), and postgresGetForeignPlan().

◆ make_limit()

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

Definition at line 6921 of file createplan.c.

6924 {
6925  Limit *node = makeNode(Limit);
6926  Plan *plan = &node->plan;
6927 
6928  plan->targetlist = lefttree->targetlist;
6929  plan->qual = NIL;
6930  plan->lefttree = lefttree;
6931  plan->righttree = NULL;
6932 
6933  node->limitOffset = limitOffset;
6934  node->limitCount = limitCount;
6935  node->limitOption = limitOption;
6936  node->uniqNumCols = uniqNumCols;
6937  node->uniqColIdx = uniqColIdx;
6938  node->uniqOperators = uniqOperators;
6939  node->uniqCollations = uniqCollations;
6940 
6941  return node;
6942 }
LimitOption limitOption
Definition: plannodes.h:1282
Plan plan
Definition: plannodes.h:1273
Node * limitCount
Definition: plannodes.h:1279
int uniqNumCols
Definition: plannodes.h:1285
Node * limitOffset
Definition: plannodes.h:1276

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

Referenced by create_limit_plan(), and create_minmaxagg_plan().

◆ make_sort_from_sortclauses()

Sort* make_sort_from_sortclauses ( List sortcls,
Plan lefttree 
)

Definition at line 6383 of file createplan.c.

6384 {
6385  List *sub_tlist = lefttree->targetlist;
6386  ListCell *l;
6387  int numsortkeys;
6388  AttrNumber *sortColIdx;
6389  Oid *sortOperators;
6390  Oid *collations;
6391  bool *nullsFirst;
6392 
6393  /* Convert list-ish representation to arrays wanted by executor */
6394  numsortkeys = list_length(sortcls);
6395  sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
6396  sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
6397  collations = (Oid *) palloc(numsortkeys * sizeof(Oid));
6398  nullsFirst = (bool *) palloc(numsortkeys * sizeof(bool));
6399 
6400  numsortkeys = 0;
6401  foreach(l, sortcls)
6402  {
6403  SortGroupClause *sortcl = (SortGroupClause *) lfirst(l);
6404  TargetEntry *tle = get_sortgroupclause_tle(sortcl, sub_tlist);
6405 
6406  sortColIdx[numsortkeys] = tle->resno;
6407  sortOperators[numsortkeys] = sortcl->sortop;
6408  collations[numsortkeys] = exprCollation((Node *) tle->expr);
6409  nullsFirst[numsortkeys] = sortcl->nulls_first;
6410  numsortkeys++;
6411  }
6412 
6413  return make_sort(lefttree, numsortkeys,
6414  sortColIdx, sortOperators,
6415  collations, nullsFirst);
6416 }
int16 AttrNumber
Definition: attnum.h:21
static Sort * make_sort(Plan *lefttree, int numCols, AttrNumber *sortColIdx, Oid *sortOperators, Oid *collations, bool *nullsFirst)
Definition: createplan.c:6036
void * palloc(Size size)
Definition: mcxt.c:1210
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:764
static int list_length(const List *l)
Definition: pg_list.h:152
unsigned int Oid
Definition: postgres_ext.h:31
Expr * expr
Definition: primnodes.h:1722
AttrNumber resno
Definition: primnodes.h:1724
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition: tlist.c:367

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

◆ match_foreign_keys_to_quals()

void match_foreign_keys_to_quals ( PlannerInfo root)

Definition at line 2867 of file initsplan.c.

2868 {
2869  List *newlist = NIL;
2870  ListCell *lc;
2871 
2872  foreach(lc, root->fkey_list)
2873  {
2874  ForeignKeyOptInfo *fkinfo = (ForeignKeyOptInfo *) lfirst(lc);
2875  RelOptInfo *con_rel;
2876  RelOptInfo *ref_rel;
2877  int colno;
2878 
2879  /*
2880  * Either relid might identify a rel that is in the query's rtable but
2881  * isn't referenced by the jointree so won't have a RelOptInfo. Hence
2882  * don't use find_base_rel() here. We can ignore such FKs.
2883  */
2884  if (fkinfo->con_relid >= root->simple_rel_array_size ||
2885  fkinfo->ref_relid >= root->simple_rel_array_size)
2886  continue; /* just paranoia */
2887  con_rel = root->simple_rel_array[fkinfo->con_relid];
2888  if (con_rel == NULL)
2889  continue;
2890  ref_rel = root->simple_rel_array[fkinfo->ref_relid];
2891  if (ref_rel == NULL)
2892  continue;
2893 
2894  /*
2895  * Ignore FK unless both rels are baserels. This gets rid of FKs that
2896  * link to inheritance child rels (otherrels) and those that link to
2897  * rels removed by join removal (dead rels).
2898  */
2899  if (con_rel->reloptkind != RELOPT_BASEREL ||
2900  ref_rel->reloptkind != RELOPT_BASEREL)
2901  continue;
2902 
2903  /*
2904  * Scan the columns and try to match them to eclasses and quals.
2905  *
2906  * Note: for simple inner joins, any match should be in an eclass.
2907  * "Loose" quals that syntactically match an FK equality must have
2908  * been rejected for EC status because they are outer-join quals or
2909  * similar. We can still consider them to match the FK.
2910  */
2911  for (colno = 0; colno < fkinfo->nkeys; colno++)
2912  {
2913  EquivalenceClass *ec;
2914  AttrNumber con_attno,
2915  ref_attno;
2916  Oid fpeqop;
2917  ListCell *lc2;
2918 
2919  ec = match_eclasses_to_foreign_key_col(root, fkinfo, colno);
2920  /* Don't bother looking for loose quals if we got an EC match */
2921  if (ec != NULL)
2922  {
2923  fkinfo->nmatched_ec++;
2924  if (ec->ec_has_const)
2925  fkinfo->nconst_ec++;
2926  continue;
2927  }
2928 
2929  /*
2930  * Scan joininfo list for relevant clauses. Either rel's joininfo
2931  * list would do equally well; we use con_rel's.
2932  */
2933  con_attno = fkinfo->conkey[colno];
2934  ref_attno = fkinfo->confkey[colno];
2935  fpeqop = InvalidOid; /* we'll look this up only if needed */
2936 
2937  foreach(lc2, con_rel->joininfo)
2938  {
2939  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc2);
2940  OpExpr *clause = (OpExpr *) rinfo->clause;
2941  Var *leftvar;
2942  Var *rightvar;
2943 
2944  /* Only binary OpExprs are useful for consideration */
2945  if (!IsA(clause, OpExpr) ||
2946  list_length(clause->args) != 2)
2947  continue;
2948  leftvar = (Var *) get_leftop((Expr *) clause);
2949  rightvar = (Var *) get_rightop((Expr *) clause);
2950 
2951  /* Operands must be Vars, possibly with RelabelType */
2952  while (leftvar && IsA(leftvar, RelabelType))
2953  leftvar = (Var *) ((RelabelType *) leftvar)->arg;
2954  if (!(leftvar && IsA(leftvar, Var)))
2955  continue;
2956  while (rightvar && IsA(rightvar, RelabelType))
2957  rightvar = (Var *) ((RelabelType *) rightvar)->arg;
2958  if (!(rightvar && IsA(rightvar, Var)))
2959  continue;
2960 
2961  /* Now try to match the vars to the current foreign key cols */
2962  if (fkinfo->ref_relid == leftvar->varno &&
2963  ref_attno == leftvar->varattno &&
2964  fkinfo->con_relid == rightvar->varno &&
2965  con_attno == rightvar->varattno)
2966  {
2967  /* Vars match, but is it the right operator? */
2968  if (clause->opno == fkinfo->conpfeqop[colno])
2969  {
2970  fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
2971  rinfo);
2972  fkinfo->nmatched_ri++;
2973  }
2974  }
2975  else if (fkinfo->ref_relid == rightvar->varno &&
2976  ref_attno == rightvar->varattno &&
2977  fkinfo->con_relid == leftvar->varno &&
2978  con_attno == leftvar->varattno)
2979  {
2980  /*
2981  * Reverse match, must check commutator operator. Look it
2982  * up if we didn't already. (In the worst case we might
2983  * do multiple lookups here, but that would require an FK
2984  * equality operator without commutator, which is
2985  * unlikely.)
2986  */
2987  if (!OidIsValid(fpeqop))
2988  fpeqop = get_commutator(fkinfo->conpfeqop[colno]);
2989  if (clause->opno == fpeqop)
2990  {
2991  fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
2992  rinfo);
2993  fkinfo->nmatched_ri++;
2994  }
2995  }
2996  }
2997  /* If we found any matching loose quals, count col as matched */
2998  if (fkinfo->rinfos[colno])
2999  fkinfo->nmatched_rcols++;
3000  }
3001 
3002  /*
3003  * Currently, we drop multicolumn FKs that aren't fully matched to the
3004  * query. Later we might figure out how to derive some sort of
3005  * estimate from them, in which case this test should be weakened to
3006  * "if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) > 0)".
3007  */
3008  if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) == fkinfo->nkeys)
3009  newlist = lappend(newlist, fkinfo);
3010  }
3011  /* Replace fkey_list, thereby discarding any useless entries */
3012  root->fkey_list = newlist;
3013 }
EquivalenceClass * match_eclasses_to_foreign_key_col(PlannerInfo *root, ForeignKeyOptInfo *fkinfo, int colno)
Definition: equivclass.c:2452
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
Oid get_commutator(Oid opno)
Definition: lsyscache.c:1491
static Node * get_rightop(const void *clause)
Definition: nodeFuncs.h:93
static Node * get_leftop(const void *clause)
Definition: nodeFuncs.h:81
List * rinfos[INDEX_MAX_KEYS]
Definition: pathnodes.h:1249
Oid opno
Definition: primnodes.h:742
List * args
Definition: primnodes.h:760
List * fkey_list
Definition: pathnodes.h:382
List * joininfo
Definition: pathnodes.h:980
Expr * clause
Definition: pathnodes.h:2517

References OpExpr::args, RestrictInfo::clause, ForeignKeyOptInfo::con_relid, EquivalenceClass::ec_has_const, PlannerInfo::fkey_list, get_commutator(), get_leftop(), get_rightop(), if(), 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, ForeignKeyOptInfo::ref_relid, RELOPT_BASEREL, RelOptInfo::reloptkind, ForeignKeyOptInfo::rinfos, and PlannerInfo::simple_rel_array_size.

Referenced by query_planner().

◆ materialize_finished_plan()

Plan* materialize_finished_plan ( Plan subplan)

Definition at line 6495 of file createplan.c.

6496 {
6497  Plan *matplan;
6498  Path matpath; /* dummy for result of cost_material */
6499 
6500  matplan = (Plan *) make_material(subplan);
6501 
6502  /*
6503  * XXX horrid kluge: if there are any initPlans attached to the subplan,
6504  * move them up to the Material node, which is now effectively the top
6505  * plan node in its query level. This prevents failure in
6506  * SS_finalize_plan(), which see for comments. We don't bother adjusting
6507  * the subplan's cost estimate for this.
6508  */
6509  matplan->initPlan = subplan->initPlan;
6510  subplan->initPlan = NIL;
6511 
6512  /* Set cost data */
6513  cost_material(&matpath,
6514  subplan->startup_cost,
6515  subplan->total_cost,
6516  subplan->plan_rows,
6517  subplan->plan_width);
6518  matplan->startup_cost = matpath.startup_cost;
6519  matplan->total_cost = matpath.total_cost;
6520  matplan->plan_rows = subplan->plan_rows;
6521  matplan->plan_width = subplan->plan_width;
6522  matplan->parallel_aware = false;
6523  matplan->parallel_safe = subplan->parallel_safe;
6524 
6525  return matplan;
6526 }
void cost_material(Path *path, Cost input_startup_cost, Cost input_total_cost, double tuples, int width)
Definition: costsize.c:2424
static Material * make_material(Plan *lefttree)
Definition: createplan.c:6473
Cost startup_cost
Definition: pathnodes.h:1639
Cost total_cost
Definition: pathnodes.h:1640
Cost total_cost
Definition: plannodes.h:133
bool parallel_aware
Definition: plannodes.h:144
Cost startup_cost
Definition: plannodes.h:132
int plan_width
Definition: plannodes.h:139
Cardinality plan_rows
Definition: plannodes.h:138
List * initPlan
Definition: plannodes.h:160

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

Referenced by build_subplan(), and standard_planner().

◆ preprocess_minmax_aggregates()

void preprocess_minmax_aggregates ( PlannerInfo root)

Definition at line 73 of file planagg.c.

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  * Examine all the aggregates and verify all are MIN/MAX aggregates. Stop
141  * 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 }
Oid get_equality_op_for_ordering_op(Oid opno, bool *reverse)
Definition: lsyscache.c:266
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
MinMaxAggPath * create_minmaxagg_path(PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *mmaggregates, List *quals)
Definition: pathnode.c:3338
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:422
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:561
@ UPPERREL_GROUP_AGG
Definition: pathnodes.h:74
#define linitial(l)
Definition: pg_list.h:178
static bool can_minmax_aggs(PlannerInfo *root, List **context)
Definition: planagg.c:237
static bool build_minmax_path(PlannerInfo *root, MinMaxAggInfo *mminfo, Oid eqop, Oid sortop, bool nulls_first)
Definition: planagg.c:317
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:717
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1395
Param * param
Definition: pathnodes.h:3067
Expr * target
Definition: pathnodes.h:3052
List * minmax_aggs
Definition: pathnodes.h:472
Param * SS_make_initplan_output_param(PlannerInfo *root, Oid resulttype, int32 resulttypmod, Oid resultcollation)
Definition: subselect.c:2936
#define create_pathtarget(root, tlist)
Definition: tlist.h:53

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

Referenced by grouping_planner().

◆ process_implied_equality()

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

Definition at line 2674 of file initsplan.c.

2682 {
2683  RestrictInfo *restrictinfo;
2684  Node *clause;
2685  Relids relids;
2686  bool pseudoconstant = false;
2687 
2688  /*
2689  * Build the new clause. Copy to ensure it shares no substructure with
2690  * original (this is necessary in case there are subselects in there...)
2691  */
2692  clause = (Node *) make_opclause(opno,
2693  BOOLOID, /* opresulttype */
2694  false, /* opretset */
2695  copyObject(item1),
2696  copyObject(item2),
2697  InvalidOid,
2698  collation);
2699 
2700  /* If both constant, try to reduce to a boolean constant. */
2701  if (both_const)
2702  {
2703  clause = eval_const_expressions(root, clause);
2704 
2705  /* If we produced const TRUE, just drop the clause */
2706  if (clause && IsA(clause, Const))
2707  {
2708  Const *cclause = (Const *) clause;
2709 
2710  Assert(cclause->consttype == BOOLOID);
2711  if (!cclause->constisnull && DatumGetBool(cclause->constvalue))
2712  return NULL;
2713  }
2714  }
2715 
2716  /*
2717  * The rest of this is a very cut-down version of distribute_qual_to_rels.
2718  * We can skip most of the work therein, but there are a couple of special
2719  * cases we still have to handle.
2720  *
2721  * Retrieve all relids mentioned within the possibly-simplified clause.
2722  */
2723  relids = pull_varnos(root, clause);
2724  Assert(bms_is_subset(relids, qualscope));
2725 
2726  /*
2727  * If the clause is variable-free, our normal heuristic for pushing it
2728  * down to just the mentioned rels doesn't work, because there are none.
2729  * Apply it as a gating qual at the given qualscope.
2730  */
2731  if (bms_is_empty(relids))
2732  {
2733  /* eval at join domain level */
2734  relids = bms_copy(qualscope);
2735  /* mark as gating qual */
2736  pseudoconstant = true;
2737  /* tell createplan.c to check for gating quals */
2738  root->hasPseudoConstantQuals = true;
2739  }
2740 
2741  /*
2742  * Build the RestrictInfo node itself.
2743  */
2744  restrictinfo = make_restrictinfo(root,
2745  (Expr *) clause,
2746  true, /* is_pushed_down */
2747  pseudoconstant,
2748  security_level,
2749  relids,
2750  NULL); /* outer_relids */
2751 
2752  /*
2753  * If it's a join clause, add vars used in the clause to targetlists of
2754  * their relations, so that they will be emitted by the plan nodes that
2755  * scan those relations (else they won't be available at the join node!).
2756  *
2757  * Typically, we'd have already done this when the component expressions
2758  * were first seen by distribute_qual_to_rels; but it is possible that
2759  * some of the Vars could have missed having that done because they only
2760  * appeared in single-relation clauses originally. So do it here for
2761  * safety.
2762  */
2763  if (bms_membership(relids) == BMS_MULTIPLE)
2764  {
2765  List *vars = pull_var_clause(clause,
2769 
2770  add_vars_to_targetlist(root, vars, relids);
2771  list_free(vars);
2772  }
2773 
2774  /*
2775  * Check mergejoinability. This will usually succeed, since the op came
2776  * from an EquivalenceClass; but we could have reduced the original clause
2777  * to a constant.
2778  */
2779  check_mergejoinable(restrictinfo);
2780 
2781  /*
2782  * Note we don't do initialize_mergeclause_eclasses(); the caller can
2783  * handle that much more cheaply than we can. It's okay to call
2784  * distribute_restrictinfo_to_rels() before that happens.
2785  */
2786 
2787  /*
2788  * Push the new clause into all the appropriate restrictinfo lists.
2789  */
2790  distribute_restrictinfo_to_rels(root, restrictinfo);
2791 
2792  return restrictinfo;
2793 }
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2134
void distribute_restrictinfo_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2583
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
Oid consttype
Definition: primnodes.h:287
bool hasPseudoConstantQuals
Definition: pathnodes.h:498
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:108

References add_vars_to_targetlist(), Assert(), bms_copy(), bms_is_empty(), bms_is_subset(), bms_membership(), BMS_MULTIPLE, check_mergejoinable(), Const::consttype, copyObject, DatumGetBool(), distribute_restrictinfo_to_rels(), eval_const_expressions(), PlannerInfo::hasPseudoConstantQuals, InvalidOid, IsA, list_free(), make_opclause(), make_restrictinfo(), pull_var_clause(), pull_varnos(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, and PVC_RECURSE_WINDOWFUNCS.

Referenced by generate_base_implied_equalities_const(), and generate_base_implied_equalities_no_const().

◆ query_is_distinct_for()

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

Definition at line 821 of file analyzejoins.c.

822 {
823  ListCell *l;
824  Oid opid;
825 
826  Assert(list_length(colnos) == list_length(opids));
827 
828  /*
829  * DISTINCT (including DISTINCT ON) guarantees uniqueness if all the
830  * columns in the DISTINCT clause appear in colnos and operator semantics
831  * match. This is true even if there are SRFs in the DISTINCT columns or
832  * elsewhere in the tlist.
833  */
834  if (query->distinctClause)
835  {
836  foreach(l, query->distinctClause)
837  {
838  SortGroupClause *sgc = (SortGroupClause *) lfirst(l);
840  query->targetList);
841 
842  opid = distinct_col_search(tle->resno, colnos, opids);
843  if (!OidIsValid(opid) ||
844  !equality_ops_are_compatible(opid, sgc->eqop))
845  break; /* exit early if no match */
846  }
847  if (l == NULL) /* had matches for all? */
848  return true;
849  }
850 
851  /*
852  * Otherwise, a set-returning function in the query's targetlist can
853  * result in returning duplicate rows, despite any grouping that might
854  * occur before tlist evaluation. (If all tlist SRFs are within GROUP BY
855  * columns, it would be safe because they'd be expanded before grouping.
856  * But it doesn't currently seem worth the effort to check for that.)
857  */
858  if (query->hasTargetSRFs)
859  return false;
860 
861  /*
862  * Similarly, GROUP BY without GROUPING SETS guarantees uniqueness if all
863  * the grouped columns appear in colnos and operator semantics match.
864  */
865  if (query->groupClause && !query->groupingSets)
866  {
867  foreach(l, query->groupClause)
868  {
869  SortGroupClause *sgc = (SortGroupClause *) lfirst(l);
871  query->targetList);
872 
873  opid = distinct_col_search(tle->resno, colnos, opids);
874  if (!OidIsValid(opid) ||
875  !equality_ops_are_compatible(opid, sgc->eqop))
876  break; /* exit early if no match */
877  }
878  if (l == NULL) /* had matches for all? */
879  return true;
880  }
881  else if (query->groupingSets)
882  {
883  /*
884  * If we have grouping sets with expressions, we probably don't have
885  * uniqueness and analysis would be hard. Punt.
886  */
887  if (query->groupClause)
888  return false;
889 
890  /*
891  * If we have no groupClause (therefore no grouping expressions), we
892  * might have one or many empty grouping sets. If there's just one,
893  * then we're returning only one row and are certainly unique. But
894  * otherwise, we know we're certainly not unique.
895  */
896  if (list_length(query->groupingSets) == 1 &&
897  ((GroupingSet *) linitial(query->groupingSets))->kind == GROUPING_SET_EMPTY)
898  return true;
899  else
900  return false;
901  }
902  else
903  {
904  /*
905  * If we have no GROUP BY, but do have aggregates or HAVING, then the
906  * result is at most one row so it's surely unique, for any operators.
907  */
908  if (query->hasAggs || query->havingQual)
909  return true;
910  }
911 
912  /*
913  * UNION, INTERSECT, EXCEPT guarantee uniqueness of the whole output row,
914  * except with ALL.
915  */
916  if (query->setOperations)
917  {
919 
920  Assert(topop->op != SETOP_NONE);
921 
922  if (!topop->all)
923  {
924  ListCell *lg;
925 
926  /* We're good if all the nonjunk output columns are in colnos */
927  lg = list_head(topop->groupClauses);
928  foreach(l, query->targetList)
929  {
930  TargetEntry *tle = (TargetEntry *) lfirst(l);
931  SortGroupClause *sgc;
932 
933  if (tle->resjunk)
934  continue; /* ignore resjunk columns */
935 
936  /* non-resjunk columns should have grouping clauses */
937  Assert(lg != NULL);
938  sgc = (SortGroupClause *) lfirst(lg);
939  lg = lnext(topop->groupClauses, lg);
940 
941  opid = distinct_col_search(tle->resno, colnos, opids);
942  if (!OidIsValid(opid) ||
943  !equality_ops_are_compatible(opid, sgc->eqop))
944  break; /* exit early if no match */
945  }
946  if (l == NULL) /* had matches for all? */
947  return true;
948  }
949  }
950 
951  /*
952  * XXX Are there any other cases in which we can easily see the result
953  * must be distinct?
954  *
955  * If you do add more smarts to this function, be sure to update
956  * query_supports_distinctness() to match.
957  */
958 
959  return false;
960 }
static Oid distinct_col_search(int colno, List *colnos, List *opids)
Definition: analyzejoins.c:970
bool equality_ops_are_compatible(Oid opno1, Oid opno2)
Definition: lsyscache.c:697
@ GROUPING_SET_EMPTY
Definition: parsenodes.h:1452
@ SETOP_NONE
Definition: parsenodes.h:1821
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
Node * setOperations
Definition: parsenodes.h:217
List * groupClause
Definition: parsenodes.h:198
List * targetList
Definition: parsenodes.h:189
List * groupingSets
Definition: parsenodes.h:201
List * distinctClause
Definition: parsenodes.h:207
SetOperation op
Definition: parsenodes.h:1899

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

Referenced by create_unique_path(), and rel_is_distinct_for().

◆ query_planner()

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

Definition at line 55 of file planmain.c.

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

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, PlannerInfo::full_join_clauses, generate_base_implied_equalities(), PlannerInfo::glob, is_parallel_safe(), IsA, PlannerInfo::join_cur_level, PlannerInfo::join_info_list, PlannerInfo::join_rel_list, PlannerInfo::left_join_clauses, linitial, list_length(), make_one_rel(), match_foreign_keys_to_quals(), NIL, PlannerGlobal::parallelModeOK, parse(), PlannerInfo::parse, PlannerInfo::placeholder_list, PlannerInfo::processed_tlist, reconsider_outer_join_clauses(), reduce_unique_semijoins(), RelOptInfo::reltarget, remove_useless_joins(), PlannerInfo::right_join_clauses, RTE_RESULT, RangeTblEntry::rtekind, set_cheapest(), and setup_simple_rel_arrays().

Referenced by build_minmax_path(), and grouping_planner().

◆ query_supports_distinctness()

bool query_supports_distinctness ( Query query)

Definition at line 784 of file analyzejoins.c.

785 {
786  /* SRFs break distinctness except with DISTINCT, see below */
787  if (query->hasTargetSRFs && query->distinctClause == NIL)
788  return false;
789 
790  /* check for features we can prove distinctness with */
791  if (query->distinctClause != NIL ||
792  query->groupClause != NIL ||
793  query->groupingSets != NIL ||
794  query->hasAggs ||
795  query->havingQual ||
796  query->setOperations)
797  return true;
798 
799  return false;
800 }

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

Referenced by create_unique_path(), and rel_supports_distinctness().

◆ record_plan_function_dependency()

void record_plan_function_dependency ( PlannerInfo root,
Oid  funcid 
)

Definition at line 3396 of file setrefs.c.

3397 {
3398  /*
3399  * For performance reasons, we don't bother to track built-in functions;
3400  * we just assume they'll never change (or at least not in ways that'd
3401  * invalidate plans using them). For this purpose we can consider a
3402  * built-in function to be one with OID less than FirstUnpinnedObjectId.
3403  * Note that the OID generator guarantees never to generate such an OID
3404  * after startup, even at OID wraparound.
3405  */
3406  if (funcid >= (Oid) FirstUnpinnedObjectId)
3407  {
3408  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3409 
3410  /*
3411  * It would work to use any syscache on pg_proc, but the easiest is
3412  * PROCOID since we already have the function's OID at hand. Note
3413  * that plancache.c knows we use PROCOID.
3414  */
3415  inval_item->cacheId = PROCOID;
3416  inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
3417  ObjectIdGetDatum(funcid));
3418 
3419  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3420  }
3421 }
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
uint32 hashValue
Definition: plannodes.h:1577
List * invalItems
Definition: pathnodes.h:135
@ PROCOID
Definition: syscache.h:79
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:206
#define FirstUnpinnedObjectId
Definition: transam.h:196

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

◆ record_plan_type_dependency()

void record_plan_type_dependency ( PlannerInfo root,
Oid  typid 
)

Definition at line 3436 of file setrefs.c.

3437 {
3438  /*
3439  * As in record_plan_function_dependency, ignore the possibility that
3440  * someone would change a built-in domain.
3441  */
3442  if (typid >= (Oid) FirstUnpinnedObjectId)
3443  {
3444  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3445 
3446  /*
3447  * It would work to use any syscache on pg_type, but the easiest is
3448  * TYPEOID since we already have the type's OID at hand. Note that
3449  * plancache.c knows we use TYPEOID.
3450  */
3451  inval_item->cacheId = TYPEOID;
3452  inval_item->hashValue = GetSysCacheHashValue1(TYPEOID,
3453  ObjectIdGetDatum(typid));
3454 
3455  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3456  }
3457 }
@ TYPEOID
Definition: syscache.h:114

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

Referenced by eval_const_expressions_mutator().

◆ reduce_unique_semijoins()

void reduce_unique_semijoins ( PlannerInfo root)

Definition at line 556 of file analyzejoins.c.

557 {
558  ListCell *lc;
559 
560  /*
561  * Scan the join_info_list to find semijoins.
562  */
563  foreach(lc, root->join_info_list)
564  {
565  SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
566  int innerrelid;
567  RelOptInfo *innerrel;
568  Relids joinrelids;
569  List *restrictlist;
570 
571  /*
572  * Must be a semijoin to a single baserel, else we aren't going to be
573  * able to do anything with it.
574  */
575  if (sjinfo->jointype != JOIN_SEMI)
576  continue;
577 
578  if (!bms_get_singleton_member(sjinfo->min_righthand, &innerrelid))
579  continue;
580 
581  innerrel = find_base_rel(root, innerrelid);
582 
583  /*
584  * Before we trouble to run generate_join_implied_equalities, make a
585  * quick check to eliminate cases in which we will surely be unable to
586  * prove uniqueness of the innerrel.
587  */
588  if (!rel_supports_distinctness(root, innerrel))
589  continue;
590 
591  /* Compute the relid set for the join we are considering */
592  joinrelids = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
593  Assert(sjinfo->ojrelid == 0); /* SEMI joins don't have RT indexes */
594 
595  /*
596  * Since we're only considering a single-rel RHS, any join clauses it
597  * has must be clauses linking it to the semijoin's min_lefthand. We
598  * can also consider EC-derived join clauses.
599  */
600  restrictlist =
602  joinrelids,
603  sjinfo->min_lefthand,
604  innerrel),
605  innerrel->joininfo);
606 
607  /* Test whether the innerrel is unique for those clauses. */
608  if (!innerrel_is_unique(root,
609  joinrelids, sjinfo->min_lefthand, innerrel,
610  JOIN_SEMI, restrictlist, true))
611  continue;
612 
613  /* OK, remove the SpecialJoinInfo from the list. */
615  }
616 }
bool innerrel_is_unique(PlannerInfo *root, Relids joinrelids, Relids outerrelids, RelOptInfo *innerrel, JoinType jointype, List *restrictlist, bool force_cache)
List * generate_join_implied_equalities(PlannerInfo *root, Relids join_relids, Relids outer_relids, RelOptInfo *inner_rel)
Definition: equivclass.c:1375
List * list_concat(List *list1, const List *list2)
Definition: list.c:560
@ JOIN_SEMI
Definition: nodes.h:318
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:390
Relids min_righthand
Definition: pathnodes.h:2832
JoinType jointype
Definition: pathnodes.h:2835
Relids min_lefthand
Definition: pathnodes.h:2831

References Assert(), bms_get_singleton_member(), bms_union(), 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, SpecialJoinInfo::ojrelid, and rel_supports_distinctness().

Referenced by query_planner().

◆ remove_useless_joins()

List* remove_useless_joins ( PlannerInfo root,
List joinlist 
)

Definition at line 61 of file analyzejoins.c.

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  Relids joinrelids;
74  int innerrelid;
75  int nremoved;
76 
77  /* Skip if not removable */
78  if (!join_is_removable(root, sjinfo))
79  continue;
80 
81  /*
82  * Currently, join_is_removable can only succeed when the sjinfo's
83  * righthand is a single baserel. Remove that rel from the query and
84  * joinlist.
85  */
86  innerrelid = bms_singleton_member(sjinfo->min_righthand);
87 
88  /* Compute the relid set for the join we are considering */
89  joinrelids = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
90  if (sjinfo->ojrelid != 0)
91  joinrelids = bms_add_member(joinrelids, sjinfo->ojrelid);
92 
93  remove_rel_from_query(root, innerrelid, sjinfo->ojrelid, joinrelids);
94 
95  /* We verify that exactly one reference gets removed from joinlist */
96  nremoved = 0;
97  joinlist = remove_rel_from_joinlist(joinlist, innerrelid, &nremoved);
98  if (nremoved != 1)
99  elog(ERROR, "failed to find relation %d in joinlist", innerrelid);
100 
101  /*
102  * We can delete this SpecialJoinInfo from the list too, since it's no
103  * longer of interest. (Since we'll restart the foreach loop
104  * immediately, we don't bother with foreach_delete_current.)
105  */
107 
108  /*
109  * Restart the scan. This is necessary to ensure we find all
110  * removable joins independently of ordering of the join_info_list
111  * (note that removal of attr_needed bits may make a join appear
112  * removable that did not before).
113  */
114  goto restart;
115  }
116 
117  return joinlist;
118 }
static void remove_rel_from_query(PlannerInfo *root, int relid, int ojrelid, Relids joinrelids)
Definition: analyzejoins.c:329
static List * remove_rel_from_joinlist(List *joinlist, int relid, int *nremoved)
Definition: analyzejoins.c:502
static bool join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo)
Definition: analyzejoins.c:163
List * list_delete_cell(List *list, ListCell *cell)
Definition: list.c:840

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

Referenced by query_planner().

◆ set_plan_references()

Plan* set_plan_references ( PlannerInfo root,
Plan plan 
)

Definition at line 289 of file setrefs.c.

290 {
291  Plan *result;
292  PlannerGlobal *glob = root->glob;
293  int rtoffset = list_length(glob->finalrtable);
294  ListCell *lc;
295 
296  /*
297  * Add all the query's RTEs to the flattened rangetable. The live ones
298  * will have their rangetable indexes increased by rtoffset. (Additional
299  * RTEs, not referenced by the Plan tree, might get added after those.)
300  */
301  add_rtes_to_flat_rtable(root, false);
302 
303  /*
304  * Adjust RT indexes of PlanRowMarks and add to final rowmarks list
305  */
306  foreach(lc, root->rowMarks)
307  {
309  PlanRowMark *newrc;
310 
311  /* flat copy is enough since all fields are scalars */
312  newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark));
313  memcpy(newrc, rc, sizeof(PlanRowMark));
314 
315  /* adjust indexes ... but *not* the rowmarkId */
316  newrc->rti += rtoffset;
317  newrc->prti += rtoffset;
318 
319  glob->finalrowmarks = lappend(glob->finalrowmarks, newrc);
320  }
321 
322  /*
323  * Adjust RT indexes of AppendRelInfos and add to final appendrels list.
324  * We assume the AppendRelInfos were built during planning and don't need
325  * to be copied.
326  */
327  foreach(lc, root->append_rel_list)
328  {
329  AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
330 
331  /* adjust RT indexes */
332  appinfo->parent_relid += rtoffset;
333  appinfo->child_relid += rtoffset;
334 
335  /*
336  * Rather than adjust the translated_vars entries, just drop 'em.
337  * Neither the executor nor EXPLAIN currently need that data.
338  */
339  appinfo->translated_vars = NIL;
340 
341  glob->appendRelations = lappend(glob->appendRelations, appinfo);
342  }
343 
344  /* If needed, create workspace for processing AlternativeSubPlans */
345  if (root->hasAlternativeSubPlans)
346  {
347  root->isAltSubplan = (bool *)
348  palloc0(list_length(glob->subplans) * sizeof(bool));
349  root->isUsedSubplan = (bool *)
350  palloc0(list_length(glob->subplans) * sizeof(bool));
351  }
352 
353  /* Now fix the Plan tree */
354  result = set_plan_refs(root, plan, rtoffset);
355 
356  /*
357  * If we have AlternativeSubPlans, it is likely that we now have some
358  * unreferenced subplans in glob->subplans. To avoid expending cycles on
359  * those subplans later, get rid of them by setting those list entries to
360  * NULL. (Note: we can't do this immediately upon processing an
361  * AlternativeSubPlan, because there may be multiple copies of the
362  * AlternativeSubPlan, and they can get resolved differently.)
363  */
364  if (root->hasAlternativeSubPlans)
365  {
366  foreach(lc, glob->subplans)
367  {
368  int ndx = foreach_current_index(lc);
369 
370  /*
371  * If it was used by some AlternativeSubPlan in this query level,
372  * but wasn't selected as best by any AlternativeSubPlan, then we
373  * don't need it. Do not touch subplans that aren't parts of
374  * AlternativeSubPlans.
375  */
376  if (root->isAltSubplan[ndx] && !root->isUsedSubplan[ndx])
377  lfirst(lc) = NULL;
378  }
379  }
380 
381  /* Also fix up the information in PartitionPruneInfos. */
382  foreach(lc, root->partPruneInfos)
383  {
384  PartitionPruneInfo *pruneinfo = lfirst(lc);
385  ListCell *l;
386 
387  pruneinfo->root_parent_relids =
388  offset_relid_set(pruneinfo->root_parent_relids, rtoffset);
389  foreach(l, pruneinfo->prune_infos)
390  {
391  List *prune_infos = lfirst(l);
392  ListCell *l2;
393 
394  foreach(l2, prune_infos)
395  {
396  PartitionedRelPruneInfo *pinfo = lfirst(l2);
397 
398  /* RT index of the table to which the pinfo belongs. */
399  pinfo->rtindex += rtoffset;
400  }
401  }
402 
403  glob->partPruneInfos = lappend(glob->partPruneInfos, pruneinfo);
404  }
405 
406  return result;
407 }
unsigned char bool
Definition: c.h:440
void * palloc0(Size size)
Definition: mcxt.c:1241
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define foreach_current_index(cell)
Definition: pg_list.h:403
static void add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
Definition: setrefs.c:418
static Relids offset_relid_set(Relids relids, int rtoffset)
Definition: setrefs.c:1887
static Plan * set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:630
Index child_relid
Definition: pathnodes.h:2904
List * translated_vars
Definition: pathnodes.h:2931
Index parent_relid
Definition: pathnodes.h:2903
Bitmapset * root_parent_relids
Definition: plannodes.h:1431
Index prti
Definition: plannodes.h:1384
List * subplans
Definition: pathnodes.h:105
List * appendRelations
Definition: pathnodes.h:126
List * finalrowmarks
Definition: pathnodes.h:120
List * partPruneInfos
Definition: pathnodes.h:129
List * finalrtable
Definition: pathnodes.h:114
List * append_rel_list
Definition: pathnodes.h:365
bool hasAlternativeSubPlans
Definition: pathnodes.h:500
List * partPruneInfos
Definition: pathnodes.h:552
List * rowMarks
Definition: pathnodes.h:371

References add_rtes_to_flat_rtable(), PlannerInfo::append_rel_list, PlannerGlobal::appendRelations, AppendRelInfo::child_relid, PlannerGlobal::finalrowmarks, PlannerGlobal::finalrtable, foreach_current_index, PlannerInfo::glob, PlannerInfo::hasAlternativeSubPlans, lappend(), lfirst, lfirst_node, list_length(), NIL, offset_relid_set(), palloc(), palloc0(), AppendRelInfo::parent_relid, PlannerGlobal::partPruneInfos, PlannerInfo::partPruneInfos, PlanRowMark::prti, PartitionPruneInfo::prune_infos, PartitionPruneInfo::root_parent_relids, PlannerInfo::rowMarks, PlanRowMark::rti, PartitionedRelPruneInfo::rtindex, set_plan_refs(), PlannerGlobal::subplans, and AppendRelInfo::translated_vars.

Referenced by set_subqueryscan_references(), and standard_planner().

◆ trivial_subqueryscan()

bool trivial_subqueryscan ( SubqueryScan plan)

Definition at line 1470 of file setrefs.c.

1471 {
1472  int attrno;
1473  ListCell *lp,
1474  *lc;
1475 
1476  /* We might have detected this already; in which case reuse the result */
1477  if (plan->scanstatus == SUBQUERY_SCAN_TRIVIAL)
1478  return true;
1479  if (plan->scanstatus == SUBQUERY_SCAN_NONTRIVIAL)
1480  return false;
1482  /* Initially, mark the SubqueryScan as non-deletable from the plan tree */
1484 
1485  if (plan->scan.plan.qual != NIL)
1486  return false;
1487 
1488  if (list_length(plan->scan.plan.targetlist) !=
1489  list_length(plan->subplan->targetlist))
1490  return false; /* tlists not same length */
1491 
1492  attrno = 1;
1493  forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
1494  {
1495  TargetEntry *ptle = (TargetEntry *) lfirst(lp);
1496  TargetEntry *ctle = (TargetEntry *) lfirst(lc);
1497 
1498  if (ptle->resjunk != ctle->resjunk)
1499  return false; /* tlist doesn't match junk status */
1500 
1501  /*
1502  * We accept either a Var referencing the corresponding element of the
1503  * subplan tlist, or a Const equaling the subplan element. See
1504  * generate_setop_tlist() for motivation.
1505  */
1506  if (ptle->expr && IsA(ptle->expr, Var))
1507  {
1508  Var *var = (Var *) ptle->expr;
1509 
1510  Assert(var->varno == plan->scan.scanrelid);
1511  Assert(var->varlevelsup == 0);
1512  if (var->varattno != attrno)
1513  return false; /* out of order */
1514  }
1515  else if (ptle->expr && IsA(ptle->expr, Const))
1516  {
1517  if (!equal(ptle->expr, ctle->expr))
1518  return false;
1519  }
1520  else
1521  return false;
1522 
1523  attrno++;
1524  }
1525 
1526  /* Re-mark the SubqueryScan as deletable from the plan tree */
1528 
1529  return true;
1530 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:225
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:467
@ SUBQUERY_SCAN_NONTRIVIAL
Definition: plannodes.h:596
@ SUBQUERY_SCAN_UNKNOWN
Definition: plannodes.h:594
@ SUBQUERY_SCAN_TRIVIAL
Definition: plannodes.h:595
SubqueryScanStatus scanstatus
Definition: plannodes.h:603
Plan * subplan
Definition: plannodes.h:602
Index varlevelsup
Definition: primnodes.h:255

References Assert(), equal(), TargetEntry::expr, forboth, IsA, lfirst, list_length(), NIL, SubqueryScan::scan, Scan::scanrelid, SubqueryScan::scanstatus, SubqueryScan::subplan, SUBQUERY_SCAN_NONTRIVIAL, SUBQUERY_SCAN_TRIVIAL, SUBQUERY_SCAN_UNKNOWN, Plan::targetlist, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by mark_async_capable_plan(), and set_subqueryscan_references().

Variable Documentation

◆ cursor_tuple_fraction

PGDLLIMPORT double cursor_tuple_fraction
extern

Definition at line 72 of file planner.c.

Referenced by standard_planner().

◆ from_collapse_limit

PGDLLIMPORT int from_collapse_limit
extern

Definition at line 39 of file initsplan.c.

Referenced by deconstruct_recurse().

◆ join_collapse_limit

PGDLLIMPORT int join_collapse_limit
extern

Definition at line 40 of file initsplan.c.

Referenced by deconstruct_recurse().