From 1b1106cace29025ef96b364e5bcd5bc7930c2eb7 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
Date: Wed, 21 Apr 2021 15:42:03 -0400
Subject: [PATCH 2/2] Make partitions-omitted partdescs have stmt lifetime

---
 src/backend/partitioning/partdesc.c | 50 ++++++++++++++++++++---------
 1 file changed, 35 insertions(+), 15 deletions(-)

diff --git a/src/backend/partitioning/partdesc.c b/src/backend/partitioning/partdesc.c
index 7d019a72be..399390b42c 100644
--- a/src/backend/partitioning/partdesc.c
+++ b/src/backend/partitioning/partdesc.c
@@ -88,6 +88,12 @@ RelationGetPartitionDesc(Relation rel, bool include_detached)
  * context the current context except in very brief code sections, out of fear
  * that some of our callees allocate memory on their own which would be leaked
  * permanently.
+ *
+ * As a special case, partition descriptors that are requested to omit
+ * partitions being detached (and which contain such partitions) are transient
+ * and are not to be associated with the relcache entry.  Such descriptors only
+ * last through the requesting Portal, so we use the corresponding memory
+ * context for them.
  */
 static PartitionDesc
 RelationBuildPartitionDesc(Relation rel, bool include_detached)
@@ -262,25 +268,39 @@ RelationBuildPartitionDesc(Relation rel, bool include_detached)
 	}
 
 	/*
-	 * We have a fully valid partdesc ready to store into the relcache.
-	 * Reparent it so it has the right lifespan.
+	 * We have a fully valid partdesc.  Reparent it so that it has the right
+	 * lifespan, and if appropriate put it into the relation's relcache entry.
 	 */
-	MemoryContextSetParent(new_pdcxt, CacheMemoryContext);
+	if (!include_detached && detached_exist)
+	{
+		/*
+		 * A transient partition descriptor is only good for the current
+		 * statement, so make it a child of the current portal's context.
+		 */
+		MemoryContextSetParent(new_pdcxt, PortalContext);
+	}
+	else
+	{
+		/*
+		 * This partdesc goes into relcache.
+		 */
 
-	/*
-	 * But first, a kluge: if there's an old rd_pdcxt, it contains an old
-	 * partition descriptor that may still be referenced somewhere.  Preserve
-	 * it, while not leaking it, by reattaching it as a child context of the
-	 * new rd_pdcxt.  Eventually it will get dropped by either RelationClose
-	 * or RelationClearRelation.
-	 */
-	if (rel->rd_pdcxt != NULL)
-		MemoryContextSetParent(rel->rd_pdcxt, new_pdcxt);
-	rel->rd_pdcxt = new_pdcxt;
+		MemoryContextSetParent(new_pdcxt, CacheMemoryContext);
 
-	/* Store it into relcache, but only if no detached partitions exist */
-	if (!detached_exist)
+		/*
+		 * But first, a kluge: if there's an old rd_pdcxt, it contains an old
+		 * partition descriptor that may still be referenced somewhere.
+		 * Preserve it, while not leaking it, by reattaching it as a child
+		 * context of the new rd_pdcxt.  Eventually it will get dropped by
+		 * either RelationClose or RelationClearRelation.
+		 */
+		if (rel->rd_pdcxt != NULL)
+			MemoryContextSetParent(rel->rd_pdcxt, new_pdcxt);
+		rel->rd_pdcxt = new_pdcxt;
+
+		/* Store it into relcache */
 		rel->rd_partdesc = partdesc;
+	}
 
 	return partdesc;
 }
-- 
2.20.1

