Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

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 add_vars_to_attr_needed (PlannerInfo *root, List *vars, Relids where_needed)
 
void remove_useless_groupby_columns (PlannerInfo *root)
 
void find_lateral_references (PlannerInfo *root)
 
void rebuild_lateral_attr_needed (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 rebuild_joinclause_attr_needed (PlannerInfo *root)
 
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 **extra_clauses)
 
Listremove_useless_self_joins (PlannerInfo *root, List *joinlist)
 
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_elimination
 
PGDLLIMPORT int from_collapse_limit
 
PGDLLIMPORT int join_collapse_limit
 

Macro Definition Documentation

◆ DEFAULT_CURSOR_TUPLE_FRACTION

#define DEFAULT_CURSOR_TUPLE_FRACTION   0.1

Definition at line 21 of file planmain.h.

Typedef Documentation

◆ query_pathkeys_callback

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

Definition at line 26 of file planmain.h.

Function Documentation

◆ add_base_rels_to_query()

void add_base_rels_to_query ( PlannerInfo root,
Node jtnode 
)

Definition at line 158 of file initsplan.c.

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

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

Referenced by add_base_rels_to_query(), and query_planner().

◆ add_other_rels_to_query()

void add_other_rels_to_query ( PlannerInfo root)

Definition at line 196 of file initsplan.c.

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

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

Referenced by query_planner().

◆ add_vars_to_attr_needed()

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

Definition at line 353 of file initsplan.c.

355{
356 ListCell *temp;
357
358 Assert(!bms_is_empty(where_needed));
359
360 foreach(temp, vars)
361 {
362 Node *node = (Node *) lfirst(temp);
363
364 if (IsA(node, Var))
365 {
366 Var *var = (Var *) node;
367 RelOptInfo *rel = find_base_rel(root, var->varno);
368 int attno = var->varattno;
369
370 if (bms_is_subset(where_needed, rel->relids))
371 continue;
372 Assert(attno >= rel->min_attr && attno <= rel->max_attr);
373 attno -= rel->min_attr;
374 rel->attr_needed[attno] = bms_add_members(rel->attr_needed[attno],
375 where_needed);
376 }
377 else if (IsA(node, PlaceHolderVar))
378 {
379 PlaceHolderVar *phv = (PlaceHolderVar *) node;
381
382 phinfo->ph_needed = bms_add_members(phinfo->ph_needed,
383 where_needed);
384 }
385 else
386 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
387 }
388}
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
Assert(PointerIsAligned(start, uint64))
PlaceHolderInfo * find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv)
Definition: placeholder.c:83
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:416
Definition: nodes.h:135
Relids ph_needed
Definition: pathnodes.h:3229
Relids relids
Definition: pathnodes.h:908
AttrNumber min_attr
Definition: pathnodes.h:960
Definition: primnodes.h:262
AttrNumber varattno
Definition: primnodes.h:274
int varno
Definition: primnodes.h:269
Definition: regcomp.c:282

References Assert(), bms_add_members(), bms_is_empty, bms_is_subset(), elog, ERROR, find_base_rel(), find_placeholder_info(), IsA, lfirst, RelOptInfo::min_attr, nodeTag, PlaceHolderInfo::ph_needed, RelOptInfo::relids, root, Var::varattno, and Var::varno.

Referenced by rebuild_eclass_attr_needed(), rebuild_joinclause_attr_needed(), rebuild_lateral_attr_needed(), and rebuild_placeholder_attr_needed().

◆ add_vars_to_targetlist()

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

Definition at line 282 of file initsplan.c.

284{
285 ListCell *temp;
286
287 Assert(!bms_is_empty(where_needed));
288
289 foreach(temp, vars)
290 {
291 Node *node = (Node *) lfirst(temp);
292
293 if (IsA(node, Var))
294 {
295 Var *var = (Var *) node;
296 RelOptInfo *rel = find_base_rel(root, var->varno);
297 int attno = var->varattno;
298
299 if (bms_is_subset(where_needed, rel->relids))
300 continue;
301 Assert(attno >= rel->min_attr && attno <= rel->max_attr);
302 attno -= rel->min_attr;
303 if (rel->attr_needed[attno] == NULL)
304 {
305 /*
306 * Variable not yet requested, so add to rel's targetlist.
307 *
308 * The value available at the rel's scan level has not been
309 * nulled by any outer join, so drop its varnullingrels.
310 * (We'll put those back as we climb up the join tree.)
311 */
312 var = copyObject(var);
313 var->varnullingrels = NULL;
314 rel->reltarget->exprs = lappend(rel->reltarget->exprs, var);
315 /* reltarget cost and width will be computed later */
316 }
317 rel->attr_needed[attno] = bms_add_members(rel->attr_needed[attno],
318 where_needed);
319 }
320 else if (IsA(node, PlaceHolderVar))
321 {
322 PlaceHolderVar *phv = (PlaceHolderVar *) node;
324
325 phinfo->ph_needed = bms_add_members(phinfo->ph_needed,
326 where_needed);
327 }
328 else
329 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
330 }
331}
List * lappend(List *list, void *datum)
Definition: list.c:339
#define copyObject(obj)
Definition: nodes.h:232
List * exprs
Definition: pathnodes.h:1691
struct PathTarget * reltarget
Definition: pathnodes.h:930

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

