diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c index 1d7ec28806dff0d37180e6d9a7c62b619db1e946..129bdb549ffabdccb3f039781f0ab3ee757ddf9a 100644 --- a/contrib/postgres_fdw/deparse.c +++ b/contrib/postgres_fdw/deparse.c @@ -243,7 +243,7 @@ is_foreign_expr(PlannerInfo *root, * because the upperrel's own relids currently aren't set to anything * meaningful by the core code. For other relation, use their own relids. */ - if (baserel->reloptkind == RELOPT_UPPER_REL) + if (IS_UPPER_REL(baserel)) glob_cxt.relids = fpinfo->outerrel->relids; else glob_cxt.relids = baserel->relids; @@ -677,7 +677,7 @@ foreign_expr_walker(Node *node, ListCell *lc; /* Not safe to pushdown when not in grouping context */ - if (glob_cxt->foreignrel->reloptkind != RELOPT_UPPER_REL) + if (!IS_UPPER_REL(glob_cxt->foreignrel)) return false; /* Only non-split aggregates are pushable. */ @@ -874,7 +874,7 @@ build_tlist_to_deparse(RelOptInfo *foreignrel) * For an upper relation, we have already built the target list while * checking shippability, so just return that. */ - if (foreignrel->reloptkind == RELOPT_UPPER_REL) + if (IS_UPPER_REL(foreignrel)) return fpinfo->grouped_tlist; /* @@ -929,17 +929,13 @@ deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel, * We handle relations for foreign tables, joins between those and upper * relations. */ - Assert(rel->reloptkind == RELOPT_JOINREL || - rel->reloptkind == RELOPT_BASEREL || - rel->reloptkind == RELOPT_OTHER_MEMBER_REL || - rel->reloptkind == RELOPT_UPPER_REL); + Assert(IS_JOIN_REL(rel) || IS_SIMPLE_REL(rel) || IS_UPPER_REL(rel)); /* Fill portions of context common to upper, join and base relation */ context.buf = buf; context.root = root; context.foreignrel = rel; - context.scanrel = (rel->reloptkind == RELOPT_UPPER_REL) ? - fpinfo->outerrel : rel; + context.scanrel = IS_UPPER_REL(rel) ? fpinfo->outerrel : rel; context.params_list = params_list; /* Construct SELECT clause */ @@ -950,7 +946,7 @@ deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel, * conditions of the underlying scan relation; otherwise, we can use the * supplied list of remote conditions directly. */ - if (rel->reloptkind == RELOPT_UPPER_REL) + if (IS_UPPER_REL(rel)) { PgFdwRelationInfo *ofpinfo; @@ -963,7 +959,7 @@ deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel, /* Construct FROM and WHERE clauses */ deparseFromExpr(quals, &context); - if (rel->reloptkind == RELOPT_UPPER_REL) + if (IS_UPPER_REL(rel)) { /* Append GROUP BY clause */ appendGroupByClause(tlist, &context); @@ -1020,8 +1016,7 @@ deparseSelectSql(List *tlist, bool is_subquery, List **retrieved_attrs, */ deparseSubqueryTargetList(context); } - else if (foreignrel->reloptkind == RELOPT_JOINREL || - foreignrel->reloptkind == RELOPT_UPPER_REL) + else if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel)) { /* * For a join or upper relation the input tlist gives the list of @@ -1062,9 +1057,8 @@ deparseFromExpr(List *quals, deparse_expr_cxt *context) RelOptInfo *scanrel = context->scanrel; /* For upper relations, scanrel must be either a joinrel or a baserel */ - Assert(context->foreignrel->reloptkind != RELOPT_UPPER_REL || - scanrel->reloptkind == RELOPT_JOINREL || - scanrel->reloptkind == RELOPT_BASEREL); + Assert(!IS_UPPER_REL(context->foreignrel) || + IS_JOIN_REL(scanrel) || IS_SIMPLE_REL(scanrel)); /* Construct FROM clause */ appendStringInfoString(buf, " FROM "); @@ -1219,7 +1213,7 @@ deparseLockingClause(deparse_expr_cxt *context) appendStringInfoString(buf, " FOR UPDATE"); /* Add the relation alias if we are here for a join relation */ - if (rel->reloptkind == RELOPT_JOINREL) + if (IS_JOIN_REL(rel)) appendStringInfo(buf, " OF %s%d", REL_ALIAS_PREFIX, relid); } else @@ -1384,8 +1378,7 @@ deparseSubqueryTargetList(deparse_expr_cxt *context) ListCell *lc; /* Should only be called in these cases. */ - Assert(foreignrel->reloptkind == RELOPT_BASEREL || - foreignrel->reloptkind == RELOPT_JOINREL); + Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel)); first = true; foreach(lc, foreignrel->reltarget->exprs) @@ -1417,7 +1410,7 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, { PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private; - if (foreignrel->reloptkind == RELOPT_JOINREL) + if (IS_JOIN_REL(foreignrel)) { StringInfoData join_sql_o; StringInfoData join_sql_i; @@ -1495,8 +1488,7 @@ deparseRangeTblRef(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private; /* Should only be called in these cases. */ - Assert(foreignrel->reloptkind == RELOPT_BASEREL || - foreignrel->reloptkind == RELOPT_JOINREL); + Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel)); Assert(fpinfo->local_conds == NIL); @@ -3097,15 +3089,13 @@ is_subquery_var(Var *node, RelOptInfo *foreignrel, int *relno, int *colno) RelOptInfo *innerrel = fpinfo->innerrel; /* Should only be called in these cases. */ - Assert(foreignrel->reloptkind == RELOPT_BASEREL || - foreignrel->reloptkind == RELOPT_JOINREL || - foreignrel->reloptkind == RELOPT_OTHER_MEMBER_REL); + Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel)); /* * If the given relation isn't a join relation, it doesn't have any lower * subqueries, so the Var isn't a subquery output column. */ - if (foreignrel->reloptkind != RELOPT_JOINREL) + if (!IS_JOIN_REL(foreignrel)) return false; /* diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 54b938734a87bced4659a41de2bc7c151a6a5017..2851869932dd1c55c4879d44f8345f8aa37710e6 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -729,8 +729,11 @@ get_useful_ecs_for_relation(PlannerInfo *root, RelOptInfo *rel) return useful_eclass_list; /* If this is a child rel, we must use the topmost parent rel to search. */ - if (rel->reloptkind == RELOPT_OTHER_MEMBER_REL) - relids = find_childrel_top_parent(root, rel)->relids; + if (IS_OTHER_REL(rel)) + { + Assert(!bms_is_empty(rel->top_parent_relids)); + relids = rel->top_parent_relids; + } else relids = rel->relids; @@ -1129,8 +1132,7 @@ postgresGetForeignPlan(PlannerInfo *root, * For base relations, set scan_relid as the relid of the relation. For * other kinds of relations set it to 0. */ - if (foreignrel->reloptkind == RELOPT_BASEREL || - foreignrel->reloptkind == RELOPT_OTHER_MEMBER_REL) + if (IS_SIMPLE_REL(foreignrel)) scan_relid = foreignrel->relid; else { @@ -1189,8 +1191,7 @@ postgresGetForeignPlan(PlannerInfo *root, local_exprs = lappend(local_exprs, rinfo->clause); } - if (foreignrel->reloptkind == RELOPT_JOINREL || - foreignrel->reloptkind == RELOPT_UPPER_REL) + if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel)) { /* For a join relation, get the conditions from fdw_private structure */ remote_conds = fpinfo->remote_conds; @@ -1216,7 +1217,7 @@ postgresGetForeignPlan(PlannerInfo *root, * joins. Queries involving aggregates or grouping do not require * EPQ mechanism, hence should not have an outer plan here. */ - Assert(foreignrel->reloptkind != RELOPT_UPPER_REL); + Assert(!IS_UPPER_REL(foreignrel)); outer_plan->targetlist = fdw_scan_tlist; @@ -1255,8 +1256,7 @@ postgresGetForeignPlan(PlannerInfo *root, remote_conds, retrieved_attrs, makeInteger(fpinfo->fetch_size)); - if (foreignrel->reloptkind == RELOPT_JOINREL || - foreignrel->reloptkind == RELOPT_UPPER_REL) + if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel)) fdw_private = lappend(fdw_private, makeString(fpinfo->relation_name->data)); @@ -2535,8 +2535,7 @@ estimate_path_cost_size(PlannerInfo *root, &remote_param_join_conds, &local_param_join_conds); /* Build the list of columns to be fetched from the foreign server. */ - if (foreignrel->reloptkind == RELOPT_JOINREL || - foreignrel->reloptkind == RELOPT_UPPER_REL) + if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel)) fdw_scan_tlist = build_tlist_to_deparse(foreignrel); else fdw_scan_tlist = NIL; @@ -2617,7 +2616,7 @@ estimate_path_cost_size(PlannerInfo *root, startup_cost = fpinfo->rel_startup_cost; run_cost = fpinfo->rel_total_cost - fpinfo->rel_startup_cost; } - else if (foreignrel->reloptkind == RELOPT_JOINREL) + else if (IS_JOIN_REL(foreignrel)) { PgFdwRelationInfo *fpinfo_i; PgFdwRelationInfo *fpinfo_o; @@ -2683,7 +2682,7 @@ estimate_path_cost_size(PlannerInfo *root, run_cost += nrows * remote_conds_cost.per_tuple; run_cost += fpinfo->local_conds_cost.per_tuple * retrieved_rows; } - else if (foreignrel->reloptkind == RELOPT_UPPER_REL) + else if (IS_UPPER_REL(foreignrel)) { PgFdwRelationInfo *ofpinfo; PathTarget *ptarget = root->upper_targets[UPPERREL_GROUP_AGG]; diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c index 5a45558b915f9c2e2dd6820c634dc7480dd19b75..a113bf540da29be78e79e46f3c0ca1df1c509029 100644 --- a/src/backend/foreign/foreign.c +++ b/src/backend/foreign/foreign.c @@ -717,7 +717,7 @@ GetExistingLocalJoinPath(RelOptInfo *joinrel) { ListCell *lc; - Assert(joinrel->reloptkind == RELOPT_JOINREL); + Assert(IS_JOIN_REL(joinrel)); foreach(lc, joinrel->pathlist) { @@ -782,7 +782,7 @@ GetExistingLocalJoinPath(RelOptInfo *joinrel) ForeignPath *foreign_path; foreign_path = (ForeignPath *) joinpath->outerjoinpath; - if (foreign_path->path.parent->reloptkind == RELOPT_JOINREL) + if (IS_JOIN_REL(foreign_path->path.parent)) joinpath->outerjoinpath = foreign_path->fdw_outerpath; } @@ -791,7 +791,7 @@ GetExistingLocalJoinPath(RelOptInfo *joinrel) ForeignPath *foreign_path; foreign_path = (ForeignPath *) joinpath->innerjoinpath; - if (foreign_path->path.parent->reloptkind == RELOPT_JOINREL) + if (IS_JOIN_REL(foreign_path->path.parent)) joinpath->innerjoinpath = foreign_path->fdw_outerpath; } diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 343b35aa326a40e741c8970662f275d14c4ced64..b93b4fc77369a551636d418b9789bdbb553b0411 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -539,8 +539,7 @@ set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel, Assert(root->glob->parallelModeOK); /* This should only be called for baserels and appendrel children. */ - Assert(rel->reloptkind == RELOPT_BASEREL || - rel->reloptkind == RELOPT_OTHER_MEMBER_REL); + Assert(IS_SIMPLE_REL(rel)); /* Assorted checks based on rtekind. */ switch (rte->rtekind) @@ -846,7 +845,7 @@ set_foreign_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) /* * set_append_rel_size - * Set size estimates for an "append relation" + * Set size estimates for a simple "append relation" * * The passed-in rel and RTE represent the entire append relation. The * relation's contents are computed by appending together the output of @@ -867,6 +866,8 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, int nattrs; ListCell *l; + Assert(IS_SIMPLE_REL(rel)); + /* * Initialize to compute size estimates for whole append relation. * diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index a329dd1e10d70b11c302c0c1524d5ad29d6969a8..67bd760fb47f2fe564ff59336086d73bcb6e781e 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -1060,10 +1060,12 @@ generate_join_implied_equalities_for_ecs(PlannerInfo *root, ListCell *lc; /* If inner rel is a child, extra setup work is needed */ - if (inner_rel->reloptkind == RELOPT_OTHER_MEMBER_REL) + if (IS_OTHER_REL(inner_rel)) { + Assert(!bms_is_empty(inner_rel->top_parent_relids)); + /* Fetch relid set for the topmost parent rel */ - nominal_inner_relids = find_childrel_top_parent(root, inner_rel)->relids; + nominal_inner_relids = inner_rel->top_parent_relids; /* ECs will be marked with the parent's relid, not the child's */ nominal_join_relids = bms_union(outer_relids, nominal_inner_relids); } @@ -1324,8 +1326,7 @@ generate_join_implied_equalities_broken(PlannerInfo *root, * mentioned in the ec_sources clauses, we have to be prepared to apply * multiple levels of Var translation. */ - if (inner_rel->reloptkind == RELOPT_OTHER_MEMBER_REL && - result != NIL) + if (IS_OTHER_REL(inner_rel) && result != NIL) result = (List *) adjust_appendrel_attrs_multilevel(root, (Node *) result, inner_rel); @@ -2180,6 +2181,9 @@ generate_implied_equalities_for_column(PlannerInfo *root, Relids parent_relids; ListCell *lc1; + /* Indexes are available only on base or "other" member relations. */ + Assert(IS_SIMPLE_REL(rel)); + /* If it's a child rel, we'll need to know what its parent(s) are */ if (is_child_rel) parent_relids = find_childrel_parents(root, rel); @@ -2413,8 +2417,11 @@ eclass_useful_for_merging(PlannerInfo *root, */ /* If specified rel is a child, we must consider the topmost parent rel */ - if (rel->reloptkind == RELOPT_OTHER_MEMBER_REL) - relids = find_childrel_top_parent(root, rel)->relids; + if (IS_OTHER_REL(rel)) + { + Assert(!bms_is_empty(rel->top_parent_relids)); + relids = rel->top_parent_relids; + } else relids = rel->relids; diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index a5d19f9b1c58b212994730f69ab9306ae8c1991f..cec9822cb79ebc952faf2c49324c32f1311fc7cd 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -2779,6 +2779,9 @@ check_index_predicates(PlannerInfo *root, RelOptInfo *rel) Relids otherrels; ListCell *lc; + /* Indexes are available only on base or "other" member relations. */ + Assert(IS_SIMPLE_REL(rel)); + /* * Initialize the indrestrictinfo lists to be identical to * baserestrictinfo, and check whether there are any partial indexes. If diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 2a78595e1f2cc76c8f0f0342972d752225a6ae6b..b121f40ff8cb129e8491272521e28b9875c211c3 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -3461,7 +3461,7 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path, * upper rel doesn't have relids set, but it covers all the base relations * participating in the underlying scan, so use root's all_baserels. */ - if (rel->reloptkind == RELOPT_UPPER_REL) + if (IS_UPPER_REL(rel)) scan_plan->fs_relids = root->all_baserels; else scan_plan->fs_relids = best_path->path.parent->relids; diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 53aefbd1a3dea8fc56f89d15d6ce4aee83072ee2..ebd442ad4db8301b9b8e1f1ace34041f3d990c34 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -109,7 +109,7 @@ add_base_rels_to_query(PlannerInfo *root, Node *jtnode) { int varno = ((RangeTblRef *) jtnode)->rtindex; - (void) build_simple_rel(root, varno, RELOPT_BASEREL); + (void) build_simple_rel(root, varno, NULL); } else if (IsA(jtnode, FromExpr)) { diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index 3c58d0596c69c9fdad079e9d75e2a1a32ad56468..ef0de3fb1a99917f02e51a5568b7904e0f8464a8 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -242,8 +242,7 @@ query_planner(PlannerInfo *root, List *tlist, Assert(brel->relid == rti); /* sanity check on array */ - if (brel->reloptkind == RELOPT_BASEREL || - brel->reloptkind == RELOPT_OTHER_MEMBER_REL) + if (IS_SIMPLE_REL(brel)) total_pages += (double) brel->pages; } root->total_table_pages = total_pages; diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 9d1a98220a7fce62bae6101cb845d05bf2602956..17cd683d8535ee28206c2a8ff35a8d6ec4507d41 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -6001,7 +6001,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid) setup_simple_rel_arrays(root); /* Build RelOptInfo */ - rel = build_simple_rel(root, 1, RELOPT_BASEREL); + rel = build_simple_rel(root, 1, NULL); /* Locate IndexOptInfo for the target index */ indexInfo = NULL; diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index e327e66f6b9ee5430ef96bd816ce4999bfbcc201..b5cb4de6a2618f84233e3449cc5699b7554b642d 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -271,7 +271,7 @@ recurse_set_operations(Node *setOp, PlannerInfo *root, * used for much here, but it carries the subroot data structures * forward to setrefs.c processing. */ - rel = build_simple_rel(root, rtr->rtindex, RELOPT_BASEREL); + rel = build_simple_rel(root, rtr->rtindex, NULL); /* plan_params should not be in use in current query level */ Assert(root->plan_params == NIL); @@ -2143,7 +2143,7 @@ adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node, RelOptInfo *parent_rel = find_base_rel(root, appinfo->parent_relid); /* If parent is also a child, first recurse to apply its translations */ - if (parent_rel->reloptkind == RELOPT_OTHER_MEMBER_REL) + if (IS_OTHER_REL(parent_rel)) node = adjust_appendrel_attrs_multilevel(root, node, parent_rel); else Assert(parent_rel->reloptkind == RELOPT_BASEREL); diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 1cd21c0fdcb1b10e30b108d2159d3dd3ddc483f5..19904b54bd5a50604d1ca28968c6c8d29377017a 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -1337,6 +1337,9 @@ relation_excluded_by_constraints(PlannerInfo *root, List *safe_constraints; ListCell *lc; + /* As of now, constraint exclusion works only with simple relations. */ + Assert(IS_SIMPLE_REL(rel)); + /* * Regardless of the setting of constraint_exclusion, detect * constant-FALSE-or-NULL restriction clauses. Because const-folding will diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 7912df0baaae5a3c3295864d3fdb284590df602f..3aa701fd843dd01e449ba69f1e274349426b1675 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -88,7 +88,7 @@ setup_simple_rel_arrays(PlannerInfo *root) * Construct a new RelOptInfo for a base relation or 'other' relation. */ RelOptInfo * -build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) +build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent) { RelOptInfo *rel; RangeTblEntry *rte; @@ -103,7 +103,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) Assert(rte != NULL); rel = makeNode(RelOptInfo); - rel->reloptkind = reloptkind; + rel->reloptkind = parent ? RELOPT_OTHER_MEMBER_REL : RELOPT_BASEREL; rel->relids = bms_make_singleton(relid); rel->rows = 0; /* cheap startup cost is interesting iff not all tuples to be retrieved */ @@ -144,6 +144,22 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) rel->joininfo = NIL; rel->has_eclass_joins = false; + /* + * Pass top parent's relids down the inheritance hierarchy. If the parent + * has top_parent_relids set, it's a direct or an indirect child of the top + * parent indicated by top_parent_relids. By extention this child is also + * an indirect child of that parent. + */ + if (parent) + { + if (parent->top_parent_relids) + rel->top_parent_relids = parent->top_parent_relids; + else + rel->top_parent_relids = bms_copy(parent->relids); + } + else + rel->top_parent_relids = NULL; + /* Check type of rtable entry */ switch (rte->rtekind) { @@ -209,7 +225,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) continue; (void) build_simple_rel(root, appinfo->child_relid, - RELOPT_OTHER_MEMBER_REL); + rel); } } @@ -504,6 +520,7 @@ build_join_rel(PlannerInfo *root, joinrel->baserestrict_min_security = UINT_MAX; joinrel->joininfo = NIL; joinrel->has_eclass_joins = false; + joinrel->top_parent_relids = NULL; /* Compute information relevant to the foreign relations. */ set_foreign_rel_properties(joinrel, outer_rel, inner_rel); @@ -965,32 +982,6 @@ find_childrel_appendrelinfo(PlannerInfo *root, RelOptInfo *rel) } -/* - * find_childrel_top_parent - * Fetch the topmost appendrel parent rel of an appendrel child rel. - * - * Since appendrels can be nested, a child could have multiple levels of - * appendrel ancestors. This function locates the topmost ancestor, - * which will be a regular baserel not an otherrel. - */ -RelOptInfo * -find_childrel_top_parent(PlannerInfo *root, RelOptInfo *rel) -{ - do - { - AppendRelInfo *appinfo = find_childrel_appendrelinfo(root, rel); - Index prelid = appinfo->parent_relid; - - /* traverse up to the parent rel, loop if it's also a child rel */ - rel = find_base_rel(root, prelid); - } while (rel->reloptkind == RELOPT_OTHER_MEMBER_REL); - - Assert(rel->reloptkind == RELOPT_BASEREL); - - return rel; -} - - /* * find_childrel_parents * Compute the set of parent relids of an appendrel child rel. @@ -1004,6 +995,8 @@ find_childrel_parents(PlannerInfo *root, RelOptInfo *rel) { Relids result = NULL; + Assert(rel->reloptkind == RELOPT_OTHER_MEMBER_REL); + do { AppendRelInfo *appinfo = find_childrel_appendrelinfo(root, rel); diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 5c382a2013e2b09905deef9cfaa70bf1ad765e3e..68b54235b3f84526a4b7f5cbe883a0f28a626f59 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -3473,7 +3473,7 @@ estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows, /* * Sanity check --- don't divide by zero if empty relation. */ - Assert(rel->reloptkind == RELOPT_BASEREL); + Assert(IS_SIMPLE_REL(rel)); if (rel->tuples > 0) { /* diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index ebf9480f3773b160112443abb7f9457b6027f01f..fc53eb171aab685a2fede2fa7b04fd68740ebe26 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -484,6 +484,23 @@ typedef enum RelOptKind RELOPT_DEADREL } RelOptKind; +/* + * Is the given relation a simple relation i.e a base or "other" member + * relation? + */ +#define IS_SIMPLE_REL(rel) \ + ((rel)->reloptkind == RELOPT_BASEREL || \ + (rel)->reloptkind == RELOPT_OTHER_MEMBER_REL) + +/* Is the given relation a join relation? */ +#define IS_JOIN_REL(rel) ((rel)->reloptkind == RELOPT_JOINREL) + +/* Is the given relation an upper relation? */ +#define IS_UPPER_REL(rel) ((rel)->reloptkind == RELOPT_UPPER_REL) + +/* Is the given relation an "other" relation? */ +#define IS_OTHER_REL(rel) ((rel)->reloptkind == RELOPT_OTHER_MEMBER_REL) + typedef struct RelOptInfo { NodeTag type; @@ -554,6 +571,9 @@ typedef struct RelOptInfo List *joininfo; /* RestrictInfo structures for join clauses * involving this rel */ bool has_eclass_joins; /* T means joininfo is incomplete */ + + /* used by "other" relations. */ + Relids top_parent_relids; /* Relids of topmost parents. */ } RelOptInfo; /* diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h index 82d4e8701c893c1568474360946389ce74c593ee..2e712c6a35d2c745f8b4e44f88862e53a57dc847 100644 --- a/src/include/optimizer/pathnode.h +++ b/src/include/optimizer/pathnode.h @@ -256,7 +256,7 @@ extern Path *reparameterize_path(PlannerInfo *root, Path *path, */ extern void setup_simple_rel_arrays(PlannerInfo *root); extern RelOptInfo *build_simple_rel(PlannerInfo *root, int relid, - RelOptKind reloptkind); + RelOptInfo *parent); extern RelOptInfo *find_base_rel(PlannerInfo *root, int relid); extern RelOptInfo *find_join_rel(PlannerInfo *root, Relids relids); extern RelOptInfo *build_join_rel(PlannerInfo *root, @@ -274,7 +274,6 @@ extern RelOptInfo *fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids); extern AppendRelInfo *find_childrel_appendrelinfo(PlannerInfo *root, RelOptInfo *rel); -extern RelOptInfo *find_childrel_top_parent(PlannerInfo *root, RelOptInfo *rel); extern Relids find_childrel_parents(PlannerInfo *root, RelOptInfo *rel); extern ParamPathInfo *get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel,