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, Cardinality numGroups, 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 setup_eager_aggregation (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 165 of file initsplan.c.

166{
167 if (jtnode == NULL)
168 return;
169 if (IsA(jtnode, RangeTblRef))
170 {
171 int varno = ((RangeTblRef *) jtnode)->rtindex;
172
173 (void) build_simple_rel(root, varno, NULL);
174 }
175 else if (IsA(jtnode, FromExpr))
176 {
177 FromExpr *f = (FromExpr *) jtnode;
178 ListCell *l;
179
180 foreach(l, f->fromlist)
182 }
183 else if (IsA(jtnode, JoinExpr))
184 {
185 JoinExpr *j = (JoinExpr *) jtnode;
186
189 }
190 else
191 elog(ERROR, "unrecognized node type: %d",
192 (int) nodeTag(jtnode));
193}
#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:165
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:206
List * fromlist
Definition: primnodes.h:2357

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

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

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

362{
363 ListCell *temp;
364
365 Assert(!bms_is_empty(where_needed));
366
367 foreach(temp, vars)
368 {
369 Node *node = (Node *) lfirst(temp);
370
371 if (IsA(node, Var))
372 {
373 Var *var = (Var *) node;
374 RelOptInfo *rel = find_base_rel(root, var->varno);
375 int attno = var->varattno;
376
377 if (bms_is_subset(where_needed, rel->relids))
378 continue;
379 Assert(attno >= rel->min_attr && attno <= rel->max_attr);
380 attno -= rel->min_attr;
381 rel->attr_needed[attno] = bms_add_members(rel->attr_needed[attno],
382 where_needed);
383 }
384 else if (IsA(node, PlaceHolderVar))
385 {
386 PlaceHolderVar *phv = (PlaceHolderVar *) node;
388
389 phinfo->ph_needed = bms_add_members(phinfo->ph_needed,
390 where_needed);
391 }
392 else
393 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
394 }
395}
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:916
#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:529
Definition: nodes.h:135
Relids ph_needed
Definition: pathnodes.h:3317
Relids relids
Definition: pathnodes.h:927
AttrNumber min_attr
Definition: pathnodes.h:979
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 289 of file initsplan.c.

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

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

243{
244 List *tlist_vars = pull_var_clause((Node *) final_tlist,
248
249 if (tlist_vars != NIL)
250 {
252 list_free(tlist_vars);
253 }
254
255 /*
256 * If there's a HAVING clause, we'll need the Vars it uses, too. Note
257 * that HAVING can contain Aggrefs but not WindowFuncs.
258 */
259 if (root->parse->havingQual)
260 {
261 List *having_vars = pull_var_clause(root->parse->havingQual,
264
265 if (having_vars != NIL)
266 {
267 add_vars_to_targetlist(root, having_vars,
269 list_free(having_vars);
270 }
271 }
272}
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:289
void list_free(List *list)
Definition: list.c:1546
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:189
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:191
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:192
#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 3787 of file initsplan.c.

3794{
3795 RestrictInfo *restrictinfo;
3796 Expr *clause;
3797
3798 /*
3799 * Build the new clause. Copy to ensure it shares no substructure with
3800 * original (this is necessary in case there are subselects in there...)
3801 */
3802 clause = make_opclause(opno,
3803 BOOLOID, /* opresulttype */
3804 false, /* opretset */
3805 copyObject(item1),
3806 copyObject(item2),
3807 InvalidOid,
3808 collation);
3809
3810 /*
3811 * Build the RestrictInfo node itself.
3812 */
3813 restrictinfo = make_restrictinfo(root,
3814 clause,
3815 true, /* is_pushed_down */
3816 false, /* !has_clone */
3817 false, /* !is_clone */
3818 false, /* pseudoconstant */
3819 security_level, /* security_level */
3820 qualscope, /* required_relids */
3821 NULL, /* incompatible_relids */
3822 NULL); /* outer_relids */
3823
3824 /* Set mergejoinability/hashjoinability flags */
3825 check_mergejoinable(restrictinfo);
3826 check_hashjoinable(restrictinfo);
3827 check_memoizable(restrictinfo);
3828
3829 return restrictinfo;
3830}
static void check_hashjoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:4164
static void check_mergejoinable(RestrictInfo *restrictinfo)
Definition: initsplan.c:4127
static void check_memoizable(RestrictInfo *restrictinfo)
Definition: initsplan.c:4192
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 1991 of file createplan.c.

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

1213{
1214 bool found_laterals = false;
1215 Index rti;
1216 ListCell *lc;
1217
1218 /* We need do nothing if the query contains no LATERAL RTEs */
1219 if (!root->hasLateralRTEs)
1220 return;
1221
1222 /* We'll need to have the ph_eval_at values for PlaceHolderVars */
1223 Assert(root->placeholdersFrozen);
1224
1225 /*
1226 * Examine all baserels (the rel array has been set up by now).
1227 */
1228 for (rti = 1; rti < root->simple_rel_array_size; rti++)
1229 {
1230 RelOptInfo *brel = root->simple_rel_array[rti];
1231 Relids lateral_relids;
1232
1233 /* there may be empty slots corresponding to non-baserel RTEs */
1234 if (brel == NULL)
1235 continue;
1236
1237 Assert(brel->relid == rti); /* sanity check on array */
1238
1239 /* ignore RTEs that are "other rels" */
1240 if (brel->reloptkind != RELOPT_BASEREL)
1241 continue;
1242
1243 lateral_relids = NULL;
1244
1245 /* consider each laterally-referenced Var or PHV */
1246 foreach(lc, brel->lateral_vars)
1247 {
1248 Node *node = (Node *) lfirst(lc);
1249
1250 if (IsA(node, Var))
1251 {
1252 Var *var = (Var *) node;
1253
1254 found_laterals = true;
1255 lateral_relids = bms_add_member(lateral_relids,
1256 var->varno);
1257 }
1258 else if (IsA(node, PlaceHolderVar))
1259 {
1260 PlaceHolderVar *phv = (PlaceHolderVar *) node;
1262
1263 found_laterals = true;
1264 lateral_relids = bms_add_members(lateral_relids,
1265 phinfo->ph_eval_at);
1266 }
1267 else
1268 Assert(false);
1269 }
1270
1271 /* We now have all the simple lateral refs from this rel */
1272 brel->direct_lateral_relids = lateral_relids;
1273 brel->lateral_relids = bms_copy(lateral_relids);
1274 }
1275
1276 /*
1277 * Now check for lateral references within PlaceHolderVars, and mark their
1278 * eval_at rels as having lateral references to the source rels.
1279 *
1280 * For a PHV that is due to be evaluated at a baserel, mark its source(s)
1281 * as direct lateral dependencies of the baserel (adding onto the ones
1282 * recorded above). If it's due to be evaluated at a join, mark its
1283 * source(s) as indirect lateral dependencies of each baserel in the join,
1284 * ie put them into lateral_relids but not direct_lateral_relids. This is
1285 * appropriate because we can't put any such baserel on the outside of a
1286 * join to one of the PHV's lateral dependencies, but on the other hand we
1287 * also can't yet join it directly to the dependency.
1288 */
1289 foreach(lc, root->placeholder_list)
1290 {
1291 PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc);
1292 Relids eval_at = phinfo->ph_eval_at;
1293 Relids lateral_refs;
1294 int varno;
1295
1296 if (phinfo->ph_lateral == NULL)
1297 continue; /* PHV is uninteresting if no lateral refs */
1298
1299 found_laterals = true;
1300
1301 /*
1302 * Include only baserels not outer joins in the evaluation sites'
1303 * lateral relids. This avoids problems when outer join order gets
1304 * rearranged, and it should still ensure that the lateral values are
1305 * available when needed.
1306 */
1307 lateral_refs = bms_intersect(phinfo->ph_lateral, root->all_baserels);
1308 Assert(!bms_is_empty(lateral_refs));
1309
1310 if (bms_get_singleton_member(eval_at, &varno))
1311 {
1312 /* Evaluation site is a baserel */
1313 RelOptInfo *brel = find_base_rel(root, varno);
1314
1315 brel->direct_lateral_relids =
1317 lateral_refs);
1318 brel->lateral_relids =
1320 lateral_refs);
1321 }
1322 else
1323 {
1324 /* Evaluation site is a join */
1325 varno = -1;
1326 while ((varno = bms_next_member(eval_at, varno)) >= 0)
1327 {
1329
1330 if (brel == NULL)
1331 continue; /* ignore outer joins in eval_at */
1333 lateral_refs);
1334 }
1335 }
1336 }
1337
1338 /*
1339 * If we found no actual lateral references, we're done; but reset the
1340 * hasLateralRTEs flag to avoid useless work later.
1341 */
1342 if (!found_laterals)
1343 {
1344 root->hasLateralRTEs = false;
1345 return;
1346 }
1347
1348 /*
1349 * Calculate the transitive closure of the lateral_relids sets, so that
1350 * they describe both direct and indirect lateral references. If relation
1351 * X references Y laterally, and Y references Z laterally, then we will
1352 * have to scan X on the inside of a nestloop with Z, so for all intents
1353 * and purposes X is laterally dependent on Z too.
1354 *
1355 * This code is essentially Warshall's algorithm for transitive closure.
1356 * The outer loop considers each baserel, and propagates its lateral
1357 * dependencies to those baserels that have a lateral dependency on it.
1358 */
1359 for (rti = 1; rti < root->simple_rel_array_size; rti++)
1360 {
1361 RelOptInfo *brel = root->simple_rel_array[rti];
1362 Relids outer_lateral_relids;
1363 Index rti2;
1364
1365 if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
1366 continue;
1367
1368 /* need not consider baserel further if it has no lateral refs */
1369 outer_lateral_relids = brel->lateral_relids;
1370 if (outer_lateral_relids == NULL)
1371 continue;
1372
1373 /* else scan all baserels */
1374 for (rti2 = 1; rti2 < root->simple_rel_array_size; rti2++)
1375 {
1376 RelOptInfo *brel2 = root->simple_rel_array[rti2];
1377
1378 if (brel2 == NULL || brel2->reloptkind != RELOPT_BASEREL)
1379 continue;
1380
1381 /* if brel2 has lateral ref to brel, propagate brel's refs */
1382 if (bms_is_member(rti, brel2->lateral_relids))
1384 outer_lateral_relids);
1385 }
1386 }
1387
1388 /*
1389 * Now that we've identified all lateral references, mark each baserel
1390 * with the set of relids of rels that reference it laterally (possibly
1391 * indirectly) --- that is, the inverse mapping of lateral_relids.
1392 */
1393 for (rti = 1; rti < root->simple_rel_array_size; rti++)
1394 {
1395 RelOptInfo *brel = root->simple_rel_array[rti];
1396 Relids lateral_relids;
1397 int rti2;
1398
1399 if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
1400 continue;
1401
1402 /* Nothing to do at rels with no lateral refs */
1403 lateral_relids = brel->lateral_relids;
1404 if (bms_is_empty(lateral_relids))
1405 continue;
1406
1407 /* No rel should have a lateral dependency on itself */
1408 Assert(!bms_is_member(rti, lateral_relids));
1409
1410 /* Mark this rel's referencees */
1411 rti2 = -1;
1412 while ((rti2 = bms_next_member(lateral_relids, rti2)) >= 0)
1413 {
1414 RelOptInfo *brel2 = root->simple_rel_array[rti2];
1415
1416 if (brel2 == NULL)
1417 continue; /* must be an OJ */
1418
1419 Assert(brel2->reloptkind == RELOPT_BASEREL);
1420 brel2->lateral_referencers =
1422 }
1423 }
1424}
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:1305
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:814
bool bms_get_singleton_member(const Bitmapset *a, int *member)
Definition: bitmapset.c:714
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:122
unsigned int Index
Definition: c.h:633
RelOptInfo * find_base_rel_ignore_join(PlannerInfo *root, int relid)
Definition: relnode.c:569
Relids ph_lateral
Definition: pathnodes.h:3314
Relids ph_eval_at
Definition: pathnodes.h:3311
Index relid
Definition: pathnodes.h:973
List * lateral_vars
Definition: pathnodes.h:991
Relids lateral_relids
Definition: pathnodes.h:968
Relids lateral_referencers
Definition: pathnodes.h:993
Relids direct_lateral_relids
Definition: pathnodes.h:966

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

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