236{
237 List *tlist_vars = pull_var_clause((Node *) final_tlist,
241
242 if (tlist_vars != NIL)
243 {
245 list_free(tlist_vars);
246 }
247
248 /*
249 * If there's a HAVING clause, we'll need the Vars it uses, too. Note
250 * that HAVING can contain Aggrefs but not WindowFuncs.
251 */
252 if (root->parse->havingQual)
253 {
254 List *having_vars = pull_var_clause(root->parse->havingQual,
257
258 if (having_vars != NIL)
259 {
260 add_vars_to_targetlist(root, having_vars,
262 list_free(having_vars);
263 }
264 }
265}
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:282
void list_free(List *list)
Definition: list.c:1546
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:184
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:186
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:187
#define NIL
Definition: pg_list.h:68
Definition: pg_list.h:54
List * pull_var_clause(Node *node, int flags)
Definition: var.c:653

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

3443{
3444 RestrictInfo *restrictinfo;
3445 Expr *clause;
3446
3447 /*
3448 * Build the new clause. Copy to ensure it shares no substructure with
3449 * original (this is necessary in case there are subselects in there...)
3450 */
3451 clause = make_opclause(opno,
3452 BOOLOID, /* opresulttype */
3453 false, /* opretset */
3454 copyObject(item1),
3455 copyObject(item2),
3456 InvalidOid,
3457 collation);
3458
3459 /*
3460 * Build the RestrictInfo node itself.
3461 */
3462 restrictinfo = make_restrictinfo(root,
3463 clause,
3464 true, /* is_pushed_down */
3465 false, /* !has_clone */
3466 false, /* !is_clone */
3467 false, /* pseudoconstant */
3468 security_level, /* security_level */
3469 qualscope, /* required_relids */
3470 NULL, /* incompatible_relids */
3471 NULL); /* outer_relids */
3472
3473 /* Set mergejoinability/hashjoinability flags */
3474 check_mergejoinable(restrictinfo);
3475 check_hashjoinable(restrictinfo);
3476 check_memoizable(restrictinfo);
3477
3478 return restrictinfo;
3479}
static void check_hashjoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3813
static void check_mergejoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3776
static void check_memoizable(RestrictInfo *restrictinfo)
Definition: initsplan.c:3841
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: makefuncs.c:701
#define InvalidOid
Definition: postgres_ext.h:37
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:52

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

1993{
1994 /*
1995 * If the top plan node can't do projections and its existing target list
1996 * isn't already what we need, we need to add a Result node to help it
1997 * along.
1998 */
1999 if (!is_projection_capable_plan(subplan) &&
2000 !tlist_same_exprs(tlist, subplan->targetlist))
2001 subplan = inject_projection_plan(subplan, tlist,
2002 subplan->parallel_safe &&
2003 tlist_parallel_safe);
2004 else
2005 {
2006 /* Else we can just replace the plan node's tlist */
2007 subplan->targetlist = tlist;
2008 subplan->parallel_safe &= tlist_parallel_safe;
2009 }
2010 return subplan;
2011}
bool is_projection_capable_plan(Plan *plan)
Definition: createplan.c:7283
static Plan * inject_projection_plan(Plan *subplan, List *tlist, bool parallel_safe)
Definition: createplan.c:1960
bool parallel_safe
Definition: plannodes.h:206
List * targetlist
Definition: plannodes.h:220
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_nestloop_plan(), and postgresGetForeignPlan().

◆ create_lateral_join_info()

void create_lateral_join_info ( PlannerInfo root)

Definition at line 845 of file initsplan.c.

846{
847 bool found_laterals = false;
848 Index rti;
849 ListCell *lc;
850
851 /* We need do nothing if the query contains no LATERAL RTEs */
852 if (!root->hasLateralRTEs)
853 return;
854
855 /* We'll need to have the ph_eval_at values for PlaceHolderVars */
856 Assert(root->placeholdersFrozen);
857
858 /*
859 * Examine all baserels (the rel array has been set up by now).
860 */
861 for (rti = 1; rti < root->simple_rel_array_size; rti++)
862 {
863 RelOptInfo *brel = root->simple_rel_array[rti];
864 Relids lateral_relids;
865
866 /* there may be empty slots corresponding to non-baserel RTEs */
867 if (brel == NULL)
868 continue;
869
870 Assert(brel->relid == rti); /* sanity check on array */
871
872 /* ignore RTEs that are "other rels" */
873 if (brel->reloptkind != RELOPT_BASEREL)
874 continue;
875
876 lateral_relids = NULL;
877
878 /* consider each laterally-referenced Var or PHV */
879 foreach(lc, brel->lateral_vars)
880 {
881 Node *node = (Node *) lfirst(lc);
882
883 if (IsA(node, Var))
884 {
885 Var *var = (Var *) node;
886
887 found_laterals = true;
888 lateral_relids = bms_add_member(lateral_relids,
889 var->varno);
890 }
891 else if (IsA(node, PlaceHolderVar))
892 {
893 PlaceHolderVar *phv = (PlaceHolderVar *) node;
895
896 found_laterals = true;
897 lateral_relids = bms_add_members(lateral_relids,
898 phinfo->ph_eval_at);
899 }
900 else
901 Assert(false);
902 }
903
904 /* We now have all the simple lateral refs from this rel */
905 brel->direct_lateral_relids = lateral_relids;
906 brel->lateral_relids = bms_copy(lateral_relids);
907 }
908
909 /*
910 * Now check for lateral references within PlaceHolderVars, and mark their
911 * eval_at rels as having lateral references to the source rels.
912 *
913 * For a PHV that is due to be evaluated at a baserel, mark its source(s)
914 * as direct lateral dependencies of the baserel (adding onto the ones
915 * recorded above). If it's due to be evaluated at a join, mark its
916 * source(s) as indirect lateral dependencies of each baserel in the join,
917 * ie put them into lateral_relids but not direct_lateral_relids. This is
918 * appropriate because we can't put any such baserel on the outside of a
919 * join to one of the PHV's lateral dependencies, but on the other hand we
920 * also can't yet join it directly to the dependency.
921 */
922 foreach(lc, root->placeholder_list)
923 {
924 PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc);
925 Relids eval_at = phinfo->ph_eval_at;
926 Relids lateral_refs;
927 int varno;
928
929 if (phinfo->ph_lateral == NULL)
930 continue; /* PHV is uninteresting if no lateral refs */
931
932 found_laterals = true;
933
934 /*
935 * Include only baserels not outer joins in the evaluation sites'
936 * lateral relids. This avoids problems when outer join order gets
937 * rearranged, and it should still ensure that the lateral values are
938 * available when needed.
939 */
940 lateral_refs = bms_intersect(phinfo->ph_lateral, root->all_baserels);
941 Assert(!bms_is_empty(lateral_refs));
942
943 if (bms_get_singleton_member(eval_at, &varno))
944 {
945 /* Evaluation site is a baserel */
946 RelOptInfo *brel = find_base_rel(root, varno);
947
950 lateral_refs);
951 brel->lateral_relids =
953 lateral_refs);
954 }
955 else
956 {
957 /* Evaluation site is a join */
958 varno = -1;
959 while ((varno = bms_next_member(eval_at, varno)) >= 0)
960 {
962
963 if (brel == NULL)
964 continue; /* ignore outer joins in eval_at */
966 lateral_refs);
967 }
968 }
969 }
970
971 /*
972 * If we found no actual lateral references, we're done; but reset the
973 * hasLateralRTEs flag to avoid useless work later.
974 */
975 if (!found_laterals)
976 {
977 root->hasLateralRTEs = false;
978 return;
979 }
980
981 /*
982 * Calculate the transitive closure of the lateral_relids sets, so that
983 * they describe both direct and indirect lateral references. If relation
984 * X references Y laterally, and Y references Z laterally, then we will
985 * have to scan X on the inside of a nestloop with Z, so for all intents
986 * and purposes X is laterally dependent on Z too.
987 *
988 * This code is essentially Warshall's algorithm for transitive closure.
989 * The outer loop considers each baserel, and propagates its lateral
990 * dependencies to those baserels that have a lateral dependency on it.
991 */
992 for (rti = 1; rti < root->simple_rel_array_size; rti++)
993 {
994 RelOptInfo *brel = root->simple_rel_array[rti];
995 Relids outer_lateral_relids;
996 Index rti2;
997
998 if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
999 continue;
1000
1001 /* need not consider baserel further if it has no lateral refs */
1002 outer_lateral_relids = brel->lateral_relids;
1003 if (outer_lateral_relids == NULL)
1004 continue;
1005
1006 /* else scan all baserels */
1007 for (rti2 = 1; rti2 < root->simple_rel_array_size; rti2++)
1008 {
1009 RelOptInfo *brel2 = root->simple_rel_array[rti2];
1010
1011 if (brel2 == NULL || brel2->reloptkind != RELOPT_BASEREL)
1012 continue;
1013
1014 /* if brel2 has lateral ref to brel, propagate brel's refs */
1015 if (bms_is_member(rti, brel2->lateral_relids))
1017 outer_lateral_relids);
1018 }
1019 }
1020
1021 /*
1022 * Now that we've identified all lateral references, mark each baserel
1023 * with the set of relids of rels that reference it laterally (possibly
1024 * indirectly) --- that is, the inverse mapping of lateral_relids.
1025 */
1026 for (rti = 1; rti < root->simple_rel_array_size; rti++)
1027 {
1028 RelOptInfo *brel = root->simple_rel_array[rti];
1029 Relids lateral_relids;
1030 int rti2;
1031
1032 if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
1033 continue;
1034
1035 /* Nothing to do at rels with no lateral refs */
1036 lateral_relids = brel->lateral_relids;
1037 if (bms_is_empty(lateral_relids))
1038 continue;
1039
1040 /* No rel should have a lateral dependency on itself */
1041 Assert(!bms_is_member(rti, lateral_relids));
1042
1043 /* Mark this rel's referencees */
1044 rti2 = -1;
1045 while ((rti2 = bms_next_member(lateral_relids, rti2)) >= 0)
1046 {
1047 RelOptInfo *brel2 = root->simple_rel_array[rti2];
1048
1049 if (brel2 == NULL)
1050 continue; /* must be an OJ */
1051
1052 Assert(brel2->reloptkind == RELOPT_BASEREL);
1053 brel2->lateral_referencers =
1055 }
1056 }
1057}
Bitmapset * bms_intersect(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:292
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
bool bms_get_singleton_member(const Bitmapset *a, int *member)
Definition: bitmapset.c:715
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:122
unsigned int Index
Definition: c.h:619
RelOptInfo * find_base_rel_ignore_join(PlannerInfo *root, int relid)
Definition: relnode.c:456
Relids ph_lateral
Definition: pathnodes.h:3226
Relids ph_eval_at
Definition: pathnodes.h:3223
Index relid
Definition: pathnodes.h:954
List * lateral_vars
Definition: pathnodes.h:972
Relids lateral_relids
Definition: pathnodes.h:949
Relids lateral_referencers
Definition: pathnodes.h:974
Relids direct_lateral_relids
Definition: pathnodes.h:947

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

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

1085{
1086 List *result;
1087 JoinDomain *top_jdomain;
1088 List *item_list = NIL;
1089 ListCell *lc;
1090
1091 /*
1092 * After this point, no more PlaceHolderInfos may be made, because
1093 * make_outerjoininfo requires all active placeholders to be present in
1094 * root->placeholder_list while we crawl up the join tree.
1095 */
1096 root->placeholdersFrozen = true;
1097
1098 /* Fetch the already-created top-level join domain for the query */
1099 top_jdomain = linitial_node(JoinDomain, root->join_domains);
1100 top_jdomain->jd_relids = NULL; /* filled during deconstruct_recurse */
1101
1102 /* Start recursion at top of jointree */
1103 Assert(root->parse->jointree != NULL &&
1104 IsA(root->parse->jointree, FromExpr));
1105
1106 /* These are filled as we scan the jointree */
1107 root->all_baserels = NULL;
1108 root->outer_join_rels = NULL;
1109
1110 /* Perform the initial scan of the jointree */
1111 result = deconstruct_recurse(root, (Node *) root->parse->jointree,
1112 top_jdomain, NULL,
1113 &item_list);
1114
1115 /* Now we can form the value of all_query_rels, too */
1116 root->all_query_rels = bms_union(root->all_baserels, root->outer_join_rels);
1117
1118 /* ... which should match what we computed for the top join domain */
1119 Assert(bms_equal(root->all_query_rels, top_jdomain->jd_relids));
1120
1121 /* Now scan all the jointree nodes again, and distribute quals */
1122 foreach(lc, item_list)
1123 {
1124 JoinTreeItem *jtitem = (JoinTreeItem *) lfirst(lc);
1125
1127 }
1128
1129 /*
1130 * If there were any special joins then we may have some postponed LEFT
1131 * JOIN clauses to deal with.
1132 */
1133 if (root->join_info_list)
1134 {
1135 foreach(lc, item_list)
1136 {
1137 JoinTreeItem *jtitem = (JoinTreeItem *) lfirst(lc);
1138
1139 if (jtitem->oj_joinclauses != NIL)
1140 deconstruct_distribute_oj_quals(root, item_list, jtitem);
1141 }
1142 }
1143
1144 /* Don't need the JoinTreeItems any more */
1145 list_free_deep(item_list);
1146
1147 return result;
1148}
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:1166
static void deconstruct_distribute_oj_quals(PlannerInfo *root, List *jtitems, JoinTreeItem *jtitem)
Definition: initsplan.c:2226
static void deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem)
Definition: initsplan.c:1464
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:1380
List * oj_joinclauses
Definition: initsplan.c:78

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

3209{
3210 Relids relids = restrictinfo->required_relids;
3211
3212 if (!bms_is_empty(relids))
3213 {
3214 int relid;
3215
3216 if (bms_get_singleton_member(relids, &relid))
3217 {
3218 /*
3219 * There is only one relation participating in the clause, so it
3220 * is a restriction clause for that relation.
3221 */
3222 add_base_clause_to_rel(root, relid, restrictinfo);
3223 }
3224 else
3225 {
3226 /*
3227 * The clause is a join clause, since there is more than one rel
3228 * in its relid set.
3229 */
3230
3231 /*
3232 * Check for hashjoinable operators. (We don't bother setting the
3233 * hashjoin info except in true join clauses.)
3234 */
3235 check_hashjoinable(restrictinfo);
3236
3237 /*
3238 * Likewise, check if the clause is suitable to be used with a
3239 * Memoize node to cache inner tuples during a parameterized
3240 * nested loop.
3241 */
3242 check_memoizable(restrictinfo);
3243
3244 /*
3245 * Add clause to the join lists of all the relevant relations.
3246 */
3247 add_join_clause_to_rels(root, restrictinfo, relids);
3248 }
3249 }
3250 else
3251 {
3252 /*
3253 * clause references no rels, and therefore we have no place to attach
3254 * it. Shouldn't get here if callers are working properly.
3255 */
3256 elog(ERROR, "cannot cope with variable-free clause");
3257 }
3258}
static void add_base_clause_to_rel(PlannerInfo *root, Index relid, RestrictInfo *restrictinfo)
Definition: initsplan.c:2980
void add_join_clause_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo, Relids join_relids)
Definition: joininfo.c:98
Relids required_relids
Definition: pathnodes.h:2735

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 add_non_redundant_clauses(), distribute_qual_to_rels(), generate_base_implied_equalities_broken(), generate_base_implied_equalities_const(), process_implied_equality(), reconsider_outer_join_clauses(), and remove_leftjoinrel_from_query().

◆ extract_query_dependencies_walker()

bool extract_query_dependencies_walker ( Node node,
PlannerInfo context 
)

Definition at line 3673 of file setrefs.c.

