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)
 
bool innerrel_is_unique_ext (PlannerInfo *root, Relids joinrelids, Relids outerrelids, RelOptInfo *innerrel, JoinType jointype, List *restrictlist, bool force_cache, List **uclauses)
 
Listremove_useless_self_joins (PlannerInfo *root, List *jointree)
 
Planset_plan_references (PlannerInfo *root, Plan *plan)
 
bool trivial_subqueryscan (SubqueryScan *plan)
 
Paramfind_minmax_agg_replacement_param (PlannerInfo *root, Aggref *aggref)
 
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 bool enable_self_join_removal
 
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 26 of file planmain.h.

Function Documentation

◆ add_base_rels_to_query()

void add_base_rels_to_query ( PlannerInfo root,
Node jtnode 
)

Definition at line 158 of file initsplan.c.

159 {
160  if (jtnode == NULL)
161  return;
162  if (IsA(jtnode, RangeTblRef))
163  {
164  int varno = ((RangeTblRef *) jtnode)->rtindex;
165 
166  (void) build_simple_rel(root, varno, NULL);
167  }
168  else if (IsA(jtnode, FromExpr))
169  {
170  FromExpr *f = (FromExpr *) jtnode;
171  ListCell *l;
172 
173  foreach(l, f->fromlist)
174  add_base_rels_to_query(root, lfirst(l));
175  }
176  else if (IsA(jtnode, JoinExpr))
177  {
178  JoinExpr *j = (JoinExpr *) jtnode;
179 
180  add_base_rels_to_query(root, j->larg);
181  add_base_rels_to_query(root, j->rarg);
182  }
183  else
184  elog(ERROR, "unrecognized node type: %d",
185  (int) nodeTag(jtnode));
186 }
#define ERROR
Definition: elog.h:39
void add_base_rels_to_query(PlannerInfo *root, Node *jtnode)
Definition: initsplan.c:158
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:191
List * fromlist
Definition: primnodes.h:2040

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

Referenced by query_planner().

◆ add_other_rels_to_query()

void add_other_rels_to_query ( PlannerInfo root)

Definition at line 196 of file initsplan.c.

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

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 280 of file initsplan.c.

282 {
283  ListCell *temp;
284 
285  Assert(!bms_is_empty(where_needed));
286 
287  foreach(temp, vars)
288  {
289  Node *node = (Node *) lfirst(temp);
290 
291  if (IsA(node, Var))
292  {
293  Var *var = (Var *) node;
294  RelOptInfo *rel = find_base_rel(root, var->varno);
295  int attno = var->varattno;
296 
297  if (bms_is_subset(where_needed, rel->relids))
298  continue;
299  Assert(attno >= rel->min_attr && attno <= rel->max_attr);
300  attno -= rel->min_attr;
301  if (rel->attr_needed[attno] == NULL)
302  {
303  /*
304  * Variable not yet requested, so add to rel's targetlist.
305  *
306  * The value available at the rel's scan level has not been
307  * nulled by any outer join, so drop its varnullingrels.
308  * (We'll put those back as we climb up the join tree.)
309  */
310  var = copyObject(var);
311  var->varnullingrels = NULL;
312  rel->reltarget->exprs = lappend(rel->reltarget->exprs, var);
313  /* reltarget cost and width will be computed later */
314  }
315  rel->attr_needed[attno] = bms_add_members(rel->attr_needed[attno],
316  where_needed);
317  }
318  else if (IsA(node, PlaceHolderVar))
319  {
320  PlaceHolderVar *phv = (PlaceHolderVar *) node;
321  PlaceHolderInfo *phinfo = find_placeholder_info(root, phv);
322 
323  phinfo->ph_needed = bms_add_members(phinfo->ph_needed,
324  where_needed);
325  }
326  else
327  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
328  }
329 }
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:363
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:835
#define bms_is_empty(a)
Definition: bitmapset.h:105
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:405
Definition: nodes.h:129
List * exprs
Definition: pathnodes.h:1501
Relids ph_needed
Definition: pathnodes.h:3053
Relids relids
Definition: pathnodes.h:856
struct PathTarget * reltarget
Definition: pathnodes.h:878
AttrNumber min_attr
Definition: pathnodes.h:909
Definition: primnodes.h:234
AttrNumber varattno
Definition: primnodes.h:246
int varno
Definition: primnodes.h:241
Definition: regcomp.c:281

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 235 of file initsplan.c.

236 {
237  List *tlist_vars = pull_var_clause((Node *) final_tlist,
241 
242  if (tlist_vars != NIL)
243  {
244  add_vars_to_targetlist(root, tlist_vars, bms_make_singleton(0));
245  list_free(tlist_vars);
246  }
247 
248  /*
249  * If there's a HAVING clause, we'll need the Vars it uses, too. Note
250  * that HAVING can contain Aggrefs but not WindowFuncs.
251  */
252  if (root->parse->havingQual)
253  {
254  List *having_vars = pull_var_clause(root->parse->havingQual,
257 
258  if (having_vars != NIL)
259  {
260  add_vars_to_targetlist(root, having_vars,
261  bms_make_singleton(0));
262  list_free(having_vars);
263  }
264  }
265 }
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:171
void add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed)
Definition: initsplan.c:280
void list_free(List *list)
Definition: list.c:1545
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:186
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:188
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:189
#define NIL
Definition: pg_list.h:68
Definition: pg_list.h:54
Query * parse
Definition: pathnodes.h:199
Node * havingQual
Definition: parsenodes.h:195
List * pull_var_clause(Node *node, int flags)
Definition: var.c:607

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 distribute_row_identity_vars(), and 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 2863 of file initsplan.c.

2870 {
2871  RestrictInfo *restrictinfo;
2872  Expr *clause;
2873 
2874  /*
2875  * Build the new clause. Copy to ensure it shares no substructure with
2876  * original (this is necessary in case there are subselects in there...)
2877  */
2878  clause = make_opclause(opno,
2879  BOOLOID, /* opresulttype */
2880  false, /* opretset */
2881  copyObject(item1),
2882  copyObject(item2),
2883  InvalidOid,
2884  collation);
2885 
2886  /*
2887  * Build the RestrictInfo node itself.
2888  */
2889  restrictinfo = make_restrictinfo(root,
2890  clause,
2891  true, /* is_pushed_down */
2892  false, /* !has_clone */
2893  false, /* !is_clone */
2894  false, /* pseudoconstant */
2895  security_level, /* security_level */
2896  qualscope, /* required_relids */
2897  NULL, /* incompatible_relids */
2898  NULL); /* outer_relids */
2899 
2900  /* Set mergejoinability/hashjoinability flags */
2901  check_mergejoinable(restrictinfo);
2902  check_hashjoinable(restrictinfo);
2903  check_memoizable(restrictinfo);
2904 
2905  return restrictinfo;
2906 }
static void check_hashjoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3174
static void check_mergejoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3137
static void check_memoizable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3202
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: makefuncs.c:613
#define InvalidOid
Definition: postgres_ext.h:36
RestrictInfo * make_restrictinfo(PlannerInfo *root, Expr *clause, bool is_pushed_down, bool has_clone, bool is_clone, bool pseudoconstant, Index security_level, Relids required_relids, Relids incompatible_relids, Relids outer_relids)
Definition: restrictinfo.c:63

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

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

2151 {
2152  /*
2153  * If the top plan node can't do projections and its existing target list
2154  * isn't already what we need, we need to add a Result node to help it
2155  * along.
2156  */
2157  if (!is_projection_capable_plan(subplan) &&
2158  !tlist_same_exprs(tlist, subplan->targetlist))
2159  subplan = inject_projection_plan(subplan, tlist,
2160  subplan->parallel_safe &&
2161  tlist_parallel_safe);
2162  else
2163  {
2164  /* Else we can just replace the plan node's tlist */
2165  subplan->targetlist = tlist;
2166  subplan->parallel_safe &= tlist_parallel_safe;
2167  }
2168  return subplan;
2169 }
bool is_projection_capable_plan(Plan *plan)
Definition: createplan.c:7227
static Plan * inject_projection_plan(Plan *subplan, List *tlist, bool parallel_safe)
Definition: createplan.c:2118
bool parallel_safe
Definition: plannodes.h:141
List * targetlist
Definition: plannodes.h:152
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 502 of file initsplan.c.

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

References PlannerInfo::all_baserels, Assert(), bms_add_member(), bms_add_members(), bms_copy(), bms_get_singleton_member(), bms_intersect(), 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, PlannerInfo::placeholdersFrozen, 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))
357  apply_tlist_labeling(plan->targetlist, root->processed_tlist);
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
#define plan(x)
Definition: pg_regress.c:162
List * processed_tlist
Definition: pathnodes.h:453
Relids curOuterRels
Definition: pathnodes.h:529
List * plan_params
Definition: pathnodes.h:217
List * curOuterParams
Definition: pathnodes.h:531
void SS_attach_initplans(PlannerInfo *root, Plan *plan)
Definition: subselect.c:2236
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, plan, PlannerInfo::plan_params, PlannerInfo::processed_tlist, and SS_attach_initplans().

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 741 of file initsplan.c.

