From 4565bcc63b9b2cf864493edc2afa72cebd812f25 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 4 Mar 2019 15:10:29 +0900
Subject: [PATCH v31 3/8] Delay adding inheritance child tables until
 query_planner

Inheritance child tables are now added by add_other_rels_to_query,
which is called by query_planner.  This replaces
expand_inherited_tables called by subquery_planner as the method
of adding child tables.  At the point when add_other_rels_to_query
is called, restriction clauses have already been assigned to
individual base relations, so it will now be possible to perform
partition pruning so that we know exact child tables to add in that
case.  This commit however doesn't change when pruning is performed.

inheritance_planner now adds the child target tables on its own,
because subquery_planner doesn't.  Also, since it calls query_planner
once for every child relation, source inheritance child tables are
added multiple times.  This both slows down queries when there are
inherited tables in UPDATE/DELETE's FROM clause (source inheritance)
and changes the EXPLAIN output a bit because source inheritance
child tables' aliases come out different for every targer child
subplan.  Another patch will fix both these issues.
---
 .../postgres_fdw/expected/postgres_fdw.out    |  46 +++---
 src/backend/optimizer/plan/planner.c          |  58 +++++--
 src/backend/optimizer/util/inherit.c          | 152 ++++++++++++------
 src/backend/optimizer/util/plancat.c          |   9 +-
 src/backend/optimizer/util/relnode.c          |  83 ++++++----
 src/include/optimizer/inherit.h               |   4 +-
 src/include/optimizer/pathnode.h              |   1 +
 src/test/regress/expected/partition_prune.out |  12 +-
 src/test/regress/expected/rowsecurity.out     |  16 +-
 9 files changed, 246 insertions(+), 135 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index c912e95fe1..bbc9ead2e9 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -7190,8 +7190,8 @@ select * from bar where f1 in (select f1 from foo) for share;
 -- Check UPDATE with inherited target and an inherited source table
 explain (verbose, costs off)
 update bar set f2 = f2 + 100 where f1 in (select f1 from foo);
-                                         QUERY PLAN                                          
----------------------------------------------------------------------------------------------
+                                            QUERY PLAN                                             
+---------------------------------------------------------------------------------------------------
  Update on public.bar
    Update on public.bar
    Foreign Update on public.bar2
@@ -7214,22 +7214,22 @@ update bar set f2 = f2 + 100 where f1 in (select f1 from foo);
                                  Output: foo2.f1, foo2.ctid, foo2.*, foo2.tableoid
                                  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1
    ->  Hash Join
-         Output: bar2.f1, (bar2.f2 + 100), bar2.f3, bar2.ctid, foo.ctid, foo.*, foo.tableoid
+         Output: bar2.f1, (bar2.f2 + 100), bar2.f3, bar2.ctid, foo_1.ctid, foo_1.*, foo_1.tableoid
          Inner Unique: true
-         Hash Cond: (bar2.f1 = foo.f1)
+         Hash Cond: (bar2.f1 = foo_1.f1)
          ->  Foreign Scan on public.bar2
                Output: bar2.f1, bar2.f2, bar2.f3, bar2.ctid
                Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
          ->  Hash
-               Output: foo.f1, foo.ctid, foo.*, foo.tableoid
+               Output: foo_1.f1, foo_1.ctid, foo_1.*, foo_1.tableoid
                ->  HashAggregate
-                     Output: foo.f1, foo.ctid, foo.*, foo.tableoid
-                     Group Key: foo.f1
+                     Output: foo_1.f1, foo_1.ctid, foo_1.*, foo_1.tableoid
+                     Group Key: foo_1.f1
                      ->  Append
-                           ->  Seq Scan on public.foo
-                                 Output: foo.f1, foo.ctid, foo.*, foo.tableoid
-                           ->  Foreign Scan on public.foo2
-                                 Output: foo2.f1, foo2.ctid, foo2.*, foo2.tableoid
+                           ->  Seq Scan on public.foo foo_1
+                                 Output: foo_1.f1, foo_1.ctid, foo_1.*, foo_1.tableoid
+                           ->  Foreign Scan on public.foo2 foo2_1
+                                 Output: foo2_1.f1, foo2_1.ctid, foo2_1.*, foo2_1.tableoid
                                  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1
 (39 rows)
 