3674{
3675 if (node == NULL)
3676 return false;
3677 Assert(!IsA(node, PlaceHolderVar));
3678 if (IsA(node, Query))
3679 {
3680 Query *query = (Query *) node;
3681 ListCell *lc;
3682
3683 if (query->commandType == CMD_UTILITY)
3684 {
3685 /*
3686 * This logic must handle any utility command for which parse
3687 * analysis was nontrivial (cf. stmt_requires_parse_analysis).
3688 *
3689 * Notably, CALL requires its own processing.
3690 */
3691 if (IsA(query->utilityStmt, CallStmt))
3692 {
3693 CallStmt *callstmt = (CallStmt *) query->utilityStmt;
3694
3695 /* We need not examine funccall, just the transformed exprs */
3696 (void) extract_query_dependencies_walker((Node *) callstmt->funcexpr,
3697 context);
3698 (void) extract_query_dependencies_walker((Node *) callstmt->outargs,
3699 context);
3700 return false;
3701 }
3702
3703 /*
3704 * Ignore other utility statements, except those (such as EXPLAIN)
3705 * that contain a parsed-but-not-planned query. For those, we
3706 * just need to transfer our attention to the contained query.
3707 */
3708 query = UtilityContainsQuery(query->utilityStmt);
3709 if (query == NULL)
3710 return false;
3711 }
3712
3713 /* Remember if any Query has RLS quals applied by rewriter */
3714 if (query->hasRowSecurity)
3715 context->glob->dependsOnRole = true;
3716
3717 /* Collect relation OIDs in this Query's rtable */
3718 foreach(lc, query->rtable)
3719 {
3720 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3721
3722 if (rte->rtekind == RTE_RELATION ||
3723 (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)) ||
3724 (rte->rtekind == RTE_NAMEDTUPLESTORE && OidIsValid(rte->relid)))
3725 context->glob->relationOids =
3726 lappend_oid(context->glob->relationOids, rte->relid);
3727 }
3728
3729 /* And recurse into the query's subexpressions */
3731 context, 0);
3732 }
3733 /* Extract function dependencies and check for regclass Consts */
3734 fix_expr_common(context, node);
3736 context);
3737}
#define OidIsValid(objectId)
Definition: c.h:774
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
#define query_tree_walker(q, w, c, f)
Definition: nodeFuncs.h:158
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:153
@ CMD_UTILITY
Definition: nodes.h:280
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1049
@ RTE_SUBQUERY
Definition: parsenodes.h:1043
@ RTE_RELATION
Definition: parsenodes.h:1042
static void fix_expr_common(PlannerInfo *root, Node *node)
Definition: setrefs.c:2032
bool extract_query_dependencies_walker(Node *node, PlannerInfo *context)
Definition: setrefs.c:3673
FuncExpr * funcexpr
Definition: parsenodes.h:3643
List * outargs
Definition: parsenodes.h:3645
bool dependsOnRole
Definition: pathnodes.h:169
List * relationOids
Definition: pathnodes.h:148
PlannerGlobal * glob
Definition: pathnodes.h:223
List * rtable
Definition: parsenodes.h:175
CmdType commandType
Definition: parsenodes.h:121
Node * utilityStmt
Definition: parsenodes.h:141
RTEKind rtekind
Definition: parsenodes.h:1077
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2171

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

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

◆ find_lateral_references()

void find_lateral_references ( PlannerInfo root)

Definition at line 658 of file initsplan.c.

659{
660 Index rti;
661
662 /* We need do nothing if the query contains no LATERAL RTEs */
663 if (!root->hasLateralRTEs)
664 return;
665
666 /*
667 * Examine all baserels (the rel array has been set up by now).
668 */
669 for (rti = 1; rti < root->simple_rel_array_size; rti++)
670 {
671 RelOptInfo *brel = root->simple_rel_array[rti];
672
673 /* there may be empty slots corresponding to non-baserel RTEs */
674 if (brel == NULL)
675 continue;
676
677 Assert(brel->relid == rti); /* sanity check on array */
678
679 /*
680 * This bit is less obvious than it might look. We ignore appendrel
681 * otherrels and consider only their parent baserels. In a case where
682 * a LATERAL-containing UNION ALL subquery was pulled up, it is the
683 * otherrel that is actually going to be in the plan. However, we
684 * want to mark all its lateral references as needed by the parent,
685 * because it is the parent's relid that will be used for join
686 * planning purposes. And the parent's RTE will contain all the
687 * lateral references we need to know, since the pulled-up member is
688 * nothing but a copy of parts of the original RTE's subquery. We
689 * could visit the parent's children instead and transform their
690 * references back to the parent's relid, but it would be much more
691 * complicated for no real gain. (Important here is that the child
692 * members have not yet received any processing beyond being pulled
693 * up.) Similarly, in appendrels created by inheritance expansion,
694 * it's sufficient to look at the parent relation.
695 */
696
697 /* ignore RTEs that are "other rels" */
698 if (brel->reloptkind != RELOPT_BASEREL)
699 continue;
700
702 }
703}
static void extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex)
Definition: initsplan.c:706

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

3524{
3525 if (root->minmax_aggs != NIL &&
3526 list_length(aggref->args) == 1)
3527 {
3528 TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
3529 ListCell *lc;
3530
3531 foreach(lc, root->minmax_aggs)
3532 {
3533 MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
3534
3535 if (mminfo->aggfnoid == aggref->aggfnoid &&
3536 equal(mminfo->target, curTarget->expr))
3537 return mminfo->param;
3538 }
3539 }
3540 return NULL;
3541}
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:463
List * args
Definition: primnodes.h:487
Param * param
Definition: pathnodes.h:3268
Expr * target
Definition: pathnodes.h:3253
Expr * expr
Definition: primnodes.h:2225

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

1312{
1313 return innerrel_is_unique_ext(root, joinrelids, outerrelids, innerrel,
1314 jointype, restrictlist, force_cache, NULL);
1315}
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 **  extra_clauses 
)

Definition at line 1327 of file analyzejoins.c.

1335{
1336 MemoryContext old_context;
1337 ListCell *lc;
1338 UniqueRelInfo *uniqueRelInfo;
1339 List *outer_exprs = NIL;
1340 bool self_join = (extra_clauses != NULL);
1341
1342 /* Certainly can't prove uniqueness when there are no joinclauses */
1343 if (restrictlist == NIL)
1344 return false;
1345
1346 /*
1347 * Make a quick check to eliminate cases in which we will surely be unable
1348 * to prove uniqueness of the innerrel.
1349 */
1350 if (!rel_supports_distinctness(root, innerrel))
1351 return false;
1352
1353 /*
1354 * Query the cache to see if we've managed to prove that innerrel is
1355 * unique for any subset of this outerrel. For non-self-join search, we
1356 * don't need an exact match, as extra outerrels can't make the innerrel
1357 * any less unique (or more formally, the restrictlist for a join to a
1358 * superset outerrel must be a superset of the conditions we successfully
1359 * used before). For self-join search, we require an exact match of
1360 * outerrels because we need extra clauses to be valid for our case. Also,
1361 * for self-join checking we've filtered the clauses list. Thus, we can
1362 * match only the result cached for a self-join search for another
1363 * self-join check.
1364 */
1365 foreach(lc, innerrel->unique_for_rels)
1366 {
1367 uniqueRelInfo = (UniqueRelInfo *) lfirst(lc);
1368
1369 if ((!self_join && bms_is_subset(uniqueRelInfo->outerrelids, outerrelids)) ||
1370 (self_join && bms_equal(uniqueRelInfo->outerrelids, outerrelids) &&
1371 uniqueRelInfo->self_join))
1372 {
1373 if (extra_clauses)
1374 *extra_clauses = uniqueRelInfo->extra_clauses;
1375 return true; /* Success! */
1376 }
1377 }
1378
1379 /*
1380 * Conversely, we may have already determined that this outerrel, or some
1381 * superset thereof, cannot prove this innerrel to be unique.
1382 */
1383 foreach(lc, innerrel->non_unique_for_rels)
1384 {
1385 Relids unique_for_rels = (Relids) lfirst(lc);
1386
1387 if (bms_is_subset(outerrelids, unique_for_rels))
1388 return false;
1389 }
1390
1391 /* No cached information, so try to make the proof. */
1392 if (is_innerrel_unique_for(root, joinrelids, outerrelids, innerrel,
1393 jointype, restrictlist,
1394 self_join ? &outer_exprs : NULL))
1395 {
1396 /*
1397 * Cache the positive result for future probes, being sure to keep it
1398 * in the planner_cxt even if we are working in GEQO.
1399 *
1400 * Note: one might consider trying to isolate the minimal subset of
1401 * the outerrels that proved the innerrel unique. But it's not worth
1402 * the trouble, because the planner builds up joinrels incrementally
1403 * and so we'll see the minimally sufficient outerrels before any
1404 * supersets of them anyway.
1405 */
1406 old_context = MemoryContextSwitchTo(root->planner_cxt);
1407 uniqueRelInfo = makeNode(UniqueRelInfo);
1408 uniqueRelInfo->outerrelids = bms_copy(outerrelids);
1409 uniqueRelInfo->self_join = self_join;
1410 uniqueRelInfo->extra_clauses = outer_exprs;
1411 innerrel->unique_for_rels = lappend(innerrel->unique_for_rels,
1412 uniqueRelInfo);
1413 MemoryContextSwitchTo(old_context);
1414
1415 if (extra_clauses)
1416 *extra_clauses = outer_exprs;
1417 return true; /* Success! */
1418 }
1419 else
1420 {
1421 /*
1422 * None of the join conditions for outerrel proved innerrel unique, so
1423 * we can safely reject this outerrel or any subset of it in future
1424 * checks.
1425 *
1426 * However, in normal planning mode, caching this knowledge is totally
1427 * pointless; it won't be queried again, because we build up joinrels
1428 * from smaller to larger. It is useful in GEQO mode, where the
1429 * knowledge can be carried across successive planning attempts; and
1430 * it's likely to be useful when using join-search plugins, too. Hence
1431 * cache when join_search_private is non-NULL. (Yeah, that's a hack,
1432 * but it seems reasonable.)
1433 *
1434 * Also, allow callers to override that heuristic and force caching;
1435 * that's useful for reduce_unique_semijoins, which calls here before
1436 * the normal join search starts.
1437 */
1438 if (force_cache || root->join_search_private)
1439 {
1440 old_context = MemoryContextSwitchTo(root->planner_cxt);
1441 innerrel->non_unique_for_rels =
1442 lappend(innerrel->non_unique_for_rels,
1443 bms_copy(outerrelids));
1444 MemoryContextSwitchTo(old_context);
1445 }
1446
1447 return false;
1448 }
1449}
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:920
#define makeNode(_type_)
Definition: nodes.h:161
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
Bitmapset * Relids
Definition: pathnodes.h:30
List * unique_for_rels
Definition: pathnodes.h:1009
List * non_unique_for_rels
Definition: pathnodes.h:1011
Relids outerrelids
Definition: pathnodes.h:3585
List * extra_clauses
Definition: pathnodes.h:3599

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

7234{
7235 /* Most plan types can project, so just list the ones that can't */
7236 switch (path->pathtype)
7237 {
7238 case T_Hash:
7239 case T_Material:
7240 case T_Memoize:
7241 case T_Sort:
7242 case T_IncrementalSort:
7243 case T_Unique:
7244 case T_SetOp:
7245 case T_LockRows:
7246 case T_Limit:
7247 case T_ModifyTable:
7248 case T_MergeAppend:
7249 case T_RecursiveUnion:
7250 return false;
7251 case T_CustomScan:
7253 return true;
7254 return false;
7255 case T_Append:
7256
7257 /*
7258 * Append can't project, but if an AppendPath is being used to
7259 * represent a dummy path, what will actually be generated is a
7260 * Result which can project.
7261 */
7262 return IS_DUMMY_APPEND(path);
7263 case T_ProjectSet:
7264
7265 /*
7266 * Although ProjectSet certainly projects, say "no" because we
7267 * don't want the planner to randomly replace its tlist with
7268 * something else; the SRFs have to stay at top level. This might
7269 * get relaxed later.
7270 */
7271 return false;
7272 default:
7273 break;
7274 }
7275 return true;
7276}
#define CUSTOMPATH_SUPPORT_PROJECTION
Definition: extensible.h:86
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
#define IS_DUMMY_APPEND(p)
Definition: pathnodes.h:2097
NodeTag pathtype
Definition: pathnodes.h:1784

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