742 {
743  List *result;
744  JoinDomain *top_jdomain;
745  List *item_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, NULL,
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  }
785 
786  /*
787  * If there were any special joins then we may have some postponed LEFT
788  * JOIN clauses to deal with.
789  */
790  if (root->join_info_list)
791  {
792  foreach(lc, item_list)
793  {
794  JoinTreeItem *jtitem = (JoinTreeItem *) lfirst(lc);
795 
796  if (jtitem->oj_joinclauses != NIL)
797  deconstruct_distribute_oj_quals(root, item_list, jtitem);
798  }
799  }
800 
801  /* Don't need the JoinTreeItems any more */
802  list_free_deep(item_list);
803 
804  return result;
805 }
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:97
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:211
static List * deconstruct_recurse(PlannerInfo *root, Node *jtnode, JoinDomain *parent_domain, JoinTreeItem *parent_jtitem, List **item_list)
Definition: initsplan.c:823
static void deconstruct_distribute_oj_quals(PlannerInfo *root, List *jtitems, JoinTreeItem *jtitem)
Definition: initsplan.c:1879
static void deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem)
Definition: initsplan.c:1121
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:1306
List * oj_joinclauses
Definition: initsplan.c:78
Relids all_query_rels
Definition: pathnodes.h:266
Relids outer_join_rels
Definition: pathnodes.h:258
List * join_domains
Definition: pathnodes.h:308
List * join_info_list
Definition: pathnodes.h:337
FromExpr * jointree
Definition: parsenodes.h:174

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 2631 of file initsplan.c.

2633 {
2634  Relids relids = restrictinfo->required_relids;
2635  RelOptInfo *rel;
2636 
2637  if (!bms_is_empty(relids))
2638  {
2639  int relid;
2640 
2641  if (bms_get_singleton_member(relids, &relid))
2642  {
2643  /*
2644  * There is only one relation participating in the clause, so it
2645  * is a restriction clause for that relation.
2646  */
2647  rel = find_base_rel(root, relid);
2648 
2649  /* Add clause to rel's restriction list */
2651  restrictinfo);
2652  /* Update security level info */
2654  restrictinfo->security_level);
2655  }
2656  else
2657  {
2658  /*
2659  * The clause is a join clause, since there is more than one rel
2660  * in its relid set.
2661  */
2662 
2663  /*
2664  * Check for hashjoinable operators. (We don't bother setting the
2665  * hashjoin info except in true join clauses.)
2666  */
2667  check_hashjoinable(restrictinfo);
2668 
2669  /*
2670  * Likewise, check if the clause is suitable to be used with a
2671  * Memoize node to cache inner tuples during a parameterized
2672  * nested loop.
2673  */
2674  check_memoizable(restrictinfo);
2675 
2676  /*
2677  * Add clause to the join lists of all the relevant relations.
2678  */
2679  add_join_clause_to_rels(root, restrictinfo, relids);
2680  }
2681  }
2682  else
2683  {
2684  /*
2685  * clause references no rels, and therefore we have no place to attach
2686  * it. Shouldn't get here if callers are working properly.
2687  */
2688  elog(ERROR, "cannot cope with variable-free clause");
2689  }
2690 }
#define Min(x, y)
Definition: c.h:993
void add_join_clause_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo, Relids join_relids)
Definition: joininfo.c:95
List * baserestrictinfo
Definition: pathnodes.h:964
Index baserestrict_min_security
Definition: pathnodes.h:968
Index security_level
Definition: pathnodes.h:2551
Relids required_relids
Definition: pathnodes.h:2560

References add_join_clause_to_rels(), RelOptInfo::baserestrict_min_security, RelOptInfo::baserestrictinfo, bms_get_singleton_member(), bms_is_empty, 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(), remove_leftjoinrel_from_query(), and remove_self_join_rel().

◆ extract_query_dependencies_walker()

bool extract_query_dependencies_walker ( Node node,
PlannerInfo context 
)

Definition at line 3562 of file setrefs.c.

3563 {
3564  if (node == NULL)
3565  return false;
3566  Assert(!IsA(node, PlaceHolderVar));
3567  if (IsA(node, Query))
3568  {
3569  Query *query = (Query *) node;
3570  ListCell *lc;
3571 
3572  if (query->commandType == CMD_UTILITY)
3573  {
3574  /*
3575  * This logic must handle any utility command for which parse
3576  * analysis was nontrivial (cf. stmt_requires_parse_analysis).
3577  *
3578  * Notably, CALL requires its own processing.
3579  */
3580  if (IsA(query->utilityStmt, CallStmt))
3581  {
3582  CallStmt *callstmt = (CallStmt *) query->utilityStmt;
3583 
3584  /* We need not examine funccall, just the transformed exprs */
3585  (void) extract_query_dependencies_walker((Node *) callstmt->funcexpr,
3586  context);
3587  (void) extract_query_dependencies_walker((Node *) callstmt->outargs,
3588  context);
3589  return false;
3590  }
3591 
3592  /*
3593  * Ignore other utility statements, except those (such as EXPLAIN)
3594  * that contain a parsed-but-not-planned query. For those, we
3595  * just need to transfer our attention to the contained query.
3596  */
3597  query = UtilityContainsQuery(query->utilityStmt);
3598  if (query == NULL)
3599  return false;
3600  }
3601 
3602  /* Remember if any Query has RLS quals applied by rewriter */
3603  if (query->hasRowSecurity)
3604  context->glob->dependsOnRole = true;
3605 
3606  /* Collect relation OIDs in this Query's rtable */
3607  foreach(lc, query->rtable)
3608  {
3609  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3610 
3611  if (rte->rtekind == RTE_RELATION ||
3612  (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)) ||
3613  (rte->rtekind == RTE_NAMEDTUPLESTORE && OidIsValid(rte->relid)))
3614  context->glob->relationOids =
3615  lappend_oid(context->glob->relationOids, rte->relid);
3616  }
3617 
3618  /* And recurse into the query's subexpressions */
3620  (void *) context, 0);
3621  }
3622  /* Extract function dependencies and check for regclass Consts */
3623  fix_expr_common(context, node);
3625  (void *) context);
3626 }
#define OidIsValid(objectId)
Definition: c.h:764
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:1013
@ RTE_SUBQUERY
Definition: parsenodes.h:1007
@ RTE_RELATION
Definition: parsenodes.h:1006
static void fix_expr_common(PlannerInfo *root, Node *node)
Definition: setrefs.c:1951
bool extract_query_dependencies_walker(Node *node, PlannerInfo *context)
Definition: setrefs.c:3562
FuncExpr * funcexpr
Definition: parsenodes.h:3358
List * outargs
Definition: parsenodes.h:3360
bool dependsOnRole
Definition: pathnodes.h:150
List * relationOids
Definition: pathnodes.h:129
PlannerGlobal * glob
Definition: pathnodes.h:202
List * rtable
Definition: parsenodes.h:167
CmdType commandType
Definition: parsenodes.h:120
Node * utilityStmt
Definition: parsenodes.h:135
RTEKind rtekind
Definition: parsenodes.h:1025
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2184

References Assert(), CMD_UTILITY, Query::commandType, PlannerGlobal::dependsOnRole, expression_tree_walker, fix_expr_common(), CallStmt::funcexpr, PlannerInfo::glob, IsA, lappend_oid(), lfirst, OidIsValid, CallStmt::outargs, 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 359 of file initsplan.c.

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

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

Referenced by query_planner().

◆ find_minmax_agg_replacement_param()

Param* find_minmax_agg_replacement_param ( PlannerInfo root,
Aggref aggref 
)

Definition at line 3412 of file setrefs.c.