@@ -7276,8 +7276,8 @@ where bar.f1 = ss.f1;
                ->  Seq Scan on public.bar
                      Output: bar.f1, bar.f2, bar.ctid
    ->  Merge Join
-         Output: bar2.f1, (bar2.f2 + 100), bar2.f3, bar2.ctid, (ROW(foo.f1))
-         Merge Cond: (bar2.f1 = foo.f1)
+         Output: bar2.f1, (bar2.f2 + 100), bar2.f3, bar2.ctid, (ROW(foo_2.f1))
+         Merge Cond: (bar2.f1 = foo_2.f1)
          ->  Sort
                Output: bar2.f1, bar2.f2, bar2.f3, bar2.ctid
                Sort Key: bar2.f1
@@ -7285,18 +7285,18 @@ where bar.f1 = ss.f1;
                      Output: bar2.f1, bar2.f2, bar2.f3, bar2.ctid
                      Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
          ->  Sort
-               Output: foo.f1, (ROW(foo.f1))
-               Sort Key: foo.f1
+               Output: foo_2.f1, (ROW(foo_2.f1))
+               Sort Key: foo_2.f1
                ->  Append
-                     ->  Seq Scan on public.foo
-                           Output: foo.f1, ROW(foo.f1)
-                     ->  Foreign Scan on public.foo2
-                           Output: foo2.f1, ROW(foo2.f1)
+                     ->  Seq Scan on public.foo foo_2
+                           Output: foo_2.f1, ROW(foo_2.f1)
+                     ->  Foreign Scan on public.foo2 foo2_2
+                           Output: foo2_2.f1, ROW(foo2_2.f1)
                            Remote SQL: SELECT f1 FROM public.loct1
-                     ->  Seq Scan on public.foo foo_1
-                           Output: (foo_1.f1 + 3), ROW((foo_1.f1 + 3))
-                     ->  Foreign Scan on public.foo2 foo2_1
-                           Output: (foo2_1.f1 + 3), ROW((foo2_1.f1 + 3))
+                     ->  Seq Scan on public.foo foo_3
+                           Output: (foo_3.f1 + 3), ROW((foo_3.f1 + 3))
+                     ->  Foreign Scan on public.foo2 foo2_3
+                           Output: (foo2_3.f1 + 3), ROW((foo2_3.f1 + 3))
                            Remote SQL: SELECT f1 FROM public.loct1
 (45 rows)
 
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 0db82453ac..2b77fa6d90 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -698,6 +698,8 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
 	 * remove_useless_result_rtes().  Also check for outer joins --- if none,
 	 * we can skip reduce_outer_joins().  And check for LATERAL RTEs, too.
 	 * This must be done after we have done pull_up_subqueries(), of course.
+	 * For RTE_RELATION rangetable entries whose inh flag is it, adjust the
+	 * value of the flag by checking whether has_subclass() returns true.
 	 */
 	root->hasJoinRTEs = false;
 	root->hasLateralRTEs = false;
@@ -717,28 +719,29 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
 		{
 			hasResultRTEs = true;
 		}
+		else if (rte->rtekind == RTE_RELATION && rte->inh)
+		{
+			rte->inh = has_subclass(rte->relid);
+
+			/*
+			 * While at it, initialize the PartitionDesc infrastructure for
+			 * this query, if not done yet.
+			 */
+			if (root->glob->partition_directory == NULL)
+				root->glob->partition_directory =
+					CreatePartitionDirectory(CurrentMemoryContext);
+		}
+
 		if (rte->lateral)
 			root->hasLateralRTEs = true;
 	}
 
 	/*
 	 * Preprocess RowMark information.  We need to do this after subquery
-	 * pullup (so that all non-inherited RTEs are present) and before
-	 * inheritance expansion (so that the info is available for
-	 * expand_inherited_tables to examine and modify).
+	 * pullup (so that all non-inherited RTEs are present).
 	 */
 	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 RTE_RELATION entries, so it's OK (and marginally more efficient)