7284{
7285 /* Most plan types can project, so just list the ones that can't */
7286 switch (nodeTag(plan))
7287 {
7288 case T_Hash:
7289 case T_Material:
7290 case T_Memoize:
7291 case T_Sort:
7292 case T_Unique:
7293 case T_SetOp:
7294 case T_LockRows:
7295 case T_Limit:
7296 case T_ModifyTable:
7297 case T_Append:
7298 case T_MergeAppend:
7299 case T_RecursiveUnion:
7300 return false;
7301 case T_CustomScan:
7303 return true;
7304 return false;
7305 case T_ProjectSet:
7306
7307 /*
7308 * Although ProjectSet certainly projects, say "no" because we
7309 * don't want the planner to randomly replace its tlist with
7310 * something else; the SRFs have to stay at top level. This might
7311 * get relaxed later.
7312 */
7313 return false;
7314 default:
7315 break;
7316 }
7317 return true;
7318}

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

6589{
6590 Agg *node = makeNode(Agg);
6591 Plan *plan = &node->plan;
6592 long numGroups;
6593
6594 /* Reduce to long, but 'ware overflow! */
6595 numGroups = clamp_cardinality_to_long(dNumGroups);
6596
6597 node->aggstrategy = aggstrategy;
6598 node->aggsplit = aggsplit;
6599 node->numCols = numGroupCols;
6600 node->grpColIdx = grpColIdx;
6601 node->grpOperators = grpOperators;
6602 node->grpCollations = grpCollations;
6603 node->numGroups = numGroups;
6604 node->transitionSpace = transitionSpace;
6605 node->aggParams = NULL; /* SS_finalize_plan() will fill this */
6606 node->groupingSets = groupingSets;
6607 node->chain = chain;
6608
6609 plan->qual = qual;
6610 plan->targetlist = tlist;
6611 plan->lefttree = lefttree;
6612 plan->righttree = NULL;
6613
6614 return node;
6615}
long clamp_cardinality_to_long(Cardinality x)
Definition: costsize.c:265
AggSplit aggsplit
Definition: plannodes.h:1189
List * chain
Definition: plannodes.h:1216
long numGroups
Definition: plannodes.h:1202
List * groupingSets
Definition: plannodes.h:1213
Bitmapset * aggParams
Definition: plannodes.h:1208
Plan plan
Definition: plannodes.h:1183
int numCols
Definition: plannodes.h:1192
uint64 transitionSpace
Definition: plannodes.h:1205
AggStrategy aggstrategy
Definition: plannodes.h:1186

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(), and create_groupingsets_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 5805 of file createplan.c.

5813{
5815 Plan *plan = &node->scan.plan;
5816
5817 /* cost will be filled in by create_foreignscan_plan */
5818 plan->targetlist = qptlist;
5819 plan->qual = qpqual;
5820 plan->lefttree = outer_plan;
5821 plan->righttree = NULL;
5822 node->scan.scanrelid = scanrelid;
5823
5824 /* these may be overridden by the FDW's PlanDirectModify callback. */
5825 node->operation = CMD_SELECT;
5826 node->resultRelation = 0;
5827
5828 /* checkAsUser, fs_server will be filled in by create_foreignscan_plan */
5829 node->checkAsUser = InvalidOid;
5830 node->fs_server = InvalidOid;
5831 node->fdw_exprs = fdw_exprs;
5832 node->fdw_private = fdw_private;
5833 node->fdw_scan_tlist = fdw_scan_tlist;
5834 node->fdw_recheck_quals = fdw_recheck_quals;
5835 /* fs_relids, fs_base_relids will be filled by create_foreignscan_plan */
5836 node->fs_relids = NULL;
5837 node->fs_base_relids = NULL;
5838 /* fsSystemCol will be filled in by create_foreignscan_plan */
5839 node->fsSystemCol = false;
5840
5841 return node;
5842}
@ CMD_SELECT
Definition: nodes.h:275
Oid checkAsUser
Definition: plannodes.h:870
CmdType operation
Definition: plannodes.h:866
Oid fs_server
Definition: plannodes.h:872
List * fdw_exprs
Definition: plannodes.h:874
bool fsSystemCol
Definition: plannodes.h:886
Bitmapset * fs_relids
Definition: plannodes.h:882
List * fdw_private
Definition: plannodes.h:876
Bitmapset * fs_base_relids
Definition: plannodes.h:884
Index resultRelation
Definition: plannodes.h:868
List * fdw_recheck_quals
Definition: plannodes.h:880
List * fdw_scan_tlist
Definition: plannodes.h:878
Index scanrelid
Definition: plannodes.h:516

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

6910{
6911 Limit *node = makeNode(Limit);
6912 Plan *plan = &node->plan;
6913
6914 plan->targetlist = lefttree->targetlist;
6915 plan->qual = NIL;
6916 plan->lefttree = lefttree;
6917 plan->righttree = NULL;
6918
6919 node->limitOffset = limitOffset;
6920 node->limitCount = limitCount;
6921 node->limitOption = limitOption;
6922 node->uniqNumCols = uniqNumCols;
6923 node->uniqColIdx = uniqColIdx;
6924 node->uniqOperators = uniqOperators;
6925 node->uniqCollations = uniqCollations;
6926
6927 return node;
6928}
LimitOption limitOption
Definition: plannodes.h:1481
Plan plan
Definition: plannodes.h:1472
Node * limitCount
Definition: plannodes.h:1478
int uniqNumCols
Definition: plannodes.h:1484
Node * limitOffset
Definition: plannodes.h:1475

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

6400{
6401 List *sub_tlist = lefttree->targetlist;
6402 ListCell *l;
6403 int numsortkeys;
6404 AttrNumber *sortColIdx;
6405 Oid *sortOperators;
6406 Oid *collations;
6407 bool *nullsFirst;
6408
6409 /* Convert list-ish representation to arrays wanted by executor */
6410 numsortkeys = list_length(sortcls);
6411 sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
6412 sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
6413 collations = (Oid *) palloc(numsortkeys * sizeof(Oid));
6414 nullsFirst = (bool *) palloc(numsortkeys * sizeof(bool));
6415
6416 numsortkeys = 0;
6417 foreach(l, sortcls)
6418 {
6419 SortGroupClause *sortcl = (SortGroupClause *) lfirst(l);
6420 TargetEntry *tle = get_sortgroupclause_tle(sortcl, sub_tlist);
6421
6422 sortColIdx[numsortkeys] = tle->resno;
6423 sortOperators[numsortkeys] = sortcl->sortop;
6424 collations[numsortkeys] = exprCollation((Node *) tle->expr);
6425 nullsFirst[numsortkeys] = sortcl->nulls_first;
6426 numsortkeys++;
6427 }
6428
6429 return make_sort(lefttree, numsortkeys,
6430 sortColIdx, sortOperators,
6431 collations, nullsFirst);
6432}
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:6051
void * palloc(Size size)
Definition: mcxt.c:1365
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:821
unsigned int Oid
Definition: postgres_ext.h:32
AttrNumber resno
Definition: primnodes.h:2227
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.

◆ match_foreign_keys_to_quals()

void match_foreign_keys_to_quals ( PlannerInfo root)

Definition at line 3611 of file initsplan.c.

3612{
3613 List *newlist = NIL;
3614 ListCell *lc;
3615
3616 foreach(lc, root->fkey_list)
3617 {
3618 ForeignKeyOptInfo *fkinfo = (ForeignKeyOptInfo *) lfirst(lc);
3619 RelOptInfo *con_rel;
3620 RelOptInfo *ref_rel;
3621 int colno;
3622
3623 /*
3624 * Either relid might identify a rel that is in the query's rtable but
3625 * isn't referenced by the jointree, or has been removed by join
3626 * removal, so that it won't have a RelOptInfo. Hence don't use
3627 * find_base_rel() here. We can ignore such FKs.
3628 */
3629 if (fkinfo->con_relid >= root->simple_rel_array_size ||
3630 fkinfo->ref_relid >= root->simple_rel_array_size)
3631 continue; /* just paranoia */
3632 con_rel = root->simple_rel_array[fkinfo->con_relid];
3633 if (con_rel == NULL)
3634 continue;
3635 ref_rel = root->simple_rel_array[fkinfo->ref_relid];
3636 if (ref_rel == NULL)
3637 continue;
3638
3639 /*
3640 * Ignore FK unless both rels are baserels. This gets rid of FKs that
3641 * link to inheritance child rels (otherrels).
3642 */
3643 if (con_rel->reloptkind != RELOPT_BASEREL ||
3644 ref_rel->reloptkind != RELOPT_BASEREL)
3645 continue;
3646
3647 /*
3648 * Scan the columns and try to match them to eclasses and quals.
3649 *
3650 * Note: for simple inner joins, any match should be in an eclass.
3651 * "Loose" quals that syntactically match an FK equality must have
3652 * been rejected for EC status because they are outer-join quals or
3653 * similar. We can still consider them to match the FK.
3654 */
3655 for (colno = 0; colno < fkinfo->nkeys; colno++)
3656 {
3657 EquivalenceClass *ec;
3658 AttrNumber con_attno,
3659 ref_attno;
3660 Oid fpeqop;
3661 ListCell *lc2;
3662
3663 ec = match_eclasses_to_foreign_key_col(root, fkinfo, colno);
3664 /* Don't bother looking for loose quals if we got an EC match */
3665 if (ec != NULL)
3666 {
3667 fkinfo->nmatched_ec++;
3668 if (ec->ec_has_const)
3669 fkinfo->nconst_ec++;
3670 continue;
3671 }
3672
3673 /*
3674 * Scan joininfo list for relevant clauses. Either rel's joininfo
3675 * list would do equally well; we use con_rel's.
3676 */
3677 con_attno = fkinfo->conkey[colno];
3678 ref_attno = fkinfo->confkey[colno];
3679 fpeqop = InvalidOid; /* we'll look this up only if needed */
3680
3681 foreach(lc2, con_rel->joininfo)
3682 {
3683 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc2);
3684 OpExpr *clause = (OpExpr *) rinfo->clause;
3685 Var *leftvar;
3686 Var *rightvar;
3687
3688 /* Only binary OpExprs are useful for consideration */
3689 if (!IsA(clause, OpExpr) ||
3690 list_length(clause->args) != 2)
3691 continue;
3692 leftvar = (Var *) get_leftop((Expr *) clause);
3693 rightvar = (Var *) get_rightop((Expr *) clause);
3694
3695 /* Operands must be Vars, possibly with RelabelType */
3696 while (leftvar && IsA(leftvar, RelabelType))
3697 leftvar = (Var *) ((RelabelType *) leftvar)->arg;
3698 if (!(leftvar && IsA(leftvar, Var)))
3699 continue;
3700 while (rightvar && IsA(rightvar, RelabelType))
3701 rightvar = (Var *) ((RelabelType *) rightvar)->arg;
3702 if (!(rightvar && IsA(rightvar, Var)))
3703 continue;
3704
3705 /* Now try to match the vars to the current foreign key cols */
3706 if (fkinfo->ref_relid == leftvar->varno &&
3707 ref_attno == leftvar->varattno &&
3708 fkinfo->con_relid == rightvar->varno &&
3709 con_attno == rightvar->varattno)
3710 {
3711 /* Vars match, but is it the right operator? */
3712 if (clause->opno == fkinfo->conpfeqop[colno])
3713 {
3714 fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
3715 rinfo);
3716 fkinfo->nmatched_ri++;
3717 }
3718 }
3719 else if (fkinfo->ref_relid == rightvar->varno &&
3720 ref_attno == rightvar->varattno &&
3721 fkinfo->con_relid == leftvar->varno &&
3722 con_attno == leftvar->varattno)
3723 {
3724 /*
3725 * Reverse match, must check commutator operator. Look it
3726 * up if we didn't already. (In the worst case we might
3727 * do multiple lookups here, but that would require an FK
3728 * equality operator without commutator, which is
3729 * unlikely.)
3730 */
3731 if (!OidIsValid(fpeqop))
3732 fpeqop = get_commutator(fkinfo->conpfeqop[colno]);
3733 if (clause->opno == fpeqop)
3734 {
3735 fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
3736 rinfo);
3737 fkinfo->nmatched_ri++;
3738 }
3739 }
3740 }
3741 /* If we found any matching loose quals, count col as matched */
3742 if (fkinfo->rinfos[colno])
3743 fkinfo->nmatched_rcols++;
3744 }
3745
3746 /*
3747 * Currently, we drop multicolumn FKs that aren't fully matched to the
3748 * query. Later we might figure out how to derive some sort of
3749 * estimate from them, in which case this test should be weakened to
3750 * "if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) > 0)".
3751 */
3752 if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) == fkinfo->nkeys)
3753 newlist = lappend(newlist, fkinfo);
3754 }
3755 /* Replace fkey_list, thereby discarding any useless entries */
3756 root->fkey_list = newlist;
3757}
EquivalenceClass * match_eclasses_to_foreign_key_col(PlannerInfo *root, ForeignKeyOptInfo *fkinfo, int colno)
Definition: equivclass.c:2710
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
Oid get_commutator(Oid opno)
Definition: lsyscache.c:1676
static Node * get_rightop(const void *clause)
Definition: nodeFuncs.h:95
static Node * get_leftop(const void *clause)
Definition: nodeFuncs.h:83
List * rinfos[INDEX_MAX_KEYS]
Definition: pathnodes.h:1313
Oid opno
Definition: primnodes.h:837
List * args
Definition: primnodes.h:855
List * joininfo
Definition: pathnodes.h:1033
Expr * clause
Definition: pathnodes.h:2704

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

