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)
 
bool restriction_is_always_true (PlannerInfo *root, RestrictInfo *restrictinfo)
 
bool restriction_is_always_false (PlannerInfo *root, RestrictInfo *restrictinfo)
 
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 157 of file initsplan.c.

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

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

Referenced by query_planner().

◆ add_other_rels_to_query()

void add_other_rels_to_query ( PlannerInfo root)

Definition at line 195 of file initsplan.c.

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

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

Referenced by query_planner().

◆ add_vars_to_targetlist()

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

Definition at line 279 of file initsplan.c.

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

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

References add_vars_to_targetlist(), bms_make_singleton(), list_free(), NIL, pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, and root.

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

3067 {
3068  RestrictInfo *restrictinfo;
3069  Expr *clause;
3070 
3071  /*
3072  * Build the new clause. Copy to ensure it shares no substructure with
3073  * original (this is necessary in case there are subselects in there...)
3074  */
3075  clause = make_opclause(opno,
3076  BOOLOID, /* opresulttype */
3077  false, /* opretset */
3078  copyObject(item1),
3079  copyObject(item2),
3080  InvalidOid,
3081  collation);
3082 
3083  /*
3084  * Build the RestrictInfo node itself.
3085  */
3086  restrictinfo = make_restrictinfo(root,
3087  clause,
3088  true, /* is_pushed_down */
3089  false, /* !has_clone */
3090  false, /* !is_clone */
3091  false, /* pseudoconstant */
3092  security_level, /* security_level */
3093  qualscope, /* required_relids */
3094  NULL, /* incompatible_relids */
3095  NULL); /* outer_relids */
3096 
3097  /* Set mergejoinability/hashjoinability flags */
3098  check_mergejoinable(restrictinfo);
3099  check_hashjoinable(restrictinfo);
3100  check_memoizable(restrictinfo);
3101 
3102  return restrictinfo;
3103 }
static void check_hashjoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3371
static void check_mergejoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3334
static void check_memoizable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3399
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: makefuncs.c:628
#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(), JoinTreeItem::qualscope, and root.

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

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

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

References 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(), IsA, RelOptInfo::lateral_referencers, RelOptInfo::lateral_relids, RelOptInfo::lateral_vars, lfirst, PlaceHolderInfo::ph_eval_at, PlaceHolderInfo::ph_lateral, RelOptInfo::relid, RELOPT_BASEREL, RelOptInfo::reloptkind, root, and Var::varno.

Referenced by query_planner().

◆ create_plan()

Plan* create_plan ( PlannerInfo root,
Path best_path 
)

Definition at line 337 of file createplan.c.

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

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

References Assert, bms_equal(), bms_union(), deconstruct_distribute(), deconstruct_distribute_oj_quals(), deconstruct_recurse(), IsA, JoinDomain::jd_relids, lfirst, linitial_node, list_free_deep(), NIL, JoinTreeItem::oj_joinclauses, and root.

Referenced by query_planner().

◆ distribute_restrictinfo_to_rels()

void distribute_restrictinfo_to_rels ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 2836 of file initsplan.c.

2838 {
2839  Relids relids = restrictinfo->required_relids;
2840 
2841  if (!bms_is_empty(relids))
2842  {
2843  int relid;
2844 
2845  if (bms_get_singleton_member(relids, &relid))
2846  {
2847  /*
2848  * There is only one relation participating in the clause, so it
2849  * is a restriction clause for that relation.
2850  */
2851  add_base_clause_to_rel(root, relid, restrictinfo);
2852  }
2853  else
2854  {
2855  /*
2856  * The clause is a join clause, since there is more than one rel
2857  * in its relid set.
2858  */
2859 
2860  /*
2861  * Check for hashjoinable operators. (We don't bother setting the
2862  * hashjoin info except in true join clauses.)
2863  */
2864  check_hashjoinable(restrictinfo);
2865 
2866  /*
2867  * Likewise, check if the clause is suitable to be used with a
2868  * Memoize node to cache inner tuples during a parameterized
2869  * nested loop.
2870  */
2871  check_memoizable(restrictinfo);
2872 
2873  /*
2874  * Add clause to the join lists of all the relevant relations.
2875  */
2876  add_join_clause_to_rels(root, restrictinfo, relids);
2877  }
2878  }
2879  else
2880  {
2881  /*
2882  * clause references no rels, and therefore we have no place to attach
2883  * it. Shouldn't get here if callers are working properly.
2884  */
2885  elog(ERROR, "cannot cope with variable-free clause");
2886  }
2887 }
static void add_base_clause_to_rel(PlannerInfo *root, Index relid, RestrictInfo *restrictinfo)
Definition: initsplan.c:2629
void add_join_clause_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo, Relids join_relids)
Definition: joininfo.c:98
Relids required_relids
Definition: pathnodes.h:2583

References add_base_clause_to_rel(), add_join_clause_to_rels(), bms_get_singleton_member(), bms_is_empty, check_hashjoinable(), check_memoizable(), elog, ERROR, RestrictInfo::required_relids, and root.

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