-	 * to do it after checking for joins and other special RTEs.  We must do
-	 * this 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
@@ -1215,9 +1218,34 @@ inheritance_planner(PlannerInfo *root)
 	Query	   *parent_parse;
 	Bitmapset  *parent_relids = bms_make_singleton(top_parentRTindex);
 	PlannerInfo **parent_roots = NULL;
+	List	   *orig_append_rel_list = list_copy(root->append_rel_list);
 
 	Assert(parse->commandType != CMD_INSERT);
 
+	/*
+	 * Add child target relations.  Note that this only adds the children of
+	 * the query's target relation and no other.  Especially, children of any
+	 * source relations are added when the loop below calls grouping_planner
+	 * on the *1st* child target relation.
+	 */
+	parent_rte = rt_fetch(top_parentRTindex, root->parse->rtable);
+
+	expand_inherited_rtentry(root, parent_rte, top_parentRTindex);
+
+	/*
+	 * If parent no longer has any children, then treat this as an update of
+	 * a single table.
+	 */
+	if (!parent_rte->inh)
+	{
+		/*
+		 * We'll be retrieving all tuples to modify, so passing 0.0 for
+		 * tuple_fraction.
+		 */
+		grouping_planner(root, false, 0.0);
+		return;
+	}
+
 	/*
 	 * We generate a modified instance of the original Query for each target
 	 * relation, plan that, and put all the plans into a list that will be
@@ -1279,7 +1307,6 @@ inheritance_planner(PlannerInfo *root)
 	 * not appear anywhere else in the plan, so the confusion explained below
 	 * for non-partitioning inheritance cases is not possible.
 	 */
