From a0b1b7c2eadaebd236c48d9017effdf7c20fafc4 Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Wed, 30 Aug 2017 15:22:08 -0400
Subject: [PATCH 2/2] EIBO

---
 src/backend/optimizer/prep/prepunion.c | 126 ++++++++++++++++++++++++++-------
 src/test/regress/expected/insert.out   |   4 +-
 2 files changed, 104 insertions(+), 26 deletions(-)

diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 870a4a6bfd..3f5138f54e 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -33,6 +33,7 @@
 #include "access/heapam.h"
 #include "access/htup_details.h"
 #include "access/sysattr.h"
+#include "catalog/partition.h"
 #include "catalog/pg_inherits_fn.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
@@ -100,6 +101,13 @@ static List *generate_append_tlist(List *colTypes, List *colCollations,
 static List *generate_setop_grouplist(SetOperationStmt *op, List *targetlist);
 static void expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte,
 						 Index rti);
+static void expand_partitions_recursively(PlannerInfo *root,
+							  RangeTblEntry *rte,
+							  Index rti, Relation oldrelation,
+							  PlanRowMark *oldrc, PartitionDesc partdesc,
+							  LOCKMODE lockmode,
+							  bool *has_child, List **appinfos,
+							  List **partitioned_child_rels);
 static void expand_single_inheritance_child(PlannerInfo *root,
 								RangeTblEntry *rte,
 								Index rti, Relation oldrelation,
@@ -1461,37 +1469,62 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 	/* Scan the inheritance set and expand it */
 	appinfos = NIL;
 	has_child = false;
-	foreach(l, inhOIDs)
+	if (RelationGetPartitionDesc(oldrelation) != NULL)
 	{
-		Oid			childOID = lfirst_oid(l);
-		Relation	newrelation;
-
-		/* Open rel if needed; we already have required locks */
-		if (childOID != parentOID)
-			newrelation = heap_open(childOID, NoLock);
-		else
-			newrelation = oldrelation;
-
 		/*
-		 * It is possible that the parent table has children that are temp
-		 * tables of other backends.  We cannot safely access such tables
-		 * (because of buffering issues), and the best thing to do seems to be
-		 * to silently ignore them.
+		 * If this table has partitions, recursively expand them in the order
+		 * in which they appear in the PartitionDesc.  But first, expand the
+		 * parent itself.
 		 */
-		if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
-		{
-			heap_close(newrelation, lockmode);
-			continue;
-		}
-
 		expand_single_inheritance_child(root, rte, rti, oldrelation, oldrc,
-										newrelation,
+										oldrelation,
 										&has_child, &appinfos,
 										&partitioned_child_rels);
+		expand_partitions_recursively(root, rte, rti, oldrelation, oldrc,
+									  RelationGetPartitionDesc(oldrelation),
+									  lockmode,
+									  &has_child, &appinfos,
+									  &partitioned_child_rels);
+	}
+	else
+	{
+		/*
+		 * This table has no partitions.  Expand any plain inheritance
+		 * children in the order the OIDs were returned by
+		 * find_all_inheritors.
+		 */
+		foreach(l, inhOIDs)
+		{
+			Oid			childOID = lfirst_oid(l);
+			Relation	newrelation;
 
-		/* Close child relations, but keep locks */
-		if (childOID != parentOID)
-			heap_close(newrelation, NoLock);
+			/* Open rel if needed; we already have required locks */
+			if (childOID != parentOID)
+				newrelation = heap_open(childOID, NoLock);
+			else
+				newrelation = oldrelation;
+
+			/*
+			 * It is possible that the parent table has children that are temp
+			 * tables of other backends.  We cannot safely access such tables
+			 * (because of buffering issues), and the best thing to do seems
+			 * to be to silently ignore them.
+			 */
+			if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
+			{
+				heap_close(newrelation, lockmode);
+				continue;
+			}
+
+			expand_single_inheritance_child(root, rte, rti, oldrelation, oldrc,
+											newrelation,
+											&has_child, &appinfos,
+											&partitioned_child_rels);
+
+			/* Close child relations, but keep locks */
+			if (childOID != parentOID)
+				heap_close(newrelation, NoLock);
+		}
 	}
 
 	heap_close(oldrelation, NoLock);
@@ -1532,6 +1565,51 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 	root->append_rel_list = list_concat(root->append_rel_list, appinfos);
 }
 
+static void
+expand_partitions_recursively(PlannerInfo *root, RangeTblEntry *rte,
+							  Index rti, Relation oldrelation,
+							  PlanRowMark *oldrc, PartitionDesc partdesc,
+							  LOCKMODE lockmode,
+							  bool *has_child, List **appinfos,
+							  List **partitioned_child_rels)
+{
+	int			i;
+
+	check_stack_depth();
+
+	for (i = 0; i < partdesc->nparts; i++)
+	{
+		Oid			childOID = partdesc->oids[i];
+		Relation	newrelation;
+
+		/* Open rel; we already have required locks */
+		newrelation = heap_open(childOID, NoLock);
+
+		/* As in expand_inherited_rtentry, skip non-local temp tables */
+		if (RELATION_IS_OTHER_TEMP(newrelation))
+		{
+			heap_close(newrelation, lockmode);
+			continue;
+		}
+
+		expand_single_inheritance_child(root, rte, rti, oldrelation, oldrc,
+										newrelation,
+										has_child, appinfos,
+										partitioned_child_rels);
+
+		/* If this child is itself partitioned, recurse */
+		if (newrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+			expand_partitions_recursively(root, rte, rti, oldrelation, oldrc,
+										  RelationGetPartitionDesc(newrelation),
+										  lockmode,
+										  has_child, appinfos,
+										  partitioned_child_rels);
+
+		/* Close child relation, but keep locks */
+		heap_close(newrelation, NoLock);
+	}
+}
+
 /*
  * expand_single_inheritance_child
  *		Expand a single inheritance child, if needed.
diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out
index a2d9469592..e159d62b66 100644
--- a/src/test/regress/expected/insert.out
+++ b/src/test/regress/expected/insert.out
@@ -278,12 +278,12 @@ select tableoid::regclass, * from list_parted;
 -------------+----+----
  part_aa_bb  | aA |   
  part_cc_dd  | cC |  1
- part_null   |    |  0
- part_null   |    |  1
  part_ee_ff1 | ff |  1
  part_ee_ff1 | EE |  1
  part_ee_ff2 | ff | 11
  part_ee_ff2 | EE | 10
+ part_null   |    |  0
+ part_null   |    |  1
 (8 rows)
 
 -- some more tests to exercise tuple-routing with multi-level partitioning
-- 
2.11.0 (Apple Git-81)