6512{
6513 Plan *matplan;
6514 Path matpath; /* dummy for result of cost_material */
6515 Cost initplan_cost;
6516 bool unsafe_initplans;
6517
6518 matplan = (Plan *) make_material(subplan);
6519
6520 /*
6521 * XXX horrid kluge: if there are any initPlans attached to the subplan,
6522 * move them up to the Material node, which is now effectively the top
6523 * plan node in its query level. This prevents failure in
6524 * SS_finalize_plan(), which see for comments.
6525 */
6526 matplan->initPlan = subplan->initPlan;
6527 subplan->initPlan = NIL;
6528
6529 /* Move the initplans' cost delta, as well */
6531 &initplan_cost, &unsafe_initplans);
6532 subplan->startup_cost -= initplan_cost;
6533 subplan->total_cost -= initplan_cost;
6534
6535 /* Set cost data */
6536 cost_material(&matpath,
6537 subplan->disabled_nodes,
6538 subplan->startup_cost,
6539 subplan->total_cost,
6540 subplan->plan_rows,
6541 subplan->plan_width);
6542 matplan->disabled_nodes = subplan->disabled_nodes;
6543 matplan->startup_cost = matpath.startup_cost + initplan_cost;
6544 matplan->total_cost = matpath.total_cost + initplan_cost;
6545 matplan->plan_rows = subplan->plan_rows;
6546 matplan->plan_width = subplan->plan_width;
6547 matplan->parallel_aware = false;
6548 matplan->parallel_safe = subplan->parallel_safe;
6549
6550 return matplan;
6551}
void cost_material(Path *path, int input_disabled_nodes, Cost input_startup_cost, Cost input_total_cost, double tuples, int width)
Definition: costsize.c:2509
static Material * make_material(Plan *lefttree)
Definition: createplan.c:6489
double Cost
Definition: nodes.h:261
Cost startup_cost
Definition: pathnodes.h:1820
Cost total_cost
Definition: pathnodes.h:1821
Cost total_cost
Definition: plannodes.h:190
bool parallel_aware
Definition: plannodes.h:204
Cost startup_cost
Definition: plannodes.h:188
int plan_width
Definition: plannodes.h:198
Cardinality plan_rows
Definition: plannodes.h:196
int disabled_nodes
Definition: plannodes.h:186
List * initPlan
Definition: plannodes.h:227
void SS_compute_initplan_cost(List *init_plans, Cost *initplan_cost_p, bool *unsafe_initplans_p)
Definition: subselect.c:2346

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

Referenced by build_subplan(), and standard_planner().

◆ preprocess_minmax_aggregates()

void preprocess_minmax_aggregates ( PlannerInfo root)

Definition at line 73 of file planagg.c.

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