3578 {
3579  if (node == NULL)
3580  return false;
3581  Assert(!IsA(node, PlaceHolderVar));
3582  if (IsA(node, Query))
3583  {
3584  Query *query = (Query *) node;
3585  ListCell *lc;
3586 
3587  if (query->commandType == CMD_UTILITY)
3588  {
3589  /*
3590  * This logic must handle any utility command for which parse
3591  * analysis was nontrivial (cf. stmt_requires_parse_analysis).
3592  *
3593  * Notably, CALL requires its own processing.
3594  */
3595  if (IsA(query->utilityStmt, CallStmt))
3596  {
3597  CallStmt *callstmt = (CallStmt *) query->utilityStmt;
3598 
3599  /* We need not examine funccall, just the transformed exprs */
3600  (void) extract_query_dependencies_walker((Node *) callstmt->funcexpr,
3601  context);
3602  (void) extract_query_dependencies_walker((Node *) callstmt->outargs,
3603  context);
3604  return false;
3605  }
3606 
3607  /*
3608  * Ignore other utility statements, except those (such as EXPLAIN)
3609  * that contain a parsed-but-not-planned query. For those, we
3610  * just need to transfer our attention to the contained query.
3611  */
3612  query = UtilityContainsQuery(query->utilityStmt);
3613  if (query == NULL)
3614  return false;
3615  }
3616 
3617  /* Remember if any Query has RLS quals applied by rewriter */
3618  if (query->hasRowSecurity)
3619  context->glob->dependsOnRole = true;
3620 
3621  /* Collect relation OIDs in this Query's rtable */
3622  foreach(lc, query->rtable)
3623  {
3624  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3625 
3626  if (rte->rtekind == RTE_RELATION ||
3627  (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)) ||
3628  (rte->rtekind == RTE_NAMEDTUPLESTORE && OidIsValid(rte->relid)))
3629  context->glob->relationOids =
3630  lappend_oid(context->glob->relationOids, rte->relid);
3631  }
3632 
3633  /* And recurse into the query's subexpressions */
3635  (void *) context, 0);
3636  }
3637  /* Extract function dependencies and check for regclass Consts */
3638  fix_expr_common(context, node);
3640  (void *) context);
3641 }
#define OidIsValid(objectId)
Definition: c.h:775
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
#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:270
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1035
@ RTE_SUBQUERY
Definition: parsenodes.h:1029
@ RTE_RELATION
Definition: parsenodes.h:1028
tree context
Definition: radixtree.h:1829
static void fix_expr_common(PlannerInfo *root, Node *node)
Definition: setrefs.c:1966
bool extract_query_dependencies_walker(Node *node, PlannerInfo *context)
Definition: setrefs.c:3577
FuncExpr * funcexpr
Definition: parsenodes.h:3520
List * outargs
Definition: parsenodes.h:3522
List * rtable
Definition: parsenodes.h:168
CmdType commandType
Definition: parsenodes.h:121
Node * utilityStmt
Definition: parsenodes.h:136
RTEKind rtekind
Definition: parsenodes.h:1057
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2176

References Assert, CMD_UTILITY, Query::commandType, context, expression_tree_walker, fix_expr_common(), CallStmt::funcexpr, IsA, lappend_oid(), lfirst, OidIsValid, CallStmt::outargs, query_tree_walker, 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 358 of file initsplan.c.

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

References Assert, extract_lateral_references(), RelOptInfo::relid, RELOPT_BASEREL, RelOptInfo::reloptkind, and root.

Referenced by query_planner().

◆ find_minmax_agg_replacement_param()

Param* find_minmax_agg_replacement_param ( PlannerInfo root,
Aggref aggref 
)

Definition at line 3427 of file setrefs.c.

3428 {
3429  if (root->minmax_aggs != NIL &&
3430  list_length(aggref->args) == 1)
3431  {
3432  TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
3433  ListCell *lc;
3434 
3435  foreach(lc, root->minmax_aggs)
3436  {
3437  MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
3438 
3439  if (mminfo->aggfnoid == aggref->aggfnoid &&
3440  equal(mminfo->target, curTarget->expr))
3441  return mminfo->param;
3442  }
3443  }
3444  return NULL;
3445 }
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:444
List * args
Definition: primnodes.h:468
Param * param
Definition: pathnodes.h:3121
Expr * target
Definition: pathnodes.h:3106
Expr * expr
Definition: primnodes.h:2162

References MinMaxAggInfo::aggfnoid, Aggref::aggfnoid, Aggref::args, equal(), TargetEntry::expr, lfirst, linitial, list_length(), NIL, MinMaxAggInfo::param, root, 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 1224 of file analyzejoins.c.

1231 {
1232  return innerrel_is_unique_ext(root, joinrelids, outerrelids, innerrel,
1233  jointype, restrictlist, force_cache, NULL);
1234 }
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(), and root.

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

1252 {
1253  MemoryContext old_context;
1254  ListCell *lc;
1255  UniqueRelInfo *uniqueRelInfo;
1256  List *outer_exprs = NIL;
1257  bool self_join = (extra_clauses != NULL);
1258 
1259  /* Certainly can't prove uniqueness when there are no joinclauses */
1260  if (restrictlist == NIL)
1261  return false;
1262 
1263  /*
1264  * Make a quick check to eliminate cases in which we will surely be unable
1265  * to prove uniqueness of the innerrel.
1266  */
1267  if (!rel_supports_distinctness(root, innerrel))
1268  return false;
1269 
1270  /*
1271  * Query the cache to see if we've managed to prove that innerrel is
1272  * unique for any subset of this outerrel. For non self-join search, we
1273  * don't need an exact match, as extra outerrels can't make the innerrel
1274  * any less unique (or more formally, the restrictlist for a join to a
1275  * superset outerrel must be a superset of the conditions we successfully
1276  * used before). For self-join search, we require an exact match of
1277  * outerrels, because we need extra clauses to be valid for our case.
1278  * Also, for self-join checking we've filtered the clauses list. Thus,
1279  * for a self-join search, we can match only the result cached for another
1280  * self-join check.
1281  */
1282  foreach(lc, innerrel->unique_for_rels)
1283  {
1284  uniqueRelInfo = (UniqueRelInfo *) lfirst(lc);
1285 
1286  if ((!self_join && bms_is_subset(uniqueRelInfo->outerrelids, outerrelids)) ||
1287  (self_join && bms_equal(uniqueRelInfo->outerrelids, outerrelids) &&
1288  uniqueRelInfo->self_join))
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,
1311  self_join ? &outer_exprs : NULL))
1312  {
1313  /*
1314  * Cache the positive result for future probes, being sure to keep it
1315  * in the planner_cxt even if we are working in GEQO.
1316  *
1317  * Note: one might consider trying to isolate the minimal subset of
1318  * the outerrels that proved the innerrel unique. But it's not worth
1319  * the trouble, because the planner builds up joinrels incrementally
1320  * and so we'll see the minimally sufficient outerrels before any
1321  * supersets of them anyway.
1322  */
1323  old_context = MemoryContextSwitchTo(root->planner_cxt);
1324  uniqueRelInfo = makeNode(UniqueRelInfo);
1325  uniqueRelInfo->outerrelids = bms_copy(outerrelids);
1326  uniqueRelInfo->self_join = self_join;
1327  uniqueRelInfo->extra_clauses = outer_exprs;
1328  innerrel->unique_for_rels = lappend(innerrel->unique_for_rels,
1329  uniqueRelInfo);
1330  MemoryContextSwitchTo(old_context);
1331 
1332  if (extra_clauses)
1333  *extra_clauses = outer_exprs;
1334  return true; /* Success! */
1335  }
1336  else
1337  {
1338  /*
1339  * None of the join conditions for outerrel proved innerrel unique, so
1340  * we can safely reject this outerrel or any subset of it in future
1341  * checks.
1342  *
1343  * However, in normal planning mode, caching this knowledge is totally
1344  * pointless; it won't be queried again, because we build up joinrels
1345  * from smaller to larger. It is useful in GEQO mode, where the
1346  * knowledge can be carried across successive planning attempts; and
1347  * it's likely to be useful when using join-search plugins, too. Hence
1348  * cache when join_search_private is non-NULL. (Yeah, that's a hack,
1349  * but it seems reasonable.)
1350  *
1351  * Also, allow callers to override that heuristic and force caching;
1352  * that's useful for reduce_unique_semijoins, which calls here before
1353  * the normal join search starts.
1354  */
1355  if (force_cache || root->join_search_private)
1356  {
1357  old_context = MemoryContextSwitchTo(root->planner_cxt);
1358  innerrel->non_unique_for_rels =
1359  lappend(innerrel->non_unique_for_rels,
1360  bms_copy(outerrelids));
1361  MemoryContextSwitchTo(old_context);
1362  }
1363 
1364  return false;
1365  }
1366 }
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:840
#define makeNode(_type_)
Definition: nodes.h:155
Bitmapset * Relids
Definition: pathnodes.h:30
MemoryContextSwitchTo(old_ctx)
List * unique_for_rels
Definition: pathnodes.h:967
List * non_unique_for_rels
Definition: pathnodes.h:969
Relids outerrelids
Definition: pathnodes.h:3437
List * extra_clauses
Definition: pathnodes.h:3451

