diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 6db354cd4f957e00bb9889e7b4a7120d1791c182..ec7959a9f5fcb180bb40c8c0c9332e1fe56824a3 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.281 2006/12/04 02:06:55 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.282 2006/12/26 21:37:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2247,6 +2247,10 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
 
 	rtsize = list_length(estate->es_range_table);
 
+	/*
+	 * It's tempting to think about using CreateSubExecutorState here, but
+	 * at present we can't because of memory leakage concerns ...
+	 */
 	epq->estate = epqstate = CreateExecutorState();
 
 	oldcontext = MemoryContextSwitchTo(epqstate->es_query_cxt);
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index d8290b3b5be7aebe27fbb6384f3ae897c54b898f..eef515a1de7e4ec877580e9bf3d4203c801c2315 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -8,13 +8,14 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.140 2006/10/04 00:29:52 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.141 2006/12/26 21:37:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * INTERFACE ROUTINES
  *		CreateExecutorState		Create/delete executor working state
+ *		CreateSubExecutorState
  *		FreeExecutorState
  *		CreateExprContext
  *		CreateStandaloneExprContext
@@ -65,6 +66,8 @@ int			NIndexTupleInserted;
 int			NIndexTupleProcessed;
 
 
+static EState *InternalCreateExecutorState(MemoryContext qcontext,
+										   bool is_subquery);
 static void ShutdownExprContext(ExprContext *econtext);
 
 
@@ -149,9 +152,7 @@ DisplayTupleCount(FILE *statfp)
 EState *
 CreateExecutorState(void)
 {
-	EState	   *estate;
 	MemoryContext qcontext;
-	MemoryContext oldcontext;
 
 	/*
 	 * Create the per-query context for this Executor run.
@@ -162,6 +163,37 @@ CreateExecutorState(void)
 									 ALLOCSET_DEFAULT_INITSIZE,
 									 ALLOCSET_DEFAULT_MAXSIZE);
 
+	return InternalCreateExecutorState(qcontext, false);
+}
+
+/* ----------------
+ *		CreateSubExecutorState
+ *
+ *		Create and initialize an EState node for a sub-query.
+ *
+ * Ideally, sub-queries probably shouldn't have their own EState at all,
+ * but right now this is necessary because they have their own rangetables
+ * and we access the rangetable via the EState.  It is critical that a
+ * sub-query share the parent's es_query_cxt, else structures allocated by
+ * the sub-query (especially its result tuple descriptor) may disappear
+ * too soon during executor shutdown.
+ * ----------------
+ */
+EState *
+CreateSubExecutorState(EState *parent_estate)
+{
+	return InternalCreateExecutorState(parent_estate->es_query_cxt, true);
+}
+
+/*
+ * Guts of CreateExecutorState/CreateSubExecutorState
+ */
+static EState *
+InternalCreateExecutorState(MemoryContext qcontext, bool is_subquery)
+{
+	EState	   *estate;
+	MemoryContext oldcontext;
+
 	/*
 	 * Make the EState node within the per-query context.  This way, we don't
 	 * need a separate pfree() operation for it at shutdown.
@@ -200,6 +232,8 @@ CreateExecutorState(void)
 	estate->es_lastoid = InvalidOid;
 	estate->es_rowMarks = NIL;
 
+	estate->es_is_subquery = is_subquery;
+
 	estate->es_instrument = false;
 	estate->es_select_into = false;
 	estate->es_into_oids = false;
@@ -258,9 +292,12 @@ FreeExecutorState(EState *estate)
 
 	/*
 	 * Free the per-query memory context, thereby releasing all working
-	 * memory, including the EState node itself.
+	 * memory, including the EState node itself.  In a subquery, we don't
+	 * do this, leaving the memory cleanup to happen when the topmost query
+	 * is closed down.
 	 */
-	MemoryContextDelete(estate->es_query_cxt);
+	if (!estate->es_is_subquery)
+		MemoryContextDelete(estate->es_query_cxt);
 }
 
 /* ----------------
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index 2a5fd6d955da4eb18c37f5095272122e6817caff..069b5b7aa22d8524aa810ccdc55a6969c8350b07 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.80 2006/10/04 00:29:53 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.81 2006/12/26 21:37:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -635,7 +635,6 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
 {
 	SubPlan    *subplan = (SubPlan *) node->xprstate.expr;
 	EState	   *sp_estate;
-	MemoryContext oldcontext;
 
 	/*
 	 * Do access checking on the rangetable entries in the subquery.
@@ -661,15 +660,13 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
 	 * create an EState for the subplan
 	 *
 	 * The subquery needs its own EState because it has its own rangetable. It
-	 * shares our Param ID space, however.	XXX if rangetable access were done
-	 * differently, the subquery could share our EState, which would eliminate
-	 * some thrashing about in this module...
+	 * shares our Param ID space and es_query_cxt, however.  XXX if rangetable
+	 * access were done differently, the subquery could share our EState,
+	 * which would eliminate some thrashing about in this module...
 	 */
-	sp_estate = CreateExecutorState();
+	sp_estate = CreateSubExecutorState(estate);
 	node->sub_estate = sp_estate;
 
-	oldcontext = MemoryContextSwitchTo(sp_estate->es_query_cxt);
-
 	sp_estate->es_range_table = subplan->rtable;
 	sp_estate->es_param_list_info = estate->es_param_list_info;
 	sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
@@ -694,8 +691,6 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
 
 	node->needShutdown = true;	/* now we need to shutdown the subplan */
 
-	MemoryContextSwitchTo(oldcontext);
-
 	/*
 	 * If this plan is un-correlated or undirect correlated one and want to
 	 * set params for parent plan then mark parameters as needing evaluation.
@@ -1036,11 +1031,7 @@ ExecEndSubPlan(SubPlanState *node)
 {
 	if (node->needShutdown)
 	{
-		MemoryContext oldcontext;
-
-		oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
 		ExecEndPlan(node->planstate, node->sub_estate);
-		MemoryContextSwitchTo(oldcontext);
 		FreeExecutorState(node->sub_estate);
 		node->sub_estate = NULL;
 		node->planstate = NULL;
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
index 45dfdb838d55e36d1fb328fbb89529ab52f193bd..f715676d6e2aeaa731139f3b930781dcda8204aa 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.33 2006/12/26 19:26:46 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.34 2006/12/26 21:37:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -49,7 +49,6 @@ SubqueryNext(SubqueryScanState *node)
 	EState	   *estate;
 	ScanDirection direction;
 	TupleTableSlot *slot;
-	MemoryContext oldcontext;
 
 	/*
 	 * get information from the estate and scan state
@@ -63,17 +62,12 @@ SubqueryNext(SubqueryScanState *node)
 	 */
 
 	/*
-	 * Get the next tuple from the sub-query.  We have to be careful to run it
-	 * in its appropriate memory context.
+	 * Get the next tuple from the sub-query.
 	 */
 	node->sss_SubEState->es_direction = direction;
 
-	oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
-
 	slot = ExecProcNode(node->subplan);
 
-	MemoryContextSwitchTo(oldcontext);
-
 	/*
 	 * We just overwrite our ScanTupleSlot with the subplan's result slot,
 	 * rather than expending the cycles for ExecCopySlot().
@@ -112,7 +106,6 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
 	SubqueryScanState *subquerystate;
 	RangeTblEntry *rte;
 	EState	   *sp_estate;
-	MemoryContext oldcontext;
 
 	/* check for unsupported flags */
 	Assert(!(eflags & EXEC_FLAG_MARK));
@@ -170,15 +163,13 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
 
 	/*
 	 * The subquery needs its own EState because it has its own rangetable. It
-	 * shares our Param ID space, however.	XXX if rangetable access were done
-	 * differently, the subquery could share our EState, which would eliminate
-	 * some thrashing about in this module...
+	 * shares our Param ID space and es_query_cxt, however.  XXX if rangetable
+	 * access were done differently, the subquery could share our EState,
+	 * which would eliminate some thrashing about in this module...
 	 */
-	sp_estate = CreateExecutorState();
+	sp_estate = CreateSubExecutorState(estate);
 	subquerystate->sss_SubEState = sp_estate;
 
-	oldcontext = MemoryContextSwitchTo(sp_estate->es_query_cxt);
-
 	sp_estate->es_range_table = rte->subquery->rtable;
 	sp_estate->es_param_list_info = estate->es_param_list_info;
 	sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
@@ -193,8 +184,6 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
 	 */
 	subquerystate->subplan = ExecInitNode(node->subplan, sp_estate, eflags);
 
-	MemoryContextSwitchTo(oldcontext);
-
 	subquerystate->ss.ps.ps_TupFromTlist = false;
 
 	/*
@@ -235,8 +224,6 @@ ExecCountSlotsSubqueryScan(SubqueryScan *node)
 void
 ExecEndSubqueryScan(SubqueryScanState *node)
 {
-	MemoryContext oldcontext;
-
 	/*
 	 * Free the exprcontext
 	 */
@@ -251,12 +238,8 @@ ExecEndSubqueryScan(SubqueryScanState *node)
 	/*
 	 * close down subquery
 	 */
-	oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
-
 	ExecEndPlan(node->subplan, node->sss_SubEState);
 
-	MemoryContextSwitchTo(oldcontext);
-
 	FreeExecutorState(node->sss_SubEState);
 }
 