1452{
1453 List *result;
1454 JoinDomain *top_jdomain;
1455 List *item_list = NIL;
1456 ListCell *lc;
1457
1458 /*
1459 * After this point, no more PlaceHolderInfos may be made, because
1460 * make_outerjoininfo requires all active placeholders to be present in
1461 * root->placeholder_list while we crawl up the join tree.
1462 */
1463 root->placeholdersFrozen = true;
1464
1465 /* Fetch the already-created top-level join domain for the query */
1466 top_jdomain = linitial_node(JoinDomain, root->join_domains);
1467 top_jdomain->jd_relids = NULL; /* filled during deconstruct_recurse */
1468
1469 /* Start recursion at top of jointree */
1470 Assert(root->parse->jointree != NULL &&
1471 IsA(root->parse->jointree, FromExpr));
1472
1473 /* These are filled as we scan the jointree */
1474 root->all_baserels = NULL;
1475 root->outer_join_rels = NULL;
1476
1477 /* Perform the initial scan of the jointree */
1478 result = deconstruct_recurse(root, (Node *) root->parse->jointree,
1479 top_jdomain, NULL,
1480 &item_list);
1481
1482 /* Now we can form the value of all_query_rels, too */
1483 root->all_query_rels = bms_union(root->all_baserels, root->outer_join_rels);
1484
1485 /* ... which should match what we computed for the top join domain */
1486 Assert(bms_equal(root->all_query_rels, top_jdomain->jd_relids));
1487
1488 /* Now scan all the jointree nodes again, and distribute quals */
1489 foreach(lc, item_list)
1490 {
1491 JoinTreeItem *jtitem = (JoinTreeItem *) lfirst(lc);
1492
1494 }
1495
1496 /*
1497 * If there were any special joins then we may have some postponed LEFT
1498 * JOIN clauses to deal with.
1499 */
1500 if (root->join_info_list)
1501 {
1502 foreach(lc, item_list)
1503 {
1504 JoinTreeItem *jtitem = (JoinTreeItem *) lfirst(lc);
1505
1506 if (jtitem->oj_joinclauses != NIL)
1507 deconstruct_distribute_oj_quals(root, item_list, jtitem);
1508 }
1509 }
1510
1511 /* Don't need the JoinTreeItems any more */
1512 list_free_deep(item_list);
1513
1514 return result;
1515}
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:1533
static void deconstruct_distribute_oj_quals(PlannerInfo *root, List *jtitems, JoinTreeItem *jtitem)
Definition: initsplan.c:2593
static void deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem)
Definition: initsplan.c:1831
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:1469
List * oj_joinclauses
Definition: initsplan.c:79

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

