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:
@ -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)
|
||||
---------------------------------------------
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user