References bms_copy(), bms_equal(), 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(), root, UniqueRelInfo::self_join, 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 7207 of file createplan.c.

7208 {
7209  /* Most plan types can project, so just list the ones that can't */
7210  switch (path->pathtype)
7211  {
7212  case T_Hash:
7213  case T_Material:
7214  case T_Memoize:
7215  case T_Sort:
7216  case T_IncrementalSort:
7217  case T_Unique:
7218  case T_SetOp:
7219  case T_LockRows:
7220  case T_Limit:
7221  case T_ModifyTable:
7222  case T_MergeAppend:
7223  case T_RecursiveUnion:
7224  return false;
7225  case T_CustomScan:
7227  return true;
7228  return false;
7229  case T_Append:
7230 
7231  /*
7232  * Append can't project, but if an AppendPath is being used to
7233  * represent a dummy path, what will actually be generated is a
7234  * Result which can project.
7235  */
7236  return IS_DUMMY_APPEND(path);
7237  case T_ProjectSet:
7238 
7239  /*
7240  * Although ProjectSet certainly projects, say "no" because we
7241  * don't want the planner to randomly replace its tlist with
7242  * something else; the SRFs have to stay at top level. This might
7243  * get relaxed later.
7244  */
7245  return false;
7246  default:
7247  break;
7248  }
7249  return true;
7250 }
#define CUSTOMPATH_SUPPORT_PROJECTION
Definition: extensible.h:86
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
#define IS_DUMMY_APPEND(p)
Definition: pathnodes.h:1927
NodeTag pathtype
Definition: pathnodes.h:1615

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

7258 {
7259  /* Most plan types can project, so just list the ones that can't */
7260  switch (nodeTag(plan))
7261  {
7262  case T_Hash:
7263  case T_Material:
7264  case T_Memoize:
7265  case T_Sort:
7266  case T_Unique:
7267  case T_SetOp:
7268  case T_LockRows:
7269  case T_Limit:
7270  case T_ModifyTable:
7271  case T_Append:
7272  case T_MergeAppend:
7273  case T_RecursiveUnion:
7274  return false;
7275  case T_CustomScan:
7276  if (((CustomScan *) plan)->flags & CUSTOMPATH_SUPPORT_PROJECTION)
7277  return true;
7278  return false;
7279  case T_ProjectSet:
7280 
7281  /*
7282  * Although ProjectSet certainly projects, say "no" because we
7283  * don't want the planner to randomly replace its tlist with
7284  * something else; the SRFs have to stay at top level. This might
7285  * get relaxed later.
7286  */
7287  return false;
7288  default:
7289  break;
7290  }
7291  return true;
7292 }

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

6598 {
6599  Agg *node = makeNode(Agg);
6600  Plan *plan = &node->plan;
6601  long numGroups;
6602 
6603  /* Reduce to long, but 'ware overflow! */
6604  numGroups = clamp_cardinality_to_long(dNumGroups);
6605 
6606  node->aggstrategy = aggstrategy;
6607  node->aggsplit = aggsplit;
6608  node->numCols = numGroupCols;
6609  node->grpColIdx = grpColIdx;
6610  node->grpOperators = grpOperators;
6611  node->grpCollations = grpCollations;
6612  node->numGroups = numGroups;
6613  node->transitionSpace = transitionSpace;
6614  node->aggParams = NULL; /* SS_finalize_plan() will fill this */
6615  node->groupingSets = groupingSets;
6616  node->chain = chain;
6617 
6618  plan->qual = qual;
6619  plan->targetlist = tlist;
6620  plan->lefttree = lefttree;
6621  plan->righttree = NULL;
6622 
6623  return node;
6624 }
long clamp_cardinality_to_long(Cardinality x)
Definition: costsize.c:254
Definition: plannodes.h:997
AggSplit aggsplit
Definition: plannodes.h:1004
List * chain
Definition: plannodes.h:1031
long numGroups
Definition: plannodes.h:1017
List * groupingSets
Definition: plannodes.h:1028
Bitmapset * aggParams
Definition: plannodes.h:1023
Plan plan
Definition: plannodes.h:998
int numCols
Definition: plannodes.h:1007
uint64 transitionSpace
Definition: plannodes.h:1020
AggStrategy aggstrategy
Definition: plannodes.h:1001

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