3560{
3561 Relids relids = restrictinfo->required_relids;
3562
3563 if (!bms_is_empty(relids))
3564 {
3565 int relid;
3566
3567 if (bms_get_singleton_member(relids, &relid))
3568 {
3569 /*
3570 * There is only one relation participating in the clause, so it
3571 * is a restriction clause for that relation.
3572 */
3573 add_base_clause_to_rel(root, relid, restrictinfo);
3574 }
3575 else
3576 {
3577 /*
3578 * The clause is a join clause, since there is more than one rel
3579 * in its relid set.
3580 */
3581
3582 /*
3583 * Check for hashjoinable operators. (We don't bother setting the
3584 * hashjoin info except in true join clauses.)
3585 */
3586 check_hashjoinable(restrictinfo);
3587
3588 /*
3589 * Likewise, check if the clause is suitable to be used with a
3590 * Memoize node to cache inner tuples during a parameterized
3591 * nested loop.
3592 */
3593 check_memoizable(restrictinfo);
3594
3595 /*
3596 * Add clause to the join lists of all the relevant relations.
3597 */
3598 add_join_clause_to_rels(root, restrictinfo, relids);
3599 }
3600 }
3601 else
3602 {
3603 /*
3604 * clause references no rels, and therefore we have no place to attach
3605 * it. Shouldn't get here if callers are working properly.
3606 */
3607 elog(ERROR, "cannot cope with variable-free clause");
3608 }
3609}
static void add_base_clause_to_rel(PlannerInfo *root, Index relid, RestrictInfo *restrictinfo)
Definition: initsplan.c:3347
void add_join_clause_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo, Relids join_relids)
Definition: joininfo.c:98
Relids required_relids
Definition: pathnodes.h:2823

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

3693{
3694 if (node == NULL)
3695 return false;
3696 Assert(!IsA(node, PlaceHolderVar));
3697 if (IsA(node, Query))
3698 {
3699 Query *query = (Query *) node;
3700 ListCell *lc;
3701
3702 if (query->commandType == CMD_UTILITY)
3703 {
3704 /*
3705 * This logic must handle any utility command for which parse
3706 * analysis was nontrivial (cf. stmt_requires_parse_analysis).
3707 *
3708 * Notably, CALL requires its own processing.
3709 */
3710 if (IsA(query->utilityStmt, CallStmt))
3711 {
3712 CallStmt *callstmt = (CallStmt *) query->utilityStmt;
3713
3714 /* We need not examine funccall, just the transformed exprs */
3715 (void) extract_query_dependencies_walker((Node *) callstmt->funcexpr,
3716 context);
3717 (void) extract_query_dependencies_walker((Node *) callstmt->outargs,
3718 context);
3719 return false;
3720 }
3721
3722 /*
3723 * Ignore other utility statements, except those (such as EXPLAIN)
3724 * that contain a parsed-but-not-planned query. For those, we
3725 * just need to transfer our attention to the contained query.
3726 */
3727 query = UtilityContainsQuery(query->utilityStmt);
3728 if (query == NULL)
3729 return false;
3730 }
3731
3732 /* Remember if any Query has RLS quals applied by rewriter */
3733 if (query->hasRowSecurity)
3734 context->glob->dependsOnRole = true;
3735
3736 /* Collect relation OIDs in this Query's rtable */
3737 foreach(lc, query->rtable)
3738 {
3739 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3740
3741 if (rte->rtekind == RTE_RELATION ||
3742 (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)) ||
3743 (rte->rtekind == RTE_NAMEDTUPLESTORE && OidIsValid(rte->relid)))
3744 context->glob->relationOids =
3745 lappend_oid(context->glob->relationOids, rte->relid);
3746 }
3747
3748 /* And recurse into the query's subexpressions */
3750 context, 0);
3751 }
3752 /* Extract function dependencies and check for regclass Consts */
3753 fix_expr_common(context, node);
3755 context);
3756}
#define OidIsValid(objectId)
Definition: c.h:788
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:1050
@ RTE_SUBQUERY
Definition: parsenodes.h:1044
@ RTE_RELATION
Definition: parsenodes.h:1043
static void fix_expr_common(PlannerInfo *root, Node *node)
Definition: setrefs.c:2051
bool extract_query_dependencies_walker(Node *node, PlannerInfo *context)
Definition: setrefs.c:3692
FuncExpr * funcexpr
Definition: parsenodes.h:3644
List * outargs
Definition: parsenodes.h:3646
bool dependsOnRole
Definition: pathnodes.h:172
List * relationOids
Definition: pathnodes.h:151
PlannerGlobal * glob
Definition: pathnodes.h:230
List * rtable
Definition: parsenodes.h:175
CmdType commandType
Definition: parsenodes.h:121
Node * utilityStmt
Definition: parsenodes.h:141
RTEKind rtekind
Definition: parsenodes.h:1078
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2185

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