3300{
3301 RestrictInfo *restrictinfo;
3302 Node *clause;
3303 Relids relids;
3304 bool pseudoconstant = false;
3305
3306 /*
3307 * Build the new clause. Copy to ensure it shares no substructure with
3308 * original (this is necessary in case there are subselects in there...)
3309 */
3310 clause = (Node *) make_opclause(opno,
3311 BOOLOID, /* opresulttype */
3312 false, /* opretset */
3313 copyObject(item1),
3314 copyObject(item2),
3315 InvalidOid,
3316 collation);
3317
3318 /* If both constant, try to reduce to a boolean constant. */
3319 if (both_const)
3320 {
3321 clause = eval_const_expressions(root, clause);
3322
3323 /* If we produced const TRUE, just drop the clause */
3324 if (clause && IsA(clause, Const))
3325 {
3326 Const *cclause = (Const *) clause;
3327
3328 Assert(cclause->consttype == BOOLOID);
3329 if (!cclause->constisnull && DatumGetBool(cclause->constvalue))
3330 return NULL;
3331 }
3332 }
3333
3334 /*
3335 * The rest of this is a very cut-down version of distribute_qual_to_rels.
3336 * We can skip most of the work therein, but there are a couple of special
3337 * cases we still have to handle.
3338 *
3339 * Retrieve all relids mentioned within the possibly-simplified clause.
3340 */
3341 relids = pull_varnos(root, clause);
3342 Assert(bms_is_subset(relids, qualscope));
3343
3344 /*
3345 * If the clause is variable-free, our normal heuristic for pushing it
3346 * down to just the mentioned rels doesn't work, because there are none.
3347 * Apply it as a gating qual at the appropriate level (see comments for
3348 * get_join_domain_min_rels).
3349 */
3350 if (bms_is_empty(relids))
3351 {
3352 /* eval at join domain's safe level */
3353 relids = get_join_domain_min_rels(root, qualscope);
3354 /* mark as gating qual */
3355 pseudoconstant = true;
3356 /* tell createplan.c to check for gating quals */
3357 root->hasPseudoConstantQuals = true;
3358 }
3359
3360 /*
3361 * Build the RestrictInfo node itself.
3362 */
3363 restrictinfo = make_restrictinfo(root,
3364 (Expr *) clause,
3365 true, /* is_pushed_down */
3366 false, /* !has_clone */
3367 false, /* !is_clone */
3368 pseudoconstant,
3369 security_level,
3370 relids,
3371 NULL, /* incompatible_relids */
3372 NULL); /* outer_relids */
3373
3374 /*
3375 * If it's a join clause, add vars used in the clause to targetlists of
3376 * their relations, so that they will be emitted by the plan nodes that
3377 * scan those relations (else they won't be available at the join node!).
3378 *
3379 * Typically, we'd have already done this when the component expressions
3380 * were first seen by distribute_qual_to_rels; but it is possible that
3381 * some of the Vars could have missed having that done because they only
3382 * appeared in single-relation clauses originally. So do it here for
3383 * safety.
3384 *
3385 * See also rebuild_joinclause_attr_needed, which has to partially repeat
3386 * this work after removal of an outer join. (Since we will put this
3387 * clause into the joininfo lists, that function needn't do any extra work
3388 * to find it.)
3389 */
3390 if (bms_membership(relids) == BMS_MULTIPLE)
3391 {
3392 List *vars = pull_var_clause(clause,
3396
3398 list_free(vars);
3399 }
3400
3401 /*
3402 * Check mergejoinability. This will usually succeed, since the op came
3403 * from an EquivalenceClass; but we could have reduced the original clause
3404 * to a constant.
3405 */
3406 check_mergejoinable(restrictinfo);
3407
3408 /*
3409 * Note we don't do initialize_mergeclause_eclasses(); the caller can
3410 * handle that much more cheaply than we can. It's okay to call
3411 * distribute_restrictinfo_to_rels() before that happens.
3412 */
3413
3414 /*
3415 * Push the new clause into all the appropriate restrictinfo lists.
3416 */
3418
3419 return restrictinfo;
3420}
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:2262
void distribute_restrictinfo_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:3207
static Relids get_join_domain_min_rels(PlannerInfo *root, Relids domain_relids)
Definition: initsplan.c:3505
static bool DatumGetBool(Datum X)
Definition: postgres.h:100
Oid consttype
Definition: primnodes.h:329
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:114

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

1117{
1118 ListCell *l;
1119 Oid opid;
1120
1121 Assert(list_length(colnos) == list_length(opids));
1122
1123 /*
1124 * DISTINCT (including DISTINCT ON) guarantees uniqueness if all the
1125 * columns in the DISTINCT clause appear in colnos and operator semantics
1126 * match. This is true even if there are SRFs in the DISTINCT columns or
1127 * elsewhere in the tlist.
1128 */
1129 if (query->distinctClause)
1130 {
1131 foreach(l, query->distinctClause)
1132 {
1135 query->targetList);
1136
1137 opid = distinct_col_search(tle->resno, colnos, opids);
1138 if (!OidIsValid(opid) ||
1139 !equality_ops_are_compatible(opid, sgc->eqop))
1140 break; /* exit early if no match */
1141 }
1142 if (l == NULL) /* had matches for all? */
1143 return true;
1144 }
1145
1146 /*
1147 * Otherwise, a set-returning function in the query's targetlist can
1148 * result in returning duplicate rows, despite any grouping that might
1149 * occur before tlist evaluation. (If all tlist SRFs are within GROUP BY
1150 * columns, it would be safe because they'd be expanded before grouping.
1151 * But it doesn't currently seem worth the effort to check for that.)
1152 */
1153 if (query->hasTargetSRFs)
1154 return false;
1155
1156 /*
1157 * Similarly, GROUP BY without GROUPING SETS guarantees uniqueness if all
1158 * the grouped columns appear in colnos and operator semantics match.
1159 */
1160 if (query->groupClause && !query->groupingSets)
1161 {
1162 foreach(l, query->groupClause)
1163 {
1166 query->targetList);
1167
1168 opid = distinct_col_search(tle->resno, colnos, opids);
1169 if (!OidIsValid(opid) ||
1170 !equality_ops_are_compatible(opid, sgc->eqop))
1171 break; /* exit early if no match */
1172 }
1173 if (l == NULL) /* had matches for all? */
1174 return true;
1175 }
1176 else if (query->groupingSets)
1177 {
1178 /*
1179 * If we have grouping sets with expressions, we probably don't have
1180 * uniqueness and analysis would be hard. Punt.
1181 */
1182 if (query->groupClause)
1183 return false;
1184
1185 /*
1186 * If we have no groupClause (therefore no grouping expressions), we
1187 * might have one or many empty grouping sets. If there's just one,
1188 * then we're returning only one row and are certainly unique. But
1189 * otherwise, we know we're certainly not unique.
1190 */
1191 if (list_length(query->groupingSets) == 1 &&
1192 ((GroupingSet *) linitial(query->groupingSets))->kind == GROUPING_SET_EMPTY)
1193 return true;
1194 else
1195 return false;
1196 }
1197 else
1198 {
1199 /*
1200 * If we have no GROUP BY, but do have aggregates or HAVING, then the
1201 * result is at most one row so it's surely unique, for any operators.
1202 */
1203 if (query->hasAggs || query->havingQual)
1204 return true;
1205 }
1206
1207 /*
1208 * UNION, INTERSECT, EXCEPT guarantee uniqueness of the whole output row,
1209 * except with ALL.
1210 */
1211 if (query->setOperations)
1212 {
1214
1215 Assert(topop->op != SETOP_NONE);
1216
1217 if (!topop->all)
1218 {
1219 ListCell *lg;
1220
1221 /* We're good if all the nonjunk output columns are in colnos */
1222 lg = list_head(topop->groupClauses);
1223 foreach(l, query->targetList)
1224 {
1225 TargetEntry *tle = (TargetEntry *) lfirst(l);
1226 SortGroupClause *sgc;
1227
1228 if (tle->resjunk)
1229 continue; /* ignore resjunk columns */
1230
1231 /* non-resjunk columns should have grouping clauses */
1232 Assert(lg != NULL);
1233 sgc = (SortGroupClause *) lfirst(lg);
1234 lg = lnext(topop->groupClauses, lg);
1235
1236 opid = distinct_col_search(tle->resno, colnos, opids);
1237 if (!OidIsValid(opid) ||
1238 !equality_ops_are_compatible(opid, sgc->eqop))
1239 break; /* exit early if no match */
1240 }
1241 if (l == NULL) /* had matches for all? */
1242 return true;
1243 }
1244 }
1245
1246 /*
1247 * XXX Are there any other cases in which we can easily see the result
1248 * must be distinct?
1249 *
1250 * If you do add more smarts to this function, be sure to update
1251 * query_supports_distinctness() to match.
1252 */
1253
1254 return false;
1255}
static Oid distinct_col_search(int colno, List *colnos, List *opids)
bool equality_ops_are_compatible(Oid opno1, Oid opno2)
Definition: lsyscache.c:780
@ GROUPING_SET_EMPTY
Definition: parsenodes.h:1529
@ SETOP_NONE
Definition: parsenodes.h:2175
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:236
List * groupClause
Definition: parsenodes.h:216
Node * havingQual
Definition: parsenodes.h:222
List * targetList
Definition: parsenodes.h:198
List * groupingSets
Definition: parsenodes.h:220
List * distinctClause
Definition: parsenodes.h:226
SetOperation op
Definition: parsenodes.h:2254

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 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 *)
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 /* Remove any redundant GROUP BY columns */
174
175 /*
176 * Examine the targetlist and join tree, adding entries to baserel
177 * targetlists for all referenced Vars, and generating PlaceHolderInfo
178 * entries for all referenced PlaceHolderVars. Restrict and join clauses
179 * are added to appropriate lists belonging to the mentioned relations. We
180 * also build EquivalenceClasses for provably equivalent expressions. The
181 * SpecialJoinInfo list is also built to hold information about join order
182 * restrictions. Finally, we form a target joinlist for make_one_rel() to
183 * work from.
184 */
185 build_base_rel_tlists(root, root->processed_tlist);
186
188
190
191 joinlist = deconstruct_jointree(root);
192
193 /*
194 * Reconsider any postponed outer-join quals now that we have built up
195 * equivalence classes. (This could result in further additions or
196 * mergings of classes.)
197 */
199
200 /*
201 * If we formed any equivalence classes, generate additional restriction
202 * clauses as appropriate. (Implied join clauses are formed on-the-fly
203 * later.)
204 */
206
207 /*
208 * We have completed merging equivalence sets, so it's now possible to
209 * generate pathkeys in canonical form; so compute query_pathkeys and
210 * other pathkeys fields in PlannerInfo.
211 */
212 (*qp_callback) (root, qp_extra);
213
214 /*
215 * Examine any "placeholder" expressions generated during subquery pullup.
216 * Make sure that the Vars they need are marked as needed at the relevant
217 * join level. This must be done before join removal because it might
218 * cause Vars or placeholders to be needed above a join when they weren't
219 * so marked before.
220 */
222
223 /*
224 * Remove any useless outer joins. Ideally this would be done during
225 * jointree preprocessing, but the necessary information isn't available
226 * until we've built baserel data structures and classified qual clauses.
227 */
228 joinlist = remove_useless_joins(root, joinlist);
229
230 /*
231 * Also, reduce any semijoins with unique inner rels to plain inner joins.
232 * Likewise, this can't be done until now for lack of needed info.
233 */
235
236 /*
237 * Remove self joins on a unique column.
238 */
239 joinlist = remove_useless_self_joins(root, joinlist);
240
241 /*
242 * Now distribute "placeholders" to base rels as needed. This has to be
243 * done after join removal because removal could change whether a
244 * placeholder is evaluable at a base rel.
245 */
247
248 /*
249 * Construct the lateral reference sets now that we have finalized
250 * PlaceHolderVar eval levels.
251 */
253
254 /*
255 * Match foreign keys to equivalence classes and join quals. This must be
256 * done after finalizing equivalence classes, and it's useful to wait till
257 * after join removal so that we can skip processing foreign keys
258 * involving removed relations.
259 */
261
262 /*
263 * Look for join OR clauses that we can extract single-relation
264 * restriction OR clauses from.
265 */
267
268 /*
269 * Now expand appendrels by adding "otherrels" for their children. We
270 * delay this to the end so that we have as much information as possible
271 * available for each baserel, including all restriction clauses. That
272 * let us prune away partitions that don't satisfy a restriction clause.
273 * Also note that some information such as lateral_relids is propagated
274 * from baserels to otherrels here, so we must have computed it already.
275 */
277
278 /*
279 * Distribute any UPDATE/DELETE/MERGE row identity variables to the target
280 * relations. This can't be done till we've finished expansion of
281 * appendrels.
282 */
284
285 /*
286 * Ready to do the primary planning.
287 */
288 final_rel = make_one_rel(root, joinlist);
289
290 /* Check that we got at least one usable path */
291 if (!final_rel || !final_rel->cheapest_total_path ||
292 final_rel->cheapest_total_path->param_info != NULL)
293 elog(ERROR, "failed to construct the join relation");
294
295 return final_rel;
296}
RelOptInfo * make_one_rel(PlannerInfo *root, List *joinlist)
Definition: allpaths.c:171
List * remove_useless_joins(PlannerInfo *root, List *joinlist)
Definition: analyzejoins.c:90
List * remove_useless_self_joins(PlannerInfo *root, List *joinlist)
void reduce_unique_semijoins(PlannerInfo *root)
Definition: analyzejoins.c:844
void distribute_row_identity_vars(PlannerInfo *root)
Definition: appendinfo.c:985
bool is_parallel_safe(PlannerInfo *root, Node *node)
Definition: clauses.c:757
void generate_base_implied_equalities(PlannerInfo *root)
Definition: equivclass.c:1188
void reconsider_outer_join_clauses(PlannerInfo *root)
Definition: equivclass.c:2135
void match_foreign_keys_to_quals(PlannerInfo *root)
Definition: initsplan.c:3611
void find_lateral_references(PlannerInfo *root)
Definition: initsplan.c:658
void remove_useless_groupby_columns(PlannerInfo *root)
Definition: initsplan.c:412
void build_base_rel_tlists(PlannerInfo *root, List *final_tlist)
Definition: initsplan.c:235
List * deconstruct_jointree(PlannerInfo *root)
Definition: initsplan.c:1084
void add_other_rels_to_query(PlannerInfo *root)
Definition: initsplan.c:196
void create_lateral_join_info(PlannerInfo *root)
Definition: initsplan.c:845
@ DEBUG_PARALLEL_OFF
Definition: optimizer.h:95
void extract_restriction_or_clauses(PlannerInfo *root)
Definition: orclauses.c:75
@ RTE_RESULT
Definition: parsenodes.h:1050
void set_cheapest(RelOptInfo *parent_rel)
Definition: pathnode.c:268
GroupResultPath * create_group_result_path(PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *havingqual)
Definition: pathnode.c:1607
void add_placeholders_to_base_rels(PlannerInfo *root)
Definition: placeholder.c:356
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:69
void setup_simple_rel_arrays(PlannerInfo *root)
Definition: relnode.c:94
bool consider_parallel
Definition: pathnodes.h:924
struct Path * cheapest_total_path
Definition: pathnodes.h:939

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_groupby_columns(), 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 1078 of file analyzejoins.c.

1079{
1080 /* SRFs break distinctness except with DISTINCT, see below */
1081 if (query->hasTargetSRFs && query->distinctClause == NIL)
1082 return false;
1083
1084 /* check for features we can prove distinctness with */
1085 if (query->distinctClause != NIL ||
1086 query->groupClause != NIL ||
1087 query->groupingSets != NIL ||
1088 query->hasAggs ||
1089 query->havingQual ||
1090 query->setOperations)
1091 return true;
1092
1093 return false;
1094}

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

Referenced by rel_supports_distinctness().

◆ rebuild_joinclause_attr_needed()

void rebuild_joinclause_attr_needed ( PlannerInfo root)

Definition at line 3539 of file initsplan.c.