-	parent_rte = rt_fetch(top_parentRTindex, root->parse->rtable);
 	if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
 	{
 		nominalRelation = top_parentRTindex;
@@ -1330,6 +1357,9 @@ inheritance_planner(PlannerInfo *root)
 		subroot = makeNode(PlannerInfo);
 		memcpy(subroot, parent_root, sizeof(PlannerInfo));
 
+		/* grouping_planner doesn't need to see the target children. */
+		subroot->append_rel_list = list_copy(orig_append_rel_list);
+
 		/*
 		 * Generate modified query with this rel as target.  We first apply
 		 * adjust_appendrel_attrs, which copies the Query and changes
diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c
index 1fa154e0cb..24111c46e9 100644
--- a/src/backend/optimizer/util/inherit.c
+++ b/src/backend/optimizer/util/inherit.c
@@ -21,14 +21,14 @@
 #include "miscadmin.h"
 #include "optimizer/appendinfo.h"
 #include "optimizer/inherit.h"
+#include "optimizer/pathnode.h"
+#include "optimizer/planmain.h"
 #include "optimizer/planner.h"
 #include "optimizer/prep.h"
 #include "partitioning/partdesc.h"
 #include "utils/rel.h"
 
 
-static void expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte,
-						 Index rti);
 static void expand_partitioned_rtentry(PlannerInfo *root,
 						   RangeTblEntry *parentrte,
 						   Index parentRTindex, Relation parentrel,
@@ -44,36 +44,6 @@ static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
 					List *translated_vars);
 
 
-/*
- * 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.
@@ -94,7 +64,7 @@ expand_inherited_tables(PlannerInfo *root)
  * Since a partitioned table is not scanned, it might have only one associated
  * AppendRelInfo.
  */
-static void
+void
 expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 {
 	Oid			parentOID;
@@ -147,10 +117,6 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 	{
 		Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
 
-		if (root->glob->partition_directory == NULL)
-			root->glob->partition_directory =
-				CreatePartitionDirectory(CurrentMemoryContext);
-
 		/*
 		 * If this table has partitions, recursively expand and lock them.
 		 * While at it, also extract the partition key columns of all the
@@ -164,6 +130,8 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 		List	   *appinfos = NIL;
 		RangeTblEntry *childrte;
 		Index		childRTindex;
+		bool		is_source_inh_expansion;
+		RelOptInfo *rel = NULL;
 
 		/* Scan for all members of inheritance set, acquire needed locks */
 		inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
@@ -181,6 +149,20 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 			return;
 		}
 
+		/*
+		 * If parent is a source relation of the query, we'd need to add the
+		 * child RelOptInfos as well, in addition to RangeTblEntry's and
+		 * AppendRelInfo's.  We can tell it's source relation by noting that
+		 * simple_rel_array has been set up by query_planner.
+		 */
+		is_source_inh_expansion = (root->simple_rel_array_size > 0);
+		if (is_source_inh_expansion)
+		{
+			rel = find_base_rel(root, rti);
+			/* Expand various arrays in PlannerInfo to hold child object. */
+			expand_planner_arrays(root, list_length(inhOIDs));
+		}
+
 		/*
 		 * This table has no partitions.  Expand any plain inheritance
 		 * children in the order the OIDs were returned by
@@ -214,6 +196,10 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 											&appinfos, &childrte,
 											&childRTindex);
 
+			/* Create the otherrel RelOptInfo too. */
+			if (is_source_inh_expansion)
+				(void) build_simple_rel(root, childRTindex, rel);
+
 			/* Close child relations, but keep locks */
 			if (childOID != parentOID)
 				table_close(newrelation, NoLock);
@@ -251,12 +237,14 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
 	RangeTblEntry *childrte;
 	Index		childRTindex;
 	PartitionDesc partdesc;
+	RelOptInfo *rel = NULL;
+	bool		is_source_inh_expansion;
+
+	check_stack_depth();
 
 	partdesc = PartitionDirectoryLookup(root->glob->partition_directory,
 										parentrel);
 
-	check_stack_depth();
-
 	/* A partitioned table should always have a partition descriptor. */
 	Assert(partdesc);
 
@@ -273,6 +261,35 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
 		root->partColsUpdated =
 			has_partition_attrs(parentrel, parentrte->updatedCols, NULL);
 
+	/*
+	 * If parent is a source relation of the query, we'd need to add the child
+	 * RelOptInfos as well, in addition to RangeTblEntry's and
+	 * AppendRelInfo's.  We can tell it's source relation by noting that
+	 * simple_rel_array has been set up by query_planner.
+	 */
+	is_source_inh_expansion = (root->simple_rel_array_size > 0);
+	if (is_source_inh_expansion)
+	{
+		rel = find_base_rel(root, parentRTindex);
+
+		/*
+		 * Expand simple_rel_array and friends to hold child objects.
+		 *
+		 * We'll need nparts + 1 new slots, because we also consider parent
+		 * as a child relation. FIXME: no longer add the parent as child
+		 */
+		expand_planner_arrays(root, partdesc->nparts + 1);
+
+		/*
+		 * We also store partition RelOptInfo pointers in the parent
+		 * relation.
+		 */
+		Assert(rel->part_rels == NULL);
+		if (partdesc->nparts > 0)
+			rel->part_rels = (RelOptInfo **) palloc0(rel->nparts *
+													 sizeof(RelOptInfo *));
+	}
+
 	/* First expand the partitioned table itself. */
 	expand_single_inheritance_child(root, parentrte, parentRTindex, parentrel,
 									top_parentrc, parentrel,
@@ -308,8 +325,19 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
 										parentrel, top_parentrc, childrel,
 										appinfos, &childrte, &childRTindex);
 
-		/* If this child is itself partitioned, recurse */
-		if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		/* Create the otherrel RelOptInfo too. */
+		if (is_source_inh_expansion)
+		{
+			Assert(rel->part_rels != NULL && rel->part_rels[i] == NULL);
+			rel->part_rels[i] = build_simple_rel(root, childRTindex, rel);
+		}
+
+		/*
+		 * If this child is itself partitioned, recurse.  Back off if the inh
+		 * flag was reset by expand_single_inheritance_child().
+		 */
+		if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			childrte->inh)
 			expand_partitioned_rtentry(root, childrte, childRTindex,
 									   childrel, top_parentrc, lockmode,
 									   appinfos);
@@ -352,7 +380,14 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
 	Oid			childOID = RelationGetRelid(childrel);
 	RangeTblEntry *childrte;
 	Index		childRTindex;
-	AppendRelInfo *appinfo;
+	AppendRelInfo *appinfo = NULL;
+	PartitionDesc child_partdesc = NULL;
+	bool		is_source_inh_expansion;
+
+	if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		child_partdesc =
+			PartitionDirectoryLookup(root->glob->partition_directory,
+									 childrel);
 
 	/*
 	 * Build an RTE for the child, and attach to query's rangetable list. We
@@ -370,9 +405,11 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
 	*childrte_p = childrte;
 	childrte->relid = childOID;
 	childrte->relkind = childrel->rd_rel->relkind;
-	/* A partitioned child will need to be expanded further. */
-	if (childOID != parentOID &&
-		childrte->relkind == RELKIND_PARTITIONED_TABLE)
+	/*
+	 * A partitioned child will need to be expanded further, but only if it
+	 * actually has partitions.
+	 */
+	if (childOID != parentOID && child_partdesc && child_partdesc->nparts > 0)
 		childrte->inh = true;
 	else
 		childrte->inh = false;
@@ -383,13 +420,11 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
 	*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.
+	 * Don't need an AppendRelInfo for duplicate RTEs we create for
+	 * partitioned table parent rels.
 	 */
-	if (childrte->relkind != RELKIND_PARTITIONED_TABLE || childrte->inh)
+	if (childrte->relid != parentOID ||
+		childrte->relkind != RELKIND_PARTITIONED_TABLE)
 	{
 		appinfo = make_append_rel_info(parentrel, childrel,
 									   parentRTindex, childRTindex);
@@ -415,6 +450,21 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
 		}
 	}
 
+	/*
+	 * If we are expanding source inheritance, store the RTE and appinfo in the
+	 * respective PlannerInfo arrays, which the caller must already have
+	 * allocated space for.
+	 */
+	is_source_inh_expansion = (root->simple_rel_array_size > 0);
+	if (is_source_inh_expansion > 0)
+	{
+		Assert(childRTindex < root->simple_rel_array_size);
+		Assert(root->simple_rte_array[childRTindex] == NULL);
+		root->simple_rte_array[childRTindex] = childrte;
+		Assert(root->append_rel_array[childRTindex] == NULL);
+		root->append_rel_array[childRTindex] = appinfo;
+	}
+
 	/*
 	 * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
 	 */
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 30f4dc151b..2b22dff690 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -2091,7 +2091,14 @@ set_relation_partition_info(PlannerInfo *root, RelOptInfo *rel,
 	partkey = RelationGetPartitionKey(relation);
 	rel->part_scheme = find_partition_scheme(root, relation);
 	Assert(partdesc != NULL && rel->part_scheme != NULL);
-	rel->boundinfo = partition_bounds_copy(partdesc->boundinfo, partkey);
+	/*
+	 * XXX we should be able to Assert(partdesc->nparts > 0), but we've only
+	 * looked at inh flag so far, whose value is based on relhassubclass as
+	 * checked by subquery_planner().  relhassubclass may be stale as it's
+	 * only lazily updated as far as dropped partitions are concerned.
+	 */
+	if (partdesc->nparts > 0)
+		rel->boundinfo = partition_bounds_copy(partdesc->boundinfo, partkey);
 	rel->nparts = partdesc->nparts;
 	set_baserel_partition_key_exprs(relation, rel);
 	rel->partition_qual = RelationGetPartitionQual(relation);
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 8a59819469..9dcc3167e0 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -138,6 +138,50 @@ setup_append_rel_array(PlannerInfo *root)
 	}
 }
 
