v3-0004-WIP-generate-all-inheritance-child-RelOptInfos-af.patch

text/plain

Filename: v3-0004-WIP-generate-all-inheritance-child-RelOptInfos-af.patch
Type: text/plain
Part: 3
Message: Re: speeding up planning with partitions

Patch

Format: format-patch
Series: patch v3-0004
Subject: WIP: generate *all* inheritance child RelOptInfos after pruning
File+
src/backend/optimizer/path/allpaths.c 82 127
src/backend/optimizer/plan/initsplan.c 23 34
src/backend/optimizer/plan/planner.c 17 14
src/backend/optimizer/prep/prepunion.c 256 221
src/backend/optimizer/util/plancat.c 21 37
src/backend/optimizer/util/relnode.c 189 103
src/backend/partitioning/partprune.c 2 3
src/include/optimizer/pathnode.h 8 1
src/include/optimizer/plancat.h 6 3
src/include/optimizer/prep.h 16 12
From 45334d7f43033adbc9682d0cbb549301d2c4366d Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 13 Sep 2018 15:11:46 +0900
Subject: [PATCH v3 4/4] WIP: generate *all* inheritance child RelOptInfos
 after pruning

---
 src/backend/optimizer/path/allpaths.c  | 209 ++++++---------
 src/backend/optimizer/plan/initsplan.c |  57 ++--
 src/backend/optimizer/plan/planner.c   |  31 ++-
 src/backend/optimizer/prep/prepunion.c | 477 ++++++++++++++++++---------------
 src/backend/optimizer/util/plancat.c   |  58 ++--
 src/backend/optimizer/util/relnode.c   | 292 +++++++++++++-------
 src/backend/partitioning/partprune.c   |   5 +-
 src/include/optimizer/pathnode.h       |   9 +-
 src/include/optimizer/plancat.h        |   9 +-
 src/include/optimizer/prep.h           |  28 +-
 10 files changed, 620 insertions(+), 555 deletions(-)

diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index e54cccd077..21723e7cdc 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -367,8 +367,23 @@ static void
 set_rel_size(PlannerInfo *root, RelOptInfo *rel,
 			 Index rti, RangeTblEntry *rte)
 {
+
+	/*
+	 * Check if the relation's constraints contradict the clauses matched
+	 * to it.  Only plain relations have constraints.  In a partitioning
+	 * hierarchy, but not with regular table inheritance, it's OK to assume
+	 * that any constraints that hold for the parent also hold for every
+	 * child; for instance, table inheritance allows the parent to have
+	 * constraints marked NO INHERIT, but table partitioning does not.  We
+	 * choose to check whether the partitioning parents can be excluded here;
+	 * doing so consumes some cycles, but potentially saves us the work of
+	 * excluding each child individually.
+	 */
 	if (rel->reloptkind == RELOPT_BASEREL &&
-		relation_excluded_by_constraints(root, rel, rte))
+		rte->rtekind == RTE_RELATION &&
+		(!rte->inh || rte->relkind == RELKIND_PARTITIONED_TABLE) &&
+		relation_excluded_by_constraints(root, rel->baserestrictinfo,
+										 rti, rte->relid, false))
 	{
 		/*
 		 * We proved we don't need to scan the rel via constraint exclusion,
@@ -916,11 +931,7 @@ static void
 set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
 					Index rti, RangeTblEntry *rte)
 {
-	Relids		top_parent_relids = rel->top_parent_relids;
 	int			parentRTindex = rti;
-	int			rootParentRTindex = top_parent_relids ?
-									bms_singleton_member(top_parent_relids) :
-									parentRTindex;
 	bool		has_live_children;
 	double		parent_rows;
 	double		parent_size;
@@ -951,6 +962,17 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
 		 */
 		prune_append_rel_partitions(root, rel);
 	}
+	else
+	{
+		expand_inherited_rtentry(root, rel, rte, rti);
+		if (IS_DUMMY_REL(rel))
+			return;
+		if (!rte->inh)
+		{
+			set_rel_size(root, rel, rti, rte);
+			return;
+		}
+	}
 
 	/*
 	 * If this is a partitioned baserel, set the consider_partitionwise_join
@@ -989,9 +1011,9 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
 		int			childRTindex;
 		RangeTblEntry *childRTE;
 		RelOptInfo *childrel;
-		List	   *childquals;
+		List	   *childquals = NIL;
+		bool		have_const_false_cq = false;
 		Index		cq_min_security;
-		bool		have_const_false_cq;
 		ListCell   *parentvars;
 		ListCell   *childvars;
 		ListCell   *lc;
@@ -1004,53 +1026,23 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
 		childRTE = root->simple_rte_array[childRTindex];
 
 		/*
-		 * The child rel's RelOptInfo was already created during
-		 * add_base_rels_to_query.
+		 * The child rel's RelOptInfo may not have been created in some
+		 * cases, for example, if it is not a partition.
 		 */
-		childrel = find_base_rel(root, childRTindex);
+		childrel = root->simple_rel_array[childRTindex];
+		if (childrel == NULL)
+			childrel = build_inheritance_child_rel(root, childRTindex, rel);
 		Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
 
-		/*
-		 * We have to make child entries in the EquivalenceClass data
-		 * structures as well.  This is needed either if the parent
-		 * participates in some eclass joins (because we will want to consider
-		 * inner-indexscan joins on the individual children) or if the parent
-		 * has useful pathkeys (because we should try to build MergeAppend
-		 * paths that produce those sort orderings). Even if this child is
-		 * deemed dummy, it may fall on nullable side in a child-join, which
-		 * in turn may participate in a MergeAppend, where we will need the
-		 * EquivalenceClass data structures.
-		 */
-		if (rel->has_eclass_joins || has_useful_pathkeys(root, rel))
-			add_child_rel_equivalences(root, appinfo, rel, childrel);
-		childrel->has_eclass_joins = rel->has_eclass_joins;
-
-		/*
-		 * We have to copy the parent's quals to the child, with appropriate
-		 * substitution of variables.  However, only the baserestrictinfo
-		 * quals are needed before we can check for constraint exclusion; so
-		 * do that first and then check to see if we can disregard this child.
-		 *
-		 * The child rel's targetlist might contain non-Var expressions, which
-		 * means that substitution into the quals could produce opportunities
-		 * for const-simplification, and perhaps even pseudoconstant quals.
-		 * Therefore, transform each RestrictInfo separately to see if it
-		 * reduces to a constant or pseudoconstant.  (We must process them
-		 * separately to keep track of the security level of each qual.)
-		 */
-		childquals = NIL;
-		cq_min_security = UINT_MAX;
-		have_const_false_cq = false;
+		/* Convert parent's baserestrictinfo to store into childrel. */
 		foreach(lc, rel->baserestrictinfo)
 		{
 			RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
-			Node	   *childqual;
+			Node	   *childqual = (Node *) rinfo->clause;
 			ListCell   *lc2;
 
 			Assert(IsA(rinfo, RestrictInfo));
-			childqual = adjust_appendrel_attrs(root,
-											   (Node *) rinfo->clause,
-											   1, &appinfo);
+			childqual = adjust_appendrel_attrs(root, childqual, 1, &appinfo);
 			childqual = eval_const_expressions(root, childqual);
 			/* check for flat-out constant */
 			if (childqual && IsA(childqual, Const))
@@ -1082,13 +1074,12 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
 				}
 				/* reconstitute RestrictInfo with appropriate properties */
 				childquals = lappend(childquals,
-									 make_restrictinfo((Expr *) onecq,
-													   rinfo->is_pushed_down,
-													   rinfo->outerjoin_delayed,
-													   pseudoconstant,
-													   rinfo->security_level,
-													   NULL, NULL, NULL));
-				/* track minimum security level among child quals */
+								 make_restrictinfo((Expr *) onecq,
+												   rinfo->is_pushed_down,
+												   rinfo->outerjoin_delayed,
+												   pseudoconstant,
+												   rinfo->security_level,
+												   NULL, NULL, NULL));
 				cq_min_security = Min(cq_min_security, rinfo->security_level);
 			}
 		}
@@ -1106,6 +1097,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
 		 */
 		if (childRTE->securityQuals)
 		{
+			List	   *security_quals = NIL;
 			Index		security_level = 0;
 
 			foreach(lc, childRTE->securityQuals)
@@ -1118,16 +1110,37 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
 					Expr	   *qual = (Expr *) lfirst(lc2);
 
 					/* not likely that we'd see constants here, so no check */
-					childquals = lappend(childquals,
-										 make_restrictinfo(qual,
-														   true, false, false,
-														   security_level,
-														   NULL, NULL, NULL));
+					security_quals = lappend(security_quals,
+											 make_restrictinfo(qual,
+															   true, false,
+															   false,
+															   security_level,
+															   NULL, NULL,
+															   NULL));
 					cq_min_security = Min(cq_min_security, security_level);
 				}
 				security_level++;
 			}
 			Assert(security_level <= root->qual_security_level);