3413 {
3414  if (root->minmax_aggs != NIL &&
3415  list_length(aggref->args) == 1)
3416  {
3417  TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
3418  ListCell *lc;
3419 
3420  foreach(lc, root->minmax_aggs)
3421  {
3422  MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
3423 
3424  if (mminfo->aggfnoid == aggref->aggfnoid &&
3425  equal(mminfo->target, curTarget->expr))
3426  return mminfo->param;
3427  }
3428  }
3429  return NULL;
3430 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial(l)
Definition: pg_list.h:178
Oid aggfnoid
Definition: primnodes.h:430
List * args
Definition: primnodes.h:454
Param * param
Definition: pathnodes.h:3092
Expr * target
Definition: pathnodes.h:3077
List * minmax_aggs
Definition: pathnodes.h:469
Expr * expr
Definition: primnodes.h:1922

References MinMaxAggInfo::aggfnoid, Aggref::aggfnoid, Aggref::args, equal(), TargetEntry::expr, lfirst, linitial, list_length(), PlannerInfo::minmax_aggs, NIL, MinMaxAggInfo::param, and MinMaxAggInfo::target.

Referenced by finalize_primnode(), fix_scan_expr_mutator(), and fix_upper_expr_mutator().

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

1241 {
1242  return innerrel_is_unique_ext(root, joinrelids, outerrelids, innerrel,
1243  jointype, restrictlist, force_cache, NULL);
1244 }
bool innerrel_is_unique_ext(PlannerInfo *root, Relids joinrelids, Relids outerrelids, RelOptInfo *innerrel, JoinType jointype, List *restrictlist, bool force_cache, List **extra_clauses)

References innerrel_is_unique_ext().

Referenced by add_paths_to_joinrel(), and reduce_unique_semijoins().

◆ innerrel_is_unique_ext()

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

Definition at line 1252 of file analyzejoins.c.

1260 {
1261  MemoryContext old_context;
1262  ListCell *lc;
1263  UniqueRelInfo *uniqueRelInfo;
1264  List *outer_exprs = NIL;
1265 
1266  /* Certainly can't prove uniqueness when there are no joinclauses */
1267  if (restrictlist == NIL)
1268  return false;
1269 
1270  /*
1271  * Make a quick check to eliminate cases in which we will surely be unable
1272  * to prove uniqueness of the innerrel.
1273  */
1274  if (!rel_supports_distinctness(root, innerrel))
1275  return false;
1276 
1277  /*
1278  * Query the cache to see if we've managed to prove that innerrel is
1279  * unique for any subset of this outerrel. We don't need an exact match,
1280  * as extra outerrels can't make the innerrel any less unique (or more
1281  * formally, the restrictlist for a join to a superset outerrel must be a
1282  * superset of the conditions we successfully used before).
1283  */
1284  foreach(lc, innerrel->unique_for_rels)
1285  {
1286  uniqueRelInfo = (UniqueRelInfo *) lfirst(lc);
1287 
1288  if (bms_is_subset(uniqueRelInfo->outerrelids, outerrelids))
1289  {
1290  if (extra_clauses)
1291  *extra_clauses = uniqueRelInfo->extra_clauses;
1292  return true; /* Success! */
1293  }
1294  }
1295 
1296  /*
1297  * Conversely, we may have already determined that this outerrel, or some
1298  * superset thereof, cannot prove this innerrel to be unique.
1299  */
1300  foreach(lc, innerrel->non_unique_for_rels)
1301  {
1302  Relids unique_for_rels = (Relids) lfirst(lc);
1303 
1304  if (bms_is_subset(outerrelids, unique_for_rels))
1305  return false;
1306  }
1307 
1308  /* No cached information, so try to make the proof. */
1309  if (is_innerrel_unique_for(root, joinrelids, outerrelids, innerrel,
1310  jointype, restrictlist, &outer_exprs))
1311  {
1312  /*
1313  * Cache the positive result for future probes, being sure to keep it
1314  * in the planner_cxt even if we are working in GEQO.
1315  *
1316  * Note: one might consider trying to isolate the minimal subset of
1317  * the outerrels that proved the innerrel unique. But it's not worth
1318  * the trouble, because the planner builds up joinrels incrementally
1319  * and so we'll see the minimally sufficient outerrels before any
1320  * supersets of them anyway.
1321  */
1322  old_context = MemoryContextSwitchTo(root->planner_cxt);
1323  uniqueRelInfo = makeNode(UniqueRelInfo);
1324  uniqueRelInfo->extra_clauses = outer_exprs;
1325  uniqueRelInfo->outerrelids = bms_copy(outerrelids);
1326  innerrel->unique_for_rels = lappend(innerrel->unique_for_rels,
1327  uniqueRelInfo);
1328  MemoryContextSwitchTo(old_context);
1329 
1330  if (extra_clauses)
1331  *extra_clauses = outer_exprs;
1332  return true; /* Success! */
1333  }
1334  else
1335  {
1336  /*
1337  * None of the join conditions for outerrel proved innerrel unique, so
1338  * we can safely reject this outerrel or any subset of it in future
1339  * checks.
1340  *
1341  * However, in normal planning mode, caching this knowledge is totally
1342  * pointless; it won't be queried again, because we build up joinrels
1343  * from smaller to larger. It is useful in GEQO mode, where the
1344  * knowledge can be carried across successive planning attempts; and
1345  * it's likely to be useful when using join-search plugins, too. Hence
1346  * cache when join_search_private is non-NULL. (Yeah, that's a hack,
1347  * but it seems reasonable.)
1348  *
1349  * Also, allow callers to override that heuristic and force caching;
1350  * that's useful for reduce_unique_semijoins, which calls here before
1351  * the normal join search starts.
1352  */
1353  if (force_cache || root->join_search_private)
1354  {
1355  old_context = MemoryContextSwitchTo(root->planner_cxt);
1356  innerrel->non_unique_for_rels =
1357  lappend(innerrel->non_unique_for_rels,
1358  bms_copy(outerrelids));
1359  MemoryContextSwitchTo(old_context);
1360  }
1361 
1362  return false;
1363  }
1364 }
static bool is_innerrel_unique_for(PlannerInfo *root, Relids joinrelids, Relids outerrelids, RelOptInfo *innerrel, JoinType jointype, List *restrictlist, List **extra_clauses)
static bool rel_supports_distinctness(PlannerInfo *root, RelOptInfo *rel)
Definition: analyzejoins.c:850
#define makeNode(_type_)
Definition: nodes.h:176
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
Bitmapset * Relids
Definition: pathnodes.h:30
List * unique_for_rels
Definition: pathnodes.h:956
List * non_unique_for_rels
Definition: pathnodes.h:958
Relids outerrelids
Definition: pathnodes.h:3408
List * extra_clauses
Definition: pathnodes.h:3416

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

Referenced by innerrel_is_unique(), and remove_self_joins_one_group().

◆ is_projection_capable_path()

bool is_projection_capable_path ( Path path)

Definition at line 7177 of file createplan.c.

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

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

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

References CUSTOMPATH_SUPPORT_PROJECTION, nodeTag, and plan.

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

6570 {
6571  Agg *node = makeNode(Agg);
6572  Plan *plan = &node->plan;
6573  long numGroups;
6574 
6575  /* Reduce to long, but 'ware overflow! */
6576  numGroups = clamp_cardinality_to_long(dNumGroups);
6577 
6578  node->aggstrategy = aggstrategy;
6579  node->aggsplit = aggsplit;
6580  node->numCols = numGroupCols;
6581  node->grpColIdx = grpColIdx;
6582  node->grpOperators = grpOperators;
6583  node->grpCollations = grpCollations;
6584  node->numGroups = numGroups;
6585  node->transitionSpace = transitionSpace;
6586  node->aggParams = NULL; /* SS_finalize_plan() will fill this */
6587  node->groupingSets = groupingSets;
6588  node->chain = chain;
6589 
6590  plan->qual = qual;
6591  plan->targetlist = tlist;
6592  plan->lefttree = lefttree;
6593  plan->righttree = NULL;
6594 
6595  return node;
6596 }
long clamp_cardinality_to_long(Cardinality x)
Definition: costsize.c:226
Definition: plannodes.h:995
AggSplit aggsplit
Definition: plannodes.h:1002
List * chain
Definition: plannodes.h:1029
long numGroups
Definition: plannodes.h:1015
List * groupingSets
Definition: plannodes.h:1026
Bitmapset * aggParams
Definition: plannodes.h:1021
Plan plan
Definition: plannodes.h:996
int numCols
Definition: plannodes.h:1005
uint64 transitionSpace
Definition: plannodes.h:1018
AggStrategy aggstrategy
Definition: plannodes.h:999

References Agg::aggParams, Agg::aggsplit, Agg::aggstrategy, Agg::chain, clamp_cardinality_to_long(), Agg::groupingSets, makeNode, Agg::numCols, Agg::numGroups, Agg::plan, plan, 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 5794 of file createplan.c.

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

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, makeNode, ForeignScan::operation, plan, ForeignScan::resultRelation, ForeignScan::scan, and Scan::scanrelid.

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

6935 {
6936  Limit *node = makeNode(Limit);
6937  Plan *plan = &node->plan;
6938 
6939  plan->targetlist = lefttree->targetlist;
6940  plan->qual = NIL;
6941  plan->lefttree = lefttree;
6942  plan->righttree = NULL;
6943 
6944  node->limitOffset = limitOffset;
6945  node->limitCount = limitCount;
6946  node->limitOption = limitOption;
6947  node->uniqNumCols = uniqNumCols;
6948  node->uniqColIdx = uniqColIdx;
6949  node->uniqOperators = uniqOperators;
6950  node->uniqCollations = uniqCollations;
6951 
6952  return node;
6953 }
LimitOption limitOption
Definition: plannodes.h:1279
Plan plan
Definition: plannodes.h:1270
Node * limitCount
Definition: plannodes.h:1276
int uniqNumCols
Definition: plannodes.h:1282
Node * limitOffset
Definition: plannodes.h:1273

References Limit::limitCount, Limit::limitOffset, Limit::limitOption, makeNode, NIL, Limit::plan, plan, 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 6387 of file createplan.c.

6388 {
6389  List *sub_tlist = lefttree->targetlist;
6390  ListCell *l;
6391  int numsortkeys;
6392  AttrNumber *sortColIdx;
6393  Oid *sortOperators;
6394  Oid *collations;
6395  bool *nullsFirst;
6396 
6397  /* Convert list-ish representation to arrays wanted by executor */
6398  numsortkeys = list_length(sortcls);
6399  sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
6400  sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
6401  collations = (Oid *) palloc(numsortkeys * sizeof(Oid));
6402  nullsFirst = (bool *) palloc(numsortkeys * sizeof(bool));
6403 
6404  numsortkeys = 0;
6405  foreach(l, sortcls)
6406  {
6407  SortGroupClause *sortcl = (SortGroupClause *) lfirst(l);
6408  TargetEntry *tle = get_sortgroupclause_tle(sortcl, sub_tlist);
6409 
6410  sortColIdx[numsortkeys] = tle->resno;
6411  sortOperators[numsortkeys] = sortcl->sortop;
6412  collations[numsortkeys] = exprCollation((Node *) tle->expr);
6413  nullsFirst[numsortkeys] = sortcl->nulls_first;
6414  numsortkeys++;
6415  }
6416 
6417  return make_sort(lefttree, numsortkeys,
6418  sortColIdx, sortOperators,
6419  collations, nullsFirst);
6420 }
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:6040
void * palloc(Size size)
Definition: mcxt.c:1226
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:786
unsigned int Oid
Definition: postgres_ext.h:31
AttrNumber resno
Definition: primnodes.h:1924
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 2972 of file initsplan.c.

2973 {
2974  List *newlist = NIL;
2975  ListCell *lc;
2976 
2977  foreach(lc, root->fkey_list)
2978  {
2979  ForeignKeyOptInfo *fkinfo = (ForeignKeyOptInfo *) lfirst(lc);
2980  RelOptInfo *con_rel;
2981  RelOptInfo *ref_rel;
2982  int colno;
2983 
2984  /*
2985  * Either relid might identify a rel that is in the query's rtable but
2986  * isn't referenced by the jointree, or has been removed by join
2987  * removal, so that it won't have a RelOptInfo. Hence don't use
2988  * find_base_rel() here. We can ignore such FKs.
2989  */
2990  if (fkinfo->con_relid >= root->simple_rel_array_size ||
2991  fkinfo->ref_relid >= root->simple_rel_array_size)
2992  continue; /* just paranoia */
2993  con_rel = root->simple_rel_array[fkinfo->con_relid];
2994  if (con_rel == NULL)
2995  continue;
2996  ref_rel = root->simple_rel_array[fkinfo->ref_relid];
2997  if (ref_rel == NULL)
2998  continue;
2999 
3000  /*
3001  * Ignore FK unless both rels are baserels. This gets rid of FKs that
3002  * link to inheritance child rels (otherrels).
3003  */
3004  if (con_rel->reloptkind != RELOPT_BASEREL ||
3005  ref_rel->reloptkind != RELOPT_BASEREL)
3006  continue;
3007 
3008  /*
3009  * Scan the columns and try to match them to eclasses and quals.
3010  *
3011  * Note: for simple inner joins, any match should be in an eclass.
3012  * "Loose" quals that syntactically match an FK equality must have
3013  * been rejected for EC status because they are outer-join quals or
3014  * similar. We can still consider them to match the FK.
3015  */
3016  for (colno = 0; colno < fkinfo->nkeys; colno++)
3017  {
3018  EquivalenceClass *ec;
3019  AttrNumber con_attno,
3020  ref_attno;
3021  Oid fpeqop;
3022  ListCell *lc2;
3023 
3024  ec = match_eclasses_to_foreign_key_col(root, fkinfo, colno);
3025  /* Don't bother looking for loose quals if we got an EC match */
3026  if (ec != NULL)
3027  {
3028  fkinfo->nmatched_ec++;
3029  if (ec->ec_has_const)
3030  fkinfo->nconst_ec++;
3031  continue;
3032  }
3033 
3034  /*
3035  * Scan joininfo list for relevant clauses. Either rel's joininfo
3036  * list would do equally well; we use con_rel's.
3037  */
3038  con_attno = fkinfo->conkey[colno];
3039  ref_attno = fkinfo->confkey[colno];
3040  fpeqop = InvalidOid; /* we'll look this up only if needed */
3041 
3042  foreach(lc2, con_rel->joininfo)
3043  {
3044  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc2);
3045  OpExpr *clause = (OpExpr *) rinfo->clause;
3046  Var *leftvar;
3047  Var *rightvar;
3048 
3049  /* Only binary OpExprs are useful for consideration */
3050  if (!IsA(clause, OpExpr) ||
3051  list_length(clause->args) != 2)
3052  continue;
3053  leftvar = (Var *) get_leftop((Expr *) clause);
3054  rightvar = (Var *) get_rightop((Expr *) clause);
3055 
3056  /* Operands must be Vars, possibly with RelabelType */
3057  while (leftvar && IsA(leftvar, RelabelType))
3058  leftvar = (Var *) ((RelabelType *) leftvar)->arg;
3059  if (!(leftvar && IsA(leftvar, Var)))
3060  continue;
3061  while (rightvar && IsA(rightvar, RelabelType))
3062  rightvar = (Var *) ((RelabelType *) rightvar)->arg;
3063  if (!(rightvar && IsA(rightvar, Var)))
3064  continue;
3065 
3066  /* Now try to match the vars to the current foreign key cols */
3067  if (fkinfo->ref_relid == leftvar->varno &&
3068  ref_attno == leftvar->varattno &&
3069  fkinfo->con_relid == rightvar->varno &&
3070  con_attno == rightvar->varattno)
3071  {
3072  /* Vars match, but is it the right operator? */
3073  if (clause->opno == fkinfo->conpfeqop[colno])
3074  {
3075  fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
3076  rinfo);
3077  fkinfo->nmatched_ri++;
3078  }
3079  }
3080  else if (fkinfo->ref_relid == rightvar->varno &&
3081  ref_attno == rightvar->varattno &&
3082  fkinfo->con_relid == leftvar->varno &&
3083  con_attno == leftvar->varattno)
3084  {
3085  /*
3086  * Reverse match, must check commutator operator. Look it
3087  * up if we didn't already. (In the worst case we might
3088  * do multiple lookups here, but that would require an FK
3089  * equality operator without commutator, which is
3090  * unlikely.)
3091  */
3092  if (!OidIsValid(fpeqop))
3093  fpeqop = get_commutator(fkinfo->conpfeqop[colno]);
3094  if (clause->opno == fpeqop)
3095  {
3096  fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
3097  rinfo);
3098  fkinfo->nmatched_ri++;
3099  }
3100  }
3101  }
3102  /* If we found any matching loose quals, count col as matched */
3103  if (fkinfo->rinfos[colno])
3104  fkinfo->nmatched_rcols++;
3105  }
3106 
3107  /*
3108  * Currently, we drop multicolumn FKs that aren't fully matched to the
3109  * query. Later we might figure out how to derive some sort of
3110  * estimate from them, in which case this test should be weakened to
3111  * "if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) > 0)".
3112  */
3113  if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) == fkinfo->nkeys)
3114  newlist = lappend(newlist, fkinfo);
3115  }
3116  /* Replace fkey_list, thereby discarding any useless entries */
3117  root->fkey_list = newlist;
3118 }
EquivalenceClass * match_eclasses_to_foreign_key_col(PlannerInfo *root, ForeignKeyOptInfo *fkinfo, int colno)
Definition: equivclass.c:2490
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
Oid get_commutator(Oid opno)
Definition: lsyscache.c:1513
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:1239
Oid opno
Definition: primnodes.h:753
List * args
Definition: primnodes.h:771
List * fkey_list
Definition: pathnodes.h:379
List * joininfo
Definition: pathnodes.h:970
Expr * clause
Definition: pathnodes.h:2529

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

