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,