+
+			/* Concatenate with parent's quals. */
+			childquals = list_concat(childquals, security_quals);
+		}
+
+		/*
+		 * Check if any of the security quals contradict table
+		 * constraints.
+		 */
+		if (have_const_false_cq ||
+			(childRTE->rtekind == RTE_RELATION &&
+			 relation_excluded_by_constraints(root, childquals,
+											  childRTindex,
+											  childRTE->relid,
+											  true)))
+		{
+			childrel->reltarget = copy_pathtarget(rel->reltarget);
+			set_dummy_rel_pathlist(childrel);
+			continue;
 		}
 
 		/*
@@ -1137,77 +1150,19 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
 		childrel->baserestrict_min_security = cq_min_security;
 
 		/*
-		 * Mark the child as empty in certain cases, such as if a restriction
-		 * clause reduced to constant FALSE or NULL, or if constaint exclusion
-		 * pruned it.
+		 * We have to make child entries in the EquivalenceClass data
+		 * structures as well.  This is needed either if the parent
+		 * participates in some eclass joins (because we will want to consider
+		 * inner-indexscan joins on the individual children) or if the parent
+		 * has useful pathkeys (because we should try to build MergeAppend
+		 * paths that produce those sort orderings). Even if this child is
+		 * deemed dummy, it may fall on nullable side in a child-join, which
+		 * in turn may participate in a MergeAppend, where we will need the
+		 * EquivalenceClass data structures.
 		 */
-		if (have_const_false_cq ||
-			relation_excluded_by_constraints(root, childrel, childRTE))
-		{
-			/*
-			 * The child relation won't be scanned, but certain partitionwise
-			 * planning operations require its reltarget to contain valid
-			 * expressions, so oblige.
-			 */
-			childrel->reltarget->exprs = (List *)
-				adjust_appendrel_attrs(root,
-									   (Node *) rel->reltarget->exprs,
-									   1, &appinfo);
-
-			set_dummy_rel_pathlist(childrel);
-			continue;
-		}
-
-		/*
-		 * Copy/Modify targetlist. Even if this child is deemed empty, we need
-		 * its targetlist in case it falls on nullable side in a child-join
-		 * because of partitionwise join.
-		 *
-		 * NB: the resulting childrel->reltarget->exprs may contain arbitrary
-		 * expressions, which otherwise would not occur in a rel's targetlist.
-		 * Code that might be looking at an appendrel child must cope with
-		 * such.  (Normally, a rel's targetlist would only include Vars and
-		 * PlaceHolderVars.)  XXX we do not bother to update the cost or width
-		 * fields of childrel->reltarget; not clear if that would be useful.
-		 */
-		if (rootParentRTindex == root->parse->resultRelation)
-		{
-			Query	   *parse,
-					   *orig_parse = root->parse;
-			List	   *tlist;
-			List	   *other_exprs;
-			ListCell   *lc2;
-
-			parse = (Query *)
-					adjust_appendrel_attrs(root,
-										   (Node *) root->parse,
-										   1, &appinfo);
-			root->parse = parse;
-			tlist = preprocess_targetlist(root);
-			build_base_rel_tlists(root, tlist);
-			root->parse = orig_parse;
-
-			/*
-			 * Now add members of parent's reltarget->exprs, not already in
-			 * child's.
-			 */
-			other_exprs = (List *)
-				adjust_appendrel_attrs(root,
-									   (Node *) rel->reltarget->exprs,
-									   1, &appinfo);
-			foreach(lc2, other_exprs)
-			{
-				if (!list_member(childrel->reltarget->exprs, lfirst(lc2)))
-					childrel->reltarget->exprs =
-								lappend(childrel->reltarget->exprs,
-										lfirst(lc2));
-			}
-		}
-		else
-			childrel->reltarget->exprs = (List *)
-				adjust_appendrel_attrs(root,
-									   (Node *) rel->reltarget->exprs,
-									   1, &appinfo);
+		if (rel->has_eclass_joins || has_useful_pathkeys(root, rel))
+			add_child_rel_equivalences(root, appinfo, rel, childrel);
+		childrel->has_eclass_joins = rel->has_eclass_joins;
 
 		/* CE failed, so finish copying/modifying join quals. */
 		childrel->joininfo = (List *)
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index beb3e95101..e7927cc136 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -16,6 +16,7 @@
 
 #include "catalog/pg_type.h"
 #include "catalog/pg_class.h"
+#include "catalog/pg_inherits.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
@@ -145,47 +146,29 @@ add_rel_partitions_to_query(PlannerInfo *root, RelOptInfo *rel,
 							bool scan_all_parts,
 							Bitmapset *partindexes)
 {
-	int		new_size;
-	int		num_added_parts;
-	int		i;
+	int			i;
+	Index		rootRTindex;
+	PlanRowMark *rootrc = NULL;
 
-	Assert(partindexes != NULL || scan_all_parts);
+	rootRTindex = get_inheritance_root_parent(root, rel);
+	if (root->rowMarks)
+		rootrc = get_plan_rowmark(root->rowMarks, rootRTindex);
 
-	/* Expand the PlannerInfo arrays to hold new partition objects. */
-	num_added_parts = scan_all_parts ? rel->nparts :
-						bms_num_members(partindexes);
-	new_size = root->simple_rel_array_size + num_added_parts;
-	root->simple_rte_array = (RangeTblEntry **)
-							repalloc(root->simple_rte_array,
-									 sizeof(RangeTblEntry *) * new_size);
-	root->simple_rel_array = (RelOptInfo **)
-								repalloc(root->simple_rel_array,
-										 sizeof(RelOptInfo *) * new_size);
-	if (root->append_rel_array)
-		root->append_rel_array = (AppendRelInfo **)
-									repalloc(root->append_rel_array,
-									 sizeof(AppendRelInfo *) * new_size);
-	else
-		root->append_rel_array = (AppendRelInfo **)
-									palloc0(sizeof(AppendRelInfo *) *
-											new_size);
+	expand_planner_arrays_for_inheritance(root,
+										  scan_all_parts ? rel->nparts :
+										  bms_num_members(partindexes));
 
-	/* Set the contents of just allocated memory to 0. */
-	MemSet(root->simple_rte_array + root->simple_rel_array_size,
-		   0, sizeof(RangeTblEntry *) * num_added_parts);
-	MemSet(root->simple_rel_array + root->simple_rel_array_size,
-		   0, sizeof(RelOptInfo *) * num_added_parts);
-	MemSet(root->append_rel_array + root->simple_rel_array_size,
-		   0, sizeof(AppendRelInfo *) * num_added_parts);
-	root->simple_rel_array_size = new_size;
-
-	/* And add the partitions. */
+	/* And add the partitions to the relation. */
+	rel->part_rels = (RelOptInfo **)
+				palloc0(sizeof(RelOptInfo *) * rel->nparts);
 	if (scan_all_parts)
 	{
 		for (i = 0; i < rel->nparts; i++)
 		{
 			rel->part_rels[i] = build_partition_rel(root, rel,
-													rel->part_oids[i]);
+													rel->part_oids[i],
+													rootRTindex,
+													rootrc);
 			rel->live_parts = bms_add_member(rel->live_parts, i);
 		}
 	}
@@ -195,8 +178,12 @@ add_rel_partitions_to_query(PlannerInfo *root, RelOptInfo *rel,
 		i = -1;
 		while ((i = bms_next_member(partindexes, i)) >= 0)
 			rel->part_rels[i] = build_partition_rel(root, rel,
-													rel->part_oids[i]);
+													rel->part_oids[i],
+													rootRTindex,
+													rootrc);
 	}
+
+
 }
 
 /*****************************************************************************
@@ -683,6 +670,7 @@ create_lateral_join_info(PlannerInfo *root)
 		}
 	}
 
+#ifdef NOT_USED
 	/*
 	 * Lastly, propagate lateral_relids and lateral_referencers from appendrel
 	 * parent rels to their child rels.  We intentionally give each child rel
@@ -740,6 +728,7 @@ create_lateral_join_info(PlannerInfo *root)
 			}
 		}
 	}
+#endif
 }
 
 
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index a757aba551..556eb64ae4 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -713,16 +713,6 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
 	preprocess_rowmarks(root);
 
 	/*
-	 * Expand any rangetable entries that are inheritance sets into "append
-	 * relations".  This can add entries to the rangetable, but they must be
-	 * plain base relations not joins, so it's OK (and marginally more
-	 * efficient) to do it after checking for join RTEs.  We must do it after
-	 * pulling up subqueries, else we'd fail to handle inherited tables in
-	 * subqueries.
-	 */
-	expand_inherited_tables(root);
-
-	/*
 	 * Set hasHavingQual to remember if HAVING clause is present.  Needed
 	 * because preprocess_expression will reduce a constant-true condition to
 	 * an empty qual list ... but "HAVING TRUE" is not a semantic no-op.
@@ -2369,7 +2359,7 @@ preprocess_rowmarks(PlannerInfo *root)
 		newrc->allMarkTypes = (1 << newrc->markType);
 		newrc->strength = rc->strength;
 		newrc->waitPolicy = rc->waitPolicy;
-		newrc->isParent = false;
+		newrc->isParent = has_subclass(rte->relid);
 
 		prowmarks = lappend(prowmarks, newrc);
 	}
@@ -2394,7 +2384,9 @@ preprocess_rowmarks(PlannerInfo *root)
 		newrc->allMarkTypes = (1 << newrc->markType);
 		newrc->strength = LCS_NONE;
 		newrc->waitPolicy = LockWaitBlock;	/* doesn't matter */