1026{
1027 Index rti;
1028
1029 /* We need do nothing if the query contains no LATERAL RTEs */
1030 if (!root->hasLateralRTEs)
1031 return;
1032
1033 /*
1034 * Examine all baserels (the rel array has been set up by now).
1035 */
1036 for (rti = 1; rti < root->simple_rel_array_size; rti++)
1037 {
1038 RelOptInfo *brel = root->simple_rel_array[rti];
1039
1040 /* there may be empty slots corresponding to non-baserel RTEs */
1041 if (brel == NULL)
1042 continue;
1043
1044 Assert(brel->relid == rti); /* sanity check on array */
1045
1046 /*
1047 * This bit is less obvious than it might look. We ignore appendrel
1048 * otherrels and consider only their parent baserels. In a case where
1049 * a LATERAL-containing UNION ALL subquery was pulled up, it is the
1050 * otherrel that is actually going to be in the plan. However, we
1051 * want to mark all its lateral references as needed by the parent,
1052 * because it is the parent's relid that will be used for join
1053 * planning purposes. And the parent's RTE will contain all the
1054 * lateral references we need to know, since the pulled-up member is
1055 * nothing but a copy of parts of the original RTE's subquery. We
1056 * could visit the parent's children instead and transform their
1057 * references back to the parent's relid, but it would be much more
1058 * complicated for no real gain. (Important here is that the child
1059 * members have not yet received any processing beyond being pulled
1060 * up.) Similarly, in appendrels created by inheritance expansion,
1061 * it's sufficient to look at the parent relation.
1062 */
1063
1064 /* ignore RTEs that are "other rels" */
1065 if (brel->reloptkind != RELOPT_BASEREL)
1066 continue;
1067
1068 extract_lateral_references(root, brel, rti);
1069 }
1070}
static void extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex)
Definition: initsplan.c:1073

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

3543{
3544 if (root->minmax_aggs != NIL &&
3545 list_length(aggref->args) == 1)
3546 {
3547 TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
3548 ListCell *lc;
3549
3550 foreach(lc, root->minmax_aggs)
3551 {
3552 MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
3553
3554 if (mminfo->aggfnoid == aggref->aggfnoid &&
3555 equal(mminfo->target, curTarget->expr))
3556 return mminfo->param;
3557 }
3558 }
3559 return NULL;
3560}
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:3356
Expr * target
Definition: pathnodes.h:3341
Expr * expr
Definition: primnodes.h:2239

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

1317{
1318 return innerrel_is_unique_ext(root, joinrelids, outerrelids, innerrel,
1319 jointype, restrictlist, force_cache, NULL);
1320}
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 1332 of file analyzejoins.c.

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

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

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

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

7268{
7269 /* Most plan types can project, so just list the ones that can't */
7270 switch (nodeTag(plan))
7271 {
7272 case T_Hash:
7273 case T_Material:
7274 case T_Memoize:
7275 case T_Sort:
7276 case T_Unique:
7277 case T_SetOp:
7278 case T_LockRows:
7279 case T_Limit:
7280 case T_ModifyTable:
7281 case T_Append:
7282 case T_MergeAppend:
7283 case T_RecursiveUnion:
7284 return false;
7285 case T_CustomScan:
7287 return true;
7288 return false;
7289 case T_ProjectSet:
7290
7291 /*
7292 * Although ProjectSet certainly projects, say "no" because we
7293 * don't want the planner to randomly replace its tlist with
7294 * something else; the SRFs have to stay at top level. This might
7295 * get relaxed later.
7296 */
7297 return false;
7298 default:
7299 break;
7300 }
7301 return true;
7302}

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,
Cardinality  numGroups,
Size  transitionSpace,
Plan lefttree 
)

Definition at line 6574 of file createplan.c.

6579{
6580 Agg *node = makeNode(Agg);
6581 Plan *plan = &node->plan;
6582
6583 node->aggstrategy = aggstrategy;
6584 node->aggsplit = aggsplit;
6585 node->numCols = numGroupCols;
6586 node->grpColIdx = grpColIdx;
6587 node->grpOperators = grpOperators;
6588 node->grpCollations = grpCollations;
6589 node->numGroups = numGroups;
6590 node->transitionSpace = transitionSpace;
6591 node->aggParams = NULL; /* SS_finalize_plan() will fill this */
6592 node->groupingSets = groupingSets;
6593 node->chain = chain;
6594
6595 plan->qual = qual;
6596 plan->targetlist = tlist;
6597 plan->lefttree = lefttree;
6598 plan->righttree = NULL;
6599
6600 return node;
6601}
AggSplit aggsplit
Definition: plannodes.h:1196
List * chain
Definition: plannodes.h:1223
List * groupingSets
Definition: plannodes.h:1220
Bitmapset * aggParams
Definition: plannodes.h:1215
Cardinality numGroups
Definition: plannodes.h:1209
Plan plan
Definition: plannodes.h:1190
int numCols
Definition: plannodes.h:1199
uint64 transitionSpace
Definition: plannodes.h:1212
AggStrategy aggstrategy
Definition: plannodes.h:1193

References Agg::aggParams, Agg::aggsplit, Agg::aggstrategy, Agg::chain, 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 5795 of file createplan.c.

5803{
5805 Plan *plan = &node->scan.plan;
5806
5807 /* cost will be filled in by create_foreignscan_plan */
5808 plan->targetlist = qptlist;
5809 plan->qual = qpqual;
5810 plan->lefttree = outer_plan;
5811 plan->righttree = NULL;
5812 node->scan.scanrelid = scanrelid;
5813
5814 /* these may be overridden by the FDW's PlanDirectModify callback. */
5815 node->operation = CMD_SELECT;
5816 node->resultRelation = 0;
5817
5818 /* checkAsUser, fs_server will be filled in by create_foreignscan_plan */
5819 node->checkAsUser = InvalidOid;
5820 node->fs_server = InvalidOid;
5821 node->fdw_exprs = fdw_exprs;
5822 node->fdw_private = fdw_private;
5823 node->fdw_scan_tlist = fdw_scan_tlist;
5824 node->fdw_recheck_quals = fdw_recheck_quals;
5825 /* fs_relids, fs_base_relids will be filled by create_foreignscan_plan */
5826 node->fs_relids = NULL;
5827 node->fs_base_relids = NULL;
5828 /* fsSystemCol will be filled in by create_foreignscan_plan */
5829 node->fsSystemCol = false;
5830
5831 return node;
5832}
@ CMD_SELECT
Definition: nodes.h:275
Oid checkAsUser
Definition: plannodes.h:877
CmdType operation
Definition: plannodes.h:873
Oid fs_server
Definition: plannodes.h:879
List * fdw_exprs
Definition: plannodes.h:881
bool fsSystemCol
Definition: plannodes.h:893
Bitmapset * fs_relids
Definition: plannodes.h:889
List * fdw_private
Definition: plannodes.h:883
Bitmapset * fs_base_relids
Definition: plannodes.h:891
Index resultRelation
Definition: plannodes.h:875
List * fdw_recheck_quals
Definition: plannodes.h:887
List * fdw_scan_tlist
Definition: plannodes.h:885
Index scanrelid
Definition: plannodes.h:523

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