+/*
+ * expand_planner_arrays
+ *		Expand the PlannerInfo arrays by add_size members and initialize the
+ *		the newly added bytes with zero
+ */
+void
+expand_planner_arrays(PlannerInfo *root, int add_size)
+{
+	int		new_size;
+
+	Assert(add_size > 0);
+
+	new_size = root->simple_rel_array_size + add_size;
+
+	/* Expand various arrays and 0-initialize added bytes. */
+	root->simple_rte_array = (RangeTblEntry **)
+							repalloc(root->simple_rte_array,
+									 sizeof(RangeTblEntry *) * new_size);
+	MemSet(root->simple_rte_array + root->simple_rel_array_size,
+		   0, sizeof(RangeTblEntry *) * add_size);
+	root->simple_rel_array = (RelOptInfo **)
+								repalloc(root->simple_rel_array,
+										 sizeof(RelOptInfo *) * new_size);
+	MemSet(root->simple_rel_array + root->simple_rel_array_size,
+		   0, sizeof(RelOptInfo *) * add_size);
+
+	if (root->append_rel_array)
+	{
+		root->append_rel_array = (AppendRelInfo **)
+									repalloc(root->append_rel_array,
+									 sizeof(AppendRelInfo *) * new_size);
+		MemSet(root->append_rel_array + root->simple_rel_array_size,
+			   0, sizeof(AppendRelInfo *) * add_size);
+	}
+	else
+	{
+		root->append_rel_array = (AppendRelInfo **)
+									palloc0(sizeof(AppendRelInfo *) *
+											new_size);
+	}
+
+	root->simple_rel_array_size = new_size;
+}
+
 /*
  * build_simple_rel
  *	  Construct a new RelOptInfo for a base relation or 'other' relation.
@@ -295,22 +339,21 @@ add_appendrel_other_rels(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 {
 	ListCell	   *l;
 	RelOptInfo	   *rel;
-	int				i;
-
-	rel = find_base_rel(root, rti);
 
 	/*
-	 * For partitioned tables, we need to store the child RelOptInfos in the
-	 * rel->part_rels array too.
+	 * Add inheritance children to the query. For child tables that are
+	 * themselves partitioned, their children will be added recursively.
 	 */
-	if (rel->part_scheme)
+	if (rte->rtekind == RTE_RELATION)
 	{
-		Assert(rel->nparts > 0);
-		rel->part_rels = (RelOptInfo **)
-				palloc0(sizeof(RelOptInfo *) * rel->nparts);
+		expand_inherited_rtentry(root, rte, rti);
+		return;
 	}
 
-	i  = 0;
+	/* Add other rels of flattened UNION ALL children. */
+	Assert(rte->rtekind == RTE_SUBQUERY);
+	rel = find_base_rel(root, rti);
+
 	foreach(l, root->append_rel_list)
 	{
 		AppendRelInfo  *appinfo = lfirst(l);
@@ -326,30 +369,10 @@ add_appendrel_other_rels(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 		Assert(childrte != NULL);
 		childrel = build_simple_rel(root, childRTindex, rel);
 
-		/*
-		 * For partitioned parents, we also need to add childrel to its
-		 * part_rels array.  The order in which child tables appear in
-		 * append_rel_list is same as the order in which they appear in the
-		 * parent's PartitionDesc, so assigning partitions like this works.
-		 */
-		if (rel->part_scheme != NULL)
-		{
-			Assert(i < rel->nparts);
-			rel->part_rels[i] = childrel;
-		}
-
-		i++;
-
 		/* Child may itself be an inherited relation. */
 		if (childrte->inh)
 			add_appendrel_other_rels(root, childrte, childRTindex);
 	}
-
-	/*
-	 * For a partitioned table with non-zero number of partitions, we must
-	 * have assigned all elements of its part_rels array.
-	 */
-	Assert(rel->nparts == 0 || i == rel->nparts);
 }
 
 /*
diff --git a/src/include/optimizer/inherit.h b/src/include/optimizer/inherit.h
index d2418f15cf..427c1d0abe 100644
--- a/src/include/optimizer/inherit.h
+++ b/src/include/optimizer/inherit.h
@@ -16,7 +16,7 @@
 
 #include "nodes/pathnodes.h"
 
-
-extern void expand_inherited_tables(PlannerInfo *root);
+extern void expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte,
+								Index rti);
 
 #endif							/* INHERIT_H */
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 1a07963a7d..60361507d2 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -277,6 +277,7 @@ 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(PlannerInfo *root, int add_size);
 extern RelOptInfo *build_simple_rel(PlannerInfo *root, int relid,
 				 RelOptInfo *parent);
 extern void add_appendrel_other_rels(PlannerInfo *root, RangeTblEntry *rte,
diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out
index 30946f77b6..71942394ba 100644
--- a/src/test/regress/expected/partition_prune.out
+++ b/src/test/regress/expected/partition_prune.out
@@ -2559,16 +2559,16 @@ update ab_a1 set b = 3 from ab where ab.a = 1 and ab.a = ab_a1.a;
                            Index Cond: (a = 1)
    ->  Nested Loop (actual rows=1 loops=1)
          ->  Append (actual rows=1 loops=1)
-               ->  Bitmap Heap Scan on ab_a1_b1 ab_a1_b1_1 (actual rows=0 loops=1)
+               ->  Bitmap Heap Scan on ab_a1_b1 ab_a1_b1_2 (actual rows=0 loops=1)
                      Recheck Cond: (a = 1)
                      ->  Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1)
                            Index Cond: (a = 1)
