From 1056a963259ef0601bba6b1063d4a9d78bb52f57 Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Sat, 4 Nov 2017 23:44:02 +0100
Subject: [PATCH 4/4] remove-memory-leak-protection-v1

---
 src/backend/executor/nodeGather.c      | 14 ++------------
 src/backend/executor/nodeGatherMerge.c | 10 +---------
 src/backend/executor/tqueue.c          |  2 ++
 3 files changed, 5 insertions(+), 21 deletions(-)

diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index a1f0f7800e..1bdde15f89 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -129,7 +129,6 @@ static TupleTableSlot *
 ExecGather(PlanState *pstate)
 {
 	GatherState *node = castNode(GatherState, pstate);
-	TupleTableSlot *fslot = node->funnel_slot;
 	TupleTableSlot *slot;
 	ExprContext *econtext;
 
@@ -201,11 +200,8 @@ ExecGather(PlanState *pstate)
 
 	/*
 	 * Reset per-tuple memory context to free any expression evaluation
-	 * storage allocated in the previous tuple cycle.  This will also clear
-	 * any previous tuple returned by a TupleQueueReader; to make sure we
-	 * don't leave a dangling pointer around, clear the working slot first.
+	 * storage allocated in the previous tuple cycle.
 	 */
-	ExecClearTuple(fslot);
 	econtext = node->ps.ps_ExprContext;
 	ResetExprContext(econtext);
 
@@ -254,7 +250,6 @@ gather_getnext(GatherState *gatherstate)
 	PlanState  *outerPlan = outerPlanState(gatherstate);
 	TupleTableSlot *outerTupleSlot;
 	TupleTableSlot *fslot = gatherstate->funnel_slot;
-	MemoryContext tupleContext = gatherstate->ps.ps_ExprContext->ecxt_per_tuple_memory;
 	HeapTuple	tup;
 
 	while (gatherstate->nreaders > 0 || gatherstate->need_to_scan_locally)
@@ -263,12 +258,7 @@ gather_getnext(GatherState *gatherstate)
 
 		if (gatherstate->nreaders > 0)
 		{
-			MemoryContext oldContext;
-
-			/* Run TupleQueueReaders in per-tuple context */
-			oldContext = MemoryContextSwitchTo(tupleContext);
 			tup = gather_readnext(gatherstate);
-			MemoryContextSwitchTo(oldContext);
 
 			if (HeapTupleIsValid(tup))
 			{
@@ -276,7 +266,7 @@ gather_getnext(GatherState *gatherstate)
 							   fslot,	/* slot in which to store the tuple */
 							   InvalidBuffer,	/* buffer associated with this
 												 * tuple */
-							   false);	/* slot should not pfree tuple */
+							   true);	/* pfree tuple when done with it */
 				return fslot;
 			}
 		}
diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c
index 6da607b7c4..1f9818233b 100644
--- a/src/backend/executor/nodeGatherMerge.c
+++ b/src/backend/executor/nodeGatherMerge.c
@@ -605,7 +605,7 @@ load_tuple_array(GatherMergeState *gm_state, int reader)
 								  &tuple_buffer->done);
 		if (!HeapTupleIsValid(tuple))
 			break;
-		tuple_buffer->tuple[i] = heap_copytuple(tuple);
+		tuple_buffer->tuple[i] = tuple;
 		tuple_buffer->nTuples++;
 	}
 }
@@ -669,7 +669,6 @@ gather_merge_readnext(GatherMergeState *gm_state, int reader, bool nowait)
 								&tuple_buffer->done);
 		if (!HeapTupleIsValid(tup))
 			return false;
-		tup = heap_copytuple(tup);
 
 		/*
 		 * Attempt to read more tuples in nowait mode and store them in the
@@ -699,20 +698,13 @@ gm_readnext_tuple(GatherMergeState *gm_state, int nreader, bool nowait,
 {
 	TupleQueueReader *reader;
 	HeapTuple	tup;
-	MemoryContext oldContext;
-	MemoryContext tupleContext;
 
 	/* Check for async events, particularly messages from workers. */
 	CHECK_FOR_INTERRUPTS();
 
 	/* Attempt to read a tuple. */
 	reader = gm_state->reader[nreader - 1];
-
-	/* Run TupleQueueReaders in per-tuple context */
-	tupleContext = gm_state->ps.ps_ExprContext->ecxt_per_tuple_memory;
-	oldContext = MemoryContextSwitchTo(tupleContext);
 	tup = TupleQueueReaderNext(reader, nowait, done);
-	MemoryContextSwitchTo(oldContext);
 
 	return tup;
 }
diff --git a/src/backend/executor/tqueue.c b/src/backend/executor/tqueue.c
index e9a5d5a1a5..9fb4d7bc79 100644
--- a/src/backend/executor/tqueue.c
+++ b/src/backend/executor/tqueue.c
@@ -161,6 +161,8 @@ DestroyTupleQueueReader(TupleQueueReader *reader)
  * is set to true when there are no remaining tuples and otherwise to false.
  *
  * The returned tuple, if any, is allocated in CurrentMemoryContext.
+ * Note that this routine must not leak memory!  (We used to allow that,
+ * but not any more.)
  *
  * Even when shm_mq_receive() returns SHM_MQ_WOULD_BLOCK, this can still
  * accumulate bytes from a partially-read message, so it's useful to call
-- 
2.13.5 (Apple Git-94)