6500 {
6501  Plan *matplan;
6502  Path matpath; /* dummy for result of cost_material */
6503  Cost initplan_cost;
6504  bool unsafe_initplans;
6505 
6506  matplan = (Plan *) make_material(subplan);
6507 
6508  /*
6509  * XXX horrid kluge: if there are any initPlans attached to the subplan,
6510  * move them up to the Material node, which is now effectively the top
6511  * plan node in its query level. This prevents failure in
6512  * SS_finalize_plan(), which see for comments.
6513  */
6514  matplan->initPlan = subplan->initPlan;
6515  subplan->initPlan = NIL;
6516 
6517  /* Move the initplans' cost delta, as well */
6519  &initplan_cost, &unsafe_initplans);
6520  subplan->startup_cost -= initplan_cost;
6521  subplan->total_cost -= initplan_cost;
6522 
6523  /* Set cost data */
6524  cost_material(&matpath,
6525  subplan->startup_cost,
6526  subplan->total_cost,
6527  subplan->plan_rows,
6528  subplan->plan_width);
6529  matplan->startup_cost = matpath.startup_cost + initplan_cost;
6530  matplan->total_cost = matpath.total_cost + initplan_cost;
6531  matplan->plan_rows = subplan->plan_rows;
6532  matplan->plan_width = subplan->plan_width;
6533  matplan->parallel_aware = false;
6534  matplan->parallel_safe = subplan->parallel_safe;
6535 
6536  return matplan;
6537 }
void cost_material(Path *path, Cost input_startup_cost, Cost input_total_cost, double tuples, int width)
Definition: costsize.c:2425
static Material * make_material(Plan *lefttree)
Definition: createplan.c:6477
double Cost
Definition: nodes.h:262
Cost startup_cost
Definition: pathnodes.h:1629
Cost total_cost
Definition: pathnodes.h:1630
Cost total_cost
Definition: plannodes.h:129
bool parallel_aware
Definition: plannodes.h:140
Cost startup_cost
Definition: plannodes.h:128
int plan_width
Definition: plannodes.h:135
Cardinality plan_rows
Definition: plannodes.h:134
List * initPlan
Definition: plannodes.h:156
void SS_compute_initplan_cost(List *init_plans, Cost *initplan_cost_p, bool *unsafe_initplans_p)
Definition: subselect.c:2195