3540{
3541 /*
3542 * We must examine all join clauses, but there's no value in processing
3543 * any join clause more than once. So it's slightly annoying that we have
3544 * to find them via the per-base-relation joininfo lists. Avoid duplicate
3545 * processing by tracking the rinfo_serial numbers of join clauses we've
3546 * already seen. (This doesn't work for is_clone clauses, so we must
3547 * waste effort on them.)
3548 */
3549 Bitmapset *seen_serials = NULL;
3550 Index rti;
3551
3552 /* Scan all baserels for join clauses */
3553 for (rti = 1; rti < root->simple_rel_array_size; rti++)
3554 {
3555 RelOptInfo *brel = root->simple_rel_array[rti];
3556 ListCell *lc;
3557
3558 if (brel == NULL)
3559 continue;
3560 if (brel->reloptkind != RELOPT_BASEREL)
3561 continue;
3562
3563 foreach(lc, brel->joininfo)
3564 {
3565 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
3566 Relids relids = rinfo->required_relids;
3567
3568 if (!rinfo->is_clone) /* else serial number is not unique */
3569 {
3570 if (bms_is_member(rinfo->rinfo_serial, seen_serials))
3571 continue; /* saw it already */
3572 seen_serials = bms_add_member(seen_serials,
3573 rinfo->rinfo_serial);
3574 }
3575
3576 if (bms_membership(relids) == BMS_MULTIPLE)
3577 {
3578 List *vars = pull_var_clause((Node *) rinfo->clause,
3582 Relids where_needed;
3583
3584 if (rinfo->is_clone)
3585 where_needed = bms_intersect(relids, root->all_baserels);
3586 else
3587 where_needed = relids;
3588 add_vars_to_attr_needed(root, vars, where_needed);
3589 list_free(vars);
3590 }
3591 }
3592 }
3593}
void add_vars_to_attr_needed(PlannerInfo *root, List *vars, Relids where_needed)
Definition: initsplan.c:353
int rinfo_serial
Definition: pathnodes.h:2776

References add_vars_to_attr_needed(), bms_add_member(), bms_intersect(), bms_is_member(), bms_membership(), BMS_MULTIPLE, RestrictInfo::clause, RestrictInfo::is_clone, RelOptInfo::joininfo, lfirst, list_free(), pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, RELOPT_BASEREL, RelOptInfo::reloptkind, RestrictInfo::required_relids, RestrictInfo::rinfo_serial, and root.

Referenced by remove_leftjoinrel_from_query(), and remove_self_join_rel().

◆ rebuild_lateral_attr_needed()

void rebuild_lateral_attr_needed ( PlannerInfo root)

Definition at line 807 of file initsplan.c.

808{
809 Index rti;
810
811 /* We need do nothing if the query contains no LATERAL RTEs */
812 if (!root->hasLateralRTEs)
813 return;
814
815 /* Examine the same baserels that find_lateral_references did */
816 for (rti = 1; rti < root->simple_rel_array_size; rti++)
817 {
818 RelOptInfo *brel = root->simple_rel_array[rti];
819 Relids where_needed;
820
821 if (brel == NULL)
822 continue;
823 if (brel->reloptkind != RELOPT_BASEREL)
824 continue;
825
826 /*
827 * We don't need to repeat all of extract_lateral_references, since it
828 * kindly saved the extracted Vars/PHVs in lateral_vars.
829 */
830 if (brel->lateral_vars == NIL)
831 continue;
832
833 where_needed = bms_make_singleton(rti);
834
835 add_vars_to_attr_needed(root, brel->lateral_vars, where_needed);
836 }
837}

References add_vars_to_attr_needed(), bms_make_singleton(), RelOptInfo::lateral_vars, NIL, RELOPT_BASEREL, RelOptInfo::reloptkind, and root.

Referenced by remove_leftjoinrel_from_query(), and remove_self_join_rel().

◆ record_plan_function_dependency()

void record_plan_function_dependency ( PlannerInfo root,
Oid  funcid 
)

Definition at line 3556 of file setrefs.c.

3557{
3558 /*
3559 * For performance reasons, we don't bother to track built-in functions;
3560 * we just assume they'll never change (or at least not in ways that'd
3561 * invalidate plans using them). For this purpose we can consider a
3562 * built-in function to be one with OID less than FirstUnpinnedObjectId.
3563 * Note that the OID generator guarantees never to generate such an OID
3564 * after startup, even at OID wraparound.
3565 */
3566 if (funcid >= (Oid) FirstUnpinnedObjectId)
3567 {
3568 PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3569
3570 /*
3571 * It would work to use any syscache on pg_proc, but the easiest is
3572 * PROCOID since we already have the function's OID at hand. Note
3573 * that plancache.c knows we use PROCOID.
3574 */
3575 inval_item->cacheId = PROCOID;
3576 inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
3577 ObjectIdGetDatum(funcid));
3578
3579 root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3580 }
3581}
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
uint32 hashValue
Definition: plannodes.h:1797
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:118
#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 3596 of file setrefs.c.

3597{
3598 /*
3599 * As in record_plan_function_dependency, ignore the possibility that
3600 * someone would change a built-in domain.
3601 */
3602 if (typid >= (Oid) FirstUnpinnedObjectId)
3603 {
3604 PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3605
3606 /*
3607 * It would work to use any syscache on pg_type, but the easiest is
3608 * TYPEOID since we already have the type's OID at hand. Note that
3609 * plancache.c knows we use TYPEOID.
3610 */
3611 inval_item->cacheId = TYPEOID;
3612 inval_item->hashValue = GetSysCacheHashValue1(TYPEOID,
3613 ObjectIdGetDatum(typid));
3614
3615 root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3616 }
3617}

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

845{
846 ListCell *lc;
847
848 /*
849 * Scan the join_info_list to find semijoins.
850 */
851 foreach(lc, root->join_info_list)
852 {
853 SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
854 int innerrelid;
855 RelOptInfo *innerrel;
856 Relids joinrelids;
857 List *restrictlist;
858
859 /*
860 * Must be a semijoin to a single baserel, else we aren't going to be
861 * able to do anything with it.
862 */
863 if (sjinfo->jointype != JOIN_SEMI)
864 continue;
865
866 if (!bms_get_singleton_member(sjinfo->min_righthand, &innerrelid))
867 continue;
868
869 innerrel = find_base_rel(root, innerrelid);
870
871 /*
872 * Before we trouble to run generate_join_implied_equalities, make a
873 * quick check to eliminate cases in which we will surely be unable to
874 * prove uniqueness of the innerrel.
875 */
876 if (!rel_supports_distinctness(root, innerrel))
877 continue;
878
879 /* Compute the relid set for the join we are considering */
880 joinrelids = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
881 Assert(sjinfo->ojrelid == 0); /* SEMI joins don't have RT indexes */
882
883 /*
884 * Since we're only considering a single-rel RHS, any join clauses it
885 * has must be clauses linking it to the semijoin's min_lefthand. We
886 * can also consider EC-derived join clauses.
887 */
888 restrictlist =
890 joinrelids,
891 sjinfo->min_lefthand,
892 innerrel,
893 NULL),
894 innerrel->joininfo);
895
896 /* Test whether the innerrel is unique for those clauses. */
898 joinrelids, sjinfo->min_lefthand, innerrel,
899 JOIN_SEMI, restrictlist, true))
900 continue;
901
902 /* OK, remove the SpecialJoinInfo from the list. */
903 root->join_info_list = foreach_delete_current(root->join_info_list, lc);
904 }
905}
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:1550
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
@ JOIN_SEMI
Definition: nodes.h:317
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
Relids min_righthand
Definition: pathnodes.h:3030
JoinType jointype
Definition: pathnodes.h:3033
Relids min_lefthand
Definition: pathnodes.h:3029

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

void remove_useless_groupby_columns ( PlannerInfo root)

Definition at line 412 of file initsplan.c.