-		newrc->isParent = false;
+		newrc->isParent = rte->rtekind == RTE_RELATION ?
+							has_subclass(rte->relid) :
+							false;
 
 		prowmarks = lappend(prowmarks, newrc);
 	}
@@ -5871,8 +5863,19 @@ plan_create_index_workers(Oid tableOid, Oid indexOid)
 	rte->inFromCl = true;
 	query->rtable = list_make1(rte);
 
-	/* Set up RTE/RelOptInfo arrays */
-	setup_simple_rel_arrays(root);
+	/* Set up RTE/RelOptInfo arrays. */
+
+	/* Arrays are accessed using RT indexes (1..N) */
+	root->simple_rel_array_size = list_length(query->rtable) + 1;
+
+	/* simple_rel_array is initialized to all NULLs */
+	root->simple_rel_array = (RelOptInfo **)
+		palloc0(root->simple_rel_array_size * sizeof(RelOptInfo *));
+
+	/* simple_rte_array is an array equivalent of the rtable list */
+	root->simple_rte_array = (RangeTblEntry **)
+		palloc0(root->simple_rel_array_size * sizeof(RangeTblEntry *));
+	root->simple_rte_array[1] = rte;
 
 	/* Build RelOptInfo */
 	rel = build_simple_rel(root, 1, NULL);
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 4d9583e63b..400568a9e7 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -39,15 +39,20 @@
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/cost.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
+#include "optimizer/plancat.h"
 #include "optimizer/planmain.h"
 #include "optimizer/planner.h"
 #include "optimizer/prep.h"
+#include "optimizer/restrictinfo.h"
 #include "optimizer/tlist.h"
+#include "optimizer/var.h"
 #include "parser/parse_coerce.h"
 #include "parser/parsetree.h"
+#include "rewrite/rewriteManip.h"
 #include "utils/lsyscache.h"
 #include "utils/lsyscache.h"
 #include "utils/partcache.h"
@@ -101,12 +106,6 @@ static List *generate_append_tlist(List *colTypes, List *colCollations,
 					  List *input_tlists,
 					  List *refnames_tlist);
 static List *generate_setop_grouplist(SetOperationStmt *op, List *targetlist);
-static void expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte,
-						 Index rti);
-static void make_inh_translation_list(TupleDesc old_tupdesc,
-						  TupleDesc new_tupdesc,
-						  RangeTblEntry *oldrte, RangeTblEntry *newrte,
-						  Index newvarno, List **translated_vars);
 static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
 					List *translated_vars);
 static Node *adjust_appendrel_attrs_mutator(Node *node,
@@ -1452,37 +1451,6 @@ generate_setop_grouplist(SetOperationStmt *op, List *targetlist)
 	return grouplist;
 }
 
-
-/*
- * expand_inherited_tables
- *		Expand each rangetable entry that represents an inheritance set
- *		into an "append relation".  At the conclusion of this process,
- *		the "inh" flag is set in all and only those RTEs that are append
- *		relation parents.
- */
-void
-expand_inherited_tables(PlannerInfo *root)
-{
-	Index		nrtes;
-	Index		rti;
-	ListCell   *rl;
-
-	/*
-	 * expand_inherited_rtentry may add RTEs to parse->rtable. The function is
-	 * expected to recursively handle any RTEs that it creates with inh=true.
-	 * So just scan as far as the original end of the rtable list.
-	 */
-	nrtes = list_length(root->parse->rtable);
-	rl = list_head(root->parse->rtable);
-	for (rti = 1; rti <= nrtes; rti++)
-	{
-		RangeTblEntry *rte = (RangeTblEntry *) lfirst(rl);
-
-		expand_inherited_rtentry(root, rte, rti);
-		rl = lnext(rl);
-	}
-}
-
 /*
  * expand_inherited_rtentry
  *		Check whether a rangetable entry represents an inheritance set.
@@ -1503,30 +1471,34 @@ expand_inherited_tables(PlannerInfo *root)
  * Since a partitioned table is not scanned, it might have only one associated
  * AppendRelInfo.
  */
