aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeSubqueryscan.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2002-12-15 16:17:59 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2002-12-15 16:17:59 +0000
commit5bab36e9f6c3f3a9e14a89e1124179a339d2c3a1 (patch)
treea05154b129808efc7882599d96a1132051c2403b /src/backend/executor/nodeSubqueryscan.c
parent90b3a0b6fd3bc74804c01156491635e5d95091d9 (diff)
downloadpostgresql-5bab36e9f6c3f3a9e14a89e1124179a339d2c3a1.tar.gz
postgresql-5bab36e9f6c3f3a9e14a89e1124179a339d2c3a1.zip
Revise executor APIs so that all per-query state structure is built in
a per-query memory context created by CreateExecutorState --- and destroyed by FreeExecutorState. This provides a final solution to the longstanding problem of memory leaked by various ExecEndNode calls.
Diffstat (limited to 'src/backend/executor/nodeSubqueryscan.c')
-rw-r--r--src/backend/executor/nodeSubqueryscan.c50
1 files changed, 38 insertions, 12 deletions
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
index 68291ba6e34..4466ef34219 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -12,7 +12,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.15 2002/12/13 19:45:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.16 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,7 @@ SubqueryNext(SubqueryScanState *node)
EState *estate;
ScanDirection direction;
TupleTableSlot *slot;
+ MemoryContext oldcontext;
/*
* get information from the estate and scan state
@@ -66,12 +67,17 @@ SubqueryNext(SubqueryScanState *node)
*/
/*
- * get the next tuple from the sub-query
+ * Get the next tuple from the sub-query. We have to be careful to
+ * run it in its appropriate memory context.
*/
node->sss_SubEState->es_direction = direction;
+ oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
+
slot = ExecProcNode(node->subplan);
+ MemoryContextSwitchTo(oldcontext);
+
node->ss.ss_ScanTupleSlot = slot;
return slot;
@@ -106,6 +112,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
SubqueryScanState *subquerystate;
RangeTblEntry *rte;
EState *sp_estate;
+ MemoryContext oldcontext;
/*
* SubqueryScan should not have any "normal" children.
@@ -152,9 +159,17 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
Assert(rte->rtekind == RTE_SUBQUERY);
+ /*
+ * 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...
+ */
sp_estate = CreateExecutorState();
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;
@@ -163,8 +178,13 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
sp_estate->es_snapshot = estate->es_snapshot;
sp_estate->es_instrument = estate->es_instrument;
+ /*
+ * Start up the subplan (this is a very cut-down form of InitPlan())
+ */
subquerystate->subplan = ExecInitNode(node->subplan, sp_estate);
+ MemoryContextSwitchTo(oldcontext);
+
subquerystate->ss.ss_ScanTupleSlot = NULL;
subquerystate->ss.ps.ps_TupFromTlist = false;
@@ -197,10 +217,11 @@ ExecCountSlotsSubqueryScan(SubqueryScan *node)
void
ExecEndSubqueryScan(SubqueryScanState *node)
{
+ MemoryContext oldcontext;
+
/*
- * Free the projection info and the scan attribute info
+ * Free the exprcontext
*/
- ExecFreeProjectionInfo(&node->ss.ps);
ExecFreeExprContext(&node->ss.ps);
/*
@@ -211,15 +232,13 @@ ExecEndSubqueryScan(SubqueryScanState *node)
/*
* close down subquery
*/
- ExecEndNode(node->subplan);
+ oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
- /*
- * clean up subquery's tuple table
- */
- node->ss.ss_ScanTupleSlot = NULL;
- ExecDropTupleTable(node->sss_SubEState->es_tupleTable, true);
+ ExecEndPlan(node->subplan, node->sss_SubEState);
- /* XXX we seem to be leaking the sub-EState... */
+ MemoryContextSwitchTo(oldcontext);
+
+ FreeExecutorState(node->sss_SubEState);
}
/* ----------------------------------------------------------------
@@ -232,12 +251,17 @@ 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.
+ * changed-parameter signaling myself. This is just as well,
+ * because the subplan has its own memory context in which its
+ * chgParam lists live.
*/
if (node->ss.ps.chgParam != NULL)
SetChangedParamList(node->subplan, node->ss.ps.chgParam);
@@ -249,5 +273,7 @@ ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
if (node->subplan->chgParam == NULL)
ExecReScan(node->subplan, NULL);
+ MemoryContextSwitchTo(oldcontext);
+
node->ss.ss_ScanTupleSlot = NULL;
}