References cost_material(), Plan::initPlan, make_material(), NIL, Plan::parallel_aware, Plan::parallel_safe, Plan::plan_rows, Plan::plan_width, SS_compute_initplan_cost(), 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:3356
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:422
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:555
@ UPPERREL_GROUP_AGG
Definition: pathnodes.h:74
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:715
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1443
Param * SS_make_initplan_output_param(PlannerInfo *root, Oid resulttype, int32 resulttypmod, Oid resultcollation)
Definition: subselect.c:2998
#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 2724 of file initsplan.c.

2732 {
2733  RestrictInfo *restrictinfo;
2734  Node *clause;
2735  Relids relids;
2736  bool pseudoconstant = false;
2737 
2738  /*
2739  * Build the new clause. Copy to ensure it shares no substructure with
2740  * original (this is necessary in case there are subselects in there...)
2741  */
2742  clause = (Node *) make_opclause(opno,
2743  BOOLOID, /* opresulttype */
2744  false, /* opretset */
2745  copyObject(item1),
2746  copyObject(item2),
2747  InvalidOid,
2748  collation);
2749 
2750  /* If both constant, try to reduce to a boolean constant. */
2751  if (both_const)
2752  {
2753  clause = eval_const_expressions(root, clause);
2754 
2755  /* If we produced const TRUE, just drop the clause */
2756  if (clause && IsA(clause, Const))
2757  {
2758  Const *cclause = (Const *) clause;
2759 
2760  Assert(cclause->consttype == BOOLOID);
2761  if (!cclause->constisnull && DatumGetBool(cclause->constvalue))
2762  return NULL;
2763  }
2764  }
2765 
2766  /*
2767  * The rest of this is a very cut-down version of distribute_qual_to_rels.
2768  * We can skip most of the work therein, but there are a couple of special
2769  * cases we still have to handle.
2770  *
2771  * Retrieve all relids mentioned within the possibly-simplified clause.
2772  */
2773  relids = pull_varnos(root, clause);
2774  Assert(bms_is_subset(relids, qualscope));
2775 
2776  /*
2777  * If the clause is variable-free, our normal heuristic for pushing it
2778  * down to just the mentioned rels doesn't work, because there are none.
2779  * Apply it as a gating qual at the appropriate level (see comments for
2780  * get_join_domain_min_rels).
2781  */
2782  if (bms_is_empty(relids))
2783  {
2784  /* eval at join domain's safe level */
2785  relids = get_join_domain_min_rels(root, qualscope);
2786  /* mark as gating qual */
2787  pseudoconstant = true;
2788  /* tell createplan.c to check for gating quals */
2789  root->hasPseudoConstantQuals = true;
2790  }
2791 
2792  /*
2793  * Build the RestrictInfo node itself.
2794  */
2795  restrictinfo = make_restrictinfo(root,
2796  (Expr *) clause,
2797  true, /* is_pushed_down */
2798  false, /* !has_clone */
2799  false, /* !is_clone */
2800  pseudoconstant,
2801  security_level,
2802  relids,
2803  NULL, /* incompatible_relids */
2804  NULL); /* outer_relids */
2805 
2806  /*
2807  * If it's a join clause, add vars used in the clause to targetlists of
2808  * their relations, so that they will be emitted by the plan nodes that
2809  * scan those relations (else they won't be available at the join node!).
2810  *
2811  * Typically, we'd have already done this when the component expressions
2812  * were first seen by distribute_qual_to_rels; but it is possible that
2813  * some of the Vars could have missed having that done because they only
2814  * appeared in single-relation clauses originally. So do it here for
2815  * safety.
2816  */
2817  if (bms_membership(relids) == BMS_MULTIPLE)
2818  {
2819  List *vars = pull_var_clause(clause,
2823 
2824  add_vars_to_targetlist(root, vars, relids);
2825  list_free(vars);
2826  }
2827 
2828  /*
2829  * Check mergejoinability. This will usually succeed, since the op came
2830  * from an EquivalenceClass; but we could have reduced the original clause
2831  * to a constant.
2832  */
2833  check_mergejoinable(restrictinfo);
2834 
2835  /*
2836  * Note we don't do initialize_mergeclause_eclasses(); the caller can
2837  * handle that much more cheaply than we can. It's okay to call
2838  * distribute_restrictinfo_to_rels() before that happens.
2839  */
2840 
2841  /*
2842  * Push the new clause into all the appropriate restrictinfo lists.
2843  */
2844  distribute_restrictinfo_to_rels(root, restrictinfo);
2845 
2846  return restrictinfo;
2847 }
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:712
@ BMS_MULTIPLE
Definition: bitmapset.h:73
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2237
void distribute_restrictinfo_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2631
static Relids get_join_domain_min_rels(PlannerInfo *root, Relids domain_relids)
Definition: initsplan.c:2932
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
Oid consttype
Definition: primnodes.h:298
bool hasPseudoConstantQuals
Definition: pathnodes.h:495
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:108

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

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

1046 {
1047  ListCell *l;
1048  Oid opid;
1049 
1050  Assert(list_length(colnos) == list_length(opids));
1051 
1052  /*
1053  * DISTINCT (including DISTINCT ON) guarantees uniqueness if all the
1054  * columns in the DISTINCT clause appear in colnos and operator semantics
1055  * match. This is true even if there are SRFs in the DISTINCT columns or
1056  * elsewhere in the tlist.
1057  */
1058  if (query->distinctClause)
1059  {
1060  foreach(l, query->distinctClause)
1061  {
1062  SortGroupClause *sgc = (SortGroupClause *) lfirst(l);
1064  query->targetList);
1065 
1066  opid = distinct_col_search(tle->resno, colnos, opids);
1067  if (!OidIsValid(opid) ||
1068  !equality_ops_are_compatible(opid, sgc->eqop))
1069  break; /* exit early if no match */
1070  }
1071  if (l == NULL) /* had matches for all? */
1072  return true;
1073  }
1074 
1075  /*
1076  * Otherwise, a set-returning function in the query's targetlist can
1077  * result in returning duplicate rows, despite any grouping that might
1078  * occur before tlist evaluation. (If all tlist SRFs are within GROUP BY
1079  * columns, it would be safe because they'd be expanded before grouping.
1080  * But it doesn't currently seem worth the effort to check for that.)
1081  */
1082  if (query->hasTargetSRFs)
1083  return false;
1084 
1085  /*
1086  * Similarly, GROUP BY without GROUPING SETS guarantees uniqueness if all
1087  * the grouped columns appear in colnos and operator semantics match.
1088  */
1089  if (query->groupClause && !query->groupingSets)
1090  {
1091  foreach(l, query->groupClause)
1092  {
1093  SortGroupClause *sgc = (SortGroupClause *) lfirst(l);
1095  query->targetList);
1096 
1097  opid = distinct_col_search(tle->resno, colnos, opids);
1098  if (!OidIsValid(opid) ||
1099  !equality_ops_are_compatible(opid, sgc->eqop))
1100  break; /* exit early if no match */
1101  }
1102  if (l == NULL) /* had matches for all? */
1103  return true;
1104  }
1105  else if (query->groupingSets)
1106  {
1107  /*
1108  * If we have grouping sets with expressions, we probably don't have
1109  * uniqueness and analysis would be hard. Punt.
1110  */
1111  if (query->groupClause)
1112  return false;
1113 
1114  /*
1115  * If we have no groupClause (therefore no grouping expressions), we
1116  * might have one or many empty grouping sets. If there's just one,
1117  * then we're returning only one row and are certainly unique. But
1118  * otherwise, we know we're certainly not unique.
1119  */
1120  if (list_length(query->groupingSets) == 1 &&
1121  ((GroupingSet *) linitial(query->groupingSets))->kind == GROUPING_SET_EMPTY)
1122  return true;
1123  else
1124  return false;
1125  }
1126  else
1127  {
1128  /*
1129  * If we have no GROUP BY, but do have aggregates or HAVING, then the
1130  * result is at most one row so it's surely unique, for any operators.
1131  */
1132  if (query->hasAggs || query->havingQual)
1133  return true;
1134  }
1135 
1136  /*
1137  * UNION, INTERSECT, EXCEPT guarantee uniqueness of the whole output row,
1138  * except with ALL.
1139  */
1140  if (query->setOperations)
1141  {
1143 
1144  Assert(topop->op != SETOP_NONE);
1145 
1146  if (!topop->all)
1147  {
1148  ListCell *lg;
1149 
1150  /* We're good if all the nonjunk output columns are in colnos */
1151  lg = list_head(topop->groupClauses);
1152  foreach(l, query->targetList)
1153  {
1154  TargetEntry *tle = (TargetEntry *) lfirst(l);
1155  SortGroupClause *sgc;
1156 
1157  if (tle->resjunk)
1158  continue; /* ignore resjunk columns */
1159 
1160  /* non-resjunk columns should have grouping clauses */
1161  Assert(lg != NULL);
1162  sgc = (SortGroupClause *) lfirst(lg);
1163  lg = lnext(topop->groupClauses, lg);
1164 
1165  opid = distinct_col_search(tle->resno, colnos, opids);
1166  if (!OidIsValid(opid) ||
1167  !equality_ops_are_compatible(opid, sgc->eqop))
1168  break; /* exit early if no match */
1169  }
1170  if (l == NULL) /* had matches for all? */
1171  return true;
1172  }
1173  }
1174 
1175  /*
1176  * XXX Are there any other cases in which we can easily see the result
1177  * must be distinct?
1178  *
1179  * If you do add more smarts to this function, be sure to update
1180  * query_supports_distinctness() to match.
1181  */
1182 
1183  return false;
1184 }
static Oid distinct_col_search(int colno, List *colnos, List *opids)
bool equality_ops_are_compatible(Oid opno1, Oid opno2)
Definition: lsyscache.c:697
@ GROUPING_SET_EMPTY
Definition: parsenodes.h:1445
@ SETOP_NONE
Definition: parsenodes.h:1948
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:209
List * groupClause
Definition: parsenodes.h:190
List * targetList
Definition: parsenodes.h:181
List * groupingSets
Definition: parsenodes.h:193
List * distinctClause
Definition: parsenodes.h:199
SetOperation op
Definition: parsenodes.h:2026

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.) We should always do this in a subquery,
116  * since it might be useful to use the subquery in parallel
117  * paths in the parent level. At top level this is normally
118  * not worth the cycles, because a Result-only plan would
119  * never be interesting to parallelize. However, if
120  * debug_parallel_query is on, then we want to execute the
121  * Result in a parallel worker if possible, so we must check.
122  */
123  if (root->glob->parallelModeOK &&
124  (root->query_level > 1 ||
126  final_rel->consider_parallel =
127  is_parallel_safe(root, parse->jointree->quals);
128 
129  /*
130  * The only path for it is a trivial Result path. We cheat a
131  * bit here by using a GroupResultPath, because that way we
132  * can just jam the quals into it without preprocessing them.
133  * (But, if you hold your head at the right angle, a FROM-less
134  * SELECT is a kind of degenerate-grouping case, so it's not
135  * that much of a cheat.)
136  */
137  add_path(final_rel, (Path *)
138  create_group_result_path(root, final_rel,
139  final_rel->reltarget,
140  (List *) parse->jointree->quals));
141 
142  /* Select cheapest path (pretty easy in this case...) */
143  set_cheapest(final_rel);
144 
145  /*
146  * We don't need to run generate_base_implied_equalities, but
147  * we do need to pretend that EC merging is complete.
148  */
149  root->ec_merging_done = true;
150 
151  /*
152  * We still are required to call qp_callback, in case it's
153  * something like "SELECT 2+2 ORDER BY 1".
154  */
155  (*qp_callback) (root, qp_extra);
156 
157  return final_rel;
158  }
159  }
160  }
161 
162  /*
163  * Construct RelOptInfo nodes for all base relations used in the query.
164  * Appendrel member relations ("other rels") will be added later.
165  *
166  * Note: the reason we find the baserels by searching the jointree, rather
167  * than scanning the rangetable, is that the rangetable may contain RTEs
168  * for rels not actively part of the query, for example views. We don't
169  * want to make RelOptInfos for them.
170  */
171  add_base_rels_to_query(root, (Node *) parse->jointree);
172 
173  /*
174  * Examine the targetlist and join tree, adding entries to baserel
175  * targetlists for all referenced Vars, and generating PlaceHolderInfo
176  * entries for all referenced PlaceHolderVars. Restrict and join clauses
177  * are added to appropriate lists belonging to the mentioned relations. We
178  * also build EquivalenceClasses for provably equivalent expressions. The
179  * SpecialJoinInfo list is also built to hold information about join order
180  * restrictions. Finally, we form a target joinlist for make_one_rel() to
181  * work from.
182  */
184 
186 
188 
189  joinlist = deconstruct_jointree(root);
190 
191  /*
192  * Reconsider any postponed outer-join quals now that we have built up
193  * equivalence classes. (This could result in further additions or
194  * mergings of classes.)
195  */
197 
198  /*
199  * If we formed any equivalence classes, generate additional restriction
200  * clauses as appropriate. (Implied join clauses are formed on-the-fly
201  * later.)
202  */
204 
205  /*
206  * We have completed merging equivalence sets, so it's now possible to
207  * generate pathkeys in canonical form; so compute query_pathkeys and
208  * other pathkeys fields in PlannerInfo.
209  */
210  (*qp_callback) (root, qp_extra);
211 
212  /*
213  * Examine any "placeholder" expressions generated during subquery pullup.
214  * Make sure that the Vars they need are marked as needed at the relevant
215  * join level. This must be done before join removal because it might
216  * cause Vars or placeholders to be needed above a join when they weren't
217  * so marked before.
218  */
220 
221  /*
222  * Remove any useless outer joins. Ideally this would be done during
223  * jointree preprocessing, but the necessary information isn't available
224  * until we've built baserel data structures and classified qual clauses.
225  */
226  joinlist = remove_useless_joins(root, joinlist);
227 
228  /*
229  * Also, reduce any semijoins with unique inner rels to plain inner joins.
230  * Likewise, this can't be done until now for lack of needed info.
231  */
233 
234  /*
235  * Remove self joins on a unique column.
236  */
237  joinlist = remove_useless_self_joins(root, joinlist);
238 
239  /*
240  * Now distribute "placeholders" to base rels as needed. This has to be
241  * done after join removal because removal could change whether a
242  * placeholder is evaluable at a base rel.
243  */
245 
246  /*
247  * Construct the lateral reference sets now that we have finalized
248  * PlaceHolderVar eval levels.
249  */
251 
252  /*
253  * Match foreign keys to equivalence classes and join quals. This must be
254  * done after finalizing equivalence classes, and it's useful to wait till
255  * after join removal so that we can skip processing foreign keys
256  * involving removed relations.
257  */
259 
260  /*
261  * Look for join OR clauses that we can extract single-relation
262  * restriction OR clauses from.
263  */
265 
266  /*
267  * Now expand appendrels by adding "otherrels" for their children. We
268  * delay this to the end so that we have as much information as possible
269  * available for each baserel, including all restriction clauses. That
270  * let us prune away partitions that don't satisfy a restriction clause.
271  * Also note that some information such as lateral_relids is propagated
272  * from baserels to otherrels here, so we must have computed it already.
273  */
275 
276  /*
277  * Distribute any UPDATE/DELETE/MERGE row identity variables to the target
278  * relations. This can't be done till we've finished expansion of
279  * appendrels.
280  */
282 
283  /*
284  * Ready to do the primary planning.
285  */
286  final_rel = make_one_rel(root, joinlist);
287 
288  /* Check that we got at least one usable path */
289  if (!final_rel || !final_rel->cheapest_total_path ||
290  final_rel->cheapest_total_path->param_info != NULL)
291  elog(ERROR, "failed to construct the join relation");
292 
293  return final_rel;
294 }
RelOptInfo * make_one_rel(PlannerInfo *root, List *joinlist)
Definition: allpaths.c:174
List * remove_useless_joins(PlannerInfo *root, List *joinlist)
Definition: analyzejoins.c:94
List * remove_useless_self_joins(PlannerInfo *root, List *joinlist)
void reduce_unique_semijoins(PlannerInfo *root)
Definition: analyzejoins.c:774
void distribute_row_identity_vars(PlannerInfo *root)
Definition: appendinfo.c:966
bool is_parallel_safe(PlannerInfo *root, Node *node)
Definition: clauses.c:736
void generate_base_implied_equalities(PlannerInfo *root)
Definition: equivclass.c:1033
void reconsider_outer_join_clauses(PlannerInfo *root)
Definition: equivclass.c:1982
List * deconstruct_jointree(PlannerInfo *root)
Definition: initsplan.c:741
void match_foreign_keys_to_quals(PlannerInfo *root)
Definition: initsplan.c:2972
void find_lateral_references(PlannerInfo *root)
Definition: initsplan.c:359
void build_base_rel_tlists(PlannerInfo *root, List *final_tlist)
Definition: initsplan.c:235
void add_other_rels_to_query(PlannerInfo *root)
Definition: initsplan.c:196
void create_lateral_join_info(PlannerInfo *root)
Definition: initsplan.c:502
@ DEBUG_PARALLEL_OFF
Definition: optimizer.h:105
void extract_restriction_or_clauses(PlannerInfo *root)
Definition: orclauses.c:76
@ RTE_RESULT
Definition: parsenodes.h:1014
GroupResultPath * create_group_result_path(PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *havingqual)
Definition: pathnode.c:1516
void set_cheapest(RelOptInfo *parent_rel)
Definition: pathnode.c:244
void add_placeholders_to_base_rels(PlannerInfo *root)
Definition: placeholder.c:329
void fix_placeholder_input_needed_levels(PlannerInfo *root)
Definition: placeholder.c:300
void find_placeholders_in_jointree(PlannerInfo *root)
Definition: placeholder.c:185
int debug_parallel_query
Definition: planner.c:73
void setup_simple_rel_arrays(PlannerInfo *root)
Definition: relnode.c:93
bool parallelModeOK
Definition: pathnodes.h:153
List * canon_pathkeys
Definition: pathnodes.h:317
List * join_rel_list
Definition: pathnodes.h:277
bool ec_merging_done
Definition: pathnodes.h:314
List * left_join_clauses
Definition: pathnodes.h:323
List * full_join_clauses
Definition: pathnodes.h:334
Index query_level
Definition: pathnodes.h:205
List * right_join_clauses
Definition: pathnodes.h:329
int join_cur_level
Definition: pathnodes.h:293
bool consider_parallel
Definition: pathnodes.h:872
struct Path * cheapest_total_path
Definition: pathnodes.h:887

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(), DEBUG_PARALLEL_OFF, debug_parallel_query, 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, 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, PlannerInfo::query_level, reconsider_outer_join_clauses(), reduce_unique_semijoins(), RelOptInfo::reltarget, remove_useless_joins(), remove_useless_self_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 1008 of file analyzejoins.c.