5830 {
5831  ForeignScan *node = makeNode(ForeignScan);
5832  Plan *plan = &node->scan.plan;
5833 
5834  /* cost will be filled in by create_foreignscan_plan */
5835  plan->targetlist = qptlist;
5836  plan->qual = qpqual;
5837  plan->lefttree = outer_plan;
5838  plan->righttree = NULL;
5839  node->scan.scanrelid = scanrelid;
5840 
5841  /* these may be overridden by the FDW's PlanDirectModify callback. */
5842  node->operation = CMD_SELECT;
5843  node->resultRelation = 0;
5844 
5845  /* checkAsUser, fs_server will be filled in by create_foreignscan_plan */
5846  node->checkAsUser = InvalidOid;
5847  node->fs_server = InvalidOid;
5848  node->fdw_exprs = fdw_exprs;
5849  node->fdw_private = fdw_private;
5850  node->fdw_scan_tlist = fdw_scan_tlist;
5851  node->fdw_recheck_quals = fdw_recheck_quals;
5852  /* fs_relids, fs_base_relids will be filled by create_foreignscan_plan */
5853  node->fs_relids = NULL;
5854  node->fs_base_relids = NULL;
5855  /* fsSystemCol will be filled in by create_foreignscan_plan */
5856  node->fsSystemCol = false;
5857 
5858  return node;
5859 }
@ CMD_SELECT
Definition: nodes.h:265
Oid checkAsUser
Definition: plannodes.h:712
CmdType operation
Definition: plannodes.h:710
Oid fs_server
Definition: plannodes.h:714
List * fdw_exprs
Definition: plannodes.h:715
bool fsSystemCol
Definition: plannodes.h:721
Bitmapset * fs_relids
Definition: plannodes.h:719
List * fdw_private
Definition: plannodes.h:716
Bitmapset * fs_base_relids
Definition: plannodes.h:720
Index resultRelation
Definition: plannodes.h:711
List * fdw_recheck_quals
Definition: plannodes.h:718
List * fdw_scan_tlist
Definition: plannodes.h:717
Index scanrelid
Definition: plannodes.h:389

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

6963 {
6964  Limit *node = makeNode(Limit);
6965  Plan *plan = &node->plan;
6966 
6967  plan->targetlist = lefttree->targetlist;
6968  plan->qual = NIL;
6969  plan->lefttree = lefttree;
6970  plan->righttree = NULL;
6971 
6972  node->limitOffset = limitOffset;
6973  node->limitCount = limitCount;
6974  node->limitOption = limitOption;
6975  node->uniqNumCols = uniqNumCols;
6976  node->uniqColIdx = uniqColIdx;
6977  node->uniqOperators = uniqOperators;
6978  node->uniqCollations = uniqCollations;
6979 
6980  return node;
6981 }
LimitOption limitOption
Definition: plannodes.h:1281
Plan plan
Definition: plannodes.h:1272
Node * limitCount
Definition: plannodes.h:1278
int uniqNumCols
Definition: plannodes.h:1284
Node * limitOffset
Definition: plannodes.h:1275

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

6416 {
6417  List *sub_tlist = lefttree->targetlist;
6418  ListCell *l;
6419  int numsortkeys;
6420  AttrNumber *sortColIdx;
6421  Oid *sortOperators;
6422  Oid *collations;
6423  bool *nullsFirst;
6424 
6425  /* Convert list-ish representation to arrays wanted by executor */
6426  numsortkeys = list_length(sortcls);
6427  sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
6428  sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
6429  collations = (Oid *) palloc(numsortkeys * sizeof(Oid));
6430  nullsFirst = (bool *) palloc(numsortkeys * sizeof(bool));
6431 
6432  numsortkeys = 0;
6433  foreach(l, sortcls)
6434  {
6435  SortGroupClause *sortcl = (SortGroupClause *) lfirst(l);
6436  TargetEntry *tle = get_sortgroupclause_tle(sortcl, sub_tlist);
6437 
6438  sortColIdx[numsortkeys] = tle->resno;
6439  sortOperators[numsortkeys] = sortcl->sortop;
6440  collations[numsortkeys] = exprCollation((Node *) tle->expr);
6441  nullsFirst[numsortkeys] = sortcl->nulls_first;
6442  numsortkeys++;
6443  }
6444 
6445  return make_sort(lefttree, numsortkeys,
6446  sortColIdx, sortOperators,
6447  collations, nullsFirst);
6448 }
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:6068
void * palloc(Size size)
Definition: mcxt.c:1316
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:816
unsigned int Oid
Definition: postgres_ext.h:31
AttrNumber resno
Definition: primnodes.h:2164
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 3169 of file initsplan.c.