6896{
6897 Limit *node = makeNode(Limit);
6898 Plan *plan = &node->plan;
6899
6900 plan->targetlist = lefttree->targetlist;
6901 plan->qual = NIL;
6902 plan->lefttree = lefttree;
6903 plan->righttree = NULL;
6904
6905 node->limitOffset = limitOffset;
6906 node->limitCount = limitCount;
6907 node->limitOption = limitOption;
6908 node->uniqNumCols = uniqNumCols;
6909 node->uniqColIdx = uniqColIdx;
6910 node->uniqOperators = uniqOperators;
6911 node->uniqCollations = uniqCollations;
6912
6913 return node;
6914}
LimitOption limitOption
Definition: plannodes.h:1488
Plan plan
Definition: plannodes.h:1479
Node * limitCount
Definition: plannodes.h:1485
int uniqNumCols
Definition: plannodes.h:1491
Node * limitOffset
Definition: plannodes.h:1482

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

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

3963{
3964 List *newlist = NIL;
3965 ListCell *lc;
3966
3967 foreach(lc, root->fkey_list)
3968 {
3969 ForeignKeyOptInfo *fkinfo = (ForeignKeyOptInfo *) lfirst(lc);
3970 RelOptInfo *con_rel;
3971 RelOptInfo *ref_rel;
3972 int colno;
3973
3974 /*
3975 * Either relid might identify a rel that is in the query's rtable but
3976 * isn't referenced by the jointree, or has been removed by join
3977 * removal, so that it won't have a RelOptInfo. Hence don't use
3978 * find_base_rel() here. We can ignore such FKs.
3979 */
3980 if (fkinfo->con_relid >= root->simple_rel_array_size ||
3981 fkinfo->ref_relid >= root->simple_rel_array_size)
3982 continue; /* just paranoia */
3983 con_rel = root->simple_rel_array[fkinfo->con_relid];
3984 if (con_rel == NULL)
3985 continue;
3986 ref_rel = root->simple_rel_array[fkinfo->ref_relid];
3987 if (ref_rel == NULL)
3988 continue;
3989
3990 /*
3991 * Ignore FK unless both rels are baserels. This gets rid of FKs that
3992 * link to inheritance child rels (otherrels).
3993 */
3994 if (con_rel->reloptkind != RELOPT_BASEREL ||
3995 ref_rel->reloptkind != RELOPT_BASEREL)
3996 continue;
3997
3998 /*
3999 * Scan the columns and try to match them to eclasses and quals.
4000 *
4001 * Note: for simple inner joins, any match should be in an eclass.
4002 * "Loose" quals that syntactically match an FK equality must have
4003 * been rejected for EC status because they are outer-join quals or
4004 * similar. We can still consider them to match the FK.
4005 */
4006 for (colno = 0; colno < fkinfo->nkeys; colno++)
4007 {
4008 EquivalenceClass *ec;
4009 AttrNumber con_attno,
4010 ref_attno;
4011 Oid fpeqop;
4012 ListCell *lc2;
4013
4014 ec = match_eclasses_to_foreign_key_col(root, fkinfo, colno);
4015 /* Don't bother looking for loose quals if we got an EC match */
4016 if (ec != NULL)
4017 {
4018 fkinfo->nmatched_ec++;
4019 if (ec->ec_has_const)
4020 fkinfo->nconst_ec++;
4021 continue;
4022 }
4023
4024 /*
4025 * Scan joininfo list for relevant clauses. Either rel's joininfo
4026 * list would do equally well; we use con_rel's.
4027 */
4028 con_attno = fkinfo->conkey[colno];
4029 ref_attno = fkinfo->confkey[colno];
4030 fpeqop = InvalidOid; /* we'll look this up only if needed */
4031
4032 foreach(lc2, con_rel->joininfo)
4033 {
4034 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc2);
4035 OpExpr *clause = (OpExpr *) rinfo->clause;
4036 Var *leftvar;
4037 Var *rightvar;
4038
4039 /* Only binary OpExprs are useful for consideration */
4040 if (!IsA(clause, OpExpr) ||
4041 list_length(clause->args) != 2)
4042 continue;
4043 leftvar = (Var *) get_leftop((Expr *) clause);
4044 rightvar = (Var *) get_rightop((Expr *) clause);
4045
4046 /* Operands must be Vars, possibly with RelabelType */
4047 while (leftvar && IsA(leftvar, RelabelType))
4048 leftvar = (Var *) ((RelabelType *) leftvar)->arg;
4049 if (!(leftvar && IsA(leftvar, Var)))
4050 continue;
4051 while (rightvar && IsA(rightvar, RelabelType))
4052 rightvar = (Var *) ((RelabelType *) rightvar)->arg;
4053 if (!(rightvar && IsA(rightvar, Var)))
4054 continue;
4055
4056 /* Now try to match the vars to the current foreign key cols */
4057 if (fkinfo->ref_relid == leftvar->varno &&
4058 ref_attno == leftvar->varattno &&
4059 fkinfo->con_relid == rightvar->varno &&
4060 con_attno == rightvar->varattno)
4061 {
4062 /* Vars match, but is it the right operator? */
4063 if (clause->opno == fkinfo->conpfeqop[colno])
4064 {
4065 fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
4066 rinfo);
4067 fkinfo->nmatched_ri++;
4068 }
4069 }
4070 else if (fkinfo->ref_relid == rightvar->varno &&
4071 ref_attno == rightvar->varattno &&
4072 fkinfo->con_relid == leftvar->varno &&
4073 con_attno == leftvar->varattno)
4074 {
4075 /*
4076 * Reverse match, must check commutator operator. Look it
4077 * up if we didn't already. (In the worst case we might
4078 * do multiple lookups here, but that would require an FK
4079 * equality operator without commutator, which is
4080 * unlikely.)
4081 */
4082 if (!OidIsValid(fpeqop))
4083 fpeqop = get_commutator(fkinfo->conpfeqop[colno]);
4084 if (clause->opno == fpeqop)
4085 {
4086 fkinfo->rinfos[colno] = lappend(fkinfo->rinfos[colno],
4087 rinfo);
4088 fkinfo->nmatched_ri++;
4089 }
4090 }
4091 }
4092 /* If we found any matching loose quals, count col as matched */
4093 if (fkinfo->rinfos[colno])
4094 fkinfo->nmatched_rcols++;
4095 }
4096
4097 /*
4098 * Currently, we drop multicolumn FKs that aren't fully matched to the
4099 * query. Later we might figure out how to derive some sort of
4100 * estimate from them, in which case this test should be weakened to
4101 * "if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) > 0)".
4102 */
4103 if ((fkinfo->nmatched_ec + fkinfo->nmatched_rcols) == fkinfo->nkeys)
4104 newlist = lappend(newlist, fkinfo);
4105 }
4106 /* Replace fkey_list, thereby discarding any useless entries */
4107 root->fkey_list = newlist;
4108}
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:1674
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:1402
Oid opno
Definition: primnodes.h:850
List * args
Definition: primnodes.h:868
List * joininfo
Definition: pathnodes.h:1052
Expr * clause
Definition: pathnodes.h:2792

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

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

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

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