1009 {
1010  /* SRFs break distinctness except with DISTINCT, see below */
1011  if (query->hasTargetSRFs && query->distinctClause == NIL)
1012  return false;
1013 
1014  /* check for features we can prove distinctness with */
1015  if (query->distinctClause != NIL ||
1016  query->groupClause != NIL ||
1017  query->groupingSets != NIL ||
1018  query->hasAggs ||
1019  query->havingQual ||
1020  query->setOperations)
1021  return true;
1022 
1023  return false;
1024 }

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 3445 of file setrefs.c.

3446 {
3447  /*
3448  * For performance reasons, we don't bother to track built-in functions;
3449  * we just assume they'll never change (or at least not in ways that'd
3450  * invalidate plans using them). For this purpose we can consider a
3451  * built-in function to be one with OID less than FirstUnpinnedObjectId.
3452  * Note that the OID generator guarantees never to generate such an OID
3453  * after startup, even at OID wraparound.
3454  */
3455  if (funcid >= (Oid) FirstUnpinnedObjectId)
3456  {
3457  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3458 
3459  /*
3460  * It would work to use any syscache on pg_proc, but the easiest is
3461  * PROCOID since we already have the function's OID at hand. Note
3462  * that plancache.c knows we use PROCOID.
3463  */
3464  inval_item->cacheId = PROCOID;
3465  inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
3466  ObjectIdGetDatum(funcid));
3467 
3468  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3469  }
3470 }
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
uint32 hashValue
Definition: plannodes.h:1571
List * invalItems
Definition: pathnodes.h:132
@ PROCOID
Definition: syscache.h:79
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:209
#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 3485 of file setrefs.c.

