Revise executor APIs so that all per-query state structure is built in

a per-query memory context created by CreateExecutorState --- and destroyed
by FreeExecutorState.  This provides a final solution to the longstanding
problem of memory leaked by various ExecEndNode calls.
This commit is contained in:
Tom Lane 2002-12-15 16:17:59 +00:00
parent 90b3a0b6fd
commit 5bab36e9f6
42 changed files with 806 additions and 547 deletions

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.146 2002/12/13 19:45:45 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.147 2002/12/15 16:17:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1143,8 +1143,7 @@ index_register(Oid heap,
/* predicate will likely be null, but may as well copy it */ /* predicate will likely be null, but may as well copy it */
newind->il_info->ii_Predicate = (List *) newind->il_info->ii_Predicate = (List *)
copyObject(indexInfo->ii_Predicate); copyObject(indexInfo->ii_Predicate);
newind->il_info->ii_PredicateState = (List *) newind->il_info->ii_PredicateState = NIL;
ExecInitExpr((Expr *) newind->il_info->ii_Predicate, NULL);
newind->il_next = ILHead; newind->il_next = ILHead;
ILHead = newind; ILHead = newind;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.207 2002/12/13 19:45:47 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.208 2002/12/15 16:17:38 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
@ -41,7 +41,6 @@
#include "executor/executor.h" #include "executor/executor.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/planmain.h"
#include "optimizer/prep.h" #include "optimizer/prep.h"
#include "parser/parse_func.h" #include "parser/parse_func.h"
#include "storage/sinval.h" #include "storage/sinval.h"
@ -912,7 +911,6 @@ BuildIndexInfo(Form_pg_index indexStruct)
/* /*
* If partial index, convert predicate into expression nodetree * If partial index, convert predicate into expression nodetree
* and prepare an execution state nodetree for it
*/ */
if (VARSIZE(&indexStruct->indpred) > VARHDRSZ) if (VARSIZE(&indexStruct->indpred) > VARHDRSZ)
{ {
@ -921,9 +919,7 @@ BuildIndexInfo(Form_pg_index indexStruct)
predString = DatumGetCString(DirectFunctionCall1(textout, predString = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(&indexStruct->indpred))); PointerGetDatum(&indexStruct->indpred)));
ii->ii_Predicate = stringToNode(predString); ii->ii_Predicate = stringToNode(predString);
fix_opfuncids((Node *) ii->ii_Predicate); ii->ii_PredicateState = NIL;
ii->ii_PredicateState = (List *)
ExecInitExpr((Expr *) ii->ii_Predicate, NULL);
pfree(predString); pfree(predString);
} }
else else
@ -1489,9 +1485,10 @@ IndexBuildHeapScan(Relation heapRelation,
Datum attdata[INDEX_MAX_KEYS]; Datum attdata[INDEX_MAX_KEYS];
char nulls[INDEX_MAX_KEYS]; char nulls[INDEX_MAX_KEYS];
double reltuples; double reltuples;
List *predicate = indexInfo->ii_PredicateState; List *predicate;
TupleTable tupleTable; TupleTable tupleTable;
TupleTableSlot *slot; TupleTableSlot *slot;
EState *estate;
ExprContext *econtext; ExprContext *econtext;
Snapshot snapshot; Snapshot snapshot;
TransactionId OldestXmin; TransactionId OldestXmin;
@ -1503,28 +1500,42 @@ IndexBuildHeapScan(Relation heapRelation,
heapDescriptor = RelationGetDescr(heapRelation); heapDescriptor = RelationGetDescr(heapRelation);
/*
* Need an EState for evaluation of functional-index functions
* and partial-index predicates.
*/
estate = CreateExecutorState();
econtext = GetPerTupleExprContext(estate);
/* /*
* If this is a predicate (partial) index, we will need to evaluate * If this is a predicate (partial) index, we will need to evaluate
* the predicate using ExecQual, which requires the current tuple to * the predicate using ExecQual, which requires the current tuple to
* be in a slot of a TupleTable. In addition, ExecQual must have an * be in a slot of a TupleTable.
* ExprContext referring to that slot. Here, we initialize dummy
* TupleTable and ExprContext objects for this purpose. --Nels, Feb 92
*
* We construct the ExprContext anyway since we need a per-tuple
* temporary memory context for function evaluation -- tgl July 00
*/ */
if (predicate != NIL) if (indexInfo->ii_Predicate != NIL)
{ {
tupleTable = ExecCreateTupleTable(1); tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable); slot = ExecAllocTableSlot(tupleTable);
ExecSetSlotDescriptor(slot, heapDescriptor, false); ExecSetSlotDescriptor(slot, heapDescriptor, false);
/* Arrange for econtext's scan tuple to be the tuple under test */
econtext->ecxt_scantuple = slot;
/*
* Set up execution state for predicate. Note: we mustn't attempt to
* cache this in the indexInfo, since we're building it in a transient
* EState.
*/
predicate = (List *)
ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,
estate);
} }
else else
{ {
tupleTable = NULL; tupleTable = NULL;
slot = NULL; slot = NULL;
predicate = NIL;
} }
econtext = MakeExprContext(slot, TransactionCommandContext);
/* /*
* Ok, begin our scan of the base relation. We use SnapshotAny * Ok, begin our scan of the base relation. We use SnapshotAny
@ -1687,9 +1698,10 @@ IndexBuildHeapScan(Relation heapRelation,
heap_endscan(scan); heap_endscan(scan);
if (predicate != NIL) if (tupleTable)
ExecDropTupleTable(tupleTable, true); ExecDropTupleTable(tupleTable, true);
FreeExprContext(econtext);
FreeExecutorState(estate);
return reltuples; return reltuples;
} }

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.186 2002/12/13 19:45:48 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.187 2002/12/15 16:17:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -35,7 +35,6 @@
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
#include "optimizer/planmain.h"
#include "parser/parse_coerce.h" #include "parser/parse_coerce.h"
#include "parser/parse_relation.h" #include "parser/parse_relation.h"
#include "rewrite/rewriteHandler.h" #include "rewrite/rewriteHandler.h"
@ -803,6 +802,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
slot = ExecAllocTableSlot(tupleTable); slot = ExecAllocTableSlot(tupleTable);
ExecSetSlotDescriptor(slot, tupDesc, false); ExecSetSlotDescriptor(slot, tupDesc, false);
econtext = GetPerTupleExprContext(estate);
/* /*
* Pick up the required catalog information for each attribute in the * Pick up the required catalog information for each attribute in the
* relation, including the input function, the element type (to pass * relation, including the input function, the element type (to pass
@ -841,8 +842,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
if (defexpr != NULL) if (defexpr != NULL)
{ {
fix_opfuncids(defexpr); defexprs[num_defaults] = ExecPrepareExpr((Expr *) defexpr,
defexprs[num_defaults] = ExecInitExpr((Expr *) defexpr, NULL); estate);
defmap[num_defaults] = i; defmap[num_defaults] = i;
num_defaults++; num_defaults++;
} }
@ -873,8 +874,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
/* check whether any constraints actually found */ /* check whether any constraints actually found */
if (node != (Node *) prm) if (node != (Node *) prm)
{ {
fix_opfuncids(node); constraintexprs[i] = ExecPrepareExpr((Expr *) node,
constraintexprs[i] = ExecInitExpr((Expr *) node, NULL); estate);
hasConstraints = true; hasConstraints = true;
} }
} }
@ -934,8 +935,6 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
copy_lineno = 0; copy_lineno = 0;
fe_eof = false; fe_eof = false;
econtext = GetPerTupleExprContext(estate);
/* Make room for a PARAM_EXEC value for domain constraint checks */ /* Make room for a PARAM_EXEC value for domain constraint checks */
if (hasConstraints) if (hasConstraints)
econtext->ecxt_param_exec_vals = (ParamExecData *) econtext->ecxt_param_exec_vals = (ParamExecData *)
@ -953,9 +952,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
/* Reset the per-tuple exprcontext */ /* Reset the per-tuple exprcontext */
ResetPerTupleExprContext(estate); ResetPerTupleExprContext(estate);
/* Switch to and reset per-tuple memory context, too */ /* Switch into its memory context */
MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
MemoryContextReset(CurrentMemoryContext);
/* Initialize all values for row to NULL */ /* Initialize all values for row to NULL */
MemSet(values, 0, num_phys_attrs * sizeof(Datum)); MemSet(values, 0, num_phys_attrs * sizeof(Datum));
@ -1268,6 +1266,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
ExecDropTupleTable(tupleTable, true); ExecDropTupleTable(tupleTable, true);
ExecCloseIndices(resultRelInfo); ExecCloseIndices(resultRelInfo);
FreeExecutorState(estate);
} }

View File

@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994-5, Regents of the University of California * Portions Copyright (c) 1994-5, Regents of the University of California
* *
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.98 2002/12/14 00:17:50 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.99 2002/12/15 16:17:38 tgl Exp $
* *
*/ */
@ -206,6 +206,8 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
gettimeofday(&starttime, NULL); gettimeofday(&starttime, NULL);
ExecutorEnd(queryDesc); ExecutorEnd(queryDesc);
FreeQueryDesc(queryDesc);
CommandCounterIncrement(); CommandCounterIncrement();
totaltime += elapsed_time(&starttime); totaltime += elapsed_time(&starttime);

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.94 2002/12/13 19:45:50 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.95 2002/12/15 16:17:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -27,7 +27,6 @@
#include "executor/executor.h" #include "executor/executor.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/planmain.h"
#include "optimizer/prep.h" #include "optimizer/prep.h"
#include "parser/parsetree.h" #include "parser/parsetree.h"
#include "parser/parse_coerce.h" #include "parser/parse_coerce.h"
@ -163,7 +162,6 @@ DefineIndex(RangeVar *heapRelation,
if (predicate) if (predicate)
{ {
cnfPred = canonicalize_qual((Expr *) copyObject(predicate), true); cnfPred = canonicalize_qual((Expr *) copyObject(predicate), true);
fix_opfuncids((Node *) cnfPred);
CheckPredicate(cnfPred, rangetable, relationId); CheckPredicate(cnfPred, rangetable, relationId);
} }
@ -173,8 +171,7 @@ DefineIndex(RangeVar *heapRelation,
*/ */
indexInfo = makeNode(IndexInfo); indexInfo = makeNode(IndexInfo);
indexInfo->ii_Predicate = cnfPred; indexInfo->ii_Predicate = cnfPred;
indexInfo->ii_PredicateState = (List *) indexInfo->ii_PredicateState = NIL;
ExecInitExpr((Expr *) cnfPred, NULL);
indexInfo->ii_FuncOid = InvalidOid; indexInfo->ii_FuncOid = InvalidOid;
indexInfo->ii_Unique = unique; indexInfo->ii_Unique = unique;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.5 2002/12/05 15:50:30 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.6 2002/12/15 16:17:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -31,28 +31,22 @@
void void
PortalCleanup(Portal portal) PortalCleanup(Portal portal)
{ {
MemoryContext oldcontext;
/* /*
* sanity checks * sanity checks
*/ */
AssertArg(PortalIsValid(portal)); AssertArg(PortalIsValid(portal));
AssertArg(portal->cleanup == PortalCleanup); AssertArg(portal->cleanup == PortalCleanup);
/*
* set proper portal-executor context before calling ExecMain.
*/
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
/* /*
* tell the executor to shutdown the query * tell the executor to shutdown the query
*/ */
ExecutorEnd(PortalGetQueryDesc(portal)); ExecutorEnd(PortalGetQueryDesc(portal));
/* /*
* switch back to previous context * This should be unnecessary since the querydesc should be in the
* portal's memory context, but do it anyway for symmetry.
*/ */
MemoryContextSwitchTo(oldcontext); FreeQueryDesc(PortalGetQueryDesc(portal));
} }

View File

@ -6,7 +6,7 @@
* Copyright (c) 2002, PostgreSQL Global Development Group * Copyright (c) 2002, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.10 2002/12/13 19:45:51 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.11 2002/12/15 16:17:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -15,7 +15,6 @@
#include "commands/prepare.h" #include "commands/prepare.h"
#include "executor/executor.h" #include "executor/executor.h"
#include "utils/guc.h" #include "utils/guc.h"
#include "optimizer/planmain.h"
#include "optimizer/planner.h" #include "optimizer/planner.h"
#include "rewrite/rewriteHandler.h" #include "rewrite/rewriteHandler.h"
#include "tcop/pquery.h" #include "tcop/pquery.h"
@ -50,7 +49,6 @@ static void InitQueryHashTable(void);
static void StoreQuery(const char *stmt_name, List *query_list, static void StoreQuery(const char *stmt_name, List *query_list,
List *plan_list, List *argtype_list); List *plan_list, List *argtype_list);
static QueryHashEntry *FetchQuery(const char *plan_name); static QueryHashEntry *FetchQuery(const char *plan_name);
static void RunQuery(QueryDesc *qdesc);
/* /*
@ -96,33 +94,37 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
*query_list, *query_list,
*plan_list; *plan_list;
ParamListInfo paramLI = NULL; ParamListInfo paramLI = NULL;
EState *estate;
/* Look it up in the hash table */ /* Look it up in the hash table */
entry = FetchQuery(stmt->name); entry = FetchQuery(stmt->name);
/* Make working copies the executor can safely scribble on */ query_list = entry->query_list;
query_list = (List *) copyObject(entry->query_list); plan_list = entry->plan_list;
plan_list = (List *) copyObject(entry->plan_list);
Assert(length(query_list) == length(plan_list)); Assert(length(query_list) == length(plan_list));
/*
* Need an EState to evaluate parameters; must not delete it till end
* of query, in case parameters are pass-by-reference.
*/
estate = CreateExecutorState();
/* Evaluate parameters, if any */ /* Evaluate parameters, if any */
if (entry->argtype_list != NIL) if (entry->argtype_list != NIL)
{ {
int nargs = length(entry->argtype_list); int nargs = length(entry->argtype_list);
int i = 0; int i = 0;
List *exprstates; List *exprstates;
ExprContext *econtext = MakeExprContext(NULL, CurrentMemoryContext);
/* Parser should have caught this error, but check */ /* Parser should have caught this error, but check */
if (nargs != length(stmt->params)) if (nargs != length(stmt->params))
elog(ERROR, "ExecuteQuery: wrong number of arguments"); elog(ERROR, "ExecuteQuery: wrong number of arguments");
fix_opfuncids((Node *) stmt->params); exprstates = (List *) ExecPrepareExpr((Expr *) stmt->params, estate);
exprstates = (List *) ExecInitExpr((Expr *) stmt->params, NULL); paramLI = (ParamListInfo)
palloc0((nargs + 1) * sizeof(ParamListInfoData));
paramLI = (ParamListInfo) palloc0((nargs + 1) * sizeof(ParamListInfoData));
foreach(l, exprstates) foreach(l, exprstates)
{ {
@ -130,7 +132,7 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
bool isNull; bool isNull;
paramLI[i].value = ExecEvalExprSwitchContext(n, paramLI[i].value = ExecEvalExprSwitchContext(n,
econtext, GetPerTupleExprContext(estate),
&isNull, &isNull,
NULL); NULL);
paramLI[i].kind = PARAM_NUM; paramLI[i].kind = PARAM_NUM;
@ -173,7 +175,13 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
qdesc->dest = None; qdesc->dest = None;
} }
RunQuery(qdesc); ExecutorStart(qdesc);
ExecutorRun(qdesc, ForwardScanDirection, 0L);
ExecutorEnd(qdesc);
FreeQueryDesc(qdesc);
if (log_executor_stats) if (log_executor_stats)
ShowUsage("EXECUTOR STATISTICS"); ShowUsage("EXECUTOR STATISTICS");
@ -188,7 +196,9 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
CommandCounterIncrement(); CommandCounterIncrement();
} }
/* No need to pfree memory, MemoryContext will be reset */ FreeExecutorState(estate);
/* No need to pfree other memory, MemoryContext will be reset */
} }
/* /*
@ -333,17 +343,6 @@ FetchQueryParams(const char *plan_name)
return entry->argtype_list; return entry->argtype_list;
} }
/*
* Actually execute a prepared query.
*/
static void
RunQuery(QueryDesc *qdesc)
{
ExecutorStart(qdesc);
ExecutorRun(qdesc, ForwardScanDirection, 0L);
ExecutorEnd(qdesc);
}
/* /*
* Implements the 'DEALLOCATE' utility statement: deletes the * Implements the 'DEALLOCATE' utility statement: deletes the
* specified plan from storage. * specified plan from storage.

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.60 2002/12/13 19:45:51 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.61 2002/12/15 16:17:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -37,7 +37,6 @@
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/plancat.h" #include "optimizer/plancat.h"
#include "optimizer/planmain.h"
#include "optimizer/prep.h" #include "optimizer/prep.h"
#include "parser/gramparse.h" #include "parser/gramparse.h"
#include "parser/parse_coerce.h" #include "parser/parse_coerce.h"
@ -2713,6 +2712,7 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
ParseState *pstate; ParseState *pstate;
bool successful = true; bool successful = true;
HeapScanDesc scan; HeapScanDesc scan;
EState *estate;
ExprContext *econtext; ExprContext *econtext;
TupleTableSlot *slot; TupleTableSlot *slot;
HeapTuple tuple; HeapTuple tuple;
@ -2723,9 +2723,7 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
/* /*
* We need to make a parse state and range * We need to make a parse state and range
* table to allow us to transformExpr and * table to allow us to do transformExpr()
* fix_opfuncids to get a version of the
* expression we can pass to ExecQual
*/ */
pstate = make_parsestate(NULL); pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(pstate, rte = addRangeTableEntryForRelation(pstate,
@ -2765,19 +2763,22 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
*/ */
expr = eval_const_expressions(expr); expr = eval_const_expressions(expr);
/* And fix the opfuncids */ /* Needs to be in implicit-ANDs form for ExecQual */
fix_opfuncids(expr); qual = make_ands_implicit((Expr *) expr);
qual = makeList1(expr); /* Need an EState to run ExecQual */
estate = CreateExecutorState();
econtext = GetPerTupleExprContext(estate);
/* build execution state for qual */ /* build execution state for qual */
qualstate = (List *) ExecInitExpr((Expr *) qual, NULL); qualstate = (List *) ExecPrepareExpr((Expr *) qual, estate);
/* Make tuple slot to hold tuples */ /* Make tuple slot to hold tuples */
slot = MakeTupleTableSlot(); slot = MakeTupleTableSlot();
ExecSetSlotDescriptor(slot, RelationGetDescr(rel), false); ExecSetSlotDescriptor(slot, RelationGetDescr(rel), false);
/* Make an expression context for ExecQual */
econtext = MakeExprContext(slot, CurrentMemoryContext); /* Arrange for econtext's scan tuple to be the tuple under test */
econtext->ecxt_scantuple = slot;
/* /*
* Scan through the rows now, checking the expression at each row. * Scan through the rows now, checking the expression at each row.
@ -2797,8 +2798,8 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
heap_endscan(scan); heap_endscan(scan);
FreeExprContext(econtext);
pfree(slot); pfree(slot);
FreeExecutorState(estate);
if (!successful) if (!successful)
elog(ERROR, "AlterTableAddConstraint: rejected due to CHECK constraint %s", elog(ERROR, "AlterTableAddConstraint: rejected due to CHECK constraint %s",

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.24 2002/12/13 19:45:52 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.25 2002/12/15 16:17:43 tgl Exp $
* *
* DESCRIPTION * DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the * The "DefineFoo" routines take the parse tree and pick out the
@ -47,7 +47,6 @@
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/nodes.h" #include "nodes/nodes.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/planmain.h"
#include "optimizer/var.h" #include "optimizer/var.h"
#include "parser/parse_coerce.h" #include "parser/parse_coerce.h"
#include "parser/parse_expr.h" #include "parser/parse_expr.h"
@ -1242,6 +1241,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
List *rels; List *rels;
List *rt; List *rt;
Form_pg_type typTup; Form_pg_type typTup;
EState *estate;
ExprContext *econtext; ExprContext *econtext;
char *ccbin; char *ccbin;
Expr *expr; Expr *expr;
@ -1338,11 +1338,13 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
* the constraint is being added to. * the constraint is being added to.
*/ */
expr = (Expr *) stringToNode(ccbin); expr = (Expr *) stringToNode(ccbin);
fix_opfuncids((Node *) expr);
exprstate = ExecInitExpr(expr, NULL);
/* Make an expression context for ExecEvalExpr */ /* Need an EState to run ExecEvalExpr */
econtext = MakeExprContext(NULL, CurrentMemoryContext); estate = CreateExecutorState();
econtext = GetPerTupleExprContext(estate);
/* build execution state for expr */
exprstate = ExecPrepareExpr(expr, estate);
rels = get_rels_with_domain(domainoid); rels = get_rels_with_domain(domainoid);
@ -1377,7 +1379,9 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
econtext->domainValue_datum = d; econtext->domainValue_datum = d;
econtext->domainValue_isNull = isNull; econtext->domainValue_isNull = isNull;
conResult = ExecEvalExpr(exprstate, econtext, &isNull, NULL); conResult = ExecEvalExprSwitchContext(exprstate,
econtext,
&isNull, NULL);
if (!isNull && !DatumGetBool(conResult)) if (!isNull && !DatumGetBool(conResult))
elog(ERROR, "AlterDomainAddConstraint: Domain %s constraint %s failed", elog(ERROR, "AlterDomainAddConstraint: Domain %s constraint %s failed",
@ -1393,7 +1397,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
heap_close(testrel, NoLock); heap_close(testrel, NoLock);
} }
FreeExprContext(econtext); FreeExecutorState(estate);
/* Clean up */ /* Clean up */
heap_close(rel, NoLock); heap_close(rel, NoLock);

View File

@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.244 2002/10/31 19:25:29 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.245 2002/12/15 16:17:44 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1437,6 +1437,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
* We need a ResultRelInfo and an EState so we can use the regular * We need a ResultRelInfo and an EState so we can use the regular
* executor's index-entry-making machinery. * executor's index-entry-making machinery.
*/ */
estate = CreateExecutorState();
resultRelInfo = makeNode(ResultRelInfo); resultRelInfo = makeNode(ResultRelInfo);
resultRelInfo->ri_RangeTableIndex = 1; /* dummy */ resultRelInfo->ri_RangeTableIndex = 1; /* dummy */
resultRelInfo->ri_RelationDesc = onerel; resultRelInfo->ri_RelationDesc = onerel;
@ -1444,7 +1446,6 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
ExecOpenIndices(resultRelInfo); ExecOpenIndices(resultRelInfo);
estate = CreateExecutorState();
estate->es_result_relations = resultRelInfo; estate->es_result_relations = resultRelInfo;
estate->es_num_result_relations = 1; estate->es_num_result_relations = 1;
estate->es_result_relation_info = resultRelInfo; estate->es_result_relation_info = resultRelInfo;
@ -2484,6 +2485,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
ExecDropTupleTable(tupleTable, true); ExecDropTupleTable(tupleTable, true);
ExecCloseIndices(resultRelInfo); ExecCloseIndices(resultRelInfo);
FreeExecutorState(estate);
} }
/* /*

View File

@ -1,4 +1,4 @@
$Header: /cvsroot/pgsql/src/backend/executor/README,v 1.2 2002/12/05 15:50:30 tgl Exp $ $Header: /cvsroot/pgsql/src/backend/executor/README,v 1.3 2002/12/15 16:17:45 tgl Exp $
The Postgres Executor 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.) "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) EvalPlanQual (READ COMMITTED update checking)
--------------------------------------------- ---------------------------------------------

View File

@ -26,7 +26,7 @@
* *
* *
* IDENTIFICATION * 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/execdebug.h"
#include "executor/execdefs.h" #include "executor/execdefs.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "optimizer/planmain.h"
#include "optimizer/var.h" #include "optimizer/var.h"
#include "parser/parsetree.h" #include "parser/parsetree.h"
#include "utils/acl.h" #include "utils/acl.h"
@ -53,7 +52,6 @@ static void initResultRelInfo(ResultRelInfo *resultRelInfo,
Index resultRelationIndex, Index resultRelationIndex,
List *rangeTable, List *rangeTable,
CmdType operation); CmdType operation);
static void EndPlan(PlanState *planstate, EState *estate);
static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate, static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate,
CmdType operation, CmdType operation,
long numberTuples, 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 * 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. * returned, and the internal fields (estate and planstate) are set up.
* *
* XXX this will change soon: * NB: the CurrentMemoryContext when this is called will become the parent
* NB: the CurrentMemoryContext when this is called must be the context * of the per-query context used for this Executor invocation.
* to be used as the per-query context for the query plan. ExecutorRun()
* and ExecutorEnd() must be called in this same memory context.
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
void void
ExecutorStart(QueryDesc *queryDesc) ExecutorStart(QueryDesc *queryDesc)
{ {
EState *estate; EState *estate;
MemoryContext oldcontext;
/* sanity checks: queryDesc must not be started already */ /* sanity checks: queryDesc must not be started already */
Assert(queryDesc != NULL); Assert(queryDesc != NULL);
Assert(queryDesc->estate == NULL); Assert(queryDesc->estate == NULL);
/* /*
* Build EState, fill with parameters from queryDesc * Build EState, switch into per-query memory context for startup.
*/ */
estate = CreateExecutorState(); estate = CreateExecutorState();
queryDesc->estate = estate; queryDesc->estate = estate;
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
/*
* Fill in parameters, if any, from queryDesc
*/
estate->es_param_list_info = queryDesc->params; estate->es_param_list_info = queryDesc->params;
if (queryDesc->plantree->nParamExec > 0) if (queryDesc->plantree->nParamExec > 0)
@ -128,6 +130,8 @@ ExecutorStart(QueryDesc *queryDesc)
* Initialize the plan state tree * Initialize the plan state tree
*/ */
InitPlan(queryDesc); InitPlan(queryDesc);
MemoryContextSwitchTo(oldcontext);
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
@ -152,23 +156,30 @@ TupleTableSlot *
ExecutorRun(QueryDesc *queryDesc, ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count) ScanDirection direction, long count)
{ {
CmdType operation;
EState *estate; EState *estate;
CmdType operation;
CommandDest dest; CommandDest dest;
DestReceiver *destfunc; DestReceiver *destfunc;
TupleTableSlot *result; 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 * extract information from the query descriptor and the query
* feature. * feature.
*/ */
operation = queryDesc->operation; operation = queryDesc->operation;
estate = queryDesc->estate;
dest = queryDesc->dest; dest = queryDesc->dest;
/* /*
@ -199,6 +210,8 @@ ExecutorRun(QueryDesc *queryDesc,
*/ */
(*destfunc->cleanup) (destfunc); (*destfunc->cleanup) (destfunc);
MemoryContextSwitchTo(oldcontext);
return result; return result;
} }
@ -213,72 +226,37 @@ void
ExecutorEnd(QueryDesc *queryDesc) ExecutorEnd(QueryDesc *queryDesc)
{ {
EState *estate; EState *estate;
MemoryContext oldcontext;
/* sanity checks */ /* sanity checks */
Assert(queryDesc != NULL); Assert(queryDesc != NULL);
estate = queryDesc->estate; estate = queryDesc->estate;
EndPlan(queryDesc->planstate, estate); Assert(estate != NULL);
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;
/* /*
* 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; MemoryContextSwitchTo(oldcontext);
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;
/* /*
* 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 * Cleans up the query plan -- closes files and frees up storage
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
static void void
EndPlan(PlanState *planstate, EState *estate) ExecEndPlan(PlanState *planstate, EState *estate)
{ {
ResultRelInfo *resultRelInfo; ResultRelInfo *resultRelInfo;
int i; int i;
@ -1542,9 +1520,8 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
for (i = 0; i < ncheck; i++) for (i = 0; i < ncheck; i++)
{ {
qual = (List *) stringToNode(check[i].ccbin); qual = (List *) stringToNode(check[i].ccbin);
fix_opfuncids((Node *) qual);
resultRelInfo->ri_ConstraintExprs[i] = (List *) resultRelInfo->ri_ConstraintExprs[i] = (List *)
ExecInitExpr((Expr *) qual, NULL); ExecPrepareExpr((Expr *) qual, estate);
} }
MemoryContextSwitchTo(oldContext); MemoryContextSwitchTo(oldContext);
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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/functions.h"
#include "executor/nodeSubplan.h" #include "executor/nodeSubplan.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "optimizer/planmain.h"
#include "parser/parse_expr.h" #include "parser/parse_expr.h"
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/array.h" #include "utils/array.h"
@ -1896,9 +1897,11 @@ ExecEvalExprSwitchContext(ExprState *expression,
* cleanup work can register a shutdown callback in the ExprContext. * cleanup work can register a shutdown callback in the ExprContext.
* *
* 'node' is the root of the expression tree to examine * 'node' is the root of the expression tree to examine
* 'parent' is the PlanState node that owns the expression, * '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' 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 * ExprState *
ExecInitExpr(Expr *node, PlanState *parent) ExecInitExpr(Expr *node, PlanState *parent)
@ -2017,6 +2020,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
* parent->subPlan. The subplans will be initialized later. * parent->subPlan. The subplans will be initialized later.
*/ */
parent->subPlan = lcons(sstate, parent->subPlan); parent->subPlan = lcons(sstate, parent->subPlan);
sstate->sub_estate = NULL;
sstate->planstate = NULL; sstate->planstate = NULL;
sstate->oper = (List *) sstate->oper = (List *)
@ -2149,6 +2153,7 @@ ExecInitExprInitPlan(SubPlan *node, PlanState *parent)
elog(ERROR, "ExecInitExpr: SubPlan not expected here"); elog(ERROR, "ExecInitExpr: SubPlan not expected here");
/* The subplan's state will be initialized later */ /* The subplan's state will be initialized later */
sstate->sub_estate = NULL;
sstate->planstate = NULL; sstate->planstate = NULL;
sstate->oper = (List *) ExecInitExpr((Expr *) node->oper, parent); sstate->oper = (List *) ExecInitExpr((Expr *) node->oper, parent);
@ -2159,6 +2164,33 @@ ExecInitExprInitPlan(SubPlan *node, PlanState *parent)
return sstate; 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 * ExecQual / ExecTargetList / ExecProject

View File

@ -8,13 +8,20 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
* CreateExecutorState Create/delete executor working state
* FreeExecutorState
* CreateExprContext
* FreeExprContext
*
* ExecAssignExprContext Common code for plan node init routines. * ExecAssignExprContext Common code for plan node init routines.
* ExecAssignResultType
* etc
* *
* ExecOpenIndices \ * ExecOpenIndices \
* ExecCloseIndices | referenced by InitPlan, EndPlan, * ExecCloseIndices | referenced by InitPlan, EndPlan,
@ -26,7 +33,6 @@
* NOTES * NOTES
* This file has traditionally been the place to stick misc. * This file has traditionally been the place to stick misc.
* executor support stuff that doesn't really go anyplace else. * executor support stuff that doesn't really go anyplace else.
*
*/ */
#include "postgres.h" #include "postgres.h"
@ -64,6 +70,7 @@ extern int NIndexTupleProcessed; /* have to be defined in the
static void ShutdownExprContext(ExprContext *econtext); static void ShutdownExprContext(ExprContext *econtext);
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* statistic functions * statistic functions
* ---------------------------------------------------------------- * ----------------------------------------------------------------
@ -124,136 +131,263 @@ DisplayTupleCount(FILE *statfp)
} }
#endif #endif
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* miscellaneous node-init support functions * Executor state and memory management functions
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
/* ---------------- /* ----------------
* ExecAssignExprContext * CreateExecutorState
* *
* This initializes the ExprContext field. It is only necessary * Create and initialize an EState node, which is the root of
* to do this for nodes which use ExecQual or ExecProject * working storage for an entire Executor invocation.
* because those routines depend on econtext. Other nodes that
* don't have to evaluate expressions don't need to do this.
* *
* Note: we assume CurrentMemoryContext is the correct per-query context. * Principally, this creates the per-query memory context that will be
* This should be true during plan node initialization. * 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 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_scantuple = NULL;
econtext->ecxt_innertuple = NULL; econtext->ecxt_innertuple = NULL;
econtext->ecxt_outertuple = 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. * Create working memory for expression evaluation in this context.
*/ */
econtext->ecxt_per_tuple_memory = econtext->ecxt_per_tuple_memory =
AllocSetContextCreate(CurrentMemoryContext, AllocSetContextCreate(estate->es_query_cxt,
"PlanExprContext", "ExprContext",
ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE); ALLOCSET_DEFAULT_MAXSIZE);
econtext->ecxt_param_exec_vals = estate->es_param_exec_vals; econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
econtext->ecxt_param_list_info = estate->es_param_list_info; econtext->ecxt_param_list_info = estate->es_param_list_info;
econtext->ecxt_aggvalues = NULL; econtext->ecxt_aggvalues = NULL;
econtext->ecxt_aggnulls = NULL; econtext->ecxt_aggnulls = NULL;
econtext->domainValue_datum = (Datum) 0;
econtext->domainValue_isNull = true;
econtext->ecxt_estate = estate;
econtext->ecxt_callbacks = NULL; 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, * Link the ExprContext into the EState to ensure it is shut down
* not of the specified queryContext. This seems reasonable but I'm * when the EState is freed. Because we use lcons(), shutdowns will
* not totally sure about it... * occur in reverse order of creation, which may not be essential
* * but can't hurt.
* 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.
*/ */
econtext->ecxt_per_tuple_memory = estate->es_exprcontexts = lcons(econtext, estate->es_exprcontexts);
AllocSetContextCreate(CurrentMemoryContext,
"TempExprContext", MemoryContextSwitchTo(oldcontext);
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;
return econtext; return econtext;
} }
/* /* ----------------
* Free an ExprContext made by MakeExprContext, including the temporary * FreeExprContext
* context used for expression evaluation. Note this will cause any *
* pass-by-reference expression result to go away! * 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 void
FreeExprContext(ExprContext *econtext) FreeExprContext(ExprContext *econtext)
{ {
EState *estate;
/* Call any registered callbacks */ /* Call any registered callbacks */
ShutdownExprContext(econtext); ShutdownExprContext(econtext);
/* And clean up the memory used */ /* And clean up the memory used */
MemoryContextDelete(econtext->ecxt_per_tuple_memory); 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); pfree(econtext);
} }
/* /*
* Build a per-output-tuple ExprContext for an EState. * 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 * ExprContext *
MakePerTupleExprContext(EState *estate) MakePerTupleExprContext(EState *estate)
{ {
if (estate->es_per_tuple_exprcontext == NULL) if (estate->es_per_tuple_exprcontext == NULL)
{ estate->es_per_tuple_exprcontext = CreateExprContext(estate);
MemoryContext oldContext;
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; 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 * 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 * 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 void
@ -411,16 +523,8 @@ ExecFreeExprContext(PlanState *planstate)
if (econtext == NULL) if (econtext == NULL)
return; return;
/* FreeExprContext(econtext);
* clean up any registered callbacks
*/
ShutdownExprContext(econtext);
/*
* clean up memory used.
*/
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
pfree(econtext);
planstate->ps_ExprContext = NULL; 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++) for (i = 0; i < numIndices; i++)
{ {
IndexInfo *indexInfo; IndexInfo *indexInfo;
List *predicate;
InsertIndexResult result; InsertIndexResult result;
if (relationDescs[i] == NULL) if (relationDescs[i] == NULL)
continue; continue;
indexInfo = indexInfoArray[i]; 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 */ /* Skip this index-update if the predicate isn't satisfied */
if (!ExecQual(predicate, econtext, false)) if (!ExecQual(predicate, econtext, false))
continue; continue;
@ -811,6 +931,17 @@ static void
ShutdownExprContext(ExprContext *econtext) ShutdownExprContext(ExprContext *econtext)
{ {
ExprContext_CB *ecxt_callback; 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. * Call each callback function in reverse registration order.
@ -821,4 +952,6 @@ ShutdownExprContext(ExprContext *econtext)
(*ecxt_callback->function) (ecxt_callback->arg); (*ecxt_callback->function) (ecxt_callback->arg);
pfree(ecxt_callback); pfree(ecxt_callback);
} }
MemoryContextSwitchTo(oldcontext);
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) if (es->qd->operation != CMD_UTILITY)
ExecutorEnd(es->qd); ExecutorEnd(es->qd);
pfree(es->qd); FreeQueryDesc(es->qd);
es->qd = NULL; es->qd = NULL;
es->status = F_EXEC_DONE; es->status = F_EXEC_DONE;

View File

@ -45,7 +45,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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); tuplesort_end(peraggstate->sortstate);
} }
ExecFreeProjectionInfo(&node->ss.ps);
/* /*
* Free both the expr contexts. * Free both the expr contexts.
*/ */
@ -1401,18 +1399,13 @@ ExecEndAgg(AggState *node)
node->ss.ps.ps_ExprContext = node->tmpcontext; node->ss.ps.ps_ExprContext = node->tmpcontext;
ExecFreeExprContext(&node->ss.ps); ExecFreeExprContext(&node->ss.ps);
/* clean up tuple table */
ExecClearTuple(node->ss.ss_ScanTupleSlot);
MemoryContextDelete(node->aggcontext); MemoryContextDelete(node->aggcontext);
outerPlan = outerPlanState(node); outerPlan = outerPlanState(node);
ExecEndNode(outerPlan); 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 void

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ExecEndFunctionScan(FunctionScanState *node)
{ {
/* /*
* Free the projection info and the scan attribute info * Free the exprcontext
*/ */
ExecFreeProjectionInfo(&node->ss.ps);
ExecFreeExprContext(&node->ss.ps); ExecFreeExprContext(&node->ss.ps);
/* /*

View File

@ -15,7 +15,7 @@
* locate group boundaries. * locate group boundaries.
* *
* IDENTIFICATION * 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; PlanState *outerPlan;
ExecFreeProjectionInfo(&node->ss.ps);
ExecFreeExprContext(&node->ss.ps); ExecFreeExprContext(&node->ss.ps);
outerPlan = outerPlanState(node);
ExecEndNode(outerPlan);
/* clean up tuple table */ /* clean up tuple table */
ExecClearTuple(node->ss.ss_ScanTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot);
if (node->grp_firstTuple != NULL)
{ outerPlan = outerPlanState(node);
heap_freetuple(node->grp_firstTuple); ExecEndNode(outerPlan);
node->grp_firstTuple = NULL;
}
} }
void void

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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; PlanState *outerPlan;
/* /*
* free projection info. no need to free result type info because * free exprcontext
* that came from the outer plan...
*/ */
ExecFreeProjectionInfo(&node->ps);
ExecFreeExprContext(&node->ps); ExecFreeExprContext(&node->ps);
/* /*

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); ExecFreeExprContext(&node->js.ps);
/*
* clean up subtrees
*/
ExecEndNode(outerPlanState(node));
ExecEndNode(innerPlanState(node));
/* /*
* clean out the tuple table * clean out the tuple table
*/ */
@ -474,6 +467,11 @@ ExecEndHashJoin(HashJoinState *node)
ExecClearTuple(node->hj_OuterTupleSlot); ExecClearTuple(node->hj_OuterTupleSlot);
ExecClearTuple(node->hj_HashTupleSlot); ExecClearTuple(node->hj_HashTupleSlot);
/*
* clean up subtrees
*/
ExecEndNode(outerPlanState(node));
ExecEndNode(innerPlanState(node));
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * ExecEndIndexScan
*
* old comments
* Releases any storage allocated through C routines.
* Returns nothing.
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
void void
ExecEndIndexScan(IndexScanState *node) ExecEndIndexScan(IndexScanState *node)
{ {
ExprState ***runtimeKeyInfo;
ScanKey *scanKeys;
int *numScanKeys;
int numIndices; int numIndices;
Relation relation;
RelationPtr indexRelationDescs; RelationPtr indexRelationDescs;
IndexScanDescPtr indexScanDescs; IndexScanDescPtr indexScanDescs;
Relation relation;
int i; int i;
runtimeKeyInfo = node->iss_RuntimeKeyInfo;
/* /*
* extract information from the node * extract information from the node
*/ */
numIndices = node->iss_NumIndices; numIndices = node->iss_NumIndices;
scanKeys = node->iss_ScanKeys;
numScanKeys = node->iss_NumScanKeys;
indexRelationDescs = node->iss_RelationDescs; indexRelationDescs = node->iss_RelationDescs;
indexScanDescs = node->iss_ScanDescs; indexScanDescs = node->iss_ScanDescs;
relation = node->ss.ss_currentRelation; 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); ExecFreeExprContext(&node->ss.ps);
if (node->iss_RuntimeContext) if (node->iss_RuntimeContext)
FreeExprContext(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 * close the index relations
*/ */
@ -458,36 +452,6 @@ ExecEndIndexScan(IndexScanState *node)
* locking, however.) * locking, however.)
*/ */
heap_close(relation, NoLock); heap_close(relation, NoLock);
/*
* free the scan keys used in scanning the indices
*/
for (i = 0; i < numIndices; i++)
{
if (scanKeys[i] != NULL)
pfree(scanKeys[i]);
}
pfree(scanKeys);
pfree(numScanKeys);
if (runtimeKeyInfo)
{
for (i = 0; i < numIndices; i++)
{
if (runtimeKeyInfo[i] != NULL)
pfree(runtimeKeyInfo[i]);
}
pfree(runtimeKeyInfo);
}
/*
* clear out tuple table slots
*/
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
pfree(node->iss_RelationDescs);
pfree(node->iss_ScanDescs);
pfree(node);
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); ExecFreeExprContext(&node->ps);
ExecEndNode(outerPlanState(node));
/* clean up tuple table */ /* clean up tuple table */
ExecClearTuple(node->ps.ps_ResultTupleSlot); ExecClearTuple(node->ps.ps_ResultTupleSlot);
ExecEndNode(outerPlanState(node));
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); ExecClearTuple(node->ss.ss_ScanTupleSlot);
/*
* shut down the subplan
*/
ExecEndNode(outerPlanState(node));
/* /*
* Release tuplestore resources * Release tuplestore resources
*/ */
if (node->tuplestorestate != NULL) if (node->tuplestorestate != NULL)
tuplestore_end((Tuplestorestate *) node->tuplestorestate); tuplestore_end((Tuplestorestate *) node->tuplestorestate);
node->tuplestorestate = NULL; node->tuplestorestate = NULL;
/*
* shut down the subplan
*/
ExecEndNode(outerPlanState(node));
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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"); "ending node processing");
/* /*
* Free the projection info and the scan attribute info * Free the exprcontext
*/ */
ExecFreeProjectionInfo(&node->js.ps);
ExecFreeExprContext(&node->js.ps); ExecFreeExprContext(&node->js.ps);
/*
* shut down the subplans
*/
ExecEndNode(innerPlanState(node));
ExecEndNode(outerPlanState(node));
/* /*
* clean out the tuple table * clean out the tuple table
*/ */
ExecClearTuple(node->js.ps.ps_ResultTupleSlot); ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
ExecClearTuple(node->mj_MarkedTupleSlot); ExecClearTuple(node->mj_MarkedTupleSlot);
/*
* shut down the subplans
*/
ExecEndNode(innerPlanState(node));
ExecEndNode(outerPlanState(node));
MJ1_printf("ExecEndMergeJoin: %s\n", MJ1_printf("ExecEndMergeJoin: %s\n",
"node processing ended"); "node processing ended");
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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"); "ending node processing");
/* /*
* Free the projection info * Free the exprcontext
*/ */
ExecFreeProjectionInfo(&node->js.ps);
ExecFreeExprContext(&node->js.ps); ExecFreeExprContext(&node->js.ps);
/*
* clean out the tuple table
*/
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
/* /*
* close down subplans * close down subplans
*/ */
ExecEndNode(outerPlanState(node)); ExecEndNode(outerPlanState(node));
ExecEndNode(innerPlanState(node)); ExecEndNode(innerPlanState(node));
/*
* clean out the tuple table
*/
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
NL1_printf("ExecEndNestLoop: %s\n", NL1_printf("ExecEndNestLoop: %s\n",
"node processing ended"); "node processing ended");
} }