-static void
-expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
+void
+expand_inherited_rtentry(PlannerInfo *root,
+						 RelOptInfo *rel,
+						 RangeTblEntry *rte,
+						 Index rti)
 {
 	Query	   *parse = root->parse;
-	Oid			parentOID;
 	PlanRowMark *oldrc;
-	Relation	oldrelation;
 	LOCKMODE	lockmode;
 	List	   *inhOIDs;
-	ListCell   *l;
-	List	   *appinfos = NIL;
+	ListCell   *l,
+			   *l2;
+	List	   *childrtes = NIL,
+			   *appinfos = NIL;
+	int			num_children = 0;
 
-	/* Does RT entry allow inheritance? */
-	if (!rte->inh)
+	Assert(rte->inh);
+	/* Inheritance parent or UNION ALL parent query. */
+	Assert(rte->rtekind == RTE_RELATION || rte->rtekind == RTE_SUBQUERY);
+	/* No partitioned tables though. */
+	Assert(rte->relkind != RELKIND_PARTITIONED_TABLE);
+
+	/* Nothing to do for already-expanded UNION ALL nodes. */
+	if (rte->rtekind == RTE_SUBQUERY)
 		return;
-	/* Ignore any already-expanded UNION ALL nodes */
-	if (rte->rtekind != RTE_RELATION)
-	{
-		Assert(rte->rtekind == RTE_SUBQUERY);
-		return;
-	}
+
 	/* Fast path for common case of childless table */
-	parentOID = rte->relid;
-	if (!has_subclass(parentOID))
+	if (!has_subclass(rte->relid))
 	{
 		/* Clear flag before returning */
 		rte->inh = false;
@@ -1555,15 +1527,14 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 		lockmode = AccessShareLock;
 
 	/* Scan for all members of inheritance set, acquire needed locks */
-	if (rte->relkind != RELKIND_PARTITIONED_TABLE)
-		inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
+	inhOIDs = find_all_inheritors(rte->relid, lockmode, NULL);
 
 	/*
 	 * Check that there's at least one descendant, else treat as no-child
 	 * case.  This could happen despite above has_subclass() check, if table
 	 * once had a child but no longer does.
 	 */
-	if (rte->relkind != RELKIND_PARTITIONED_TABLE && list_length(inhOIDs) < 2)
+	if (list_length(inhOIDs) < 2)
 	{
 		/* Clear flag before returning */
 		rte->inh = false;
@@ -1578,33 +1549,145 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 	if (oldrc)
 		oldrc->isParent = true;
 
-	/* Partitioned tables are expanded elsewhere. */
-	if (rte->relkind == RELKIND_PARTITIONED_TABLE)
-		return;
-
-	/*
-	 * Must open the parent relation to examine its tupdesc.  We need not lock
-	 * it; we assume the rewriter already did.
-	 */
-	oldrelation = heap_open(parentOID, NoLock);
-
 	foreach(l, inhOIDs)
 	{
 		Oid			childOID = lfirst_oid(l);
+		Relation	childrel;
 		Index		childRTindex = 0;
 		RangeTblEntry *childrte = NULL;
-		AppendRelInfo *appinfo = NULL;
+		AppendRelInfo *appinfo;
+		List	   *childquals;
+		bool		have_const_false_cq;
+		ListCell   *lc;
 
-		add_inheritance_child_to_query(root, rte, rti,
-									   oldrelation->rd_rel->reltype,
-									   RelationGetDescr(oldrelation),
-									   oldrc, childOID, NoLock,
-									   &appinfo, &childrte,
-									   &childRTindex, NULL);
+		/* find_all_inheritors already locked. */
+		childrel = heap_open(childOID, NoLock);
+
+		/*
+		 * If childrel doesn't belong to this session, skip it, also
+		 * relinquishing the lock.
+		 */
+		if (RELATION_IS_OTHER_TEMP(childrel))
+		{
+			heap_close(childrel, lockmode);
+			continue;
+		}
+
+		/*
+		 * Initialize the AppendRelInfo that's used to map the child to its
+		 * parent in subsequent planning steps.
+		 */
+		appinfo = makeNode(AppendRelInfo);
+		appinfo->parent_relid = rti;
+
+		/*
+		 * We'll replace it with childRTindex once we're done adding the child
+		 * to the range table.
+		 */
+		appinfo->child_relid = rti;
+		appinfo->parent_reltype = rel->reltype;
+		appinfo->child_reltype = childrel->rd_rel->reltype;
+		make_inh_translation_list(rel->tupdesc,
+								  RelationGetDescr(childrel),
+								  rte->relid, childOID, rti,
+								  &appinfo->translated_vars);
+		appinfo->parent_reloid = rte->relid;
+
+		/*
+		 * Check if we don't need to include this child based on whether its
+		 * constraints contradict query's quals.  For a child that's not same
+		 * as the parent, we'll need to convert the quals' Vars so that they
+		 * contain child's attribute numbers.
+		 */
+		childquals = NIL;
+		have_const_false_cq = false;
+		foreach(lc, rel->baserestrictinfo)
+		{
+			RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
+			Node	   *childqual = (Node *) rinfo->clause;
+			ListCell   *lc2;
+
+			Assert(IsA(rinfo, RestrictInfo));
+			if (childOID != rte->relid)
+				childqual = adjust_appendrel_attrs(root, childqual,
+												   1, &appinfo);
+			childqual = eval_const_expressions(root, childqual);
+			/* check for flat-out constant */
+			if (childqual && IsA(childqual, Const))
+			{
+				if (((Const *) childqual)->constisnull ||
+					!DatumGetBool(((Const *) childqual)->constvalue))
+				{
+					/* Restriction reduces to constant FALSE or NULL */
+					have_const_false_cq = true;
+					break;
+				}
+				/* Restriction reduces to constant TRUE, so drop it */
+				continue;
+			}
+			/* might have gotten an AND clause, if so flatten it */
+			foreach(lc2, make_ands_implicit((Expr *) childqual))
+			{
+				Node	   *onecq = (Node *) lfirst(lc2);
+				bool		pseudoconstant;
+
+				/* check for pseudoconstant (no Vars or volatile functions) */
+				pseudoconstant =
+					!contain_vars_of_level(onecq, 0) &&
+					!contain_volatile_functions(onecq);
+				if (pseudoconstant)
+				{
+					/* tell createplan.c to check for gating quals */
+					root->hasPseudoConstantQuals = true;
+				}
+				/* reconstitute RestrictInfo with appropriate properties */
+				childquals = lappend(childquals,
+								 make_restrictinfo((Expr *) onecq,
+												   rinfo->is_pushed_down,
+												   rinfo->outerjoin_delayed,
+												   pseudoconstant,
+												   rinfo->security_level,
+												   NULL, NULL, NULL));
+			}
+		}
+
+		/*
+		 * Mark the child as empty in certain cases, such as if a restriction
+		 * clause reduced to constant FALSE or NULL, or if constaint exclusion
+		 * pruned it.  Note that we pass 'rti' for RT index that will be used
+		 * to initialize constraint expressions, because we haven't initialized
+		 * one for child yet.
+		 */
+		if (have_const_false_cq ||
+			relation_excluded_by_constraints(root, childquals, rti, childOID,
+											 true))
+		{
+			heap_close(childrel, NoLock);
+			continue;
+		}
+
+		childRTindex = add_inheritance_child_to_query(root, rte, childrel,
+													  appinfo, oldrc,
+													  &childrte);
+		heap_close(childrel, NoLock);
+
+		/* Fix up the AppendRelInfo using the child's actual RT index. */
 		Assert(childRTindex > 1);
-		Assert(childrte != NULL);
-		Assert(appinfo != NULL);
+		appinfo->child_relid = childRTindex;
+		ChangeVarNodes((Node *) appinfo->translated_vars, rti, childRTindex, 0);
+
+		/* Will be added to planner arrays below. */
+		childrtes = lappend(childrtes, childrte);
 		appinfos = lappend(appinfos, appinfo);
+
+		/* We'll scan this child. */
+		num_children++;
+	}
+
+	if (num_children == 0)
+	{
+		set_dummy_rel_pathlist(rel);
+		return;
 	}
 
 	/*
@@ -1620,95 +1703,28 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 		root->append_rel_list = list_concat(root->append_rel_list,
 											appinfos);
 
-	heap_close(oldrelation, NoLock);
+	expand_planner_arrays_for_inheritance(root, num_children);
+	forboth(l, childrtes, l2, appinfos)
+	{
+		RangeTblEntry *childrte = lfirst(l);
+		AppendRelInfo *appinfo = lfirst(l2);
+
+		Assert(appinfo->child_relid < root->simple_rel_array_size);
+		root->simple_rte_array[appinfo->child_relid] = childrte;
+		root->append_rel_array[appinfo->child_relid] = appinfo;
+	}
 }
 
-/*
- * add_inheritance_child_to_query
- *		Build a RangeTblEntry and an AppendRelInfo, if appropriate, plus
- *		maybe a PlanRowMark for a child relation.
- *
- * We now expand the partition hierarchy level by level, creating a
- * corresponding hierarchy of AppendRelInfos and RelOptInfos, where each
- * partitioned descendant acts as a parent of its immediate partitions.
- * (This is a difference from what older versions of PostgreSQL did and what
- * is still done in the case of table inheritance for unpartitioned tables,
- * where the hierarchy is flattened during RTE expansion.)
- *
- * PlanRowMarks still carry the top-parent's RTI, and the top-parent's
- * allMarkTypes field still accumulates values from all descendents.
- *
- * "parentrte" and "parentRTindex" are immediate parent's RTE and
- * RTI. "top_parentrc" is top parent's PlanRowMark.
- *
- * The child RangeTblEntry and its RTI are returned in "childrte_p" and
- * "childRTindex_p" resp.
- */
-void
-add_inheritance_child_to_query(PlannerInfo *root, RangeTblEntry *parentrte,
-							   Index parentRTindex, Oid parentRelType,
-							   TupleDesc parentDesc,
+Index
+add_inheritance_child_to_query(PlannerInfo *root,
+							   RangeTblEntry *parentrte,
+							   Relation childrel,
+							   AppendRelInfo *appinfo,
 							   PlanRowMark *top_parentrc,
-							   Oid childOID, int lockmode,
-							   AppendRelInfo **appinfo_p,
-							   RangeTblEntry **childrte_p,
-							   Index *childRTindex_p,
-							   PlanRowMark **child_rowmark)
+							   RangeTblEntry **childrte_p)
 {
-	Query	   *parse = root->parse;
-	Oid			parentOID = parentrte->relid;
+	Query	*parse = root->parse;
 	RangeTblEntry *childrte;
-	Index		childRTindex;
-	AppendRelInfo *appinfo;
-	Relation	childrel = NULL;
-	char		child_relkind;
-	Oid			child_reltype;
-	TupleDesc	childDesc;
-
-	*appinfo_p = NULL;
-	*childrte_p = NULL;
-	*childRTindex_p = 0;
-
-	/* Open rel if needed; we already have required locks */
-	if (childOID != parentOID)
-	{
-		childrel = heap_open(childOID, lockmode);
-
-		/*
-		 * Temporary partitions belonging to other sessions should have been
-		 * disallowed at definition, but for paranoia's sake, let's double
-		 * check.
-		 */
-		if (RELATION_IS_OTHER_TEMP(childrel))
-		{
-			if (childrel->rd_rel->relispartition)
-				elog(ERROR, "temporary relation from another session found as partition");
-			heap_close(childrel, lockmode);
-			return;
-		}
-
-		child_relkind = childrel->rd_rel->relkind;
-
-		/*
-		 * No point in adding to the query a partitioned table that has no
-		 * partitions.
-		 */
-		if (child_relkind == RELKIND_PARTITIONED_TABLE &&
-			RelationGetPartitionDesc(childrel)->nparts == 0)
-		{
-			heap_close(childrel, lockmode);
-			return;
-		}
-
-		child_reltype = childrel->rd_rel->reltype;
-		childDesc = RelationGetDescr(childrel);
-	}
-	else
-	{
-		child_relkind = parentrte->relkind;
-		child_reltype =  parentRelType;
-		childDesc = parentDesc;
-	}
 
 	/*
 	 * Build an RTE for the child, and attach to query's rangetable list. We
@@ -1723,11 +1739,10 @@ add_inheritance_child_to_query(PlannerInfo *root, RangeTblEntry *parentrte,
 	 * restriction clauses, so we don't need to do it here.
 	 */
 	childrte = copyObject(parentrte);
-	*childrte_p = childrte;
-	childrte->relid = childOID;
-	childrte->relkind = child_relkind;
+	childrte->relid = RelationGetRelid(childrel);
+	childrte->relkind = RelationGetForm(childrel)->relkind;
 	/* A partitioned child will need to be expanded further. */
-	if (childOID != parentOID &&
+	if (childrte->relid != parentrte->relid &&
 		childrte->relkind == RELKIND_PARTITIONED_TABLE)
 		childrte->inh = true;
 	else
@@ -1735,62 +1750,36 @@ add_inheritance_child_to_query(PlannerInfo *root, RangeTblEntry *parentrte,
 	childrte->requiredPerms = 0;
 	childrte->securityQuals = NIL;
 	parse->rtable = lappend(parse->rtable, childrte);
-	childRTindex = list_length(parse->rtable);
-	*childRTindex_p = childRTindex;
 
 	/*
-	 * We need an AppendRelInfo if paths will be built for the child RTE. If
-	 * childrte->inh is true, then we'll always need to generate append paths
-	 * for it.  If childrte->inh is false, we must scan it if it's not a
-	 * partitioned table; but if it is a partitioned table, then it never has
-	 * any data of its own and need not be scanned.
+	 * Translate the column permissions bitmaps to the child's attnums (we
+	 * have to build the translated_vars list before we can do this). But
+	 * if this is the parent table, leave copyObject's result alone.
+	 *
+	 * Note: we need to do this even though the executor won't run any
+	 * permissions checks on the child RTE.  The insertedCols/updatedCols
+	 * bitmaps may be examined for trigger-firing purposes.
 	 */
-	if (childrte->relkind != RELKIND_PARTITIONED_TABLE || childrte->inh)
+	if (childrte->relid != parentrte->relid)
 	{
-		appinfo = makeNode(AppendRelInfo);
-		appinfo->parent_relid = parentRTindex;
-		appinfo->child_relid = childRTindex;
-		appinfo->parent_reltype = parentRelType;
-		appinfo->child_reltype = child_reltype;
-		make_inh_translation_list(parentDesc, childDesc,
-								  parentrte, childrte, childRTindex,
-								  &appinfo->translated_vars);
-		appinfo->parent_reloid = parentOID;
-		*appinfo_p = appinfo;
-
-		/*
-		 * Translate the column permissions bitmaps to the child's attnums (we
-		 * have to build the translated_vars list before we can do this). But
-		 * if this is the parent table, leave copyObject's result alone.
-		 *
-		 * Note: we need to do this even though the executor won't run any
-		 * permissions checks on the child RTE.  The insertedCols/updatedCols
-		 * bitmaps may be examined for trigger-firing purposes.
-		 */
-		if (childOID != parentOID)
-		{
-			childrte->selectedCols = translate_col_privs(parentrte->selectedCols,
-														 appinfo->translated_vars);
-			childrte->insertedCols = translate_col_privs(parentrte->insertedCols,
-														 appinfo->translated_vars);
-			childrte->updatedCols = translate_col_privs(parentrte->updatedCols,
-														appinfo->translated_vars);
-		}
+		childrte->selectedCols = translate_col_privs(parentrte->selectedCols,
+													 appinfo->translated_vars);
+		childrte->insertedCols = translate_col_privs(parentrte->insertedCols,
+													 appinfo->translated_vars);
+		childrte->updatedCols = translate_col_privs(parentrte->updatedCols,
+													appinfo->translated_vars);
 	}
 
-	/*
-	 * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
-	 */
 	if (top_parentrc)
 	{
 		PlanRowMark *childrc = makeNode(PlanRowMark);
+		int		orig_allMarkTypes = top_parentrc->allMarkTypes;
 
-		childrc->rti = childRTindex;
+		childrc->rti = list_length(parse->rtable);
 		childrc->prti = top_parentrc->rti;
 		childrc->rowmarkId = top_parentrc->rowmarkId;
 		/* Reselect rowmark type, because relkind might not match parent */
-		childrc->markType = select_rowmark_type(childrte,
-												top_parentrc->strength);
+		childrc->markType = select_rowmark_type(childrte, top_parentrc->strength);
 		childrc->allMarkTypes = (1 << childrc->markType);
 		childrc->strength = top_parentrc->strength;
 		childrc->waitPolicy = top_parentrc->waitPolicy;
@@ -1804,18 +1793,65 @@ add_inheritance_child_to_query(PlannerInfo *root, RangeTblEntry *parentrte,
 
 		/* Include child's rowmark type in top parent's allMarkTypes */
 		top_parentrc->allMarkTypes |= childrc->allMarkTypes;
-
 		root->rowMarks = lappend(root->rowMarks, childrc);
-		if (child_rowmark)
-			*child_rowmark = childrc;
+
+		/*
+		 * Update query's targetlist if the newly added child row mark requires
+		 * additional columns and also add the relevant expressions to root
+		 * parent's reltarget.
+		 */
+		if (top_parentrc->allMarkTypes != orig_allMarkTypes)
+		{
+			List *tlist = root->parse->targetList;
+
+			tlist = add_rowmark_columns(root, tlist, list_make1(top_parentrc));
+			build_base_rel_tlists(root, tlist);
+		}
 	}
 
-	/* Close child relations, but keep locks */
-	if (childOID != parentOID)
+	*childrte_p = childrte;
+	return list_length(parse->rtable);
+}
+
+/*
+ * Starting with 'rel', find the root inheritance parent's RT index.
+ */
+Index
+get_inheritance_root_parent(PlannerInfo *root, RelOptInfo *rel)
+{
+	Index	rootRTindex = 0;
+
+	/* No AppendRelInfo array yet. */
+	if (root->append_rel_array == NULL)
+		return rel->relid;
+
+	/*
+	 * The inheritance root itself might be a child of UNION ALL subquery,
+	 * so we must resort to finding it like this.
+	 */
+	rootRTindex = rel->relid;
+	if (root->append_rel_array[rootRTindex])
 	{
-		Assert(childrel != NULL);
-		heap_close(childrel, lockmode);
+		AppendRelInfo *appinfo = root->append_rel_array[rootRTindex];
+		RangeTblEntry *parent = root->simple_rte_array[rootRTindex];
+
+		/*
+		 * Keep moving up until we reach the parent RTE that's not a
+		 * RTE_RELATION.  The last RTE_RELATION entry would be the
+		 * inheritance root's.
+		 */
+		while(parent->rtekind == RTE_RELATION)
+		{
+			appinfo = root->append_rel_array[appinfo->parent_relid];
+			if (appinfo == NULL)
+				break;
+			rootRTindex = appinfo->parent_relid;
+			parent = root->simple_rte_array[rootRTindex];
+		}
 	}
+
+	Assert(rootRTindex > 0);
+	return rootRTindex;
 }
 
 /*
@@ -1825,13 +1861,12 @@ add_inheritance_child_to_query(PlannerInfo *root, RangeTblEntry *parentrte,
  *
  * For paranoia's sake, we match type/collation as well as attribute name.
  */
-static void
+void
 make_inh_translation_list(TupleDesc old_tupdesc, TupleDesc new_tupdesc,
-						  RangeTblEntry *oldrte, RangeTblEntry *newrte,
+						  Oid from_rel, Oid to_rel,
 						  Index newvarno, List **translated_vars)
 {
 	List	   *vars = NIL;
-	Oid			new_relid = newrte->relid;
 	int			oldnatts = old_tupdesc->natts;
 	int			newnatts = new_tupdesc->natts;
 	int			old_attno;
@@ -1861,7 +1896,7 @@ make_inh_translation_list(TupleDesc old_tupdesc, TupleDesc new_tupdesc,
 		 * When we are generating the "translation list" for the parent table
 		 * of an inheritance set, no need to search for matches.
 		 */
-		if (oldrte->relid == newrte->relid)
+		if (from_rel == to_rel)
 		{
 			vars = lappend(vars, makeVar(newvarno,
 										 (AttrNumber) (old_attno + 1),
@@ -1887,10 +1922,10 @@ make_inh_translation_list(TupleDesc old_tupdesc, TupleDesc new_tupdesc,
 		{
 			HeapTuple	newtup;
 
-			newtup = SearchSysCacheAttName(new_relid, attname);
+			newtup = SearchSysCacheAttName(to_rel, attname);
 			if (!newtup)
 				elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"",
-					 attname, get_rel_name(newrte->relid));
+					 attname, get_rel_name(to_rel));
 			new_attno = ((Form_pg_attribute) GETSTRUCT(newtup))->attnum - 1;
 			ReleaseSysCache(newtup);
 
@@ -1900,10 +1935,10 @@ make_inh_translation_list(TupleDesc old_tupdesc, TupleDesc new_tupdesc,
 		/* Found it, check type and collation match */
 		if (atttypid != att->atttypid || atttypmod != att->atttypmod)
 			elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's type",
-				 attname, get_rel_name(newrte->relid));
+				 attname, get_rel_name(to_rel));
 		if (attcollation != att->attcollation)
 			elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's collation",
-				 attname, get_rel_name(newrte->relid));
+				 attname, get_rel_name(to_rel));
 
 		vars = lappend(vars, makeVar(newvarno,
 									 (AttrNumber) (new_attno + 1),
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 77ae4b538a..c4a485af91 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -65,7 +65,7 @@ static bool infer_collation_opclass_match(InferenceElem *elem, Relation idxRel,
 							  List *idxExprs);
 static int32 get_rel_data_width(Relation rel, int32 *attr_widths);
 static List *get_relation_constraints(PlannerInfo *root,
-						 Oid relationObjectId, RelOptInfo *rel,
+						 Oid relationObjectId, Index varno,
 						 bool include_notnull);
 static List *build_index_tlist(PlannerInfo *root, IndexOptInfo *index,
 				  Relation heapRelation);
@@ -99,14 +99,13 @@ static void set_baserel_partition_key_exprs(Relation relation,
  * cases these are left as zeroes, but sometimes we need to compute attr
  * widths here, and we may as well cache the results for costsize.c.
  *
- * If inhparent is true, all we need to do is set up the attr arrays:
+ * If rte->inh is true, all we need to do is set up the attr arrays:
  * the RelOptInfo actually represents the appendrel formed by an inheritance
  * tree, and so the parent rel's physical size and index information isn't
  * important for it.
  */
 void
-get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
-				  Bitmapset *updatedCols, RelOptInfo *rel)
+get_relation_info(PlannerInfo *root, RangeTblEntry *rte, RelOptInfo *rel)
 {
 	Index		varno = rel->relid;
 	Relation	relation;
@@ -118,7 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 	 * the rewriter or when expand_inherited_rtentry() added it to the query's
 	 * rangetable.
 	 */
-	relation = heap_open(relationObjectId, NoLock);
+	relation = heap_open(rte->relid, NoLock);
 
 	/* Temporary and unlogged relations are inaccessible during recovery. */
 	if (!RelationNeedsWAL(relation) && RecoveryInProgress())
@@ -142,7 +141,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 	 * must leave it zero for now to avoid bollixing the total_table_pages
 	 * calculation.
 	 */
-	if (!inhparent)
+	if (!rte->inh)
 		estimate_rel_size(relation, rel->attr_widths - rel->min_attr,
 						  &rel->pages, &rel->tuples, &rel->allvisfrac);
 
@@ -153,7 +152,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 	 * Make list of indexes.  Ignore indexes on system catalogs if told to.
 	 * Don't bother with indexes for an inheritance parent, either.
 	 */
-	if (inhparent ||
+	if (rte->inh ||
 		(IgnoreSystemIndexes && IsSystemRelation(relation)))
 		hasindex = false;
 	else
@@ -442,18 +441,18 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 	}
 
 	/* Collect info about relation's foreign keys, if relevant */
-	get_relation_foreign_keys(root, rel, relation, inhparent);
+	get_relation_foreign_keys(root, rel, relation, rte->inh);
 
 	/*
 	 * Collect info about relation's partitioning scheme, if any. Only
 	 * inheritance parents may be partitioned.
 	 */
-	if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	if (rte->inh && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
 	{
 		set_relation_partition_info(root, rel, relation);
 		if (!root->partColsUpdated)
 			root->partColsUpdated =
-				has_partition_attrs(relation, updatedCols, NULL);
+				has_partition_attrs(relation, rte->updatedCols, NULL);
 	}
 
 	rel->tupdesc = RelationGetDescr(relation);
@@ -467,7 +466,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 	 * removing an index, or adding a hypothetical index to the indexlist.
 	 */
 	if (get_relation_info_hook)
-		(*get_relation_info_hook) (root, relationObjectId, inhparent, rel);
+		(*get_relation_info_hook) (root, rte->relid, rte->inh, rel);
 }
 
 /*
@@ -1181,11 +1180,10 @@ get_relation_data_width(Oid relid, int32 *attr_widths)
  */
 static List *
 get_relation_constraints(PlannerInfo *root,
-						 Oid relationObjectId, RelOptInfo *rel,
+						 Oid relationObjectId, Index varno,
 						 bool include_notnull)
 {
 	List	   *result = NIL;
-	Index		varno = rel->relid;
 	Relation	relation;
 	TupleConstr *constr;
 
@@ -1363,16 +1361,16 @@ get_relation_statistics(RelOptInfo *rel, Relation relation)
  */
 bool
 relation_excluded_by_constraints(PlannerInfo *root,
-								 RelOptInfo *rel, RangeTblEntry *rte)
+								 List *baserestrictinfo,
+								 Index varno,
+								 Oid table_oid,
+								 bool is_child)
 {
 	List	   *safe_restrictions;
 	List	   *constraint_pred;
 	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
@@ -1382,9 +1380,9 @@ relation_excluded_by_constraints(PlannerInfo *root,
 	 * this, we'd miss some optimizations that 9.5 and earlier found via much
 	 * more roundabout methods.)
 	 */
-	if (list_length(rel->baserestrictinfo) == 1)
+	if (list_length(baserestrictinfo) == 1)
 	{
-		RestrictInfo *rinfo = (RestrictInfo *) linitial(rel->baserestrictinfo);
+		RestrictInfo *rinfo = (RestrictInfo *) linitial(baserestrictinfo);
 		Expr	   *clause = rinfo->clause;
 
 		if (clause && IsA(clause, Const) &&
@@ -1407,7 +1405,7 @@ relation_excluded_by_constraints(PlannerInfo *root,
 			 * When constraint_exclusion is set to 'partition' we only handle
 			 * OTHER_MEMBER_RELs.
 			 */
-			if (rel->reloptkind != RELOPT_OTHER_MEMBER_REL)
+			if (!is_child)
 				return false;
 			break;
 
@@ -1424,7 +1422,7 @@ relation_excluded_by_constraints(PlannerInfo *root,
 	 * expecting to see any in its predicate argument.
 	 */
 	safe_restrictions = NIL;
-	foreach(lc, rel->baserestrictinfo)
+	foreach(lc, baserestrictinfo)
 	{
 		RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
 
@@ -1440,24 +1438,10 @@ relation_excluded_by_constraints(PlannerInfo *root,
 		return true;
 
 	/*
-	 * Only plain relations have constraints.  In a partitioning hierarchy,
-	 * but not with regular table inheritance, it's OK to assume that any
-	 * constraints that hold for the parent also hold for every child; for
-	 * instance, table inheritance allows the parent to have constraints
-	 * marked NO INHERIT, but table partitioning does not.  We choose to check
-	 * whether the partitioning parents can be excluded here; doing so
-	 * consumes some cycles, but potentially saves us the work of excluding
-	 * each child individually.
-	 */
-	if (rte->rtekind != RTE_RELATION ||
-		(rte->inh && rte->relkind != RELKIND_PARTITIONED_TABLE))
-		return false;
-
-	/*
 	 * OK to fetch the constraint expressions.  Include "col IS NOT NULL"
 	 * expressions for attnotnull columns, in case we can refute those.
 	 */
-	constraint_pred = get_relation_constraints(root, rte->relid, rel, true);
+	constraint_pred = get_relation_constraints(root, table_oid, varno, true);
 
 	/*
 	 * We do not currently enforce that CHECK constraints contain only
@@ -1488,7 +1472,7 @@ relation_excluded_by_constraints(PlannerInfo *root,
 	 * We need strong refutation because we have to prove that the constraints
 	 * would yield false, not just NULL.
 	 */
-	if (predicate_refuted_by(safe_constraints, rel->baserestrictinfo, false))
+	if (predicate_refuted_by(safe_constraints, baserestrictinfo, false))
 		return true;
 
 	return false;
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index e98b626395..f87283e261 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -16,7 +16,10 @@
 
 #include <limits.h>
 
+#include "access/heapam.h"
+#include "catalog/partition.h"
 #include "catalog/pg_class.h"
+#include "catalog/pg_inherits.h"
 #include "miscadmin.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
@@ -24,12 +27,15 @@
 #include "optimizer/paths.h"
 #include "optimizer/placeholder.h"
 #include "optimizer/plancat.h"
+#include "optimizer/planmain.h"
 #include "optimizer/prep.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/tlist.h"
 #include "partitioning/partbounds.h"
+#include "rewrite/rewriteManip.h"
 #include "storage/lockdefs.h"
 #include "utils/hsearch.h"
+#include "utils/rel.h"
 
 
 typedef struct JoinHashEntry
@@ -91,6 +97,13 @@ setup_simple_rel_arrays(PlannerInfo *root)
 	{
 		RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
 
+		/*
+		 * If a table has no inheritance children, then turn off
+		 * inheritance so that further plannig steps process it as a
+		 * regular table.
+		 */
+		if (rte->rtekind == RTE_RELATION && !has_subclass(rte->relid))
+			rte->inh = false;
 		root->simple_rte_array[rti++] = rte;
 	}
 }
@@ -227,8 +240,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
 	{
 		case RTE_RELATION:
 			/* Table --- retrieve statistics from the system catalogs */
-			get_relation_info(root, rte->relid, rte->inh, rte->updatedCols,
-							  rel);
+			get_relation_info(root, rte, rel);
 			break;
 		case RTE_SUBQUERY:
 		case RTE_FUNCTION:
@@ -269,29 +281,17 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
 		root->qual_security_level = Max(root->qual_security_level,
 										list_length(rte->securityQuals));
 
+#ifdef NOT_USED
 	/*
 	 * If this rel is an appendrel parent, recurse to build "other rel"
 	 * RelOptInfos for its children.  They are "other rels" because they are
 	 * not in the main join tree, but we will need RelOptInfos to plan access
 	 * to them.
 	 */
-	if (rte->inh)
+	if (rte->inh && rte->rtekind == RTE_SUBQUERY)
 	{
 		ListCell   *l;
 
-		/*
-		 * For partitioned tables, we just allocate space for RelOptInfo's.
-		 * pointers for all partitions and copy the partition OIDs from the
-		 * relcache.  Actual RelOptInfo is built for a partition only if it is
-		 * not pruned.
-		 */
-		if (rte->relkind == RELKIND_PARTITIONED_TABLE)
-		{
-			rel->part_rels = (RelOptInfo **)
-				palloc0(sizeof(RelOptInfo *) * rel->nparts);
-			return rel;
-		}
-
 		foreach(l, root->append_rel_list)
 		{
 			AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
@@ -303,6 +303,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
 			(void) build_simple_rel(root, appinfo->child_relid, rel);
 		}
 	}
+#endif
 
 	return rel;
 }
@@ -1746,6 +1747,60 @@ build_joinrel_partition_info(RelOptInfo *joinrel, RelOptInfo *outer_rel,
 }
 
 /*
+ * build_child_join_reltarget
+ *	  Set up a child-join relation's reltarget from a parent-join relation.
+ */
+static void
+build_child_join_reltarget(PlannerInfo *root,
+						   RelOptInfo *parentrel,
+						   RelOptInfo *childrel,
+						   int nappinfos,
+						   AppendRelInfo **appinfos)
+{
+	/* Build the targetlist */
+	childrel->reltarget->exprs = (List *)
+		adjust_appendrel_attrs(root,
+							   (Node *) parentrel->reltarget->exprs,
+							   nappinfos, appinfos);
+
+	/* Set the cost and width fields */
+	childrel->reltarget->cost.startup = parentrel->reltarget->cost.startup;
+	childrel->reltarget->cost.per_tuple = parentrel->reltarget->cost.per_tuple;
+	childrel->reltarget->width = parentrel->reltarget->width;
+}
+
+/* Expand the PlannerInfo arrays to hold new inheritance children objects. */
+void
+expand_planner_arrays_for_inheritance(PlannerInfo *root, int num_children)
+{
+	int		new_size = root->simple_rel_array_size + num_children;
+
+	root->simple_rte_array = (RangeTblEntry **)
+							repalloc(root->simple_rte_array,
+									 sizeof(RangeTblEntry *) * new_size);
+	root->simple_rel_array = (RelOptInfo **)
+								repalloc(root->simple_rel_array,
+										 sizeof(RelOptInfo *) * new_size);
+	if (root->append_rel_array)
+		root->append_rel_array = (AppendRelInfo **)
+									repalloc(root->append_rel_array,
+									 sizeof(AppendRelInfo *) * new_size);
+	else
+		root->append_rel_array = (AppendRelInfo **)
+									palloc0(sizeof(AppendRelInfo *) *
+											new_size);
+
+	/* Set the contents of just allocated memory to 0. */
+	MemSet(root->simple_rte_array + root->simple_rel_array_size,
+		   0, sizeof(RangeTblEntry *) * num_children);
+	MemSet(root->simple_rel_array + root->simple_rel_array_size,
+		   0, sizeof(RelOptInfo *) * num_children);
+	MemSet(root->append_rel_array + root->simple_rel_array_size,
+		   0, sizeof(AppendRelInfo *) * num_children);
+	root->simple_rel_array_size = new_size;
+}
+
+/*
  * build_dummy_partition_rel
  *		Build a RelOptInfo and AppendRelInfo for a pruned partition
  *
@@ -1804,55 +1859,20 @@ build_dummy_partition_rel(PlannerInfo *root, RelOptInfo *parent, int partidx)
  *		range table and creating planner data structures for it
  */
 RelOptInfo *
-build_partition_rel(PlannerInfo *root, RelOptInfo *parent, Oid partoid)
+build_partition_rel(PlannerInfo *root,
+					RelOptInfo *parent,
+					Oid partoid,
+					Index rootRTindex,
+					PlanRowMark *rootrc)
 {
 	RangeTblEntry *parentrte = root->simple_rte_array[parent->relid];
-	RelOptInfo *result;
-	Index		rootRTindex = 0;
+	RangeTblEntry *partrte;
+	Relation	partrel;
+	PartitionDesc partdesc;
 	Index		partRTindex = 0;
-	RangeTblEntry *partrte = NULL;
-	AppendRelInfo *appinfo = NULL;
-	PlanRowMark *rootrc = NULL;
-	int			orig_allMarkTypes;
-	PlanRowMark *childrc = NULL;
+	AppendRelInfo *appinfo;
 	int			lockmode;
 
-	/* Locate the root partitioned table and fetch its PlanRowMark, if any. */
-	if (root->rowMarks)
-	{
-		/*
-		 * The root partitioned table itself might be a child of UNION ALL
-		 * parent, so we must resort to finding the root parent like this.
-		 */
-		rootRTindex = parent->relid;
-		if (root->append_rel_array[rootRTindex])
-		{
-			AppendRelInfo *tmp = root->append_rel_array[rootRTindex];
-
-			/*
-			 * Keep moving up until we each the parent rel that's not a
-			 * partitioned table.  The one before that one would be the root
-			 * parent.
-			 */
-			while(root->simple_rel_array[rootRTindex]->part_scheme)
-			{
-				tmp = root->append_rel_array[tmp->parent_relid];
-				if (tmp == NULL)
-					break;
-				rootRTindex = tmp->parent_relid;
-			}
-		}
-
-		rootrc = get_plan_rowmark(root->rowMarks, rootRTindex);
-
-		/*
-		 * Addition of certain child rowmarks will change the value, in which
-		 * case, we need to add additional columns to the query's targetlist.
-		 */
-		if (rootrc)
-			orig_allMarkTypes = rootrc->allMarkTypes;
-	}
-
 	/* Determine the correct lockmode to use. */
 	if (rootRTindex == root->parse->resultRelation)
 		lockmode = RowExclusiveLock;
@@ -1860,58 +1880,124 @@ build_partition_rel(PlannerInfo *root, RelOptInfo *parent, Oid partoid)
 		lockmode = RowShareLock;
 	else
 		lockmode = AccessShareLock;
-	add_inheritance_child_to_query(root, parentrte, parent->relid,
-								   parent->reltype, parent->tupdesc,
-								   rootrc, partoid, lockmode,
-								   &appinfo, &partrte, &partRTindex,
-								   &childrc);
 
-	/* Partition turned out to be a partitioned table with 0 partitions. */
-	if (partrte == NULL)
+	partrel = heap_open(partoid, lockmode);
+	Assert(!RELATION_IS_OTHER_TEMP(partrel));
+	partdesc = RelationGetPartitionDesc(partrel);
+	if (partdesc && partdesc->nparts == 0)
+	{
+		heap_close(partrel, NoLock);
 		return NULL;
+	}
+
+	appinfo = makeNode(AppendRelInfo);
+	appinfo->parent_relid = parent->relid;
+	appinfo->child_relid = 0;	/* Set to correct value below. */
+	appinfo->parent_reltype = parent->reltype;
+	appinfo->child_reltype = partrel->rd_rel->reltype;
+	make_inh_translation_list(parent->tupdesc,
+							  RelationGetDescr(partrel),
+							  parentrte->relid, partoid,
+							  parent->relid,
+							  &appinfo->translated_vars);
+	appinfo->parent_reloid = parentrte->relid;
+
+	partRTindex = add_inheritance_child_to_query(root, parentrte, partrel,
+												 appinfo, rootrc, &partrte);
+	heap_close(partrel, NoLock);
+
+	Assert(partrte != NULL);
+
+	/* Fix up the AppendRelInfo with correct child RT index. */
+	appinfo->child_relid = partRTindex;
+	ChangeVarNodes((Node *) appinfo->translated_vars, parent->relid,
+				   partRTindex, 0);
 
-	Assert(appinfo != NULL);
 	root->append_rel_list = lappend(root->append_rel_list, appinfo);
 	root->simple_rte_array[partRTindex] = partrte;
 	root->append_rel_array[partRTindex] = appinfo;
 
-	/* Build the RelOptInfo. */
-	result = build_simple_rel(root, partRTindex, parent);
-
-	/* Set the information created by create_lateral_join_info(). */
-	result->direct_lateral_relids = parent->direct_lateral_relids;
-	result->lateral_relids = parent->lateral_relids;
-	result->lateral_referencers = parent->lateral_referencers;
-
-	if (rootrc && rootrc->allMarkTypes != orig_allMarkTypes)
-	{
-		List *tlist = root->parse->targetList;
-
-		tlist = add_rowmark_columns(root, tlist, list_make1(rootrc));
-	}
-
-	return result;
+	return build_inheritance_child_rel(root, partRTindex, parent);
 }
 
-/*
- * build_child_join_reltarget
- *	  Set up a child-join relation's reltarget from a parent-join relation.
- */
-static void
-build_child_join_reltarget(PlannerInfo *root,
-						   RelOptInfo *parentrel,
-						   RelOptInfo *childrel,
-						   int nappinfos,
-						   AppendRelInfo **appinfos)
+RelOptInfo *
+build_inheritance_child_rel(PlannerInfo *root, Index childRTindex,
+							RelOptInfo *parent)
 {
-	/* Build the targetlist */
-	childrel->reltarget->exprs = (List *)
-		adjust_appendrel_attrs(root,
-							   (Node *) parentrel->reltarget->exprs,
-							   nappinfos, appinfos);
+	Relids		top_parent_relids = parent->top_parent_relids;
+	int			rootParentRTindex = top_parent_relids ?
+									bms_singleton_member(top_parent_relids) :
+									parent->relid;
+	AppendRelInfo *appinfo = root->append_rel_array[childRTindex];
+	/* Build the RelOptInfo. */
+	RelOptInfo *childrel = build_simple_rel(root, childRTindex, parent);
 
-	/* Set the cost and width fields */
-	childrel->reltarget->cost.startup = parentrel->reltarget->cost.startup;
-	childrel->reltarget->cost.per_tuple = parentrel->reltarget->cost.per_tuple;
-	childrel->reltarget->width = parentrel->reltarget->width;
+	/*
+	 * Propagate lateral_relids and lateral_referencers from appendrel
+	 * parent rels to their child rels.  We intentionally give each child rel
+	 * the same minimum parameterization, even though it's quite possible that
+	 * some don't reference all the lateral rels.  This is because any append
+	 * path for the parent will have to have the same parameterization for
+	 * every child anyway, and there's no value in forcing extra
+	 * reparameterize_path() calls.  Similarly, a lateral reference to the
+	 * parent prevents use of otherwise-movable join rels for each child.
+	 */
+	childrel->direct_lateral_relids = parent->direct_lateral_relids;
+	childrel->lateral_relids = parent->lateral_relids;
+	childrel->lateral_referencers = parent->lateral_referencers;
+
+		/*
+		 * Copy/Modify targetlist. Even if this child is deemed empty, we need
+		 * its targetlist in case it falls on nullable side in a child-join
+		 * because of partitionwise join.
+		 *
+		 * NB: the resulting childrel->reltarget->exprs may contain arbitrary
+		 * expressions, which otherwise would not occur in a rel's targetlist.
+		 * Code that might be looking at an appendrel child must cope with
+		 * such.  (Normally, a rel's targetlist would only include Vars and
+		 * PlaceHolderVars.)  XXX we do not bother to update the cost or width
+		 * fields of childrel->reltarget; not clear if that would be useful.
+		 */
+		if (rootParentRTindex == root->parse->resultRelation)
+		{
+			Query	   *parse,
+					   *orig_parse = root->parse;
+			List	   *tlist;
+			List	   *other_exprs;
+			ListCell   *lc2;
+
+			parse = (Query *)
+					adjust_appendrel_attrs(root,
+										   (Node *) root->parse,
+										   1, &appinfo);
+			root->parse = parse;
+			tlist = preprocess_targetlist(root);
+			build_base_rel_tlists(root, tlist);
+			root->parse = orig_parse;
+
+			/*
+			 * Now add members of parent's reltarget->exprs, not already in
+			 * child's.
+			 */
+			other_exprs = (List *)
+				adjust_appendrel_attrs(root,
+									   (Node *) parent->reltarget->exprs,
+									   1, &appinfo);
+			foreach(lc2, other_exprs)
+			{
+				if (!list_member(childrel->reltarget->exprs, lfirst(lc2)))
+					childrel->reltarget->exprs =
+								lappend(childrel->reltarget->exprs,
+										lfirst(lc2));
+			}
+		}
+		else
+		{
+			childrel->reltarget->exprs = (List *)
+				adjust_appendrel_attrs(root,
+									   (Node *) parent->reltarget->exprs,
+									   1, &appinfo);
+		}
+
+	return childrel;
 }
diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c
index 345ab19989..d5dad5a1e9 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -601,8 +601,6 @@ prune_append_rel_partitions(PlannerInfo *root, RelOptInfo *rel)
 			if (bms_is_empty(partindexes))
 				return;
 		}
-		else
-			scan_all_parts = true;
 	}
 	else
 		scan_all_parts = true;
@@ -611,7 +609,8 @@ prune_append_rel_partitions(PlannerInfo *root, RelOptInfo *rel)
 	 * Build selected partitions' range table entries, RelOptInfos, and
 	 * AppendRelInfos.
 	 */
-	add_rel_partitions_to_query(root, rel, scan_all_parts, partindexes);
+	if (scan_all_parts || !bms_is_empty(partindexes))
+		add_rel_partitions_to_query(root, rel, scan_all_parts, partindexes);
 }
 
 /*
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 4f567765a4..bf5a025b69 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -15,6 +15,7 @@
 #define PATHNODE_H
 
 #include "nodes/bitmapset.h"
+#include "nodes/plannodes.h"
 #include "nodes/relation.h"
 
 
@@ -261,6 +262,8 @@ extern Path *reparameterize_path_by_child(PlannerInfo *root, Path *path,
  */
 extern void setup_simple_rel_arrays(PlannerInfo *root);
 extern void setup_append_rel_array(PlannerInfo *root);
+extern void expand_planner_arrays_for_inheritance(PlannerInfo *root,
+										   int num_children);
 extern RelOptInfo *build_simple_rel(PlannerInfo *root, int relid,
 				 RelOptInfo *parent);
 extern RelOptInfo *find_base_rel(PlannerInfo *root, int relid);
@@ -300,8 +303,12 @@ extern RelOptInfo *build_child_join_rel(PlannerInfo *root,
 extern RelOptInfo *build_dummy_partition_rel(PlannerInfo *root,
 									RelOptInfo *parent,
 									int partidx);
+RelOptInfo *build_inheritance_child_rel(PlannerInfo *root, Index childRTindex,
+							RelOptInfo *parent);
 extern RelOptInfo *build_partition_rel(PlannerInfo *root,
 									   RelOptInfo *parent,
-									   Oid partoid);
+									   Oid partoid,
+									   Index rootRTindex,
+									   PlanRowMark *rootrc);
 
 #endif							/* PATHNODE_H */
diff --git a/src/include/optimizer/plancat.h b/src/include/optimizer/plancat.h
index edaf2a3b4f..5e1e7478bf 100644
--- a/src/include/optimizer/plancat.h
+++ b/src/include/optimizer/plancat.h
@@ -25,8 +25,8 @@ typedef void (*get_relation_info_hook_type) (PlannerInfo *root,
 extern PGDLLIMPORT get_relation_info_hook_type get_relation_info_hook;
 
 
-extern void get_relation_info(PlannerInfo *root, Oid relationObjectId,
-				  bool inhparent, Bitmapset *updatedCols, RelOptInfo *rel);
+extern void get_relation_info(PlannerInfo *root, RangeTblEntry *rte,
+						RelOptInfo *rel);
 
 extern List *infer_arbiter_indexes(PlannerInfo *root);
 
@@ -36,7 +36,10 @@ extern void estimate_rel_size(Relation rel, int32 *attr_widths,
 extern int32 get_relation_data_width(Oid relid, int32 *attr_widths);
 
 extern bool relation_excluded_by_constraints(PlannerInfo *root,
-								 RelOptInfo *rel, RangeTblEntry *rte);
+								 List *baserestrictinfo,
+								 Index varno,
+								 Oid table_oid,
+								 bool is_child);
 
 extern List *build_physical_tlist(PlannerInfo *root, RelOptInfo *rel);
 
diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h
index ee7406e4f6..1462e7b92f 100644
--- a/src/include/optimizer/prep.h
+++ b/src/include/optimizer/prep.h
@@ -16,6 +16,7 @@
 
 #include "nodes/plannodes.h"
 #include "nodes/relation.h"
+#include "utils/relcache.h"
 
 
 /*
@@ -50,18 +51,21 @@ extern PlanRowMark *get_plan_rowmark(List *rowmarks, Index rtindex);
  */
 extern RelOptInfo *plan_set_operations(PlannerInfo *root);
 
-extern void expand_inherited_tables(PlannerInfo *root);
-
-extern void add_inheritance_child_to_query(PlannerInfo *root,
-								RangeTblEntry *parentrte,
-								Index parentRTindex, Oid parentRelType,
-								TupleDesc parentDesc,
-								PlanRowMark *top_parentrc,
-								Oid childOID, int lockmode,
-								AppendRelInfo **appinfo_p,
-								RangeTblEntry **childrte_p,
-								Index *childRTindex_p,
-								PlanRowMark **child_rowmark);
+extern void expand_inherited_rtentry(PlannerInfo *root,
+						 RelOptInfo *rel,
+						 RangeTblEntry *rte,
+						 Index rti);
+extern Index add_inheritance_child_to_query(PlannerInfo *root,
+							   RangeTblEntry *parentrte,
+							   Relation childrel,
+							   AppendRelInfo *appinfo,
+							   PlanRowMark *top_parentrc,
+							   RangeTblEntry **childrte_p);
+extern Index get_inheritance_root_parent(PlannerInfo *root, RelOptInfo *rel);
+extern void make_inh_translation_list(TupleDesc old_tupdesc,
+						  TupleDesc new_tupdesc,
+						  Oid from_rel, Oid to_rel,
+						  Index newvarno, List **translated_vars);
 
 extern Node *adjust_appendrel_attrs(PlannerInfo *root, Node *node,
 					   int nappinfos, AppendRelInfo **appinfos);
-- 
2.11.0