@@ -270,12 +253,9 @@ void
 ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
 {
 	EState	   *estate;
-	MemoryContext oldcontext;
 
 	estate = node->ss.ps.state;
 
-	oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
-
 	/*
 	 * ExecReScan doesn't know about my subplan, so I have to do
 	 * changed-parameter signaling myself.	This is just as well, because the
@@ -291,8 +271,6 @@ ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
 	if (node->subplan->chgParam == NULL)
 		ExecReScan(node->subplan, NULL);
 
-	MemoryContextSwitchTo(oldcontext);
-
 	node->ss.ss_ScanTupleSlot = NULL;
 	node->ss.ps.ps_TupFromTlist = false;
 }
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index beb103c88e3d4932f37fa118ea8691cd0a5cf717..c5d2c1f5cefebe9dd1fcbc75cf477148f9cc2e32 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.131 2006/12/04 02:06:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.132 2006/12/26 21:37:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -225,6 +225,7 @@ extern void end_tup_output(TupOutputState *tstate);
  * prototypes from functions in execUtils.c
  */
 extern EState *CreateExecutorState(void);
+extern EState *CreateSubExecutorState(EState *parent_estate);
 extern void FreeExecutorState(EState *estate);
 extern ExprContext *CreateExprContext(EState *estate);
 extern ExprContext *CreateStandaloneExprContext(void);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index f8e8f15a5dba916194f2b556a51c3d629b5f0579..89bd31e96aef6e0a1b86b51d79e72a42c5aaa6b5 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.164 2006/12/24 00:29:20 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.165 2006/12/26 21:37:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -328,6 +328,8 @@ typedef struct EState
 	Oid			es_lastoid;		/* last oid processed (by INSERT) */
 	List	   *es_rowMarks;	/* not good place, but there is no other */
 
+	bool		es_is_subquery;	/* true if subquery (es_query_cxt not mine) */
+
 	bool		es_instrument;	/* true requests runtime instrumentation */
 	bool		es_select_into; /* true if doing SELECT INTO */
 	bool		es_into_oids;	/* true to generate OIDs in SELECT INTO */