3170 {
3171  List *newlist = NIL;
3172  ListCell *lc;
3173 
3174  foreach(lc, root->fkey_list)
3175  {
3176  ForeignKeyOptInfo *fkinfo = (ForeignKeyOptInfo *) lfirst(lc);
3177  RelOptInfo *con_rel;
3178  RelOptInfo *ref_rel;
3179  int colno;
3180 
3181  /*
3182  * Either relid might identify a rel that is in the query's rtable but
3183  * isn't referenced by the jointree, or has been removed by join
3184  * removal, so that it won't have a RelOptInfo. Hence don't use
3185  * find_base_rel() here. We can ignore such FKs.
3186  */
3187  if (fkinfo->con_relid >= root->simple_rel_array_size ||
3188  fkinfo->ref_relid >= root->simple_rel_array_size)
3189  continue; /* just paranoia */
3190  con_rel = root->simple_rel_array[fkinfo->con_relid];
3191  if (con_rel == NULL)
3192  continue;
3193  ref_rel = root->simple_rel_array[fkinfo->ref_relid];
3194  if (ref_rel == NULL)
3195  continue;
3196 
3197  /*
3198  * Ignore FK unless both rels are baserels. This gets rid of FKs that
3199  * link to inheritance child rels (otherrels).
3200  */
3201  if (con_rel->reloptkind != RELOPT_BASEREL ||
3202  ref_rel->reloptkind != RELOPT_BASEREL)
3203  continue;
3204 
3205  /*
3206  * Scan the columns and try to match them to eclasses and quals.
3207  *
3208  * Note: for simple inner joins, any match should be in an eclass.
3209  * "Loose" quals that syntactically match an FK equality must have
3210  * been rejected for EC status because they are outer-join quals or
3211  * similar. We can still consider them to match the FK.
3212  */
3213  for (colno = 0; colno < fkinfo->nkeys; colno++)
3214  {
3215  EquivalenceClass *ec;
3216  AttrNumber con_attno,
3217  ref_attno;
3218  Oid fpeqop;
3219  ListCell *lc2;
3220 
3221  ec = match_eclasses_to_foreign_key_col(root, fkinfo, colno);
3222  /* Don't bother looking for loose quals if we got an EC match */
3223  if (ec != NULL)
3224  {
3225  fkinfo->nmatched_ec++;
3226  if (ec->ec_has_const)
3227  fkinfo->nconst_ec++;
3228  continue;
3229  }
3230 
3231  /*
3232  * Scan joininfo list for relevant clauses. Either rel's joininfo
3233  * list would do equally well; we use con_rel's.
3234  */
3235  con_attno = fkinfo->conkey[colno];
3236  ref_attno = fkinfo->confkey[colno];
3237  fpeqop = InvalidOid; /* we'll look this up only if needed */
3238 
3239  foreach(lc2, con_rel->joininfo)
3240  {
3241  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc2);
3242  OpExpr *clause = (OpExpr *) rinfo->clause;
3243  Var *leftvar;
3244  Var *rightvar;
3245 
3246  /* Only binary OpExprs are useful for consideration */
3247  if (!IsA(clause, OpExpr) ||
3248  list_length(clause->args) != 2)
3249  continue;
3250  leftvar = (Var *) get_leftop((Expr *) clause);
3251  rightvar = (Var *) get_rightop((Expr *) clause);
3252 
3253  /* Operands must be Vars, possibly with RelabelType */
3254  while (leftvar && IsA(leftvar, RelabelType))
3255  leftvar = (Var *) ((RelabelType *) leftvar)->arg;
3256  if (!(leftvar && IsA(leftvar, Var)))
3257  continue;
3258  while (rightvar && IsA(rightvar, RelabelType))
3259  rightvar = (Var *) ((RelabelType *) rightvar)->arg;
3260  if (!(rightvar && IsA(rightvar, Var)))
3261  continue;
3262 
3263  /* Now try to match the vars to the current foreign key cols */
3264  if (fkinfo->ref_relid == leftvar->varno &&
3265  ref_attno == leftvar->varattno &&
3266  fkinfo->con_relid == rightvar->varno &&
3267  con_attno == rightvar->varattno)
3268  {
3269  /* Vars match, but is it the right operator? */
3270  if (clause->opno == fkinfo->conpfeqop[colno])
3271  {
3272  fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
3273  rinfo);
3274  fkinfo->nmatched_ri++;
3275  }
3276  }
3277  else if (fkinfo->ref_relid == rightvar->varno &&
3278  ref_attno == rightvar->varattno &&
3279  fkinfo->con_relid == leftvar->varno &&
3280  con_attno == leftvar->varattno)
3281  {
3282  /*
3283  * Reverse match, must check commutator operator. Look it
3284  * up if we didn't already. (In the worst case we might
3285  * do multiple lookups here, but that would require an FK
3286  * equality operator without commutator, which is
3287  * unlikely.)
3288  */
3289  if (!OidIsValid(fpeqop))
3290  fpeqop = get_commutator(fkinfo->conpfeqop[colno]);
3291  if (clause->opno == fpeqop)
3292  {
3293  fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
3294  rinfo);
3295  fkinfo->nmatched_ri++;
3296  }
3297  }
3298  }
3299  /* If we found any matching loose quals, count col as matched */
3300  if (fkinfo->rinfos[colno])
3301  fkinfo->nmatched_rcols++;
3302  }
3303 
3304  /*
3305  * Currently, we drop multicolumn FKs that aren't fully matched to the
3306  * query. Later we might figure out how to derive some sort of
3307  * estimate from them, in which case this test should be weakened to
3308  * "if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) > 0)".
3309  */
3310  if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) == fkinfo->nkeys)
3311  newlist = lappend(newlist, fkinfo);
3312  }
3313  /* Replace fkey_list, thereby discarding any useless entries */
3314  root->fkey_list = newlist;
3315 }
EquivalenceClass * match_eclasses_to_foreign_key_col(PlannerInfo *root, ForeignKeyOptInfo *fkinfo, int colno)
Definition: equivclass.c:2516
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
Oid get_commutator(Oid opno)
Definition: lsyscache.c:1509
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:1250
Oid opno
Definition: primnodes.h:788
List * args
Definition: primnodes.h:806
List * joininfo
Definition: pathnodes.h:981
Expr * clause
Definition: pathnodes.h:2552

References OpExpr::args, RestrictInfo::clause, ForeignKeyOptInfo::con_relid, EquivalenceClass::ec_has_const, 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 root.

Referenced by query_planner().

◆ materialize_finished_plan()

Plan* materialize_finished_plan ( Plan subplan)

Definition at line 6527 of file createplan.c.

