1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

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.
This commit is contained in:
Tom Lane
2002-12-15 16:17:59 +00:00
parent 90b3a0b6fd
commit 5bab36e9f6
42 changed files with 806 additions and 547 deletions

View File

@ -1,4 +1,4 @@
$Header: /cvsroot/pgsql/src/backend/executor/README,v 1.2 2002/12/05 15:50:30 tgl Exp $
$Header: /cvsroot/pgsql/src/backend/executor/README,v 1.3 2002/12/15 16:17:45 tgl Exp $
The Postgres Executor
---------------------
@ -60,6 +60,83 @@ ExprState nodes. (Actually, there are also List nodes, which are used as
"glue" in all four kinds of tree.)
Memory Management
-----------------
A "per query" memory context is created during CreateExecutorState();
all storage allocated during an executor invocation is allocated in that
context or a child context. This allows easy reclamation of storage
during executor shutdown --- rather than messing with retail pfree's and
probable storage leaks, we just destroy the memory context.
In particular, the plan state trees and expression state trees described
in the previous section are allocated in the per-query memory context.
To avoid intra-query memory leaks, most processing while a query runs
is done in "per tuple" memory contexts, which are so-called because they
are typically reset to empty once per tuple. Per-tuple contexts are usually
associated with ExprContexts, and commonly each PlanState node has its own
ExprContext to evaluate its qual and targetlist expressions in.
Query Processing Control Flow
-----------------------------
This is a sketch of control flow for full query processing:
CreateQueryDesc
ExecutorStart
CreateExecutorState
creates per-query context
switch to per-query context to run ExecInitNode
ExecInitNode --- recursively scans plan tree
CreateExprContext
creates per-tuple context
ExecInitExpr
ExecutorRun
ExecProcNode --- recursively called in per-query context
ExecEvalExpr --- called in per-tuple context
ResetExprContext --- to free memory
ExecutorEnd
ExecEndNode --- recursively releases resources
FreeExecutorState
frees per-query context and child contexts
FreeQueryDesc
Per above comments, it's not really critical for ExecEndNode to free any
memory; it'll all go away in FreeExecutorState anyway. However, we do need to
be careful to close relations, drop buffer pins, etc, so we do need to scan
the plan state tree to find these sorts of resources.
The executor can also be used to evaluate simple expressions without any Plan
tree ("simple" meaning "no aggregates and no sub-selects", though such might
be hidden inside function calls). This case has a flow of control like
CreateExecutorState
creates per-query context
CreateExprContext -- or use GetPerTupleExprContext(estate)
creates per-tuple context
ExecPrepareExpr
switch to per-query context to run ExecInitExpr
ExecInitExpr
Repeatedly do:
ExecEvalExprSwitchContext
ExecEvalExpr --- called in per-tuple context
ResetExprContext --- to free memory
FreeExecutorState
frees per-query context, as well as ExprContext
(a separate FreeExprContext call is not necessary)
EvalPlanQual (READ COMMITTED update checking)
---------------------------------------------

View File