3486 {
3487  /*
3488  * As in record_plan_function_dependency, ignore the possibility that
3489  * someone would change a built-in domain.
3490  */
3491  if (typid >= (Oid) FirstUnpinnedObjectId)
3492  {
3493  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3494 
3495  /*
3496  * It would work to use any syscache on pg_type, but the easiest is
3497  * TYPEOID since we already have the type's OID at hand. Note that
3498  * plancache.c knows we use TYPEOID.
3499  */
3500  inval_item->cacheId = TYPEOID;
3501  inval_item->hashValue = GetSysCacheHashValue1(TYPEOID,
3502  ObjectIdGetDatum(typid));
3503 
3504  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3505  }
3506 }
@ 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 774 of file analyzejoins.c.

775 {
776  ListCell *lc;
777 
778  /*
779  * Scan the join_info_list to find semijoins.
780  */
781  foreach(lc, root->join_info_list)
782  {
783  SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
784  int innerrelid;
785  RelOptInfo *innerrel;
786  Relids joinrelids;
787  List *restrictlist;
788 
789  /*
790  * Must be a semijoin to a single baserel, else we aren't going to be
791  * able to do anything with it.
792  */
793  if (sjinfo->jointype != JOIN_SEMI)
794  continue;
795 
796  if (!bms_get_singleton_member(sjinfo->min_righthand, &innerrelid))
797  continue;
798 
799  innerrel = find_base_rel(root, innerrelid);
800 
801  /*
802  * Before we trouble to run generate_join_implied_equalities, make a
803  * quick check to eliminate cases in which we will surely be unable to
804  * prove uniqueness of the innerrel.
805  */
806  if (!rel_supports_distinctness(root, innerrel))
807  continue;
808 
809  /* Compute the relid set for the join we are considering */
810  joinrelids = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
811  Assert(sjinfo->ojrelid == 0); /* SEMI joins don't have RT indexes */
812 
813  /*
814  * Since we're only considering a single-rel RHS, any join clauses it
815  * has must be clauses linking it to the semijoin's min_lefthand. We
816  * can also consider EC-derived join clauses.
817  */
818  restrictlist =
820  joinrelids,
821  sjinfo->min_lefthand,
822  innerrel,
823  NULL),
824  innerrel->joininfo);
825 
826  /* Test whether the innerrel is unique for those clauses. */
827  if (!innerrel_is_unique(root,
828  joinrelids, sjinfo->min_lefthand, innerrel,
829  JOIN_SEMI, restrictlist, true))
830  continue;
831 
832  /* OK, remove the SpecialJoinInfo from the list. */
834  }
835 }
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, SpecialJoinInfo *sjinfo)
Definition: equivclass.c:1381
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:2854
JoinType jointype
Definition: pathnodes.h:2857
Relids min_lefthand
Definition: pathnodes.h:2853

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

95 {
96  ListCell *lc;
97 
98  /*
99  * We are only interested in relations that are left-joined to, so we can
100  * scan the join_info_list to find them easily.
101  */
102 restart:
103  foreach(lc, root->join_info_list)
104  {
105  SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
106  int innerrelid;
107  int nremoved;
108 
109  /* Skip if not removable */
110  if (!join_is_removable(root, sjinfo))
111  continue;
112 
113  /*
114  * Currently, join_is_removable can only succeed when the sjinfo's
115  * righthand is a single baserel. Remove that rel from the query and
116  * joinlist.
117  */
118  innerrelid = bms_singleton_member(sjinfo->min_righthand);
119 
120  remove_leftjoinrel_from_query(root, innerrelid, sjinfo);
121 
122  /* We verify that exactly one reference gets removed from joinlist */
123  nremoved = 0;
124  joinlist = remove_rel_from_joinlist(joinlist, innerrelid, &nremoved);
125  if (nremoved != 1)
126  elog(ERROR, "failed to find relation %d in joinlist", innerrelid);
127 
128  /*
129  * We can delete this SpecialJoinInfo from the list too, since it's no
130  * longer of interest. (Since we'll restart the foreach loop
131  * immediately, we don't bother with foreach_delete_current.)
132  */
134 
135  /*
136  * Restart the scan. This is necessary to ensure we find all
137  * removable joins independently of ordering of the join_info_list
138  * (note that removal of attr_needed bits may make a join appear
139  * removable that did not before).
140  */
141  goto restart;
142  }
143 
144  return joinlist;
145 }
static List * remove_rel_from_joinlist(List *joinlist, int relid, int *nremoved)
Definition: analyzejoins.c:720
static void remove_leftjoinrel_from_query(PlannerInfo *root, int relid, SpecialJoinInfo *sjinfo)
Definition: analyzejoins.c:493
static bool join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo)
Definition: analyzejoins.c:190
int bms_singleton_member(const Bitmapset *a)
Definition: bitmapset.c:612
List * list_delete_cell(List *list, ListCell *cell)
Definition: list.c:840

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