6528 {
6529  Plan *matplan;
6530  Path matpath; /* dummy for result of cost_material */
6531  Cost initplan_cost;
6532  bool unsafe_initplans;
6533 
6534  matplan = (Plan *) make_material(subplan);
6535 
6536  /*
6537  * XXX horrid kluge: if there are any initPlans attached to the subplan,
6538  * move them up to the Material node, which is now effectively the top
6539  * plan node in its query level. This prevents failure in
6540  * SS_finalize_plan(), which see for comments.
6541  */
6542  matplan->initPlan = subplan->initPlan;
6543  subplan->initPlan = NIL;
6544 
6545  /* Move the initplans' cost delta, as well */
6547  &initplan_cost, &unsafe_initplans);
6548  subplan->startup_cost -= initplan_cost;
6549  subplan->total_cost -= initplan_cost;
6550 
6551  /* Set cost data */
6552  cost_material(&matpath,
6553  subplan->startup_cost,
6554  subplan->total_cost,
6555  subplan->plan_rows,
6556  subplan->plan_width);
6557  matplan->startup_cost = matpath.startup_cost + initplan_cost;
6558  matplan->total_cost = matpath.total_cost + initplan_cost;
6559  matplan->plan_rows = subplan->plan_rows;
6560  matplan->plan_width = subplan->plan_width;
6561  matplan->parallel_aware = false;
6562  matplan->parallel_safe = subplan->parallel_safe;
6563 
6564  return matplan;
6565 }
void cost_material(Path *path, Cost input_startup_cost, Cost input_total_cost, double tuples, int width)
Definition: costsize.c:2453
static Material * make_material(Plan *lefttree)
Definition: createplan.c:6505
double Cost
Definition: nodes.h:251
Cost startup_cost
Definition: pathnodes.h:1650
Cost total_cost
Definition: pathnodes.h:1651
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:2198

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 72 of file planagg.c.

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

2929 {
2930  RestrictInfo *restrictinfo;
2931  Node *clause;
2932  Relids relids;
2933  bool pseudoconstant = false;
2934 
2935  /*
2936  * Build the new clause. Copy to ensure it shares no substructure with
2937  * original (this is necessary in case there are subselects in there...)
2938  */
2939  clause = (Node *) make_opclause(opno,
2940  BOOLOID, /* opresulttype */
2941  false, /* opretset */
2942  copyObject(item1),
2943  copyObject(item2),
2944  InvalidOid,
2945  collation);
2946 
2947  /* If both constant, try to reduce to a boolean constant. */
2948  if (both_const)
2949  {
2950  clause = eval_const_expressions(root, clause);
2951 
2952  /* If we produced const TRUE, just drop the clause */
2953  if (clause && IsA(clause, Const))
2954  {
2955  Const *cclause = (Const *) clause;
2956 
2957  Assert(cclause->consttype == BOOLOID);
2958  if (!cclause->constisnull && DatumGetBool(cclause->constvalue))
2959  return NULL;
2960  }
2961  }
2962 
2963  /*
2964  * The rest of this is a very cut-down version of distribute_qual_to_rels.
2965  * We can skip most of the work therein, but there are a couple of special
2966  * cases we still have to handle.
2967  *
2968  * Retrieve all relids mentioned within the possibly-simplified clause.
2969  */
2970  relids = pull_varnos(root, clause);
2971  Assert(bms_is_subset(relids, qualscope));
2972 
2973  /*
2974  * If the clause is variable-free, our normal heuristic for pushing it
2975  * down to just the mentioned rels doesn't work, because there are none.
2976  * Apply it as a gating qual at the appropriate level (see comments for
2977  * get_join_domain_min_rels).
2978  */
2979  if (bms_is_empty(relids))
2980  {
2981  /* eval at join domain's safe level */
2982  relids = get_join_domain_min_rels(root, qualscope);
2983  /* mark as gating qual */
2984  pseudoconstant = true;
2985  /* tell createplan.c to check for gating quals */
2986  root->hasPseudoConstantQuals = true;
2987  }
2988 
2989  /*
2990  * Build the RestrictInfo node itself.
2991  */
2992  restrictinfo = make_restrictinfo(root,
2993  (Expr *) clause,
2994  true, /* is_pushed_down */
2995  false, /* !has_clone */
2996  false, /* !is_clone */
2997  pseudoconstant,
2998  security_level,
2999  relids,
3000  NULL, /* incompatible_relids */
3001  NULL); /* outer_relids */
3002 
3003  /*
3004  * If it's a join clause, add vars used in the clause to targetlists of
3005  * their relations, so that they will be emitted by the plan nodes that
3006  * scan those relations (else they won't be available at the join node!).
3007  *
3008  * Typically, we'd have already done this when the component expressions
3009  * were first seen by distribute_qual_to_rels; but it is possible that
3010  * some of the Vars could have missed having that done because they only
3011  * appeared in single-relation clauses originally. So do it here for
3012  * safety.
3013  */
3014  if (bms_membership(relids) == BMS_MULTIPLE)
3015  {
3016  List *vars = pull_var_clause(clause,
3020 
3021  add_vars_to_targetlist(root, vars, relids);
3022  list_free(vars);
3023  }
3024 
3025  /*
3026  * Check mergejoinability. This will usually succeed, since the op came
3027  * from an EquivalenceClass; but we could have reduced the original clause
3028  * to a constant.
3029  */
3030  check_mergejoinable(restrictinfo);
3031 
3032  /*
3033  * Note we don't do initialize_mergeclause_eclasses(); the caller can
3034  * handle that much more cheaply than we can. It's okay to call
3035  * distribute_restrictinfo_to_rels() before that happens.
3036  */
3037 
3038  /*
3039  * Push the new clause into all the appropriate restrictinfo lists.
3040  */
3041  distribute_restrictinfo_to_rels(root, restrictinfo);
3042 
3043  return restrictinfo;
3044 }
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:781
@ BMS_MULTIPLE
Definition: bitmapset.h:73
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2254
void distribute_restrictinfo_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2836
static Relids get_join_domain_min_rels(PlannerInfo *root, Relids domain_relids)
Definition: initsplan.c:3129
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
Oid consttype
Definition: primnodes.h:312
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(), InvalidOid, IsA, list_free(), make_opclause(), make_restrictinfo(), pull_var_clause(), pull_varnos(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, JoinTreeItem::qualscope, and root.

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

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

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 54 of file planmain.c.

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

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(), 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(), elog, ERROR, extract_restriction_or_clauses(), find_lateral_references(), find_placeholders_in_jointree(), fix_placeholder_input_needed_levels(), generate_base_implied_equalities(), is_parallel_safe(), IsA, linitial, list_length(), make_one_rel(), match_foreign_keys_to_quals(), NIL, parse(), reconsider_outer_join_clauses(), reduce_unique_semijoins(), RelOptInfo::reltarget, remove_useless_joins(), remove_useless_self_joins(), root, 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 998 of file analyzejoins.c.

999 {
1000  /* SRFs break distinctness except with DISTINCT, see below */
1001  if (query->hasTargetSRFs && query->distinctClause == NIL)
1002  return false;
1003 
1004  /* check for features we can prove distinctness with */
1005  if (query->distinctClause != NIL ||
1006  query->groupClause != NIL ||
1007  query->groupingSets != NIL ||
1008  query->hasAggs ||
1009  query->havingQual ||
1010  query->setOperations)
1011  return true;
1012 
1013  return false;
1014 }

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

3461 {
3462  /*
3463  * For performance reasons, we don't bother to track built-in functions;
3464  * we just assume they'll never change (or at least not in ways that'd
3465  * invalidate plans using them). For this purpose we can consider a
3466  * built-in function to be one with OID less than FirstUnpinnedObjectId.
3467  * Note that the OID generator guarantees never to generate such an OID
3468  * after startup, even at OID wraparound.
3469  */
3470  if (funcid >= (Oid) FirstUnpinnedObjectId)
3471  {
3472  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3473 
3474  /*
3475  * It would work to use any syscache on pg_proc, but the easiest is
3476  * PROCOID since we already have the function's OID at hand. Note
3477  * that plancache.c knows we use PROCOID.
3478  */
3479  inval_item->cacheId = PROCOID;
3480  inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
3481  ObjectIdGetDatum(funcid));
3482 
3483  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3484  }
3485 }
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
uint32 hashValue
Definition: plannodes.h:1573
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:113
#define FirstUnpinnedObjectId
Definition: transam.h:196

References PlanInvalItem::cacheId, FirstUnpinnedObjectId, GetSysCacheHashValue1, PlanInvalItem::hashValue, lappend(), makeNode, ObjectIdGetDatum(), and root.

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

3501 {
3502  /*
3503  * As in record_plan_function_dependency, ignore the possibility that
3504  * someone would change a built-in domain.
3505  */
3506  if (typid >= (Oid) FirstUnpinnedObjectId)
3507  {
3508  PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3509 
3510  /*
3511  * It would work to use any syscache on pg_type, but the easiest is
3512  * TYPEOID since we already have the type's OID at hand. Note that
3513  * plancache.c knows we use TYPEOID.
3514  */
3515  inval_item->cacheId = TYPEOID;
3516  inval_item->hashValue = GetSysCacheHashValue1(TYPEOID,
3517  ObjectIdGetDatum(typid));
3518 
3519  root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3520  }
3521 }

References PlanInvalItem::cacheId, FirstUnpinnedObjectId, GetSysCacheHashValue1, PlanInvalItem::hashValue, lappend(), makeNode, ObjectIdGetDatum(), and root.

Referenced by eval_const_expressions_mutator().

◆ reduce_unique_semijoins()

void reduce_unique_semijoins ( PlannerInfo root)

Definition at line 764 of file analyzejoins.c.

765 {
766  ListCell *lc;
767 
768  /*
769  * Scan the join_info_list to find semijoins.
770  */
771  foreach(lc, root->join_info_list)
772  {
773  SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
774  int innerrelid;
775  RelOptInfo *innerrel;
776  Relids joinrelids;
777  List *restrictlist;
778 
779  /*
780  * Must be a semijoin to a single baserel, else we aren't going to be
781  * able to do anything with it.
782  */
783  if (sjinfo->jointype != JOIN_SEMI)
784  continue;
785 
786  if (!bms_get_singleton_member(sjinfo->min_righthand, &innerrelid))
787  continue;
788 
789  innerrel = find_base_rel(root, innerrelid);
790 
791  /*
792  * Before we trouble to run generate_join_implied_equalities, make a
793  * quick check to eliminate cases in which we will surely be unable to
794  * prove uniqueness of the innerrel.
795  */
796  if (!rel_supports_distinctness(root, innerrel))
797  continue;
798 
799  /* Compute the relid set for the join we are considering */
800  joinrelids = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
801  Assert(sjinfo->ojrelid == 0); /* SEMI joins don't have RT indexes */
802 
803  /*
804  * Since we're only considering a single-rel RHS, any join clauses it
805  * has must be clauses linking it to the semijoin's min_lefthand. We
806  * can also consider EC-derived join clauses.
807  */
808  restrictlist =
810  joinrelids,
811  sjinfo->min_lefthand,
812  innerrel,
813  NULL),
814  innerrel->joininfo);
815 
816  /* Test whether the innerrel is unique for those clauses. */
818  joinrelids, sjinfo->min_lefthand, innerrel,
819  JOIN_SEMI, restrictlist, true))
820  continue;
821 
822  /* OK, remove the SpecialJoinInfo from the list. */
823  root->join_info_list = foreach_delete_current(root->join_info_list, lc);
824  }
825 }
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:1392
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
@ JOIN_SEMI
Definition: nodes.h:307
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
Relids min_righthand
Definition: pathnodes.h:2883
JoinType jointype
Definition: pathnodes.h:2886
Relids min_lefthand
Definition: pathnodes.h:2882