413{
414 Query *parse = root->parse;
415 Bitmapset **groupbyattnos;
416 Bitmapset **surplusvars;
417 bool tryremove = false;
418 ListCell *lc;
419 int relid;
420
421 /* No chance to do anything if there are less than two GROUP BY items */
422 if (list_length(root->processed_groupClause) < 2)
423 return;
424
425 /* Don't fiddle with the GROUP BY clause if the query has grouping sets */
426 if (parse->groupingSets)
427 return;
428
429 /*
430 * Scan the GROUP BY clause to find GROUP BY items that are simple Vars.
431 * Fill groupbyattnos[k] with a bitmapset of the column attnos of RTE k
432 * that are GROUP BY items.
433 */
434 groupbyattnos = (Bitmapset **) palloc0(sizeof(Bitmapset *) *
435 (list_length(parse->rtable) + 1));
436 foreach(lc, root->processed_groupClause)
437 {
439 TargetEntry *tle = get_sortgroupclause_tle(sgc, parse->targetList);
440 Var *var = (Var *) tle->expr;
441
442 /*
443 * Ignore non-Vars and Vars from other query levels.
444 *
445 * XXX in principle, stable expressions containing Vars could also be
446 * removed, if all the Vars are functionally dependent on other GROUP
447 * BY items. But it's not clear that such cases occur often enough to
448 * be worth troubling over.
449 */
450 if (!IsA(var, Var) ||
451 var->varlevelsup > 0)
452 continue;
453
454 /* OK, remember we have this Var */
455 relid = var->varno;
456 Assert(relid <= list_length(parse->rtable));
457
458 /*
459 * If this isn't the first column for this relation then we now have
460 * multiple columns. That means there might be some that can be
461 * removed.
462 */
463 tryremove |= !bms_is_empty(groupbyattnos[relid]);
464 groupbyattnos[relid] = bms_add_member(groupbyattnos[relid],
466 }
467
468 /*
469 * No Vars or didn't find multiple Vars for any relation in the GROUP BY?
470 * If so, nothing can be removed, so don't waste more effort trying.
471 */
472 if (!tryremove)
473 return;
474
475 /*
476 * Consider each relation and see if it is possible to remove some of its
477 * Vars from GROUP BY. For simplicity and speed, we do the actual removal
478 * in a separate pass. Here, we just fill surplusvars[k] with a bitmapset
479 * of the column attnos of RTE k that are removable GROUP BY items.
480 */
481 surplusvars = NULL; /* don't allocate array unless required */
482 relid = 0;
483 foreach(lc, parse->rtable)
484 {
486 RelOptInfo *rel;
487 Bitmapset *relattnos;
488 Bitmapset *best_keycolumns = NULL;
489 int32 best_nkeycolumns = PG_INT32_MAX;
490
491 relid++;
492
493 /* Only plain relations could have primary-key constraints */
494 if (rte->rtekind != RTE_RELATION)
495 continue;
496
497 /*
498 * We must skip inheritance parent tables as some of the child rels
499 * may cause duplicate rows. This cannot happen with partitioned
500 * tables, however.
501 */
502 if (rte->inh && rte->relkind != RELKIND_PARTITIONED_TABLE)
503 continue;
504
505 /* Nothing to do unless this rel has multiple Vars in GROUP BY */
506 relattnos = groupbyattnos[relid];
507 if (bms_membership(relattnos) != BMS_MULTIPLE)
508 continue;
509
510 rel = root->simple_rel_array[relid];
511
512 /*
513 * Now check each index for this relation to see if there are any with
514 * columns which are a proper subset of the grouping columns for this
515 * relation.
516 */
518 {
519 Bitmapset *ind_attnos;
520 bool nulls_check_ok;
521
522 /*
523 * Skip any non-unique and deferrable indexes. Predicate indexes
524 * have not been checked yet, so we must skip those too as the
525 * predOK check that's done later might fail.
526 */
527 if (!index->unique || !index->immediate || index->indpred != NIL)
528 continue;
529
530 /* For simplicity, we currently don't support expression indexes */
531 if (index->indexprs != NIL)
532 continue;
533
534 ind_attnos = NULL;
535 nulls_check_ok = true;
536 for (int i = 0; i < index->nkeycolumns; i++)
537 {
538 /*
539 * We must insist that the index columns are all defined NOT
540 * NULL otherwise duplicate NULLs could exist. However, we
541 * can relax this check when the index is defined with NULLS
542 * NOT DISTINCT as there can only be 1 NULL row, therefore
543 * functional dependency on the unique columns is maintained,
544 * despite the NULL.
545 */
546 if (!index->nullsnotdistinct &&
547 !bms_is_member(index->indexkeys[i],
548 rel->notnullattnums))
549 {
550 nulls_check_ok = false;
551 break;
552 }
553
554 ind_attnos =
555 bms_add_member(ind_attnos,
556 index->indexkeys[i] -
558 }
559
560 if (!nulls_check_ok)
561 continue;
562
563 /*
564 * Skip any indexes where the indexed columns aren't a proper
565 * subset of the GROUP BY.
566 */
567 if (bms_subset_compare(ind_attnos, relattnos) != BMS_SUBSET1)
568 continue;
569
570 /*
571 * Record the attribute numbers from the index with the fewest
572 * columns. This allows the largest number of columns to be
573 * removed from the GROUP BY clause. In the future, we may wish
574 * to consider using the narrowest set of columns and looking at
575 * pg_statistic.stawidth as it might be better to use an index
576 * with, say two INT4s, rather than, say, one long varlena column.
577 */
578 if (index->nkeycolumns < best_nkeycolumns)
579 {
580 best_keycolumns = ind_attnos;
581 best_nkeycolumns = index->nkeycolumns;
582 }
583 }
584
585 /* Did we find a suitable index? */
586 if (!bms_is_empty(best_keycolumns))
587 {
588 /*
589 * To easily remember whether we've found anything to do, we don't
590 * allocate the surplusvars[] array until we find something.
591 */
592 if (surplusvars == NULL)
593 surplusvars = (Bitmapset **) palloc0(sizeof(Bitmapset *) *
594 (list_length(parse->rtable) + 1));
595
596 /* Remember the attnos of the removable columns */
597 surplusvars[relid] = bms_difference(relattnos, best_keycolumns);
598 }
599 }
600
601 /*
602 * If we found any surplus Vars, build a new GROUP BY clause without them.
603 * (Note: this may leave some TLEs with unreferenced ressortgroupref
604 * markings, but that's harmless.)
605 */
606 if (surplusvars != NULL)
607 {
608 List *new_groupby = NIL;
609
610 foreach(lc, root->processed_groupClause)
611 {
613 TargetEntry *tle = get_sortgroupclause_tle(sgc, parse->targetList);
614 Var *var = (Var *) tle->expr;
615
616 /*
617 * New list must include non-Vars, outer Vars, and anything not
618 * marked as surplus.
619 */
620 if (!IsA(var, Var) ||
621 var->varlevelsup > 0 ||
623 surplusvars[var->varno]))
624 new_groupby = lappend(new_groupby, sgc);
625 }
626
627 root->processed_groupClause = new_groupby;
628 }
629}
Bitmapset * bms_difference(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:346
BMS_Comparison bms_subset_compare(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:445
@ BMS_SUBSET1
Definition: bitmapset.h:63
#define PG_INT32_MAX
Definition: c.h:594
int32_t int32
Definition: c.h:534
int i
Definition: isn.c:77
void * palloc0(Size size)
Definition: mcxt.c:1395
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define foreach_node(type, var, lst)
Definition: pg_list.h:496
Bitmapset * notnullattnums
Definition: pathnodes.h:968
List * indexlist
Definition: pathnodes.h:976
Index varlevelsup
Definition: primnodes.h:294
Definition: type.h:96
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27

References Assert(), bms_add_member(), bms_difference(), bms_is_empty, bms_is_member(), bms_membership(), BMS_MULTIPLE, BMS_SUBSET1, bms_subset_compare(), TargetEntry::expr, FirstLowInvalidHeapAttributeNumber, foreach_node, get_sortgroupclause_tle(), i, if(), RelOptInfo::indexlist, RangeTblEntry::inh, IsA, lappend(), lfirst_node, list_length(), NIL, RelOptInfo::notnullattnums, palloc0(), parse(), PG_INT32_MAX, root, RTE_RELATION, RangeTblEntry::rtekind, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by query_planner().

◆ remove_useless_joins()

List * remove_useless_joins ( PlannerInfo root,
List joinlist 
)

Definition at line 90 of file analyzejoins.c.

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

Definition at line 2487 of file analyzejoins.c.

2488{
2489 Relids toRemove = NULL;
2490 int relid = -1;
2491
2492 if (!enable_self_join_elimination || joinlist == NIL ||
2493 (list_length(joinlist) == 1 && !IsA(linitial(joinlist), List)))
2494 return joinlist;
2495
2496 /*
2497 * Merge pairs of relations participated in self-join. Remove unnecessary
2498 * range table entries.
2499 */
2500 toRemove = remove_self_joins_recurse(root, joinlist, toRemove);
2501
2502 if (unlikely(toRemove != NULL))
2503 {
2504 /* At the end, remove orphaned relation links */
2505 while ((relid = bms_next_member(toRemove, relid)) >= 0)
2506 {
2507 int nremoved = 0;
2508
2509 joinlist = remove_rel_from_joinlist(joinlist, relid, &nremoved);
2510 if (nremoved != 1)
2511 elog(ERROR, "failed to find relation %d in joinlist", relid);
2512 }
2513 }
2514
2515 return joinlist;
2516}
static Relids remove_self_joins_recurse(PlannerInfo *root, List *joinlist, Relids toRemove)
bool enable_self_join_elimination
Definition: analyzejoins.c:53
#define unlikely(x)
Definition: c.h:402

References bms_next_member(), elog, enable_self_join_elimination, ERROR, 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 3136 of file initsplan.c.

3138{
3139 /*
3140 * For a clone clause, we don't have a reliable way to determine if the
3141 * input expression of a NullTest is non-nullable: nullingrel bits in
3142 * clone clauses may not reflect reality, so we dare not draw conclusions
3143 * from clones about whether Vars are guaranteed not-null.
3144 */
3145 if (restrictinfo->has_clone || restrictinfo->is_clone)
3146 return false;
3147
3148 /* Check for NullTest qual */
3149 if (IsA(restrictinfo->clause, NullTest))
3150 {
3151 NullTest *nulltest = (NullTest *) restrictinfo->clause;
3152
3153 /* is this NullTest an IS_NULL qual? */
3154 if (nulltest->nulltesttype != IS_NULL)
3155 return false;
3156
3157 /*
3158 * Empty rows can appear NULL in some contexts and NOT NULL in others,
3159 * so avoid this optimization for row expressions.
3160 */
3161 if (nulltest->argisrow)
3162 return false;
3163
3164 return expr_is_nonnullable(root, nulltest->arg);
3165 }
3166
3167 /* If it's an OR, check its sub-clauses */
3168 if (restriction_is_or_clause(restrictinfo))
3169 {
3170 ListCell *lc;
3171
3172 Assert(is_orclause(restrictinfo->orclause));
3173
3174 /*
3175 * Currently, when processing OR expressions, we only return true when
3176 * all of the OR branches are always false. This could perhaps be
3177 * expanded to remove OR branches that are provably false. This may
3178 * be a useful thing to do as it could result in the OR being left
3179 * with a single arg. That's useful as it would allow the OR
3180 * condition to be replaced with its single argument which may allow
3181 * use of an index for faster filtering on the remaining condition.
3182 */
3183 foreach(lc, ((BoolExpr *) restrictinfo->orclause)->args)
3184 {
3185 Node *orarg = (Node *) lfirst(lc);
3186
3187 if (!IsA(orarg, RestrictInfo) ||
3189 return false;
3190 }
3191 return true;
3192 }
3193
3194 return false;
3195}
bool restriction_is_always_false(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:3136
static bool expr_is_nonnullable(PlannerInfo *root, Expr *expr)
Definition: initsplan.c:3054
static bool is_orclause(const void *clause)
Definition: nodeFuncs.h:116
@ IS_NULL
Definition: primnodes.h:1963
bool restriction_is_or_clause(RestrictInfo *restrictinfo)
Definition: restrictinfo.c:407
NullTestType nulltesttype
Definition: primnodes.h:1970
Expr * arg
Definition: primnodes.h:1969
bool has_clone
Definition: pathnodes.h:2716

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

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

◆ restriction_is_always_true()

bool restriction_is_always_true ( PlannerInfo root,
RestrictInfo restrictinfo 
)

Definition at line 3071 of file initsplan.c.

3073{
3074 /*
3075 * For a clone clause, we don't have a reliable way to determine if the
3076 * input expression of a NullTest is non-nullable: nullingrel bits in
3077 * clone clauses may not reflect reality, so we dare not draw conclusions
3078 * from clones about whether Vars are guaranteed not-null.
3079 */
3080 if (restrictinfo->has_clone || restrictinfo->is_clone)
3081 return false;
3082
3083 /* Check for NullTest qual */
3084 if (IsA(restrictinfo->clause, NullTest))
3085 {
3086 NullTest *nulltest = (NullTest *) restrictinfo->clause;
3087
3088 /* is this NullTest an IS_NOT_NULL qual? */
3089 if (nulltest->nulltesttype != IS_NOT_NULL)
3090 return false;
3091
3092 /*
3093 * Empty rows can appear NULL in some contexts and NOT NULL in others,
3094 * so avoid this optimization for row expressions.
3095 */
3096 if (nulltest->argisrow)
3097 return false;
3098
3099 return expr_is_nonnullable(root, nulltest->arg);
3100 }
3101
3102 /* If it's an OR, check its sub-clauses */
3103 if (restriction_is_or_clause(restrictinfo))
3104 {
3105 ListCell *lc;
3106
3107 Assert(is_orclause(restrictinfo->orclause));
3108
3109 /*
3110 * if any of the given OR branches is provably always true then the
3111 * entire condition is true.
3112 */
3113 foreach(lc, ((BoolExpr *) restrictinfo->orclause)->args)
3114 {
3115 Node *orarg = (Node *) lfirst(lc);
3116
3117 if (!IsA(orarg, RestrictInfo))
3118 continue;
3119
3121 return true;
3122 }
3123 }
3124
3125 return false;
3126}
bool restriction_is_always_true(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:3071
@ IS_NOT_NULL
Definition: primnodes.h:1963

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

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

◆ set_plan_references()

Plan * set_plan_references ( PlannerInfo root,
Plan plan 
)

Definition at line 288 of file setrefs.c.

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

References add_rtes_to_flat_rtable(), PlannerGlobal::appendRelations, Assert(), 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 1478 of file setrefs.c.

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

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

Referenced by standard_planner().

◆ enable_self_join_elimination

PGDLLIMPORT bool enable_self_join_elimination
extern

Definition at line 53 of file analyzejoins.c.

Referenced by remove_useless_self_joins().

◆ from_collapse_limit

PGDLLIMPORT int from_collapse_limit
extern

Definition at line 39 of file initsplan.c.

Referenced by deconstruct_recurse().

◆ join_collapse_limit

PGDLLIMPORT int join_collapse_limit
extern

Definition at line 40 of file initsplan.c.

Referenced by deconstruct_recurse().