View File

@ -34,7 +34,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ExecEndResult(ResultState *node)
{ {
/* /*
* Free the projection info * Free the exprcontext
*/ */
ExecFreeProjectionInfo(&node->ps);
ExecFreeExprContext(&node->ps); ExecFreeExprContext(&node->ps);
/* /*

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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; scanDesc = node->ss_currentScanDesc;
/* /*
* Free the projection info and the scan attribute info * Free the exprcontext
*/ */
ExecFreeProjectionInfo(&node->ps);
ExecFreeExprContext(&node->ps); ExecFreeExprContext(&node->ps);
/*
* close heap scan
*/
heap_endscan(scanDesc);
/* /*
* clean out the tuple table * clean out the tuple table
*/ */
ExecClearTuple(node->ps.ps_ResultTupleSlot); ExecClearTuple(node->ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss_ScanTupleSlot); ExecClearTuple(node->ss_ScanTupleSlot);
/*
* close heap scan
*/
heap_endscan(scanDesc);
/* /*
* close the heap relation. * close the heap relation.
* *

View File

@ -21,7 +21,7 @@
* *
* *
* IDENTIFICATION * 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); ExecClearTuple(node->ps.ps_ResultTupleSlot);
node->ps.ps_OuterTupleSlot = NULL; node->ps.ps_OuterTupleSlot = NULL;
ExecEndNode(outerPlanState(node));
MemoryContextDelete(node->tempContext); MemoryContextDelete(node->tempContext);
ExecEndNode(outerPlanState(node));
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); ExecClearTuple(node->ss.ss_ScanTupleSlot);
/*
* shut down the subplan
*/
ExecEndNode(outerPlanState(node));
/* /*
* Release tuplesort resources * Release tuplesort resources
*/ */
@ -296,6 +291,11 @@ ExecEndSort(SortState *node)
tuplesort_end((Tuplesortstate *) node->tuplesortstate); tuplesort_end((Tuplesortstate *) node->tuplesortstate);
node->tuplesortstate = NULL; node->tuplesortstate = NULL;
/*
* shut down the subplan
*/
ExecEndNode(outerPlanState(node));
SO1_printf("ExecEndSort: %s\n", SO1_printf("ExecEndSort: %s\n",
"sort node shutdown"); "sort node shutdown");
} }

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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. * 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) if (subplan->setParam != NIL)
elog(ERROR, "ExecSubPlan: can't set parent params from subquery"); 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 * ExecProcNode() call. node->curTuple keeps track of the
* copied tuple for eventual freeing. * copied tuple for eventual freeing.
*/ */
MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
tup = heap_copytuple(tup); tup = heap_copytuple(tup);
if (node->curTuple) if (node->curTuple)
heap_freetuple(node->curTuple); heap_freetuple(node->curTuple);
node->curTuple = tup; node->curTuple = tup;
MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
result = heap_getattr(tup, col, tdesc, isNull); result = heap_getattr(tup, col, tdesc, isNull);
/* keep scanning subplan to make sure there's only one tuple */ /* keep scanning subplan to make sure there's only one tuple */
continue; continue;
@ -295,6 +299,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
{ {
SubPlan *subplan = (SubPlan *) node->xprstate.expr; SubPlan *subplan = (SubPlan *) node->xprstate.expr;
EState *sp_estate; EState *sp_estate;
MemoryContext oldcontext;
/* /*
* Do access checking on the rangetable entries in the subquery. * Do access checking on the rangetable entries in the subquery.
@ -303,15 +308,23 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
ExecCheckRTPerms(subplan->rtable, CMD_SELECT); ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
/* /*
* initialize state * initialize my state
*/ */
node->needShutdown = false; node->needShutdown = false;
node->curTuple = NULL; node->curTuple = NULL;
/* /*
* create an EState for the subplan * 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(); 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_range_table = subplan->rtable;
sp_estate->es_param_list_info = estate->es_param_list_info; 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; 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->planstate = ExecInitNode(subplan->plan, sp_estate);
node->needShutdown = true; /* now we need to shutdown the subplan */ node->needShutdown = true; /* now we need to shutdown the subplan */
MemoryContextSwitchTo(oldcontext);
/* /*
* If this plan is un-correlated or undirect correlated one and want * If this plan is un-correlated or undirect correlated one and want
* to set params for parent plan then prepare parameters. * to set params for parent plan then prepare parameters.
@ -376,10 +391,9 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
bool found = false; bool found = false;
/* /*
* We are probably in a short-lived expression-evaluation context. * Must switch to child query's per-query memory context.
* Switch to longer-lived per-query context.
*/ */
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory); oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
if (subLinkType == ANY_SUBLINK || if (subLinkType == ANY_SUBLINK ||
subLinkType == ALL_SUBLINK) subLinkType == ALL_SUBLINK)
@ -415,15 +429,18 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
found = true; found = true;
/* /*
* We need to copy the subplan's tuple in case any of the params * We need to copy the subplan's tuple into our own context,
* are pass-by-ref type --- the pointers stored in the param * in case any of the params are pass-by-ref type --- the pointers
* structs will point at this copied tuple! node->curTuple keeps * stored in the param structs will point at this copied tuple!
* track of the copied tuple for eventual freeing. * node->curTuple keeps track of the copied tuple for eventual
* freeing.
*/ */
MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
tup = heap_copytuple(tup); tup = heap_copytuple(tup);
if (node->curTuple) if (node->curTuple)
heap_freetuple(node->curTuple); heap_freetuple(node->curTuple);
node->curTuple = tup; node->curTuple = tup;
MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
foreach(lst, subplan->setParam) foreach(lst, subplan->setParam)
{ {
@ -460,7 +477,10 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
if (planstate->plan->extParam == NULL) /* un-correlated ... */ 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; node->needShutdown = false;
} }
@ -476,7 +496,12 @@ ExecEndSubPlan(SubPlanState *node)
{ {
if (node->needShutdown) 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; node->needShutdown = false;
} }
if (node->curTuple) if (node->curTuple)

View File

@ -12,7 +12,7 @@
* *
* *
* IDENTIFICATION * 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; EState *estate;
ScanDirection direction; ScanDirection direction;
TupleTableSlot *slot; TupleTableSlot *slot;
MemoryContext oldcontext;
/* /*
* get information from the estate and scan state * 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; node->sss_SubEState->es_direction = direction;
oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
slot = ExecProcNode(node->subplan); slot = ExecProcNode(node->subplan);
MemoryContextSwitchTo(oldcontext);
node->ss.ss_ScanTupleSlot = slot; node->ss.ss_ScanTupleSlot = slot;
return slot; return slot;
@ -106,6 +112,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
SubqueryScanState *subquerystate; SubqueryScanState *subquerystate;
RangeTblEntry *rte; RangeTblEntry *rte;
EState *sp_estate; EState *sp_estate;
MemoryContext oldcontext;
/* /*
* SubqueryScan should not have any "normal" children. * 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); rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
Assert(rte->rtekind == RTE_SUBQUERY); 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(); sp_estate = CreateExecutorState();
subquerystate->sss_SubEState = sp_estate; subquerystate->sss_SubEState = sp_estate;
oldcontext = MemoryContextSwitchTo(sp_estate->es_query_cxt);
sp_estate->es_range_table = rte->subquery->rtable; sp_estate->es_range_table = rte->subquery->rtable;
sp_estate->es_param_list_info = estate->es_param_list_info; sp_estate->es_param_list_info = estate->es_param_list_info;
sp_estate->es_param_exec_vals = estate->es_param_exec_vals; 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_snapshot = estate->es_snapshot;
sp_estate->es_instrument = estate->es_instrument; 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); subquerystate->subplan = ExecInitNode(node->subplan, sp_estate);
MemoryContextSwitchTo(oldcontext);
subquerystate->ss.ss_ScanTupleSlot = NULL; subquerystate->ss.ss_ScanTupleSlot = NULL;
subquerystate->ss.ps.ps_TupFromTlist = false; subquerystate->ss.ps.ps_TupFromTlist = false;
@ -197,10 +217,11 @@ ExecCountSlotsSubqueryScan(SubqueryScan *node)
void void
ExecEndSubqueryScan(SubqueryScanState *node) 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); ExecFreeExprContext(&node->ss.ps);
/* /*
@ -211,15 +232,13 @@ ExecEndSubqueryScan(SubqueryScanState *node)
/* /*
* close down subquery * close down subquery
*/ */
ExecEndNode(node->subplan); oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
/* ExecEndPlan(node->subplan, node->sss_SubEState);
* clean up subquery's tuple table
*/
node->ss.ss_ScanTupleSlot = NULL;
ExecDropTupleTable(node->sss_SubEState->es_tupleTable, true);
/* 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) ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
{ {
EState *estate; EState *estate;
MemoryContext oldcontext;
estate = node->ss.ps.state; 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 * 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) if (node->ss.ps.chgParam != NULL)
SetChangedParamList(node->subplan, node->ss.ps.chgParam); SetChangedParamList(node->subplan, node->ss.ps.chgParam);
@ -249,5 +273,7 @@ ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
if (node->subplan->chgParam == NULL) if (node->subplan->chgParam == NULL)
ExecReScan(node->subplan, NULL); ExecReScan(node->subplan, NULL);
MemoryContextSwitchTo(oldcontext);
node->ss.ss_ScanTupleSlot = NULL; node->ss.ss_ScanTupleSlot = NULL;
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) 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); ExecFreeExprContext(&node->ss.ps);
/* /*

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 */ /* clean up tuple table */
ExecClearTuple(node->ps.ps_ResultTupleSlot); ExecClearTuple(node->ps.ps_ResultTupleSlot);
if (node->priorTuple != NULL)
{
heap_freetuple(node->priorTuple);
node->priorTuple = NULL;
}
ExecEndNode(outerPlanState(node));
MemoryContextDelete(node->tempContext); MemoryContextDelete(node->tempContext);
ExecEndNode(outerPlanState(node));
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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"); 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) if (dest == SPI)
{ {
SPI_processed = _SPI_current->processed; SPI_processed = _SPI_current->processed;
SPI_lastoid = save_lastoid; SPI_lastoid = save_lastoid;
SPI_tuptable = _SPI_current->tuptable; 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; return res;
} }
/* /*

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.128 2002/12/13 19:45:56 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.129 2002/12/15 16:17:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1132,7 +1132,8 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
HeapTuple tuple; HeapTuple tuple;
ScanKeyData entry[1]; ScanKeyData entry[1];
Form_pg_amop aform; Form_pg_amop aform;
ExprContext *econtext; EState *estate;
MemoryContext oldcontext;
/* First try the equal() test */ /* First try the equal() test */
if (equal((Node *) predicate, clause)) if (equal((Node *) predicate, clause))
@ -1267,20 +1268,33 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
/* /*
* 5. Evaluate the test * 5. Evaluate the test. For this we need an EState.
*/ */
estate = CreateExecutorState();
/* We can use the estate's working context to avoid memory leaks. */
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
/* Build expression tree */
test_expr = make_opclause(test_op, test_expr = make_opclause(test_op,
BOOLOID, BOOLOID,
false, false,
(Expr *) clause_const, (Expr *) clause_const,
(Expr *) pred_const); (Expr *) pred_const);
set_opfuncid((OpExpr *) test_expr);
test_exprstate = ExecInitExpr(test_expr, NULL);
econtext = MakeExprContext(NULL, CurrentMemoryContext); /* Prepare it for execution */
test_result = ExecEvalExprSwitchContext(test_exprstate, econtext, test_exprstate = ExecPrepareExpr(test_expr, estate);
/* And execute it. */
test_result = ExecEvalExprSwitchContext(test_exprstate,
GetPerTupleExprContext(estate),
&isNull, NULL); &isNull, NULL);
FreeExprContext(econtext);
/* Get back to outer memory context */
MemoryContextSwitchTo(oldcontext);
/* Release all the junk we just created */
FreeExecutorState(estate);
if (isNull) if (isNull)
{ {

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.119 2002/12/14 00:17:59 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.120 2002/12/15 16:17:50 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
@ -1684,7 +1684,8 @@ evaluate_function(Oid funcid, List *args, HeapTuple func_tuple)
bool has_null_input = false; bool has_null_input = false;
FuncExpr *newexpr; FuncExpr *newexpr;
ExprState *newexprstate; ExprState *newexprstate;
ExprContext *econtext; EState *estate;
MemoryContext oldcontext;
Datum const_val; Datum const_val;
bool const_is_null; bool const_is_null;
List *arg; List *arg;
@ -1729,7 +1730,14 @@ evaluate_function(Oid funcid, List *args, HeapTuple func_tuple)
* *
* We use the executor's routine ExecEvalExpr() to avoid duplication of * We use the executor's routine ExecEvalExpr() to avoid duplication of
* code and ensure we get the same result as the executor would get. * code and ensure we get the same result as the executor would get.
* * To use the executor, we need an EState.
*/
estate = CreateExecutorState();
/* We can use the estate's working context to avoid memory leaks. */
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
/*
* Build a new FuncExpr node containing the already-simplified arguments. * Build a new FuncExpr node containing the already-simplified arguments.
*/ */
newexpr = makeNode(FuncExpr); newexpr = makeNode(FuncExpr);
@ -1739,27 +1747,35 @@ evaluate_function(Oid funcid, List *args, HeapTuple func_tuple)
newexpr->funcformat = COERCE_EXPLICIT_CALL; /* doesn't matter */ newexpr->funcformat = COERCE_EXPLICIT_CALL; /* doesn't matter */
newexpr->args = args; newexpr->args = args;
/* Get info needed about result datatype */ /*
get_typlenbyval(result_typeid, &resultTypLen, &resultTypByVal); * Prepare it for execution.
*/
newexprstate = ExecPrepareExpr((Expr *) newexpr, estate);
/* /*
* It is OK to use a dummy econtext because none of the * And evaluate it.
*
* It is OK to use a default econtext because none of the
* ExecEvalExpr() code used in this situation will use econtext. That * ExecEvalExpr() code used in this situation will use econtext. That
* might seem fortuitous, but it's not so unreasonable --- a constant * might seem fortuitous, but it's not so unreasonable --- a constant
* expression does not depend on context, by definition, n'est ce pas? * expression does not depend on context, by definition, n'est ce pas?
*/ */
econtext = MakeExprContext(NULL, CurrentMemoryContext); const_val = ExecEvalExprSwitchContext(newexprstate,
GetPerTupleExprContext(estate),
newexprstate = ExecInitExpr((Expr *) newexpr, NULL);
const_val = ExecEvalExprSwitchContext(newexprstate, econtext,
&const_is_null, NULL); &const_is_null, NULL);
/* Get info needed about result datatype */
get_typlenbyval(result_typeid, &resultTypLen, &resultTypByVal);
/* Get back to outer memory context */
MemoryContextSwitchTo(oldcontext);
/* Must copy result out of sub-context used by expression eval */ /* Must copy result out of sub-context used by expression eval */
if (!const_is_null) if (!const_is_null)
const_val = datumCopy(const_val, resultTypByVal, resultTypLen); const_val = datumCopy(const_val, resultTypByVal, resultTypLen);
FreeExprContext(econtext); /* Release all the junk we just created */
FreeExecutorState(estate);
/* /*
* Make the constant result node. * Make the constant result node.

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.57 2002/12/05 15:50:35 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.58 2002/12/15 16:17:52 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -52,6 +52,18 @@ CreateQueryDesc(Query *parsetree,
return qd; return qd;
} }
/*
* FreeQueryDesc
*/
void
FreeQueryDesc(QueryDesc *qdesc)
{
/* Can't be a live query */
Assert(qdesc->estate == NULL);
/* Only the QueryDesc itself need be freed */
pfree(qdesc);
}
/* ---------------- /* ----------------
* PreparePortal * PreparePortal
* ---------------- * ----------------
@ -152,9 +164,8 @@ ProcessQuery(Query *parsetree,
* QueryDesc */ * QueryDesc */
/* /*
* We stay in portal's memory context for now, so that query desc, * We stay in portal's memory context for now, so that query desc
* exec state, and plan startup info are also allocated in the portal * is also allocated in the portal context.
* context.
*/ */
} }
@ -231,4 +242,6 @@ ProcessQuery(Query *parsetree,
* Now, we close down all the scans and free allocated resources. * Now, we close down all the scans and free allocated resources.
*/ */
ExecutorEnd(queryDesc); ExecutorEnd(queryDesc);
FreeQueryDesc(queryDesc);
} }

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: execdesc.h,v 1.21 2002/12/05 15:50:36 tgl Exp $ * $Id: execdesc.h,v 1.22 2002/12/15 16:17:54 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -50,4 +50,6 @@ extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
ParamListInfo params, ParamListInfo params,
bool doInstrument); bool doInstrument);
extern void FreeQueryDesc(QueryDesc *qdesc);
#endif /* EXECDESC_H */ #endif /* EXECDESC_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: executor.h,v 1.83 2002/12/14 00:17:59 tgl Exp $ * $Id: executor.h,v 1.84 2002/12/15 16:17:54 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -54,8 +54,8 @@ extern void ExecutorStart(QueryDesc *queryDesc);
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count); ScanDirection direction, long count);
extern void ExecutorEnd(QueryDesc *queryDesc); extern void ExecutorEnd(QueryDesc *queryDesc);
extern EState *CreateExecutorState(void);
extern void ExecCheckRTPerms(List *rangeTable, CmdType operation); extern void ExecCheckRTPerms(List *rangeTable, CmdType operation);
extern void ExecEndPlan(PlanState *planstate, EState *estate);
extern void ExecConstraints(const char *caller, ResultRelInfo *resultRelInfo, extern void ExecConstraints(const char *caller, ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate); TupleTableSlot *slot, EState *estate);
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
@ -93,6 +93,7 @@ extern Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econt
bool *isNull, ExprDoneCond *isDone); bool *isNull, ExprDoneCond *isDone);
extern ExprState *ExecInitExpr(Expr *node, PlanState *parent); extern ExprState *ExecInitExpr(Expr *node, PlanState *parent);
extern SubPlanState *ExecInitExprInitPlan(SubPlan *node, PlanState *parent); extern SubPlanState *ExecInitExprInitPlan(SubPlan *node, PlanState *parent);
extern ExprState *ExecPrepareExpr(Expr *node, EState *estate);
extern bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull); extern bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull);
extern int ExecTargetListLength(List *targetlist); extern int ExecTargetListLength(List *targetlist);
extern int ExecCleanTargetListLength(List *targetlist); extern int ExecCleanTargetListLength(List *targetlist);
@ -157,23 +158,9 @@ extern void end_tup_output(TupOutputState *tstate);
/* /*
* prototypes from functions in execUtils.c * prototypes from functions in execUtils.c
*/ */
extern void ResetTupleCount(void); extern EState *CreateExecutorState(void);
extern void ExecAssignExprContext(EState *estate, PlanState *planstate); extern void FreeExecutorState(EState *estate);
extern void ExecAssignResultType(PlanState *planstate, extern ExprContext *CreateExprContext(EState *estate);
TupleDesc tupDesc, bool shouldFree);
extern void ExecAssignResultTypeFromOuterPlan(PlanState *planstate);
extern void ExecAssignResultTypeFromTL(PlanState *planstate);
extern TupleDesc ExecGetResultType(PlanState *planstate);
extern void ExecAssignProjectionInfo(PlanState *planstate);
extern void ExecFreeProjectionInfo(PlanState *planstate);
extern void ExecFreeExprContext(PlanState *planstate);
extern TupleDesc ExecGetScanType(ScanState *scanstate);
extern void ExecAssignScanType(ScanState *scanstate,
TupleDesc tupDesc, bool shouldFree);
extern void ExecAssignScanTypeFromOuterPlan(ScanState *scanstate);
extern ExprContext *MakeExprContext(TupleTableSlot *slot,
MemoryContext queryContext);
extern void FreeExprContext(ExprContext *econtext); extern void FreeExprContext(ExprContext *econtext);
#define ResetExprContext(econtext) \ #define ResetExprContext(econtext) \
@ -197,6 +184,19 @@ extern ExprContext *MakePerTupleExprContext(EState *estate);
ResetExprContext((estate)->es_per_tuple_exprcontext); \ ResetExprContext((estate)->es_per_tuple_exprcontext); \
} while (0) } while (0)
extern void ExecAssignExprContext(EState *estate, PlanState *planstate);
extern void ExecAssignResultType(PlanState *planstate,
TupleDesc tupDesc, bool shouldFree);
extern void ExecAssignResultTypeFromOuterPlan(PlanState *planstate);
extern void ExecAssignResultTypeFromTL(PlanState *planstate);
extern TupleDesc ExecGetResultType(PlanState *planstate);
extern void ExecAssignProjectionInfo(PlanState *planstate);
extern void ExecFreeExprContext(PlanState *planstate);
extern TupleDesc ExecGetScanType(ScanState *scanstate);
extern void ExecAssignScanType(ScanState *scanstate,
TupleDesc tupDesc, bool shouldFree);
extern void ExecAssignScanTypeFromOuterPlan(ScanState *scanstate);
extern void ExecOpenIndices(ResultRelInfo *resultRelInfo); extern void ExecOpenIndices(ResultRelInfo *resultRelInfo);
extern void ExecCloseIndices(ResultRelInfo *resultRelInfo); extern void ExecCloseIndices(ResultRelInfo *resultRelInfo);
extern void ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid, extern void ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: execnodes.h,v 1.85 2002/12/14 00:17:59 tgl Exp $ * $Id: execnodes.h,v 1.86 2002/12/15 16:17:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -81,14 +81,14 @@ typedef struct ExprContext_CB
* context. * context.
* *
* There are two memory contexts associated with an ExprContext: * There are two memory contexts associated with an ExprContext:
* * ecxt_per_query_memory is a relatively long-lived context (such as * * ecxt_per_query_memory is a query-lifespan context, typically the same
* TransactionCommandContext); typically it's the same context the * context the ExprContext node itself is allocated in. This context
* ExprContext node itself is allocated in. This context can be * can be used for purposes such as storing function call cache info.
* used for purposes such as storing function call cache info.
* * ecxt_per_tuple_memory is a short-term context for expression results. * * ecxt_per_tuple_memory is a short-term context for expression results.
* As the name suggests, it will typically be reset once per tuple, * As the name suggests, it will typically be reset once per tuple,
* before we begin to evaluate expressions for that tuple. Each * before we begin to evaluate expressions for that tuple. Each
* ExprContext normally has its very own per-tuple memory context. * ExprContext normally has its very own per-tuple memory context.
*
* CurrentMemoryContext should be set to ecxt_per_tuple_memory before * CurrentMemoryContext should be set to ecxt_per_tuple_memory before
* calling ExecEvalExpr() --- see ExecEvalExprSwitchContext(). * calling ExecEvalExpr() --- see ExecEvalExprSwitchContext().
* ---------------- * ----------------
@ -118,6 +118,9 @@ typedef struct ExprContext
Datum domainValue_datum; Datum domainValue_datum;
bool domainValue_isNull; bool domainValue_isNull;
/* Link to containing EState */
struct EState *ecxt_estate;
/* Functions to call back when ExprContext is shut down */ /* Functions to call back when ExprContext is shut down */
ExprContext_CB *ecxt_callbacks; ExprContext_CB *ecxt_callbacks;
} ExprContext; } ExprContext;
@ -277,45 +280,43 @@ typedef struct ResultRelInfo
/* ---------------- /* ----------------
* EState information * EState information
* *
* direction direction of the scan * Master working state for an Executor invocation
*
* snapshot time qual to use
*
* range_table array of scan relation information
*
* result_relation information for insert/update/delete queries
*
* into_relation_descriptor relation being retrieved "into"
*
* param_list_info information about Param values
*
* tupleTable this is a pointer to an array
* of pointers to tuples used by
* the executor at any given moment.
* ---------------- * ----------------
*/ */
typedef struct EState typedef struct EState
{ {
NodeTag type; NodeTag type;
ScanDirection es_direction;
Snapshot es_snapshot; /* Basic state for all query types: */
List *es_range_table; ScanDirection es_direction; /* current scan direction */
Snapshot es_snapshot; /* time qual to use */
List *es_range_table; /* List of RangeTableEntrys */
/* Info about target table for insert/update/delete queries: */
ResultRelInfo *es_result_relations; /* array of ResultRelInfos */ ResultRelInfo *es_result_relations; /* array of ResultRelInfos */
int es_num_result_relations; /* length of array */ int es_num_result_relations; /* length of array */
ResultRelInfo *es_result_relation_info; /* currently active array ResultRelInfo *es_result_relation_info; /* currently active array
* elt */ * elt */
JunkFilter *es_junkFilter; /* currently active junk filter */ JunkFilter *es_junkFilter; /* currently active junk filter */
Relation es_into_relation_descriptor; Relation es_into_relation_descriptor; /* for SELECT INTO */
/* Parameter info: */
ParamListInfo es_param_list_info; /* values of external params */ ParamListInfo es_param_list_info; /* values of external params */
ParamExecData *es_param_exec_vals; /* values of internal params */ ParamExecData *es_param_exec_vals; /* values of internal params */
TupleTable es_tupleTable;
/* Other working state: */
MemoryContext es_query_cxt; /* per-query context in which EState lives */
TupleTable es_tupleTable; /* Array of TupleTableSlots */
uint32 es_processed; /* # of tuples processed */ uint32 es_processed; /* # of tuples processed */
Oid es_lastoid; /* last oid processed (by INSERT) */ Oid es_lastoid; /* last oid processed (by INSERT) */
List *es_rowMark; /* not good place, but there is no other */ List *es_rowMark; /* not good place, but there is no other */
MemoryContext es_query_cxt; /* per-query context in which EState lives */
bool es_instrument; /* true requests runtime instrumentation */ bool es_instrument; /* true requests runtime instrumentation */
List *es_exprcontexts; /* List of ExprContexts within EState */
/* /*
* this ExprContext is for per-output-tuple operations, such as * this ExprContext is for per-output-tuple operations, such as
* constraint checks and index-value computations. It will be reset * constraint checks and index-value computations. It will be reset
@ -457,6 +458,7 @@ typedef struct BoolExprState
typedef struct SubPlanState typedef struct SubPlanState
{ {
ExprState xprstate; ExprState xprstate;
EState *sub_estate; /* subselect plan has its own EState */
struct PlanState *planstate; /* subselect plan's state tree */ struct PlanState *planstate; /* subselect plan's state tree */
bool needShutdown; /* TRUE = need to shutdown subplan */ bool needShutdown; /* TRUE = need to shutdown subplan */
HeapTuple curTuple; /* copy of most recent tuple from subplan */ HeapTuple curTuple; /* copy of most recent tuple from subplan */

View File

@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.74 2002/12/13 19:46:01 tgl Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.75 2002/12/15 16:17:58 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
@ -3227,7 +3227,6 @@ exec_eval_simple_expr(PLpgSQL_execstate * estate,
bool *isNull, bool *isNull,
Oid *rettype) Oid *rettype)
{ {
_SPI_plan *spi_plan = (_SPI_plan *) expr->plan;
Datum retval; Datum retval;
PLpgSQL_var *var; PLpgSQL_var *var;
PLpgSQL_rec *rec; PLpgSQL_rec *rec;
@ -3242,14 +3241,11 @@ exec_eval_simple_expr(PLpgSQL_execstate * estate,
ParamListInfo paramLI; ParamListInfo paramLI;
/* /*
* Create a simple expression context to hold the arguments. * Create an expression context to hold the arguments and the result
* * of this expression evaluation. This must be a child of the EState
* NOTE: we pass the SPI plan's context as the query-lifetime context for * we created in the SPI plan's context.
* function cache nodes and suchlike allocations. This is appropriate
* because that's where the expression tree itself is, and the
* function cache nodes must live as long as it does.
*/ */
econtext = MakeExprContext(NULL, spi_plan->plancxt); econtext = CreateExprContext(expr->plan_simple_estate);
/* /*
* Param list can live in econtext's temporary memory context. * Param list can live in econtext's temporary memory context.
@ -3691,13 +3687,20 @@ exec_simple_check_plan(PLpgSQL_expr * expr)
return; return;
/* /*
* Yes - this is a simple expression. Prepare to execute it, and * Yes - this is a simple expression. Prepare to execute it.
* stash away the result type. Put the expression state tree in the * We need an EState and an expression state tree, which we'll put
* plan context so it will have appropriate lifespan. * into the plan context so they will have appropriate lifespan.
*/ */
oldcontext = MemoryContextSwitchTo(spi_plan->plancxt); oldcontext = MemoryContextSwitchTo(spi_plan->plancxt);
expr->plan_simple_expr = ExecInitExpr(tle->expr, NULL);
expr->plan_simple_estate = CreateExecutorState();
expr->plan_simple_expr = ExecPrepareExpr(tle->expr,
expr->plan_simple_estate);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
/* Also stash away the expression result type */
expr->plan_simple_type = exprType((Node *) tle->expr); expr->plan_simple_type = exprType((Node *) tle->expr);
} }

View File

@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.30 2002/12/13 19:46:01 tgl Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.31 2002/12/15 16:17:59 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
@ -166,6 +166,7 @@ typedef struct
char *query; char *query;
void *plan; void *plan;
ExprState *plan_simple_expr; ExprState *plan_simple_expr;
EState *plan_simple_estate;
Oid plan_simple_type; Oid plan_simple_type;
Oid *plan_argtypes; Oid *plan_argtypes;
int nparams; int nparams;