3651{
3652 RestrictInfo *restrictinfo;
3653 Node *clause;
3654 Relids relids;
3655 bool pseudoconstant = false;
3656
3657 /*
3658 * Build the new clause. Copy to ensure it shares no substructure with
3659 * original (this is necessary in case there are subselects in there...)
3660 */
3661 clause = (Node *) make_opclause(opno,
3662 BOOLOID, /* opresulttype */
3663 false, /* opretset */
3664 copyObject(item1),
3665 copyObject(item2),
3666 InvalidOid,
3667 collation);
3668
3669 /* If both constant, try to reduce to a boolean constant. */
3670 if (both_const)
3671 {
3672 clause = eval_const_expressions(root, clause);
3673
3674 /* If we produced const TRUE, just drop the clause */
3675 if (clause && IsA(clause, Const))
3676 {
3677 Const *cclause = (Const *) clause;
3678
3679 Assert(cclause->consttype == BOOLOID);
3680 if (!cclause->constisnull && DatumGetBool(cclause->constvalue))
3681 return NULL;
3682 }
3683 }
3684
3685 /*
3686 * The rest of this is a very cut-down version of distribute_qual_to_rels.
3687 * We can skip most of the work therein, but there are a couple of special
3688 * cases we still have to handle.
3689 *
3690 * Retrieve all relids mentioned within the possibly-simplified clause.
3691 */
3692 relids = pull_varnos(root, clause);
3693 Assert(bms_is_subset(relids, qualscope));
3694
3695 /*
3696 * If the clause is variable-free, our normal heuristic for pushing it
3697 * down to just the mentioned rels doesn't work, because there are none.
3698 * Apply it as a gating qual at the appropriate level (see comments for
3699 * get_join_domain_min_rels).
3700 */
3701 if (bms_is_empty(relids))
3702 {
3703 /* eval at join domain's safe level */
3704 relids = get_join_domain_min_rels(root, qualscope);
3705 /* mark as gating qual */
3706 pseudoconstant = true;
3707 /* tell createplan.c to check for gating quals */
3708 root->hasPseudoConstantQuals = true;
3709 }
3710
3711 /*
3712 * Build the RestrictInfo node itself.
3713 */
3714 restrictinfo = make_restrictinfo(root,
3715 (Expr *) clause,
3716 true, /* is_pushed_down */
3717 false, /* !has_clone */
3718 false, /* !is_clone */
3719 pseudoconstant,
3720 security_level,
3721 relids,
3722 NULL, /* incompatible_relids */
3723 NULL); /* outer_relids */
3724
3725 /*
3726 * If it's a join clause, add vars used in the clause to targetlists of
3727 * their relations, so that they will be emitted by the plan nodes that
3728 * scan those relations (else they won't be available at the join node!).
3729 *
3730 * Typically, we'd have already done this when the component expressions
3731 * were first seen by distribute_qual_to_rels; but it is possible that
3732 * some of the Vars could have missed having that done because they only
3733 * appeared in single-relation clauses originally. So do it here for
3734 * safety.
3735 *
3736 * See also rebuild_joinclause_attr_needed, which has to partially repeat
3737 * this work after removal of an outer join. (Since we will put this
3738 * clause into the joininfo lists, that function needn't do any extra work
3739 * to find it.)
3740 */
3741 if (bms_membership(relids) == BMS_MULTIPLE)
3742 {
3743 List *vars = pull_var_clause(clause,
3747
3749 list_free(vars);
3750 }
3751
3752 /*
3753 * Check mergejoinability. This will usually succeed, since the op came
3754 * from an EquivalenceClass; but we could have reduced the original clause
3755 * to a constant.
3756 */
3757 check_mergejoinable(restrictinfo);
3758
3759 /*
3760 * Note we don't do initialize_mergeclause_eclasses(); the caller can
3761 * handle that much more cheaply than we can. It's okay to call
3762 * distribute_restrictinfo_to_rels() before that happens.
3763 */
3764
3765 /*
3766 * Push the new clause into all the appropriate restrictinfo lists.
3767 */
3769
3770 return restrictinfo;
3771}
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:780
@ BMS_MULTIPLE
Definition: bitmapset.h:73
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2270
void distribute_restrictinfo_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:3558
static Relids get_join_domain_min_rels(PlannerInfo *root, Relids domain_relids)
Definition: initsplan.c:3856
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 1117 of file analyzejoins.c.

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

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

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

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

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

3891{
3892 /*
3893 * We must examine all join clauses, but there's no value in processing
3894 * any join clause more than once. So it's slightly annoying that we have
3895 * to find them via the per-base-relation joininfo lists. Avoid duplicate
3896 * processing by tracking the rinfo_serial numbers of join clauses we've
3897 * already seen. (This doesn't work for is_clone clauses, so we must
3898 * waste effort on them.)
3899 */
3900 Bitmapset *seen_serials = NULL;
3901 Index rti;
3902
3903 /* Scan all baserels for join clauses */
3904 for (rti = 1; rti < root->simple_rel_array_size; rti++)
3905 {
3906 RelOptInfo *brel = root->simple_rel_array[rti];
3907 ListCell *lc;
3908
3909 if (brel == NULL)
3910 continue;
3911 if (brel->reloptkind != RELOPT_BASEREL)
3912 continue;
3913
3914 foreach(lc, brel->joininfo)
3915 {
3916 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
3917 Relids relids = rinfo->required_relids;
3918
3919 if (!rinfo->is_clone) /* else serial number is not unique */
3920 {
3921 if (bms_is_member(rinfo->rinfo_serial, seen_serials))
3922 continue; /* saw it already */
3923 seen_serials = bms_add_member(seen_serials,
3924 rinfo->rinfo_serial);
3925 }
3926
3927 if (bms_membership(relids) == BMS_MULTIPLE)
3928 {
3929 List *vars = pull_var_clause((Node *) rinfo->clause,
3933 Relids where_needed;
3934
3935 if (rinfo->is_clone)
3936 where_needed = bms_intersect(relids, root->all_baserels);
3937 else
3938 where_needed = relids;
3939 add_vars_to_attr_needed(root, vars, where_needed);
3940 list_free(vars);
3941 }
3942 }
3943 }
3944}
void add_vars_to_attr_needed(PlannerInfo *root, List *vars, Relids where_needed)
Definition: initsplan.c:360
int rinfo_serial
Definition: pathnodes.h:2864

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

1175{
1176 Index rti;
1177
1178 /* We need do nothing if the query contains no LATERAL RTEs */
1179 if (!root->hasLateralRTEs)
1180 return;
1181
1182 /* Examine the same baserels that find_lateral_references did */
1183 for (rti = 1; rti < root->simple_rel_array_size; rti++)
1184 {
1185 RelOptInfo *brel = root->simple_rel_array[rti];
1186 Relids where_needed;
1187
1188 if (brel == NULL)
1189 continue;
1190 if (brel->reloptkind != RELOPT_BASEREL)
1191 continue;
1192
1193 /*
1194 * We don't need to repeat all of extract_lateral_references, since it
1195 * kindly saved the extracted Vars/PHVs in lateral_vars.
1196 */
1197 if (brel->lateral_vars == NIL)
1198 continue;
1199
1200 where_needed = bms_make_singleton(rti);
1201
1202 add_vars_to_attr_needed(root, brel->lateral_vars, where_needed);
1203 }
1204}

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

3576{
3577 /*
3578 * For performance reasons, we don't bother to track built-in functions;
3579 * we just assume they'll never change (or at least not in ways that'd
3580 * invalidate plans using them). For this purpose we can consider a
3581 * built-in function to be one with OID less than FirstUnpinnedObjectId.
3582 * Note that the OID generator guarantees never to generate such an OID
3583 * after startup, even at OID wraparound.
3584 */
3585 if (funcid >= (Oid) FirstUnpinnedObjectId)
3586 {
3587 PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3588
3589 /*
3590 * It would work to use any syscache on pg_proc, but the easiest is
3591 * PROCOID since we already have the function's OID at hand. Note
3592 * that plancache.c knows we use PROCOID.
3593 */
3594 inval_item->cacheId = PROCOID;
3595 inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
3596 ObjectIdGetDatum(funcid));
3597
3598 root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3599 }
3600}
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
uint32 hashValue
Definition: plannodes.h:1804
#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_function_in_from().

◆ record_plan_type_dependency()

void record_plan_type_dependency ( PlannerInfo root,
Oid  typid 
)

Definition at line 3615 of file setrefs.c.

3616{
3617 /*
3618 * As in record_plan_function_dependency, ignore the possibility that
3619 * someone would change a built-in domain.
3620 */
3621 if (typid >= (Oid) FirstUnpinnedObjectId)
3622 {
3623 PlanInvalItem *inval_item = makeNode(PlanInvalItem);
3624
3625 /*
3626 * It would work to use any syscache on pg_type, but the easiest is
3627 * TYPEOID since we already have the type's OID at hand. Note that
3628 * plancache.c knows we use TYPEOID.
3629 */
3630 inval_item->cacheId = TYPEOID;
3631 inval_item->hashValue = GetSysCacheHashValue1(TYPEOID,
3632 ObjectIdGetDatum(typid));
3633
3634 root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
3635 }
3636}

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

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

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

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

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

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

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

3489{
3490 /*
3491 * For a clone clause, we don't have a reliable way to determine if the
3492 * input expression of a NullTest is non-nullable: nullingrel bits in
3493 * clone clauses may not reflect reality, so we dare not draw conclusions
3494 * from clones about whether Vars are guaranteed not-null.
3495 */
3496 if (restrictinfo->has_clone || restrictinfo->is_clone)
3497 return false;
3498
3499 /* Check for NullTest qual */
3500 if (IsA(restrictinfo->clause, NullTest))
3501 {
3502 NullTest *nulltest = (NullTest *) restrictinfo->clause;
3503
3504 /* is this NullTest an IS_NULL qual? */
3505 if (nulltest->nulltesttype != IS_NULL)
3506 return false;
3507
3508 /*
3509 * Empty rows can appear NULL in some contexts and NOT NULL in others,
3510 * so avoid this optimization for row expressions.
3511 */
3512 if (nulltest->argisrow)
3513 return false;
3514
3515 return expr_is_nonnullable(root, nulltest->arg, true);
3516 }
3517
3518 /* If it's an OR, check its sub-clauses */
3519 if (restriction_is_or_clause(restrictinfo))
3520 {
3521 ListCell *lc;
3522
3523 Assert(is_orclause(restrictinfo->orclause));
3524
3525 /*
3526 * Currently, when processing OR expressions, we only return true when
3527 * all of the OR branches are always false. This could perhaps be
3528 * expanded to remove OR branches that are provably false. This may
3529 * be a useful thing to do as it could result in the OR being left
3530 * with a single arg. That's useful as it would allow the OR
3531 * condition to be replaced with its single argument which may allow
3532 * use of an index for faster filtering on the remaining condition.
3533 */
3534 foreach(lc, ((BoolExpr *) restrictinfo->orclause)->args)
3535 {
3536 Node *orarg = (Node *) lfirst(lc);
3537
3538 if (!IsA(orarg, RestrictInfo) ||
3540 return false;
3541 }
3542 return true;
3543 }
3544
3545 return false;
3546}
bool expr_is_nonnullable(PlannerInfo *root, Expr *expr, bool use_rel_info)
Definition: clauses.c:4329
bool restriction_is_always_false(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:3487
static bool is_orclause(const void *clause)
Definition: nodeFuncs.h:116
@ IS_NULL
Definition: primnodes.h:1977
bool restriction_is_or_clause(RestrictInfo *restrictinfo)
Definition: restrictinfo.c:407
NullTestType nulltesttype
Definition: primnodes.h:1984
Expr * arg
Definition: primnodes.h:1983
bool has_clone
Definition: pathnodes.h:2804

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

3424{
3425 /*
3426 * For a clone clause, we don't have a reliable way to determine if the
3427 * input expression of a NullTest is non-nullable: nullingrel bits in
3428 * clone clauses may not reflect reality, so we dare not draw conclusions
3429 * from clones about whether Vars are guaranteed not-null.
3430 */
3431 if (restrictinfo->has_clone || restrictinfo->is_clone)
3432 return false;
3433
3434 /* Check for NullTest qual */
3435 if (IsA(restrictinfo->clause, NullTest))
3436 {
3437 NullTest *nulltest = (NullTest *) restrictinfo->clause;
3438
3439 /* is this NullTest an IS_NOT_NULL qual? */
3440 if (nulltest->nulltesttype != IS_NOT_NULL)
3441 return false;
3442
3443 /*
3444 * Empty rows can appear NULL in some contexts and NOT NULL in others,
3445 * so avoid this optimization for row expressions.
3446 */
3447 if (nulltest->argisrow)
3448 return false;
3449
3450 return expr_is_nonnullable(root, nulltest->arg, true);
3451 }
3452
3453 /* If it's an OR, check its sub-clauses */
3454 if (restriction_is_or_clause(restrictinfo))
3455 {
3456 ListCell *lc;
3457
3458 Assert(is_orclause(restrictinfo->orclause));
3459
3460 /*
3461 * if any of the given OR branches is provably always true then the
3462 * entire condition is true.
3463 */
3464 foreach(lc, ((BoolExpr *) restrictinfo->orclause)->args)
3465 {
3466 Node *orarg = (Node *) lfirst(lc);
3467
3468 if (!IsA(orarg, RestrictInfo))
3469 continue;
3470
3472 return true;
3473 }
3474 }
3475
3476 return false;
3477}
bool restriction_is_always_true(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:3422
@ IS_NOT_NULL
Definition: primnodes.h:1977

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 = palloc_object(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 palloc_object(type)
Definition: fe_memutils.h:74
void * palloc0(Size size)
Definition: mcxt.c:1395
#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:3193
List * translated_vars
Definition: pathnodes.h:3220
Index parent_relid
Definition: pathnodes.h:3192
Index prti
Definition: plannodes.h:1592
List * subplans
Definition: pathnodes.h:105
List * appendRelations
Definition: pathnodes.h:145
List * finalrowmarks
Definition: pathnodes.h:139
List * finalrtable
Definition: pathnodes.h:120

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

◆ setup_eager_aggregation()

void setup_eager_aggregation ( PlannerInfo root)

Definition at line 642 of file initsplan.c.

643{
644 /*
645 * Don't apply eager aggregation if disabled by user.
646 */
648 return;
649
650 /*
651 * Don't apply eager aggregation if there are no available GROUP BY
652 * clauses.
653 */
654 if (!root->processed_groupClause)
655 return;
656
657 /*
658 * For now we don't try to support grouping sets.
659 */
660 if (root->parse->groupingSets)
661 return;
662
663 /*
664 * For now we don't try to support DISTINCT or ORDER BY aggregates.
665 */
666 if (root->numOrderedAggs > 0)
667 return;
668
669 /*
670 * If there are any aggregates that do not support partial mode, or any
671 * partial aggregates that are non-serializable, do not apply eager
672 * aggregation.
673 */
674 if (root->hasNonPartialAggs || root->hasNonSerialAggs)
675 return;
676
677 /*
678 * We don't try to apply eager aggregation if there are set-returning
679 * functions in targetlist.
680 */
681 if (root->parse->hasTargetSRFs)
682 return;
683
684 /*
685 * Eager aggregation only makes sense if there are multiple base rels in
686 * the query.
687 */
688 if (bms_membership(root->all_baserels) != BMS_MULTIPLE)
689 return;
690
691 /*
692 * Don't apply eager aggregation if any aggregate poses a risk of
693 * excessive memory usage during partial aggregation.
694 */
696 return;
697
698 /*
699 * Collect aggregate expressions and plain Vars that appear in the
700 * targetlist and havingQual.
701 */
703
704 /*
705 * If there are no suitable aggregate expressions, we cannot apply eager
706 * aggregation.
707 */
708 if (root->agg_clause_list == NIL)
709 return;
710
711 /*
712 * Collect grouping expressions that appear in grouping clauses.
713 */
715}
bool enable_eager_aggregate
Definition: allpaths.c:82
static void create_grouping_expr_infos(PlannerInfo *root)
Definition: initsplan.c:868
static bool is_partial_agg_memory_risky(PlannerInfo *root)
Definition: initsplan.c:729
static void create_agg_clause_infos(PlannerInfo *root)
Definition: initsplan.c:750

References bms_membership(), BMS_MULTIPLE, create_agg_clause_infos(), create_grouping_expr_infos(), enable_eager_aggregate, is_partial_agg_memory_risky(), NIL, and root.

Referenced by query_planner().

◆ trivial_subqueryscan()

bool trivial_subqueryscan ( SubqueryScan plan)

Definition at line 1497 of file setrefs.c.

1498{
1499 int attrno;
1500 ListCell *lp,
1501 *lc;
1502
1503 /* We might have detected this already; in which case reuse the result */
1504 if (plan->scanstatus == SUBQUERY_SCAN_TRIVIAL)
1505 return true;
1506 if (plan->scanstatus == SUBQUERY_SCAN_NONTRIVIAL)
1507 return false;
1508 Assert(plan->scanstatus == SUBQUERY_SCAN_UNKNOWN);
1509 /* Initially, mark the SubqueryScan as non-deletable from the plan tree */
1510 plan->scanstatus = SUBQUERY_SCAN_NONTRIVIAL;
1511
1512 if (plan->scan.plan.qual != NIL)
1513 return false;
1514
1515 if (list_length(plan->scan.plan.targetlist) !=
1516 list_length(plan->subplan->targetlist))
1517 return false; /* tlists not same length */
1518
1519 attrno = 1;
1520 forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
1521 {
1522 TargetEntry *ptle = (TargetEntry *) lfirst(lp);
1523 TargetEntry *ctle = (TargetEntry *) lfirst(lc);
1524
1525 if (ptle->resjunk != ctle->resjunk)
1526 return false; /* tlist doesn't match junk status */
1527
1528 /*
1529 * We accept either a Var referencing the corresponding element of the
1530 * subplan tlist, or a Const equaling the subplan element. See
1531 * generate_setop_tlist() for motivation.
1532 */
1533 if (ptle->expr && IsA(ptle->expr, Var))
1534 {
1535 Var *var = (Var *) ptle->expr;
1536
1537 Assert(var->varno == plan->scan.scanrelid);
1538 Assert(var->varlevelsup == 0);
1539 if (var->varattno != attrno)
1540 return false; /* out of order */
1541 }
1542 else if (ptle->expr && IsA(ptle->expr, Const))
1543 {
1544 if (!equal(ptle->expr, ctle->expr))
1545 return false;
1546 }
1547 else
1548 return false;
1549
1550 attrno++;
1551 }
1552
1553 /* Re-mark the SubqueryScan as deletable from the plan tree */
1554 plan->scanstatus = SUBQUERY_SCAN_TRIVIAL;
1555
1556 return true;
1557}
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
@ SUBQUERY_SCAN_NONTRIVIAL
Definition: plannodes.h:749
@ SUBQUERY_SCAN_UNKNOWN
Definition: plannodes.h:747
@ SUBQUERY_SCAN_TRIVIAL
Definition: plannodes.h:748

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

Referenced by remove_useless_self_joins().

◆ from_collapse_limit

PGDLLIMPORT int from_collapse_limit
extern

Definition at line 40 of file initsplan.c.

Referenced by deconstruct_recurse().

◆ join_collapse_limit

PGDLLIMPORT int join_collapse_limit
extern

Definition at line 41 of file initsplan.c.

Referenced by deconstruct_recurse().