Referenced by query_planner().

◆ remove_useless_self_joins()

List* remove_useless_self_joins ( PlannerInfo root,
List jointree 
)

Definition at line 2386 of file analyzejoins.c.

2387 {
2388  Relids toRemove = NULL;
2389  int relid = -1;
2390 
2391  if (!enable_self_join_removal || joinlist == NIL ||
2392  (list_length(joinlist) == 1 && !IsA(linitial(joinlist), List)))
2393  return joinlist;
2394 
2395  /*
2396  * Merge pairs of relations participated in self-join. Remove unnecessary
2397  * range table entries.
2398  */
2399  toRemove = remove_self_joins_recurse(root, joinlist, toRemove);
2400 
2401  if (unlikely(toRemove != NULL))
2402  {
2403  int nremoved = 0;
2404 
2405  /* At the end, remove orphaned relation links */
2406  while ((relid = bms_next_member(toRemove, relid)) >= 0)
2407  joinlist = remove_rel_from_joinlist(joinlist, relid, &nremoved);
2408  }
2409 
2410  return joinlist;
2411 }
bool enable_self_join_removal
Definition: analyzejoins.c:55
static Relids remove_self_joins_recurse(PlannerInfo *root, List *joinlist, Relids toRemove)
#define unlikely(x)
Definition: c.h:300

References bms_next_member(), enable_self_join_removal, IsA, linitial, list_length(), NIL, remove_rel_from_joinlist(), remove_self_joins_recurse(), and unlikely.

Referenced by query_planner().

◆ set_plan_references()

Plan* set_plan_references ( PlannerInfo root,
Plan plan 
)

Definition at line 288 of file setrefs.c.

289 {
290  Plan *result;
291  PlannerGlobal *glob = root->glob;
292  int rtoffset = list_length(glob->finalrtable);
293  ListCell *lc;
294 
295  /*
296  * Add all the query's RTEs to the flattened rangetable. The live ones
297  * will have their rangetable indexes increased by rtoffset. (Additional
298  * RTEs, not referenced by the Plan tree, might get added after those.)
299  */
300  add_rtes_to_flat_rtable(root, false);
301 
302  /*
303  * Adjust RT indexes of PlanRowMarks and add to final rowmarks list
304  */
305  foreach(lc, root->rowMarks)
306  {
308  PlanRowMark *newrc;
309 
310  /* flat copy is enough since all fields are scalars */
311  newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark));
312  memcpy(newrc, rc, sizeof(PlanRowMark));
313 
314  /* adjust indexes ... but *not* the rowmarkId */
315  newrc->rti += rtoffset;
316  newrc->prti += rtoffset;
317 
318  glob->finalrowmarks = lappend(glob->finalrowmarks, newrc);
319  }
320 
321  /*
322  * Adjust RT indexes of AppendRelInfos and add to final appendrels list.
323  * We assume the AppendRelInfos were built during planning and don't need
324  * to be copied.
325  */
326  foreach(lc, root->append_rel_list)
327  {
328  AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
329 
330  /* adjust RT indexes */
331  appinfo->parent_relid += rtoffset;
332  appinfo->child_relid += rtoffset;
333 
334  /*
335  * Rather than adjust the translated_vars entries, just drop 'em.
336  * Neither the executor nor EXPLAIN currently need that data.
337  */
338  appinfo->translated_vars = NIL;
339 
340  glob->appendRelations = lappend(glob->appendRelations, appinfo);
341  }
342 
343  /* If needed, create workspace for processing AlternativeSubPlans */
344  if (root->hasAlternativeSubPlans)
345  {
346  root->isAltSubplan = (bool *)
347  palloc0(list_length(glob->subplans) * sizeof(bool));
348  root->isUsedSubplan = (bool *)
349  palloc0(list_length(glob->subplans) * sizeof(bool));
350  }
351 
352  /* Now fix the Plan tree */
353  result = set_plan_refs(root, plan, rtoffset);
354 
355  /*
356  * If we have AlternativeSubPlans, it is likely that we now have some
357  * unreferenced subplans in glob->subplans. To avoid expending cycles on
358  * those subplans later, get rid of them by setting those list entries to
359  * NULL. (Note: we can't do this immediately upon processing an
360  * AlternativeSubPlan, because there may be multiple copies of the
361  * AlternativeSubPlan, and they can get resolved differently.)
362  */
363  if (root->hasAlternativeSubPlans)
364  {
365  foreach(lc, glob->subplans)
366  {
367  int ndx = foreach_current_index(lc);
368 
369  /*
370  * If it was used by some AlternativeSubPlan in this query level,
371  * but wasn't selected as best by any AlternativeSubPlan, then we
372  * don't need it. Do not touch subplans that aren't parts of
373  * AlternativeSubPlans.
374  */
375  if (root->isAltSubplan[ndx] && !root->isUsedSubplan[ndx])
376  lfirst(lc) = NULL;
377  }
378  }
379 
380  return result;
381 }
unsigned char bool
Definition: c.h:445
void * palloc0(Size size)
Definition: mcxt.c:1257
#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:392
static Plan * set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
Definition: setrefs.c:609
Index child_relid
Definition: pathnodes.h:2929
List * translated_vars
Definition: pathnodes.h:2956
Index parent_relid
Definition: pathnodes.h:2928
Index prti
Definition: plannodes.h:1381
List * subplans
Definition: pathnodes.h:105
List * appendRelations
Definition: pathnodes.h:126
List * finalrowmarks
Definition: pathnodes.h:120
List * finalrtable
Definition: pathnodes.h:114
List * append_rel_list
Definition: pathnodes.h:362
bool hasAlternativeSubPlans
Definition: pathnodes.h:497
List * rowMarks
Definition: pathnodes.h:368

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, palloc(), palloc0(), AppendRelInfo::parent_relid, plan, PlanRowMark::prti, PlannerInfo::rowMarks, PlanRowMark::rti, 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 1449 of file setrefs.c.

1450 {
1451  int attrno;
1452  ListCell *lp,
1453  *lc;
1454 
1455  /* We might have detected this already; in which case reuse the result */
1456  if (plan->scanstatus == SUBQUERY_SCAN_TRIVIAL)
1457  return true;
1458  if (plan->scanstatus == SUBQUERY_SCAN_NONTRIVIAL)
1459  return false;
1460  Assert(plan->scanstatus == SUBQUERY_SCAN_UNKNOWN);
1461  /* Initially, mark the SubqueryScan as non-deletable from the plan tree */
1462  plan->scanstatus = SUBQUERY_SCAN_NONTRIVIAL;
1463 
1464  if (plan->scan.plan.qual != NIL)
1465  return false;
1466 
1467  if (list_length(plan->scan.plan.targetlist) !=
1468  list_length(plan->subplan->targetlist))
1469  return false; /* tlists not same length */
1470 
1471  attrno = 1;
1472  forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
1473  {
1474  TargetEntry *ptle = (TargetEntry *) lfirst(lp);
1475  TargetEntry *ctle = (TargetEntry *) lfirst(lc);
1476 
1477  if (ptle->resjunk != ctle->resjunk)
1478  return false; /* tlist doesn't match junk status */
1479 
1480  /*
1481  * We accept either a Var referencing the corresponding element of the
1482  * subplan tlist, or a Const equaling the subplan element. See
1483  * generate_setop_tlist() for motivation.
1484  */
1485  if (ptle->expr && IsA(ptle->expr, Var))
1486  {
1487  Var *var = (Var *) ptle->expr;
1488 
1489  Assert(var->varno == plan->scan.scanrelid);
1490  Assert(var->varlevelsup == 0);
1491  if (var->varattno != attrno)
1492  return false; /* out of order */
1493  }
1494  else if (ptle->expr && IsA(ptle->expr, Const))
1495  {
1496  if (!equal(ptle->expr, ctle->expr))
1497  return false;
1498  }
1499  else
1500  return false;
1501 
1502  attrno++;
1503  }
1504 
1505  /* Re-mark the SubqueryScan as deletable from the plan tree */
1506  plan->scanstatus = SUBQUERY_SCAN_TRIVIAL;
1507 
1508  return true;
1509 }
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:467
@ SUBQUERY_SCAN_NONTRIVIAL
Definition: plannodes.h:593
@ SUBQUERY_SCAN_UNKNOWN
Definition: plannodes.h:591
@ SUBQUERY_SCAN_TRIVIAL
Definition: plannodes.h:592
Index varlevelsup
Definition: primnodes.h:266

References Assert(), equal(), TargetEntry::expr, forboth, IsA, lfirst, list_length(), NIL, plan, SUBQUERY_SCAN_NONTRIVIAL, SUBQUERY_SCAN_TRIVIAL, SUBQUERY_SCAN_UNKNOWN, 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().

◆ enable_self_join_removal

PGDLLIMPORT bool enable_self_join_removal
extern

Definition at line 55 of file analyzejoins.c.

Referenced by remove_useless_self_joins().

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