@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.192 2002/12/13 19:45:52 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.193 2002/12/15 16:17:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -40,7 +40,6 @@
#include "executor/execdebug.h"
#include "executor/execdefs.h"
#include "miscadmin.h"
#include "optimizer/planmain.h"
#include "optimizer/var.h"
#include "parser/parsetree.h"
#include "utils/acl.h"
@ -53,7 +52,6 @@ static void initResultRelInfo(ResultRelInfo *resultRelInfo,
Index resultRelationIndex,
List *rangeTable,
CmdType operation);
static void EndPlan(PlanState *planstate, EState *estate);
static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate,
CmdType operation,
long numberTuples,
@ -86,27 +84,31 @@ static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
* field of the QueryDesc is filled in to describe the tuples that will be
* returned, and the internal fields (estate and planstate) are set up.
*
* XXX this will change soon:
* NB: the CurrentMemoryContext when this is called must be the context
* to be used as the per-query context for the query plan. ExecutorRun()
* and ExecutorEnd() must be called in this same memory context.
* NB: the CurrentMemoryContext when this is called will become the parent
* of the per-query context used for this Executor invocation.
* ----------------------------------------------------------------
*/
void
ExecutorStart(QueryDesc *queryDesc)
{
EState *estate;
MemoryContext oldcontext;
/* sanity checks: queryDesc must not be started already */
Assert(queryDesc != NULL);
Assert(queryDesc->estate == NULL);
/*
* Build EState, fill with parameters from queryDesc
* Build EState, switch into per-query memory context for startup.
*/
estate = CreateExecutorState();
queryDesc->estate = estate;
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
/*
* Fill in parameters, if any, from queryDesc
*/
estate->es_param_list_info = queryDesc->params;
if (queryDesc->plantree->nParamExec > 0)
@ -128,6 +130,8 @@ ExecutorStart(QueryDesc *queryDesc)
* Initialize the plan state tree
*/
InitPlan(queryDesc);
MemoryContextSwitchTo(oldcontext);
}
/* ----------------------------------------------------------------
@ -152,23 +156,30 @@ TupleTableSlot *
ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count)
{
CmdType operation;
EState *estate;
CmdType operation;
CommandDest dest;
DestReceiver *destfunc;
TupleTableSlot *result;
MemoryContext oldcontext;
/* sanity checks */
Assert(queryDesc != NULL);
estate = queryDesc->estate;
Assert(estate != NULL);
/*
* sanity checks
* Switch into per-query memory context
*/
Assert(queryDesc != NULL);
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
/*
* extract information from the query descriptor and the query
* feature.
*/
operation = queryDesc->operation;
estate = queryDesc->estate;
dest = queryDesc->dest;
/*
@ -199,6 +210,8 @@ ExecutorRun(QueryDesc *queryDesc,
*/
(*destfunc->cleanup) (destfunc);
MemoryContextSwitchTo(oldcontext);
return result;
}
@ -213,72 +226,37 @@ void
ExecutorEnd(QueryDesc *queryDesc)
{
EState *estate;
MemoryContext oldcontext;
/* sanity checks */
Assert(queryDesc != NULL);
estate = queryDesc->estate;
EndPlan(queryDesc->planstate, estate);
if (estate->es_snapshot != NULL)
{
if (estate->es_snapshot->xcnt > 0)
pfree(estate->es_snapshot->xip);
pfree(estate->es_snapshot);
estate->es_snapshot = NULL;
}
if (estate->es_param_exec_vals != NULL)
{
pfree(estate->es_param_exec_vals);
estate->es_param_exec_vals = NULL;
}
}
/*
* CreateExecutorState
*/
EState *
CreateExecutorState(void)
{
EState *state;
Assert(estate != NULL);
/*
* create a new executor state
* Switch into per-query memory context to run ExecEndPlan
*/
state = makeNode(EState);
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
ExecEndPlan(queryDesc->planstate, estate);
/*
* initialize the Executor State structure
* Must switch out of context before destroying it
*/
state->es_direction = ForwardScanDirection;
state->es_range_table = NIL;
state->es_result_relations = NULL;
state->es_num_result_relations = 0;
state->es_result_relation_info = NULL;
state->es_junkFilter = NULL;
state->es_into_relation_descriptor = NULL;
state->es_param_list_info = NULL;
state->es_param_exec_vals = NULL;
state->es_tupleTable = NULL;
state->es_query_cxt = CurrentMemoryContext;
state->es_instrument = false;
state->es_per_tuple_exprcontext = NULL;
MemoryContextSwitchTo(oldcontext);
/*
* return the executor state structure
* Release EState and per-query memory context. This should release
* everything the executor has allocated.
*/
return state;
FreeExecutorState(estate);
/* Reset queryDesc fields that no longer point to anything */
queryDesc->tupDesc = NULL;
queryDesc->estate = NULL;
queryDesc->planstate = NULL;
}
@ -794,13 +772,13 @@ initResultRelInfo(ResultRelInfo *resultRelInfo,
}
/* ----------------------------------------------------------------
* EndPlan
* ExecEndPlan
*
* Cleans up the query plan -- closes files and frees up storage
* ----------------------------------------------------------------
*/
static void
EndPlan(PlanState *planstate, EState *estate)
void
ExecEndPlan(PlanState *planstate, EState *estate)
{
ResultRelInfo *resultRelInfo;
int i;
@ -1542,9 +1520,8 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
for (i = 0; i < ncheck; i++)
{
qual = (List *) stringToNode(check[i].ccbin);
fix_opfuncids((Node *) qual);
resultRelInfo->ri_ConstraintExprs[i] = (List *)
ExecInitExpr((Expr *) qual, NULL);
ExecPrepareExpr((Expr *) qual, estate);
}
MemoryContextSwitchTo(oldContext);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.120 2002/12/14 00:17:50 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.121 2002/12/15 16:17:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -40,6 +40,7 @@
#include "executor/functions.h"
#include "executor/nodeSubplan.h"
#include "miscadmin.h"
#include "optimizer/planmain.h"
#include "parser/parse_expr.h"
#include "utils/acl.h"
#include "utils/array.h"
@ -1896,9 +1897,11 @@ ExecEvalExprSwitchContext(ExprState *expression,
* cleanup work can register a shutdown callback in the ExprContext.
*
* 'node' is the root of the expression tree to examine
* 'parent' is the PlanState node that owns the expression,
* or NULL if we are preparing an expression that is not associated
* with a plan. (If so, it can't have aggs or subplans.)
* 'parent' is the PlanState node that owns the expression.
*
* 'parent' may be NULL if we are preparing an expression that is not
* associated with a plan tree. (If so, it can't have aggs or subplans.)
* This case should usually come through ExecPrepareExpr, not directly here.
*/
ExprState *
ExecInitExpr(Expr *node, PlanState *parent)
@ -2017,6 +2020,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
* parent->subPlan. The subplans will be initialized later.
*/
parent->subPlan = lcons(sstate, parent->subPlan);
sstate->sub_estate = NULL;
sstate->planstate = NULL;
sstate->oper = (List *)
@ -2149,6 +2153,7 @@ ExecInitExprInitPlan(SubPlan *node, PlanState *parent)
elog(ERROR, "ExecInitExpr: SubPlan not expected here");
/* The subplan's state will be initialized later */
sstate->sub_estate = NULL;
sstate->planstate = NULL;
sstate->oper = (List *) ExecInitExpr((Expr *) node->oper, parent);
@ -2159,6 +2164,33 @@ ExecInitExprInitPlan(SubPlan *node, PlanState *parent)
return sstate;
}
/*
* ExecPrepareExpr --- initialize for expression execution outside a normal
* Plan tree context.
*
* This differs from ExecInitExpr in that we don't assume the caller is
* already running in the EState's per-query context. Also, we apply
* fix_opfuncids() to the passed expression tree to be sure it is ready
* to run. (In ordinary Plan trees the planner will have fixed opfuncids,
* but callers outside the executor will not have done this.)
*/
ExprState *
ExecPrepareExpr(Expr *node, EState *estate)
{
ExprState *result;
MemoryContext oldcontext;
fix_opfuncids((Node *) node);
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
result = ExecInitExpr(node, NULL);
MemoryContextSwitchTo(oldcontext);
return result;
}
/* ----------------------------------------------------------------
* ExecQual / ExecTargetList / ExecProject

View File

@ -8,13 +8,20 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.92 2002/12/13 19:45:52 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.93 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
* CreateExecutorState Create/delete executor working state
* FreeExecutorState
* CreateExprContext
* FreeExprContext
*
* ExecAssignExprContext Common code for plan node init routines.
* ExecAssignResultType
* etc
*
* ExecOpenIndices \
* ExecCloseIndices | referenced by InitPlan, EndPlan,
@ -26,7 +33,6 @@
* NOTES
* This file has traditionally been the place to stick misc.
* executor support stuff that doesn't really go anyplace else.
*
*/
#include "postgres.h"
@ -64,6 +70,7 @@ extern int NIndexTupleProcessed; /* have to be defined in the
static void ShutdownExprContext(ExprContext *econtext);
/* ----------------------------------------------------------------
* statistic functions
* ----------------------------------------------------------------
@ -124,136 +131,263 @@ DisplayTupleCount(FILE *statfp)
}
#endif
/* ----------------------------------------------------------------
* miscellaneous node-init support functions
* Executor state and memory management functions
* ----------------------------------------------------------------
*/
/* ----------------
* ExecAssignExprContext
* CreateExecutorState
*
* This initializes the ExprContext field. It is only necessary
* to do this for nodes which use ExecQual or ExecProject
* because those routines depend on econtext. Other nodes that
* don't have to evaluate expressions don't need to do this.
* Create and initialize an EState node, which is the root of
* working storage for an entire Executor invocation.
*
* Note: we assume CurrentMemoryContext is the correct per-query context.
* This should be true during plan node initialization.
* Principally, this creates the per-query memory context that will be
* used to hold all working data that lives till the end of the query.
* Note that the per-query context will become a child of the caller's
* CurrentMemoryContext.
* ----------------
*/
EState *
CreateExecutorState(void)
{
EState *estate;
MemoryContext qcontext;
MemoryContext oldcontext;
/*
* Create the per-query context for this Executor run.
*/
qcontext = AllocSetContextCreate(CurrentMemoryContext,
"ExecutorState",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/*
* Make the EState node within the per-query context. This way,
* we don't need a separate pfree() operation for it at shutdown.
*/
oldcontext = MemoryContextSwitchTo(qcontext);
estate = makeNode(EState);
/*
* Initialize all fields of the Executor State structure
*/
estate->es_direction = ForwardScanDirection;
estate->es_snapshot = SnapshotNow;
estate->es_range_table = NIL;
estate->es_result_relations = NULL;
estate->es_num_result_relations = 0;
estate->es_result_relation_info = NULL;
estate->es_junkFilter = NULL;
estate->es_into_relation_descriptor = NULL;
estate->es_param_list_info = NULL;
estate->es_param_exec_vals = NULL;
estate->es_query_cxt = qcontext;
estate->es_tupleTable = NULL;
estate->es_processed = 0;
estate->es_lastoid = InvalidOid;
estate->es_rowMark = NIL;
estate->es_instrument = false;
estate->es_exprcontexts = NIL;
estate->es_per_tuple_exprcontext = NULL;
estate->es_origPlan = NULL;
estate->es_evalPlanQual = NULL;
estate->es_evTupleNull = NULL;
estate->es_evTuple = NULL;
estate->es_useEvalPlan = false;
/*
* Return the executor state structure
*/
MemoryContextSwitchTo(oldcontext);
return estate;
}
/* ----------------
* FreeExecutorState
*
* Release an EState along with all remaining working storage.
*
* Note: this is not responsible for releasing non-memory resources,
* such as open relations or buffer pins. But it will shut down any
* still-active ExprContexts within the EState. That is sufficient
* cleanup for situations where the EState has only been used for expression
* evaluation, and not to run a complete Plan.
*
* This can be called in any memory context ... so long as it's not one
* of the ones to be freed.
* ----------------
*/
void
ExecAssignExprContext(EState *estate, PlanState *planstate)
FreeExecutorState(EState *estate)
{
ExprContext *econtext = makeNode(ExprContext);
/*
* Shut down and free any remaining ExprContexts. We do this
* explicitly to ensure that any remaining shutdown callbacks get
* called (since they might need to release resources that aren't
* simply memory within the per-query memory context).
*/
while (estate->es_exprcontexts)
{
FreeExprContext((ExprContext *) lfirst(estate->es_exprcontexts));
/* FreeExprContext removed the list link for us */
}
/*
* Free the per-query memory context, thereby releasing all working
* memory, including the EState node itself.
*/
MemoryContextDelete(estate->es_query_cxt);
}
/* ----------------
* CreateExprContext
*
* Create a context for expression evaluation within an EState.
*
* An executor run may require multiple ExprContexts (we usually make one
* for each Plan node, and a separate one for per-output-tuple processing
* such as constraint checking). Each ExprContext has its own "per-tuple"
* memory context.
*
* Note we make no assumption about the caller's memory context.
* ----------------
*/
ExprContext *
CreateExprContext(EState *estate)
{
ExprContext *econtext;
MemoryContext oldcontext;
/* Create the ExprContext node within the per-query memory context */
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
econtext = makeNode(ExprContext);
/* Initialize fields of ExprContext */
econtext->ecxt_scantuple = NULL;
econtext->ecxt_innertuple = NULL;
econtext->ecxt_outertuple = NULL;
econtext->ecxt_per_query_memory = CurrentMemoryContext;
econtext->ecxt_per_query_memory = estate->es_query_cxt;
/*
* Create working memory for expression evaluation in this context.
*/
econtext->ecxt_per_tuple_memory =
AllocSetContextCreate(CurrentMemoryContext,
"PlanExprContext",
AllocSetContextCreate(estate->es_query_cxt,
"ExprContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
econtext->ecxt_param_list_info = estate->es_param_list_info;
econtext->ecxt_aggvalues = NULL;
econtext->ecxt_aggnulls = NULL;
econtext->domainValue_datum = (Datum) 0;
econtext->domainValue_isNull = true;
econtext->ecxt_estate = estate;
econtext->ecxt_callbacks = NULL;
planstate->ps_ExprContext = econtext;
}
/* ----------------
* MakeExprContext
*
* Build an expression context for use outside normal plan-node cases.
* A fake scan-tuple slot can be supplied (pass NULL if not needed).
* A memory context sufficiently long-lived to use as fcache context
* must be supplied as well.
* ----------------
*/
ExprContext *
MakeExprContext(TupleTableSlot *slot,
MemoryContext queryContext)
{
ExprContext *econtext = makeNode(ExprContext);
econtext->ecxt_scantuple = slot;
econtext->ecxt_innertuple = NULL;
econtext->ecxt_outertuple = NULL;
econtext->ecxt_per_query_memory = queryContext;
/*
* We make the temporary context a child of current working context,
* not of the specified queryContext. This seems reasonable but I'm
* not totally sure about it...
*
* Expression contexts made via this routine typically don't live long
* enough to get reset, so specify a minsize of 0. That avoids
* alloc'ing any memory in the common case where expr eval doesn't use
* any.
* Link the ExprContext into the EState to ensure it is shut down
* when the EState is freed. Because we use lcons(), shutdowns will
* occur in reverse order of creation, which may not be essential
* but can't hurt.
*/
econtext->ecxt_per_tuple_memory =
AllocSetContextCreate(CurrentMemoryContext,
"TempExprContext",
0,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
econtext->ecxt_param_exec_vals = NULL;
econtext->ecxt_param_list_info = NULL;
econtext->ecxt_aggvalues = NULL;
econtext->ecxt_aggnulls = NULL;
econtext->ecxt_callbacks = NULL;
estate->es_exprcontexts = lcons(econtext, estate->es_exprcontexts);
MemoryContextSwitchTo(oldcontext);
return econtext;
}
/*
* Free an ExprContext made by MakeExprContext, including the temporary
* context used for expression evaluation. Note this will cause any
* pass-by-reference expression result to go away!
/* ----------------
* FreeExprContext
*
* Free an expression context, including calling any remaining
* shutdown callbacks.
*
* Since we free the temporary context used for expression evaluation,
* any previously computed pass-by-reference expression result will go away!
*
* Note we make no assumption about the caller's memory context.
* ----------------
*/
void
FreeExprContext(ExprContext *econtext)
{
EState *estate;
/* Call any registered callbacks */
ShutdownExprContext(econtext);
/* And clean up the memory used */
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
/* Unlink self from owning EState */
estate = econtext->ecxt_estate;
estate->es_exprcontexts = lremove(econtext, estate->es_exprcontexts);
/* And delete the ExprContext node */
pfree(econtext);
}
/*
* Build a per-output-tuple ExprContext for an EState.
*
* This is normally invoked via GetPerTupleExprContext() macro.
* This is normally invoked via GetPerTupleExprContext() macro,
* not directly.
*/
ExprContext *
MakePerTupleExprContext(EState *estate)
{
if (estate->es_per_tuple_exprcontext == NULL)
{
MemoryContext oldContext;
estate->es_per_tuple_exprcontext = CreateExprContext(estate);
oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
estate->es_per_tuple_exprcontext =
MakeExprContext(NULL, estate->es_query_cxt);
MemoryContextSwitchTo(oldContext);
}
return estate->es_per_tuple_exprcontext;
}
/* ----------------------------------------------------------------
* Result slot tuple type and ProjectionInfo support
* miscellaneous node-init support functions
*
* Note: all of these are expected to be called with CurrentMemoryContext
* equal to the per-query memory context.
* ----------------------------------------------------------------
*/
/* ----------------
* ExecAssignExprContext
*
* This initializes the ps_ExprContext field. It is only necessary
* to do this for nodes which use ExecQual or ExecProject
* because those routines require an econtext. Other nodes that
* don't have to evaluate expressions don't need to do this.
* ----------------
*/
void
ExecAssignExprContext(EState *estate, PlanState *planstate)
{
planstate->ps_ExprContext = CreateExprContext(estate);
}
/* ----------------
* ExecAssignResultType
* ----------------
@ -367,35 +501,13 @@ ExecAssignProjectionInfo(PlanState *planstate)
}
/* ----------------
* ExecFreeProjectionInfo
* ----------------
*/
void
ExecFreeProjectionInfo(PlanState *planstate)
{
ProjectionInfo *projInfo;
/*
* get projection info. if NULL then this node has none so we just
* return.
*/
projInfo = planstate->ps_ProjInfo;
if (projInfo == NULL)
return;
/*
* clean up memory used.
*/
if (projInfo->pi_tupValue != NULL)
pfree(projInfo->pi_tupValue);
pfree(projInfo);
planstate->ps_ProjInfo = NULL;
}
/* ----------------
* ExecFreeExprContext
*
* A plan node's ExprContext should be freed explicitly during ExecEndNode
* because there may be shutdown callbacks to call. (Other resources made
* by the above routines, such as projection info, don't need to be freed
* explicitly because they're just memory in the per-query memory context.)
* ----------------
*/
void
@ -411,16 +523,8 @@ ExecFreeExprContext(PlanState *planstate)
if (econtext == NULL)
return;
/*
* clean up any registered callbacks
*/
ShutdownExprContext(econtext);
FreeExprContext(econtext);
/*
* clean up memory used.
*/
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
pfree(econtext);
planstate->ps_ExprContext = NULL;
}
@ -612,7 +716,8 @@ ExecCloseIndices(ResultRelInfo *resultRelInfo)
}
/*
* XXX should free indexInfo array here too.
* XXX should free indexInfo array here too? Currently we assume that
* such stuff will be cleaned up automatically in FreeExecutorState.
*/
}
@ -674,16 +779,31 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
for (i = 0; i < numIndices; i++)
{
IndexInfo *indexInfo;
List *predicate;
InsertIndexResult result;
if (relationDescs[i] == NULL)
continue;
indexInfo = indexInfoArray[i];
predicate = indexInfo->ii_PredicateState;
if (predicate != NIL)
/* Check for partial index */
if (indexInfo->ii_Predicate != NIL)
{
List *predicate;
/*
* If predicate state not set up yet, create it (in the
* estate's per-query context)
*/
predicate = indexInfo->ii_PredicateState;
if (predicate == NIL)
{
predicate = (List *)
ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,
estate);
indexInfo->ii_PredicateState = predicate;
}
/* Skip this index-update if the predicate isn't satisfied */
if (!ExecQual(predicate, econtext, false))
continue;
@ -811,6 +931,17 @@ static void
ShutdownExprContext(ExprContext *econtext)
{
ExprContext_CB *ecxt_callback;
MemoryContext oldcontext;
/* Fast path in normal case where there's nothing to do. */
if (econtext->ecxt_callbacks == NULL)
return;
/*
* Call the callbacks in econtext's per-tuple context. This ensures
* that any memory they might leak will get cleaned up.
*/
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
/*
* Call each callback function in reverse registration order.
@ -821,4 +952,6 @@ ShutdownExprContext(ExprContext *econtext)
(*ecxt_callback->function) (ecxt_callback->arg);
pfree(ecxt_callback);
}
MemoryContextSwitchTo(oldcontext);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.61 2002/12/05 15:50:32 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.62 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -284,7 +284,8 @@ postquel_end(execution_state *es)
if (es->qd->operation != CMD_UTILITY)
ExecutorEnd(es->qd);
pfree(es->qd);
FreeQueryDesc(es->qd);
es->qd = NULL;
es->status = F_EXEC_DONE;

View File

@ -45,7 +45,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.100 2002/12/13 19:45:52 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.101 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1392,8 +1392,6 @@ ExecEndAgg(AggState *node)
tuplesort_end(peraggstate->sortstate);
}
ExecFreeProjectionInfo(&node->ss.ps);
/*
* Free both the expr contexts.
*/
@ -1401,18 +1399,13 @@ ExecEndAgg(AggState *node)
node->ss.ps.ps_ExprContext = node->tmpcontext;
ExecFreeExprContext(&node->ss.ps);
/* clean up tuple table */
ExecClearTuple(node->ss.ss_ScanTupleSlot);
MemoryContextDelete(node->aggcontext);
outerPlan = outerPlanState(node);
ExecEndNode(outerPlan);
/* clean up tuple table */
ExecClearTuple(node->ss.ss_ScanTupleSlot);
if (node->grp_firstTuple != NULL)
{
heap_freetuple(node->grp_firstTuple);
node->grp_firstTuple = NULL;
}
}
void

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.15 2002/12/13 19:45:52 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.16 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -273,9 +273,8 @@ void
ExecEndFunctionScan(FunctionScanState *node)
{
/*
* Free the projection info and the scan attribute info
* Free the exprcontext
*/
ExecFreeProjectionInfo(&node->ss.ps);
ExecFreeExprContext(&node->ss.ps);
/*

View File

@ -15,7 +15,7 @@
* locate group boundaries.
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.52 2002/12/13 19:45:52 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.53 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -218,19 +218,13 @@ ExecEndGroup(GroupState *node)
{
PlanState *outerPlan;
ExecFreeProjectionInfo(&node->ss.ps);
ExecFreeExprContext(&node->ss.ps);
outerPlan = outerPlanState(node);
ExecEndNode(outerPlan);
/* clean up tuple table */
ExecClearTuple(node->ss.ss_ScanTupleSlot);
if (node->grp_firstTuple != NULL)
{
heap_freetuple(node->grp_firstTuple);
node->grp_firstTuple = NULL;
}
outerPlan = outerPlanState(node);
ExecEndNode(outerPlan);
}
void

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.70 2002/12/13 19:45:52 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.71 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -179,10 +179,8 @@ ExecEndHash(HashState *node)
PlanState *outerPlan;
/*
* free projection info. no need to free result type info because
* that came from the outer plan...
* free exprcontext
*/
ExecFreeProjectionInfo(&node->ps);
ExecFreeExprContext(&node->ps);
/*

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.44 2002/12/13 19:45:52 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.45 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -456,17 +456,10 @@ ExecEndHashJoin(HashJoinState *node)
}
/*
* Free the projection info and the scan attribute info
* Free the exprcontext
*/
ExecFreeProjectionInfo(&node->js.ps);
ExecFreeExprContext(&node->js.ps);
/*
* clean up subtrees
*/
ExecEndNode(outerPlanState(node));
ExecEndNode(innerPlanState(node));
/*
* clean out the tuple table
*/
@ -474,6 +467,11 @@ ExecEndHashJoin(HashJoinState *node)
ExecClearTuple(node->hj_OuterTupleSlot);
ExecClearTuple(node->hj_HashTupleSlot);
/*
* clean up subtrees
*/
ExecEndNode(outerPlanState(node));
ExecEndNode(innerPlanState(node));
}
/* ----------------------------------------------------------------

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.74 2002/12/13 19:45:52 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.75 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -399,44 +399,38 @@ ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt)
/* ----------------------------------------------------------------
* ExecEndIndexScan
*
* old comments
* Releases any storage allocated through C routines.
* Returns nothing.
* ----------------------------------------------------------------
*/
void
ExecEndIndexScan(IndexScanState *node)
{
ExprState ***runtimeKeyInfo;
ScanKey *scanKeys;
int *numScanKeys;
int numIndices;
Relation relation;
RelationPtr indexRelationDescs;
IndexScanDescPtr indexScanDescs;
Relation relation;
int i;
runtimeKeyInfo = node->iss_RuntimeKeyInfo;
/*
* extract information from the node
*/
numIndices = node->iss_NumIndices;
scanKeys = node->iss_ScanKeys;
numScanKeys = node->iss_NumScanKeys;
indexRelationDescs = node->iss_RelationDescs;
indexScanDescs = node->iss_ScanDescs;
relation = node->ss.ss_currentRelation;
/*
* Free the projection info and the scan attribute info
* Free the exprcontext(s)
*/
ExecFreeProjectionInfo(&node->ss.ps);
ExecFreeExprContext(&node->ss.ps);
if (node->iss_RuntimeContext)
FreeExprContext(node->iss_RuntimeContext);
/*
* clear out tuple table slots
*/
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
/*
* close the index relations
*/
@ -458,36 +452,6 @@ ExecEndIndexScan(IndexScanState *node)
* locking, however.)
*/
heap_close(relation, NoLock);
/*
* free the scan keys used in scanning the indices
*/
for (i = 0; i < numIndices; i++)
{
if (scanKeys[i] != NULL)
pfree(scanKeys[i]);
}
pfree(scanKeys);
pfree(numScanKeys);
if (runtimeKeyInfo)
{
for (i = 0; i < numIndices; i++)
{
if (runtimeKeyInfo[i] != NULL)
pfree(runtimeKeyInfo[i]);
}
pfree(runtimeKeyInfo);
}
/*
* clear out tuple table slots
*/
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
pfree(node->iss_RelationDescs);
pfree(node->iss_ScanDescs);
pfree(node);
}
/* ----------------------------------------------------------------

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.13 2002/12/13 19:45:54 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.14 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -349,10 +349,10 @@ ExecEndLimit(LimitState *node)
{
ExecFreeExprContext(&node->ps);
ExecEndNode(outerPlanState(node));
/* clean up tuple table */
ExecClearTuple(node->ps.ps_ResultTupleSlot);
ExecEndNode(outerPlanState(node));
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.39 2002/12/05 15:50:33 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.40 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -196,17 +196,17 @@ ExecEndMaterial(MaterialState *node)
*/
ExecClearTuple(node->ss.ss_ScanTupleSlot);
/*
* shut down the subplan
*/
ExecEndNode(outerPlanState(node));
/*
* Release tuplestore resources
*/
if (node->tuplestorestate != NULL)
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
node->tuplestorestate = NULL;
/*
* shut down the subplan
*/
ExecEndNode(outerPlanState(node));
}
/* ----------------------------------------------------------------

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.54 2002/12/13 19:45:54 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.55 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1551,23 +1551,22 @@ ExecEndMergeJoin(MergeJoinState *node)
"ending node processing");
/*
* Free the projection info and the scan attribute info
* Free the exprcontext
*/
ExecFreeProjectionInfo(&node->js.ps);
ExecFreeExprContext(&node->js.ps);
/*
* shut down the subplans
*/
ExecEndNode(innerPlanState(node));
ExecEndNode(outerPlanState(node));
/*
* clean out the tuple table
*/
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
ExecClearTuple(node->mj_MarkedTupleSlot);
/*
* shut down the subplans
*/
ExecEndNode(innerPlanState(node));
ExecEndNode(outerPlanState(node));
MJ1_printf("ExecEndMergeJoin: %s\n",
"node processing ended");
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.28 2002/12/13 19:45:55 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.29 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -364,22 +364,21 @@ ExecEndNestLoop(NestLoopState *node)
"ending node processing");
/*
* Free the projection info
* Free the exprcontext
*/
ExecFreeProjectionInfo(&node->js.ps);
ExecFreeExprContext(&node->js.ps);
/*
* clean out the tuple table
*/
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
/*
* close down subplans
*/
ExecEndNode(outerPlanState(node));
ExecEndNode(innerPlanState(node));
/*
* clean out the tuple table
*/
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
NL1_printf("ExecEndNestLoop: %s\n",
"node processing ended");
}

