From d14241c2cf72966c09c1acece5cb44b5c84204b4 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 21 Jun 2012 17:26:07 -0400
Subject: [PATCH] Fix memory leak in ARRAY(SELECT ...) subqueries.

Repeated execution of an uncorrelated ARRAY_SUBLINK sub-select (which
I think can only happen if the sub-select is embedded in a larger,
correlated subquery) would leak memory for the duration of the query,
due to not reclaiming the array generated in the previous execution.
Per bug #6698 from Armando Miraglia.  Diagnosis and fix idea by Heikki,
patch itself by me.

This has been like this all along, so back-patch to all supported versions.
---
 src/backend/executor/nodeSubplan.c | 18 +++++++++++++-----
 src/include/nodes/execnodes.h      |  1 +
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index da31820e2d9..4b8746f4f26 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -668,6 +668,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
 	 * initialize my state
 	 */
 	sstate->curTuple = NULL;
+	sstate->curArray = PointerGetDatum(NULL);
 	sstate->projLeft = NULL;
 	sstate->projRight = NULL;
 	sstate->hashtable = NULL;
@@ -994,16 +995,23 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
 		int			paramid = linitial_int(subplan->setParam);
 		ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
 
-		prm->execPlan = NULL;
-		/* We build the result in query context so it won't disappear */
+		/*
+		 * We build the result array in query context so it won't disappear;
+		 * to avoid leaking memory across repeated calls, we have to remember
+		 * the latest value, much as for curTuple above.
+		 */
+		if (node->curArray != PointerGetDatum(NULL))
+			pfree(DatumGetPointer(node->curArray));
 		if (astate != NULL)
-			prm->value = makeArrayResult(astate,
-										 econtext->ecxt_per_query_memory);
+			node->curArray = makeArrayResult(astate,
+											 econtext->ecxt_per_query_memory);
 		else
 		{
 			MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
-			prm->value = PointerGetDatum(construct_empty_array(subplan->firstColType));
+			node->curArray = PointerGetDatum(construct_empty_array(subplan->firstColType));
 		}
+		prm->execPlan = NULL;
+		prm->value = node->curArray;
 		prm->isnull = false;
 	}
 	else if (!found)
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 6fe8c2303a2..aa391699871 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -708,6 +708,7 @@ typedef struct SubPlanState
 	ExprState  *testexpr;		/* state of combining expression */
 	List	   *args;			/* states of argument expression(s) */
 	HeapTuple	curTuple;		/* copy of most recent tuple from subplan */
+	Datum		curArray;		/* most recent array from ARRAY() subplan */
 	/* these are used when hashing the subselect's output: */
 	ProjectionInfo *projLeft;	/* for projecting lefthand exprs */
 	ProjectionInfo *projRight;	/* for projecting subselect output */
-- 
GitLab