summaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
authorTom Lane2002-12-15 16:17:59 +0000
committerTom Lane2002-12-15 16:17:59 +0000
commit5bab36e9f6c3f3a9e14a89e1124179a339d2c3a1 (patch)
treea05154b129808efc7882599d96a1132051c2403b /src/backend/executor
parent90b3a0b6fd3bc74804c01156491635e5d95091d9 (diff)
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')
-rw-r--r--src/backend/executor/README79
-rw-r--r--src/backend/executor/execMain.c113
-rw-r--r--src/backend/executor/execQual.c40
-rw-r--r--src/backend/executor/execUtils.c345
-rw-r--r--src/backend/executor/functions.c5
-rw-r--r--src/backend/executor/nodeAgg.c15
-rw-r--r--src/backend/executor/nodeFunctionscan.c5
-rw-r--r--src/backend/executor/nodeGroup.c14
-rw-r--r--src/backend/executor/nodeHash.c6
-rw-r--r--src/backend/executor/nodeHashjoin.c16
-rw-r--r--src/backend/executor/nodeIndexscan.c54
-rw-r--r--src/backend/executor/nodeLimit.c6
-rw-r--r--src/backend/executor/nodeMaterial.c12
-rw-r--r--src/backend/executor/nodeMergejoin.c17
-rw-r--r--src/backend/executor/nodeNestloop.c15
-rw-r--r--src/backend/executor/nodeResult.c5
-rw-r--r--src/backend/executor/nodeSeqscan.c15
-rw-r--r--src/backend/executor/nodeSetOp.c6
-rw-r--r--src/backend/executor/nodeSort.c12
-rw-r--r--src/backend/executor/nodeSubplan.c53
-rw-r--r--src/backend/executor/nodeSubqueryscan.c50
-rw-r--r--src/backend/executor/nodeTidscan.c15
-rw-r--r--src/backend/executor/nodeUnique.c11
-rw-r--r--src/backend/executor/spi.c20
24 files changed, 563 insertions, 366 deletions
diff --git a/src/backend/executor/README b/src/backend/executor/README
index d9b0ea1275a..ebdbe2d9d0c 100644
--- a/src/backend/executor/README
+++ b/src/backend/executor/README
@@ -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)
---------------------------------------------
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index bac7398825e..a25f2f2e296 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -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);
}
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index a3f79c3ac80..971773b1212 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -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
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 36997a49103..6c2cece7b6e 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -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,137 +131,264 @@ 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.
* ----------------
*/
-void
-ExecAssignExprContext(EState *estate, PlanState *planstate)
+EState *
+CreateExecutorState(void)
{
- ExprContext *econtext = makeNode(ExprContext);
+ EState *estate;
+ MemoryContext qcontext;
+ MemoryContext oldcontext;
- econtext->ecxt_scantuple = NULL;
- econtext->ecxt_innertuple = NULL;
- econtext->ecxt_outertuple = NULL;
- econtext->ecxt_per_query_memory = CurrentMemoryContext;
+ /*
+ * Create the per-query context for this Executor run.
+ */
+ qcontext = AllocSetContextCreate(CurrentMemoryContext,
+ "ExecutorState",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
/*
- * Create working memory for expression evaluation in this context.
+ * Make the EState node within the per-query context. This way,
+ * we don't need a separate pfree() operation for it at shutdown.
*/
- econtext->ecxt_per_tuple_memory =
- AllocSetContextCreate(CurrentMemoryContext,
- "PlanExprContext",
- 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->ecxt_callbacks = NULL;
+ 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;
- planstate->ps_ExprContext = econtext;
+ 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
+FreeExecutorState(EState *estate)
+{
+ /*
+ * 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);
}
/* ----------------
- * MakeExprContext
+ * 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.
*
- * 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.
+ * Note we make no assumption about the caller's memory context.
* ----------------
*/
ExprContext *
-MakeExprContext(TupleTableSlot *slot,
- MemoryContext queryContext)
+CreateExprContext(EState *estate)
{
- ExprContext *econtext = makeNode(ExprContext);
+ ExprContext *econtext;
+ MemoryContext oldcontext;
- econtext->ecxt_scantuple = slot;
+ /* 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 = queryContext;
+
+ econtext->ecxt_per_query_memory = estate->es_query_cxt;
/*
- * 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.
+ * Create working memory for expression evaluation in this context.
*/
econtext->ecxt_per_tuple_memory =
- AllocSetContextCreate(CurrentMemoryContext,
- "TempExprContext",
- 0,
+ AllocSetContextCreate(estate->es_query_cxt,
+ "ExprContext",
+ ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
- econtext->ecxt_param_exec_vals = NULL;
- econtext->ecxt_param_list_info = NULL;
+
+ 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;
+ /*
+ * 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.
+ */
+ 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
* ----------------
*/
@@ -368,34 +502,12 @@ 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);
}
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 328aea5f079..d3ccf0dd905 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -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;
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index e6ba3887630..769e88a8397 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -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
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index d0bf78631da..78f66523d51 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -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);
/*
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index 8bb72ba3438..58f6c1b34e9 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -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
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index 45ba826317d..efdd3b3cabb 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -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);
/*
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index 07de8703812..8f899b577d7 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -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,24 +456,22 @@ 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
*/
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
ExecClearTuple(node->hj_OuterTupleSlot);
ExecClearTuple(node->hj_HashTupleSlot);
+ /*
+ * clean up subtrees
+ */
+ ExecEndNode(outerPlanState(node));
+ ExecEndNode(innerPlanState(node));
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 1e36e93113d..7b96723844b 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -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,45 +399,39 @@ 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
*/
for (i = 0; i < numIndices; i++)
@@ -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);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index 6abd83de8aa..39d09331ce2 100644
--- a/src/backend/executor/nodeLimit.c
+++ b/src/backend/executor/nodeLimit.c
@@ -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));
}
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index cf7ca89f4a9..a1725901a7c 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -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 $
*
*-------------------------------------------------------------------------
*/
@@ -197,16 +197,16 @@ 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));
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 1bb5878d819..af6cd8d6f3f 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -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");
}
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index 452ed7d70c3..917a7011cbf 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -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,21 +364,20 @@ ExecEndNestLoop(NestLoopState *node)
"ending node processing");
/*
- * Free the projection info
+ * Free the exprcontext
*/
- ExecFreeProjectionInfo(&node->js.ps);
ExecFreeExprContext(&node->js.ps);
/*
- * close down subplans
+ * clean out the tuple table
*/
- ExecEndNode(outerPlanState(node));
- ExecEndNode(innerPlanState(node));
+ ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
/*
- * clean out the tuple table
+ * close down subplans
*/
- ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
+ ExecEndNode(outerPlanState(node));
+ ExecEndNode(innerPlanState(node));
NL1_printf("ExecEndNestLoop: %s\n",
"node processing ended");
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index 3f2c9927e01..9ea75eb3ce7 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -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);
/*
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index 6a7393795b2..6628a9eecbe 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -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,23 +264,22 @@ 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.
*
* Currently, we do not release the AccessShareLock acquired by
diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c
index a81a4a29d91..965a2a6466a 100644
--- a/src/backend/executor/nodeSetOp.c
+++ b/src/backend/executor/nodeSetOp.c
@@ -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));
}
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
index e1b4db7a51d..a37583241fb 100644
--- a/src/backend/executor/nodeSort.c
+++ b/src/backend/executor/nodeSort.c
@@ -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 $
*
*-------------------------------------------------------------------------
*/
@@ -285,17 +285,17 @@ ExecEndSort(SortState *node)
ExecClearTuple(node->ss.ss_ScanTupleSlot);
/*
- * shut down the subplan
- */
- ExecEndNode(outerPlanState(node));
-
- /*
* Release tuplesort resources
*/
if (node->tuplesortstate != NULL)
tuplesort_end((Tuplesortstate *) node->tuplesortstate);
node->tuplesortstate = NULL;
+ /*
+ * shut down the subplan
+ */
+ ExecEndNode(outerPlanState(node));
+
SO1_printf("ExecEndSort: %s\n",
"sort node shutdown");
}
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index 3a2ca974aee..2f5ab52e213 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
- * $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)
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;
}
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index ba2793407ce..7e35bc07cd7 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -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);
/*
diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c
index 88b08061f99..415594f92c4 100644
--- a/src/backend/executor/nodeUnique.c
+++ b/src/backend/executor/nodeUnique.c
@@ -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));
}
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 147becf6ed8..cde9ab6ff6e 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -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;
- return res;
+ ExecutorEnd(queryDesc);
+
+ FreeQueryDesc(queryDesc);
+
+#ifdef SPI_EXECUTOR_STATS
+ if (ShowExecutorStats)
+ ShowUsage("SPI EXECUTOR STATS");
+#endif
+ return res;
}
/*