-               ->  Bitmap Heap Scan on ab_a1_b2 ab_a1_b2_1 (actual rows=1 loops=1)
+               ->  Bitmap Heap Scan on ab_a1_b2 ab_a1_b2_2 (actual rows=1 loops=1)
                      Recheck Cond: (a = 1)
                      Heap Blocks: exact=1
                      ->  Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1)
                            Index Cond: (a = 1)
-               ->  Bitmap Heap Scan on ab_a1_b3 ab_a1_b3_1 (actual rows=0 loops=1)
+               ->  Bitmap Heap Scan on ab_a1_b3 ab_a1_b3_2 (actual rows=0 loops=1)
                      Recheck Cond: (a = 1)
                      ->  Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=1 loops=1)
                            Index Cond: (a = 1)
@@ -2580,16 +2580,16 @@ update ab_a1 set b = 3 from ab where ab.a = 1 and ab.a = ab_a1.a;
                            Index Cond: (a = 1)
    ->  Nested Loop (actual rows=0 loops=1)
          ->  Append (actual rows=1 loops=1)
-               ->  Bitmap Heap Scan on ab_a1_b1 ab_a1_b1_1 (actual rows=0 loops=1)
+               ->  Bitmap Heap Scan on ab_a1_b1 ab_a1_b1_3 (actual rows=0 loops=1)
                      Recheck Cond: (a = 1)
                      ->  Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1)
                            Index Cond: (a = 1)
-               ->  Bitmap Heap Scan on ab_a1_b2 ab_a1_b2_1 (actual rows=1 loops=1)
+               ->  Bitmap Heap Scan on ab_a1_b2 ab_a1_b2_3 (actual rows=1 loops=1)
                      Recheck Cond: (a = 1)
                      Heap Blocks: exact=1
                      ->  Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1)
                            Index Cond: (a = 1)
-               ->  Bitmap Heap Scan on ab_a1_b3 ab_a1_b3_1 (actual rows=0 loops=1)
+               ->  Bitmap Heap Scan on ab_a1_b3 ab_a1_b3_3 (actual rows=0 loops=1)
                      Recheck Cond: (a = 1)
                      ->  Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=1 loops=1)
                            Index Cond: (a = 1)
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index 2e170497c9..a6a499ed4a 100644
--- a/src/test/regress/expected/rowsecurity.out
+++ b/src/test/regress/expected/rowsecurity.out
@@ -1815,26 +1815,26 @@ AND f_leak(t1_1.b) AND f_leak(t1_2.b) RETURNING *, t1_1, t1_2;
                ->  Seq Scan on t3 t1_2_2
                      Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
    ->  Nested Loop
-         Join Filter: (t1_1_1.b = t1_2.b)
+         Join Filter: (t1_1_1.b = t1_2_3.b)
          ->  Seq Scan on t2 t1_1_1
                Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
          ->  Append
-               ->  Seq Scan on t1 t1_2
+               ->  Seq Scan on t1 t1_2_3
                      Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
-               ->  Seq Scan on t2 t1_2_1
+               ->  Seq Scan on t2 t1_2_4
                      Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
-               ->  Seq Scan on t3 t1_2_2
+               ->  Seq Scan on t3 t1_2_5
                      Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
    ->  Nested Loop
-         Join Filter: (t1_1_2.b = t1_2.b)
+         Join Filter: (t1_1_2.b = t1_2_6.b)
          ->  Seq Scan on t3 t1_1_2
                Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
          ->  Append
-               ->  Seq Scan on t1 t1_2
+               ->  Seq Scan on t1 t1_2_6
                      Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
-               ->  Seq Scan on t2 t1_2_1
+               ->  Seq Scan on t2 t1_2_7
                      Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
-               ->  Seq Scan on t3 t1_2_2
+               ->  Seq Scan on t3 t1_2_8
                      Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
 (37 rows)
 
-- 
2.17.2 (Apple Git-113)

