diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2002-12-15 16:17:59 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2002-12-15 16:17:59 +0000 |
commit | 5bab36e9f6c3f3a9e14a89e1124179a339d2c3a1 (patch) | |
tree | a05154b129808efc7882599d96a1132051c2403b /src/backend/executor/nodeSubqueryscan.c | |
parent | 90b3a0b6fd3bc74804c01156491635e5d95091d9 (diff) | |
download | postgresql-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.c | 50 |
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; } |