References Assert, bms_get_singleton_member(), bms_union(), find_base_rel(), foreach_delete_current, generate_join_implied_equalities(), innerrel_is_unique(), JOIN_SEMI, RelOptInfo::joininfo, SpecialJoinInfo::jointype, lfirst, list_concat(), SpecialJoinInfo::min_lefthand, SpecialJoinInfo::min_righthand, SpecialJoinInfo::ojrelid, rel_supports_distinctness(), and root.

Referenced by query_planner().

◆ remove_useless_joins()

List* remove_useless_joins ( PlannerInfo root,
List joinlist 
)

Definition at line 81 of file analyzejoins.c.

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

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

Referenced by query_planner().

◆ remove_useless_self_joins()

List* remove_useless_self_joins ( PlannerInfo root,
List jointree 
)

Definition at line 2453 of file analyzejoins.c.

2454 {
2455  Relids toRemove = NULL;
2456  int relid = -1;
2457 
2458  if (!enable_self_join_removal || joinlist == NIL ||
2459  (list_length(joinlist) == 1 && !IsA(linitial(joinlist), List)))
2460  return joinlist;
2461 
2462  /*
2463  * Merge pairs of relations participated in self-join. Remove unnecessary
2464  * range table entries.
2465  */
2466  toRemove = remove_self_joins_recurse(root, joinlist, toRemove);
2467 
2468  if (unlikely(toRemove != NULL))
2469  {
2470  int nremoved = 0;
2471 
2472  /* At the end, remove orphaned relation links */
2473  while ((relid = bms_next_member(toRemove, relid)) >= 0)
2474  joinlist = remove_rel_from_joinlist(joinlist, relid, &nremoved);
2475  }
2476 
2477  return joinlist;
2478 }
bool enable_self_join_removal
Definition: analyzejoins.c:44
static Relids remove_self_joins_recurse(PlannerInfo *root, List *joinlist, Relids toRemove)
#define unlikely(x)
Definition: c.h:311

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