View File

@ -34,7 +34,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.23 2002/12/13 19:45:55 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.24 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -248,9 +248,8 @@ void
ExecEndResult(ResultState *node)
{
/*
* Free the projection info
* Free the exprcontext
*/
ExecFreeProjectionInfo(&node->ps);
ExecFreeExprContext(&node->ps);
/*

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.40 2002/12/13 19:45:55 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.41 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -264,22 +264,21 @@ ExecEndSeqScan(SeqScanState *node)
scanDesc = node->ss_currentScanDesc;
/*
* Free the projection info and the scan attribute info
* Free the exprcontext
*/
ExecFreeProjectionInfo(&node->ps);
ExecFreeExprContext(&node->ps);
/*
* close heap scan
*/
heap_endscan(scanDesc);
/*
* clean out the tuple table
*/
ExecClearTuple(node->ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss_ScanTupleSlot);
/*
* close heap scan
*/
heap_endscan(scanDesc);
/*
* close the heap relation.
*

View File

@ -21,7 +21,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.7 2002/12/05 15:50:33 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.8 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -301,9 +301,9 @@ ExecEndSetOp(SetOpState *node)
ExecClearTuple(node->ps.ps_ResultTupleSlot);
node->ps.ps_OuterTupleSlot = NULL;
ExecEndNode(outerPlanState(node));
MemoryContextDelete(node->tempContext);
ExecEndNode(outerPlanState(node));
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.41 2002/12/05 15:50:33 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.42 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -284,11 +284,6 @@ ExecEndSort(SortState *node)
*/
ExecClearTuple(node->ss.ss_ScanTupleSlot);
/*
* shut down the subplan
*/
ExecEndNode(outerPlanState(node));
/*
* Release tuplesort resources
*/
@ -296,6 +291,11 @@ ExecEndSort(SortState *node)
tuplesort_end((Tuplesortstate *) node->tuplesortstate);
node->tuplesortstate = NULL;
/*
* shut down the subplan
*/
ExecEndNode(outerPlanState(node));
SO1_printf("ExecEndSort: %s\n",
"sort node shutdown");
}

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.38 2002/12/14 00:17:50 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.39 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -47,9 +47,10 @@ ExecSubPlan(SubPlanState *node,
/*
* We are probably in a short-lived expression-evaluation context.
* Switch to longer-lived per-query context.
* Switch to the child plan's per-query context for manipulating its
* chgParam, calling ExecProcNode on it, etc.
*/
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
if (subplan->setParam != NIL)
elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
@ -132,10 +133,13 @@ ExecSubPlan(SubPlanState *node,
* ExecProcNode() call. node->curTuple keeps track of the
* copied tuple for eventual freeing.
*/
MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
tup = heap_copytuple(tup);
if (node->curTuple)
heap_freetuple(node->curTuple);
node->curTuple = tup;
MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
result = heap_getattr(tup, col, tdesc, isNull);
/* keep scanning subplan to make sure there's only one tuple */
continue;
@ -295,6 +299,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
{
SubPlan *subplan = (SubPlan *) node->xprstate.expr;
EState *sp_estate;
MemoryContext oldcontext;
/*
* Do access checking on the rangetable entries in the subquery.
@ -303,15 +308,23 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
/*
* initialize state
* initialize my state
*/
node->needShutdown = false;
node->curTuple = NULL;
/*
* 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...
*/
sp_estate = CreateExecutorState();
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;
@ -322,12 +335,14 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
sp_estate->es_instrument = estate->es_instrument;
/*
* Start up the subplan
* Start up the subplan (this is a very cut-down form of InitPlan())
*/
node->planstate = ExecInitNode(subplan->plan, sp_estate);
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 prepare parameters.
@ -376,10 +391,9 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
bool found = false;
/*
* We are probably in a short-lived expression-evaluation context.
* Switch to longer-lived per-query context.
* Must switch to child query's per-query memory context.
*/
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
if (subLinkType == ANY_SUBLINK ||
subLinkType == ALL_SUBLINK)
@ -415,15 +429,18 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
found = true;
/*
* We need to copy the subplan's tuple in case any of the params
* are pass-by-ref type --- the pointers stored in the param
* structs will point at this copied tuple! node->curTuple keeps
* track of the copied tuple for eventual freeing.
* We need to copy the subplan's tuple into our own context,
* in case any of the params are pass-by-ref type --- the pointers
* stored in the param structs will point at this copied tuple!
* node->curTuple keeps track of the copied tuple for eventual
* freeing.
*/
MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
tup = heap_copytuple(tup);
if (node->curTuple)
heap_freetuple(node->curTuple);
node->curTuple = tup;
MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
foreach(lst, subplan->setParam)
{
@ -460,7 +477,10 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
if (planstate->plan->extParam == NULL) /* un-correlated ... */
{
ExecEndNode(planstate);
ExecEndPlan(planstate, node->sub_estate);
/* mustn't free context while still in it... */
MemoryContextSwitchTo(oldcontext);
FreeExecutorState(node->sub_estate);
node->needShutdown = false;
}
@ -476,7 +496,12 @@ ExecEndSubPlan(SubPlanState *node)
{
if (node->needShutdown)
{
ExecEndNode(node->planstate);
MemoryContext oldcontext;
oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
ExecEndPlan(node->planstate, node->sub_estate);
MemoryContextSwitchTo(oldcontext);
FreeExecutorState(node->sub_estate);
node->needShutdown = false;
}
if (node->curTuple)

View File

@ -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;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.29 2002/12/13 19:45:56 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.30 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -278,19 +278,8 @@ void
ExecEndTidScan(TidScanState *node)
{
/*
* extract information from the node
* Free the exprcontext
*/
if (node && node->tss_TidList)
pfree(node->tss_TidList);
/*
* Free the projection info and the scan attribute info
*
* Note: we don't ExecFreeResultType(scanstate) because the rule manager
* depends on the tupType returned by ExecMain(). So for now, this is
* freed at end-transaction time. -cim 6/2/91
*/
ExecFreeProjectionInfo(&node->ss.ps);
ExecFreeExprContext(&node->ss.ps);
/*

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.35 2002/12/05 15:50:34 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.36 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -194,15 +194,10 @@ ExecEndUnique(UniqueState *node)
{
/* clean up tuple table */
ExecClearTuple(node->ps.ps_ResultTupleSlot);
if (node->priorTuple != NULL)
{
heap_freetuple(node->priorTuple);
node->priorTuple = NULL;
}
ExecEndNode(outerPlanState(node));
MemoryContextDelete(node->tempContext);
ExecEndNode(outerPlanState(node));
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.79 2002/12/05 15:50:34 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.80 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1287,23 +1287,23 @@ _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount)
elog(FATAL, "SPI_select: # of processed tuples check failed");
}
ExecutorEnd(queryDesc);
#ifdef SPI_EXECUTOR_STATS
if (ShowExecutorStats)
ShowUsage("SPI EXECUTOR STATS");
#endif
if (dest == SPI)
{
SPI_processed = _SPI_current->processed;
SPI_lastoid = save_lastoid;
SPI_tuptable = _SPI_current->tuptable;
}
queryDesc->dest = dest;
ExecutorEnd(queryDesc);
FreeQueryDesc(queryDesc);
#ifdef SPI_EXECUTOR_STATS
if (ShowExecutorStats)
ShowUsage("SPI EXECUTOR STATS");
#endif
return res;
}
/*