Referenced by query_planner().

◆ restriction_is_always_false()

bool restriction_is_always_false ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 2781 of file initsplan.c.

2783 {
2784  /* Check for NullTest qual */
2785  if (IsA(restrictinfo->clause, NullTest))
2786  {
2787  NullTest *nulltest = (NullTest *) restrictinfo->clause;
2788 
2789  /* is this NullTest an IS_NULL qual? */
2790  if (nulltest->nulltesttype != IS_NULL)
2791  return false;
2792 
2793  return expr_is_nonnullable(root, nulltest->arg);
2794  }
2795 
2796  /* If it's an OR, check its sub-clauses */
2797  if (restriction_is_or_clause(restrictinfo))
2798  {
2799  ListCell *lc;
2800 
2801  Assert(is_orclause(restrictinfo->orclause));
2802 
2803  /*
2804  * Currently, when processing OR expressions, we only return true when
2805  * all of the OR branches are always false. This could perhaps be
2806  * expanded to remove OR branches that are provably false. This may
2807  * be a useful thing to do as it could result in the OR being left
2808  * with a single arg. That's useful as it would allow the OR
2809  * condition to be replaced with its single argument which may allow
2810  * use of an index for faster filtering on the remaining condition.
2811  */
2812  foreach(lc, ((BoolExpr *) restrictinfo->orclause)->args)
2813  {
2814  Node *orarg = (Node *) lfirst(lc);
2815 
2816  if (!IsA(orarg, RestrictInfo) ||
2818  return false;
2819  }
2820  return true;
2821  }
2822 
2823  return false;
2824 }
bool restriction_is_always_false(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2781
static bool expr_is_nonnullable(PlannerInfo *root, Expr *expr)
Definition: initsplan.c:2696
static bool is_orclause(const void *clause)
Definition: nodeFuncs.h:114
@ IS_NULL
Definition: primnodes.h:1924
bool restriction_is_or_clause(RestrictInfo *restrictinfo)
Definition: restrictinfo.c:416
NullTestType nulltesttype
Definition: primnodes.h:1931
Expr * arg
Definition: primnodes.h:1930

References NullTest::arg, Assert, RestrictInfo::clause, expr_is_nonnullable(), if(), IS_NULL, is_orclause(), IsA, lfirst, NullTest::nulltesttype, restriction_is_or_clause(), and root.

Referenced by add_base_clause_to_rel(), add_join_clause_to_rels(), and apply_child_basequals().

◆ restriction_is_always_true()

bool restriction_is_always_true ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 2732 of file initsplan.c.

2734 {
2735  /* Check for NullTest qual */
2736  if (IsA(restrictinfo->clause, NullTest))
2737  {
2738  NullTest *nulltest = (NullTest *) restrictinfo->clause;
2739 
2740  /* is this NullTest an IS_NOT_NULL qual? */
2741  if (nulltest->nulltesttype != IS_NOT_NULL)
2742  return false;
2743 
2744  return expr_is_nonnullable(root, nulltest->arg);
2745  }
2746 
2747  /* If it's an OR, check its sub-clauses */
2748  if (restriction_is_or_clause(restrictinfo))
2749  {
2750  ListCell *lc;
2751 
2752  Assert(is_orclause(restrictinfo->orclause));
2753 
2754  /*
2755  * if any of the given OR branches is provably always true then the
2756  * entire condition is true.
2757  */
2758  foreach(lc, ((BoolExpr *) restrictinfo->orclause)->args)
2759  {
2760  Node *orarg = (Node *) lfirst(lc);
2761 
2762  if (!IsA(orarg, RestrictInfo))
2763  continue;
2764 
2766  return true;
2767  }
2768  }
2769 
2770  return false;
2771 }
bool restriction_is_always_true(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:2732
@ IS_NOT_NULL
Definition: primnodes.h:1924

References NullTest::arg, Assert, RestrictInfo::clause, expr_is_nonnullable(), if(), IS_NOT_NULL, is_orclause(), IsA, lfirst, NullTest::nulltesttype, restriction_is_or_clause(), and root.

Referenced by add_base_clause_to_rel(), add_join_clause_to_rels(), and apply_child_basequals().

◆ set_plan_references()

Plan* set_plan_references ( PlannerInfo root,
Plan plan 
)

Definition at line 287 of file setrefs.c.

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

References add_rtes_to_flat_rtable(), PlannerGlobal::appendRelations, AppendRelInfo::child_relid, PlannerGlobal::finalrowmarks, PlannerGlobal::finalrtable, foreach_current_index, lappend(), lfirst, lfirst_node, list_length(), NIL, palloc(), palloc0(), AppendRelInfo::parent_relid, plan, PlanRowMark::prti, root, 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 1464 of file setrefs.c.

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

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 66 of file planner.c.

Referenced by standard_planner().

◆ enable_self_join_removal

PGDLLIMPORT bool enable_self_join_removal
extern

Definition at line 44 of file analyzejoins.c.

Referenced by remove_useless_self_joins().

◆ from_collapse_limit

PGDLLIMPORT int from_collapse_limit
extern

Definition at line 38 of file initsplan.c.

Referenced by deconstruct_recurse().

◆ join_collapse_limit

PGDLLIMPORT int join_collapse_limit
extern

Definition at line 39 of file initsplan.c.

Referenced by deconstruct_recurse().