summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane2002-12-15 16:17:59 +0000
committerTom Lane2002-12-15 16:17:59 +0000
commit5bab36e9f6c3f3a9e14a89e1124179a339d2c3a1 (patch)
treea05154b129808efc7882599d96a1132051c2403b /src
parent90b3a0b6fd3bc74804c01156491635e5d95091d9 (diff)
Revise executor APIs so that all per-query state structure is built in
a per-query memory context created by CreateExecutorState --- and destroyed by FreeExecutorState. This provides a final solution to the longstanding problem of memory leaked by various ExecEndNode calls.
Diffstat (limited to 'src')
-rw-r--r--src/backend/bootstrap/bootstrap.c5
-rw-r--r--src/backend/catalog/index.c46
-rw-r--r--src/backend/commands/copy.c20
-rw-r--r--src/backend/commands/explain.c4
-rw-r--r--src/backend/commands/indexcmds.c7
-rw-r--r--src/backend/commands/portalcmds.c14
-rw-r--r--src/backend/commands/prepare.c49
-rw-r--r--src/backend/commands/tablecmds.c25
-rw-r--r--src/backend/commands/typecmds.c20
-rw-r--r--src/backend/commands/vacuum.c7
-rw-r--r--src/backend/executor/README79
-rw-r--r--src/backend/executor/execMain.c113
-rw-r--r--src/backend/executor/execQual.c40
-rw-r--r--src/backend/executor/execUtils.c345
-rw-r--r--src/backend/executor/functions.c5
-rw-r--r--src/backend/executor/nodeAgg.c15
-rw-r--r--src/backend/executor/nodeFunctionscan.c5
-rw-r--r--src/backend/executor/nodeGroup.c14
-rw-r--r--src/backend/executor/nodeHash.c6
-rw-r--r--src/backend/executor/nodeHashjoin.c16
-rw-r--r--src/backend/executor/nodeIndexscan.c54
-rw-r--r--src/backend/executor/nodeLimit.c6
-rw-r--r--src/backend/executor/nodeMaterial.c12
-rw-r--r--src/backend/executor/nodeMergejoin.c17
-rw-r--r--src/backend/executor/nodeNestloop.c15
-rw-r--r--src/backend/executor/nodeResult.c5
-rw-r--r--src/backend/executor/nodeSeqscan.c15
-rw-r--r--src/backend/executor/nodeSetOp.c6
-rw-r--r--src/backend/executor/nodeSort.c12
-rw-r--r--src/backend/executor/nodeSubplan.c53
-rw-r--r--src/backend/executor/nodeSubqueryscan.c50
-rw-r--r--src/backend/executor/nodeTidscan.c15
-rw-r--r--src/backend/executor/nodeUnique.c11
-rw-r--r--src/backend/executor/spi.c20
-rw-r--r--src/backend/optimizer/path/indxpath.c30
-rw-r--r--src/backend/optimizer/util/clauses.c38
-rw-r--r--src/backend/tcop/pquery.c21
-rw-r--r--src/include/executor/execdesc.h4
-rw-r--r--src/include/executor/executor.h38
-rw-r--r--src/include/nodes/execnodes.h54
-rw-r--r--src/pl/plpgsql/src/pl_exec.c29
-rw-r--r--src/pl/plpgsql/src/plpgsql.h3
42 files changed, 801 insertions, 542 deletions
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index a2180b3466f..cf0c1de7c62 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 */
newind->il_info->ii_Predicate = (List *)
copyObject(indexInfo->ii_Predicate);
- newind->il_info->ii_PredicateState = (List *)
- ExecInitExpr((Expr *) newind->il_info->ii_Predicate, NULL);
+ newind->il_info->ii_PredicateState = NIL;
newind->il_next = ILHead;
ILHead = newind;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 4e72fc53f02..5ccb70aee75 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -8,7 +8,7 @@
*
*
* 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
@@ -41,7 +41,6 @@
#include "executor/executor.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
-#include "optimizer/planmain.h"
#include "optimizer/prep.h"
#include "parser/parse_func.h"
#include "storage/sinval.h"
@@ -912,7 +911,6 @@ BuildIndexInfo(Form_pg_index indexStruct)
/*
* If partial index, convert predicate into expression nodetree
- * and prepare an execution state nodetree for it
*/
if (VARSIZE(&indexStruct->indpred) > VARHDRSZ)
{
@@ -921,9 +919,7 @@ BuildIndexInfo(Form_pg_index indexStruct)
predString = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(&indexStruct->indpred)));
ii->ii_Predicate = stringToNode(predString);
- fix_opfuncids((Node *) ii->ii_Predicate);
- ii->ii_PredicateState = (List *)
- ExecInitExpr((Expr *) ii->ii_Predicate, NULL);
+ ii->ii_PredicateState = NIL;
pfree(predString);
}
else
@@ -1489,9 +1485,10 @@ IndexBuildHeapScan(Relation heapRelation,
Datum attdata[INDEX_MAX_KEYS];
char nulls[INDEX_MAX_KEYS];
double reltuples;
- List *predicate = indexInfo->ii_PredicateState;
+ List *predicate;
TupleTable tupleTable;
TupleTableSlot *slot;
+ EState *estate;
ExprContext *econtext;
Snapshot snapshot;
TransactionId OldestXmin;
@@ -1504,27 +1501,41 @@ IndexBuildHeapScan(Relation 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
* the predicate using ExecQual, which requires the current tuple to
- * be in a slot of a TupleTable. In addition, ExecQual must have an
- * 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
+ * be in a slot of a TupleTable.
*/
- if (predicate != NIL)
+ if (indexInfo->ii_Predicate != NIL)
{
tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable);
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
{
tupleTable = NULL;
slot = NULL;
+ predicate = NIL;
}
- econtext = MakeExprContext(slot, TransactionCommandContext);
/*
* Ok, begin our scan of the base relation. We use SnapshotAny
@@ -1687,9 +1698,10 @@ IndexBuildHeapScan(Relation heapRelation,
heap_endscan(scan);
- if (predicate != NIL)
+ if (tupleTable)
ExecDropTupleTable(tupleTable, true);
- FreeExprContext(econtext);
+
+ FreeExecutorState(estate);
return reltuples;
}
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 9e8f7a46be4..fd8c6b83a82 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -9,7 +9,7 @@
*
*
* 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 "miscadmin.h"
#include "nodes/makefuncs.h"
-#include "optimizer/planmain.h"
#include "parser/parse_coerce.h"
#include "parser/parse_relation.h"
#include "rewrite/rewriteHandler.h"
@@ -803,6 +802,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
slot = ExecAllocTableSlot(tupleTable);
ExecSetSlotDescriptor(slot, tupDesc, false);
+ econtext = GetPerTupleExprContext(estate);
+
/*
* Pick up the required catalog information for each attribute in the
* 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)
{
- fix_opfuncids(defexpr);
- defexprs[num_defaults] = ExecInitExpr((Expr *) defexpr, NULL);
+ defexprs[num_defaults] = ExecPrepareExpr((Expr *) defexpr,
+ estate);
defmap[num_defaults] = i;
num_defaults++;
}
@@ -873,8 +874,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
/* check whether any constraints actually found */
if (node != (Node *) prm)
{
- fix_opfuncids(node);
- constraintexprs[i] = ExecInitExpr((Expr *) node, NULL);
+ constraintexprs[i] = ExecPrepareExpr((Expr *) node,
+ estate);
hasConstraints = true;
}
}
@@ -934,8 +935,6 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
copy_lineno = 0;
fe_eof = false;
- econtext = GetPerTupleExprContext(estate);
-
/* Make room for a PARAM_EXEC value for domain constraint checks */
if (hasConstraints)
econtext->ecxt_param_exec_vals = (ParamExecData *)
@@ -953,9 +952,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
/* Reset the per-tuple exprcontext */
ResetPerTupleExprContext(estate);
- /* Switch to and reset per-tuple memory context, too */
+ /* Switch into its memory context */
MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
- MemoryContextReset(CurrentMemoryContext);
/* Initialize all values for row to NULL */
MemSet(values, 0, num_phys_attrs * sizeof(Datum));
@@ -1268,6 +1266,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
ExecDropTupleTable(tupleTable, true);
ExecCloseIndices(resultRelInfo);
+
+ FreeExecutorState(estate);
}
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 05815a2201b..3820dd8b462 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* 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);
ExecutorEnd(queryDesc);
+ FreeQueryDesc(queryDesc);
+
CommandCounterIncrement();
totaltime += elapsed_time(&starttime);
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 7b66eea0b0b..d46b7a389a3 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,7 +8,7 @@
*
*
* 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 "miscadmin.h"
#include "optimizer/clauses.h"
-#include "optimizer/planmain.h"
#include "optimizer/prep.h"
#include "parser/parsetree.h"
#include "parser/parse_coerce.h"
@@ -163,7 +162,6 @@ DefineIndex(RangeVar *heapRelation,
if (predicate)
{
cnfPred = canonicalize_qual((Expr *) copyObject(predicate), true);
- fix_opfuncids((Node *) cnfPred);
CheckPredicate(cnfPred, rangetable, relationId);
}
@@ -173,8 +171,7 @@ DefineIndex(RangeVar *heapRelation,
*/
indexInfo = makeNode(IndexInfo);
indexInfo->ii_Predicate = cnfPred;
- indexInfo->ii_PredicateState = (List *)
- ExecInitExpr((Expr *) cnfPred, NULL);
+ indexInfo->ii_PredicateState = NIL;
indexInfo->ii_FuncOid = InvalidOid;
indexInfo->ii_Unique = unique;
diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
index c8607fcf324..b1799e49f8c 100644
--- a/src/backend/commands/portalcmds.c
+++ b/src/backend/commands/portalcmds.c
@@ -8,7 +8,7 @@
*
*
* 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,8 +31,6 @@
void
PortalCleanup(Portal portal)
{
- MemoryContext oldcontext;
-
/*
* sanity checks
*/
@@ -40,19 +38,15 @@ PortalCleanup(Portal portal)
AssertArg(portal->cleanup == PortalCleanup);
/*
- * set proper portal-executor context before calling ExecMain.
- */
- oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
-
- /*
* tell the executor to shutdown the query
*/
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));
}
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 98894372fa7..ece9802dc41 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -6,7 +6,7 @@
* Copyright (c) 2002, PostgreSQL Global Development Group
*
* 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 "executor/executor.h"
#include "utils/guc.h"
-#include "optimizer/planmain.h"
#include "optimizer/planner.h"
#include "rewrite/rewriteHandler.h"
#include "tcop/pquery.h"
@@ -50,7 +49,6 @@ static void InitQueryHashTable(void);
static void StoreQuery(const char *stmt_name, List *query_list,
List *plan_list, List *argtype_list);
static QueryHashEntry *FetchQuery(const char *plan_name);
-static void RunQuery(QueryDesc *qdesc);
/*
@@ -96,33 +94,37 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
*query_list,
*plan_list;
ParamListInfo paramLI = NULL;
+ EState *estate;
/* Look it up in the hash table */
entry = FetchQuery(stmt->name);
- /* Make working copies the executor can safely scribble on */
- query_list = (List *) copyObject(entry->query_list);
- plan_list = (List *) copyObject(entry->plan_list);
+ query_list = entry->query_list;
+ plan_list = entry->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 */
if (entry->argtype_list != NIL)
{
int nargs = length(entry->argtype_list);
int i = 0;
List *exprstates;
- ExprContext *econtext = MakeExprContext(NULL, CurrentMemoryContext);
/* Parser should have caught this error, but check */
if (nargs != length(stmt->params))
elog(ERROR, "ExecuteQuery: wrong number of arguments");
- fix_opfuncids((Node *) stmt->params);
-
- exprstates = (List *) ExecInitExpr((Expr *) stmt->params, NULL);
+ exprstates = (List *) ExecPrepareExpr((Expr *) stmt->params, estate);
- paramLI = (ParamListInfo) palloc0((nargs + 1) * sizeof(ParamListInfoData));
+ paramLI = (ParamListInfo)
+ palloc0((nargs + 1) * sizeof(ParamListInfoData));
foreach(l, exprstates)
{
@@ -130,7 +132,7 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
bool isNull;
paramLI[i].value = ExecEvalExprSwitchContext(n,
- econtext,
+ GetPerTupleExprContext(estate),
&isNull,
NULL);
paramLI[i].kind = PARAM_NUM;
@@ -173,7 +175,13 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
qdesc->dest = None;
}
- RunQuery(qdesc);
+ ExecutorStart(qdesc);
+
+ ExecutorRun(qdesc, ForwardScanDirection, 0L);
+
+ ExecutorEnd(qdesc);
+
+ FreeQueryDesc(qdesc);
if (log_executor_stats)
ShowUsage("EXECUTOR STATISTICS");
@@ -188,7 +196,9 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
CommandCounterIncrement();
}
- /* No need to pfree memory, MemoryContext will be reset */
+ FreeExecutorState(estate);
+
+ /* No need to pfree other memory, MemoryContext will be reset */
}
/*
@@ -334,17 +344,6 @@ FetchQueryParams(const char *plan_name)
}
/*
- * 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
* specified plan from storage.
*
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index a7a19c6f741..09c60bdf3f9 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
*
*
* 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 "optimizer/clauses.h"
#include "optimizer/plancat.h"
-#include "optimizer/planmain.h"
#include "optimizer/prep.h"
#include "parser/gramparse.h"
#include "parser/parse_coerce.h"
@@ -2713,6 +2712,7 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
ParseState *pstate;
bool successful = true;
HeapScanDesc scan;
+ EState *estate;
ExprContext *econtext;
TupleTableSlot *slot;
HeapTuple tuple;
@@ -2723,9 +2723,7 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
/*
* We need to make a parse state and range
- * table to allow us to transformExpr and
- * fix_opfuncids to get a version of the
- * expression we can pass to ExecQual
+ * table to allow us to do transformExpr()
*/
pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(pstate,
@@ -2765,19 +2763,22 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
*/
expr = eval_const_expressions(expr);
- /* And fix the opfuncids */
- fix_opfuncids(expr);
+ /* Needs to be in implicit-ANDs form for ExecQual */
+ 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 */
- qualstate = (List *) ExecInitExpr((Expr *) qual, NULL);
+ qualstate = (List *) ExecPrepareExpr((Expr *) qual, estate);
/* Make tuple slot to hold tuples */
slot = MakeTupleTableSlot();
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.
@@ -2797,8 +2798,8 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
heap_endscan(scan);
- FreeExprContext(econtext);
pfree(slot);
+ FreeExecutorState(estate);
if (!successful)
elog(ERROR, "AlterTableAddConstraint: rejected due to CHECK constraint %s",
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index fc0030fe762..c088aaac991 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
*
*
* 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
* The "DefineFoo" routines take the parse tree and pick out the
@@ -47,7 +47,6 @@
#include "miscadmin.h"
#include "nodes/nodes.h"
#include "optimizer/clauses.h"
-#include "optimizer/planmain.h"
#include "optimizer/var.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
@@ -1242,6 +1241,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
List *rels;
List *rt;
Form_pg_type typTup;
+ EState *estate;
ExprContext *econtext;
char *ccbin;
Expr *expr;
@@ -1338,11 +1338,13 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
* the constraint is being added to.
*/
expr = (Expr *) stringToNode(ccbin);
- fix_opfuncids((Node *) expr);
- exprstate = ExecInitExpr(expr, NULL);
- /* Make an expression context for ExecEvalExpr */
- econtext = MakeExprContext(NULL, CurrentMemoryContext);
+ /* Need an EState to run ExecEvalExpr */
+ estate = CreateExecutorState();
+ econtext = GetPerTupleExprContext(estate);
+
+ /* build execution state for expr */
+ exprstate = ExecPrepareExpr(expr, estate);
rels = get_rels_with_domain(domainoid);
@@ -1377,7 +1379,9 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
econtext->domainValue_datum = d;
econtext->domainValue_isNull = isNull;
- conResult = ExecEvalExpr(exprstate, econtext, &isNull, NULL);
+ conResult = ExecEvalExprSwitchContext(exprstate,
+ econtext,
+ &isNull, NULL);
if (!isNull && !DatumGetBool(conResult))
elog(ERROR, "AlterDomainAddConstraint: Domain %s constraint %s failed",
@@ -1393,7 +1397,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
heap_close(testrel, NoLock);
}
- FreeExprContext(econtext);
+ FreeExecutorState(estate);
/* Clean up */
heap_close(rel, NoLock);
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 51082689250..48870b4bca1 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -13,7 +13,7 @@
*
*
* 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
* executor's index-entry-making machinery.
*/
+ estate = CreateExecutorState();
+
resultRelInfo = makeNode(ResultRelInfo);
resultRelInfo->ri_RangeTableIndex = 1; /* dummy */
resultRelInfo->ri_RelationDesc = onerel;
@@ -1444,7 +1446,6 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
ExecOpenIndices(resultRelInfo);
- estate = CreateExecutorState();
estate->es_result_relations = resultRelInfo;
estate->es_num_result_relations = 1;
estate->es_result_relation_info = resultRelInfo;
@@ -2484,6 +2485,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
ExecDropTupleTable(tupleTable, true);
ExecCloseIndices(resultRelInfo);
+
+ FreeExecutorState(estate);
}
/*
diff --git a/src/backend/executor/README b/src/backend/executor/README
index d9b0ea1275a..ebdbe2d9d0c 100644
--- a/src/backend/executor/README
+++ b/src/backend/executor/README
@@ -1,4 +1,4 @@
-$Header: /cvsroot/pgsql/src/backend/executor/README,v 1.2 2002/12/05 15:50:30 tgl Exp $
+$Header: /cvsroot/pgsql/src/backend/executor/README,v 1.3 2002/12/15 16:17:45 tgl Exp $
The Postgres Executor
---------------------
@@ -60,6 +60,83 @@ ExprState nodes. (Actually, there are also List nodes, which are used as
"glue" in all four kinds of tree.)
+Memory Management
+-----------------
+
+A "per query" memory context is created during CreateExecutorState();
+all storage allocated during an executor invocation is allocated in that
+context or a child context. This allows easy reclamation of storage
+during executor shutdown --- rather than messing with retail pfree's and
+probable storage leaks, we just destroy the memory context.
+
+In particular, the plan state trees and expression state trees described
+in the previous section are allocated in the per-query memory context.
+
+To avoid intra-query memory leaks, most processing while a query runs
+is done in "per tuple" memory contexts, which are so-called because they
+are typically reset to empty once per tuple. Per-tuple contexts are usually
+associated with ExprContexts, and commonly each PlanState node has its own
+ExprContext to evaluate its qual and targetlist expressions in.
+
+
+Query Processing Control Flow
+-----------------------------
+
+This is a sketch of control flow for full query processing:
+
+ CreateQueryDesc
+
+ ExecutorStart
+ CreateExecutorState
+ creates per-query context
+ switch to per-query context to run ExecInitNode
+ ExecInitNode --- recursively scans plan tree
+ CreateExprContext
+ creates per-tuple context
+ ExecInitExpr
+
+ ExecutorRun
+ ExecProcNode --- recursively called in per-query context
+ ExecEvalExpr --- called in per-tuple context
+ ResetExprContext --- to free memory
+
+ ExecutorEnd
+ ExecEndNode --- recursively releases resources
+ FreeExecutorState
+ frees per-query context and child contexts
+
+ FreeQueryDesc
+
+Per above comments, it's not really critical for ExecEndNode to free any
+memory; it'll all go away in FreeExecutorState anyway. However, we do need to
+be careful to close relations, drop buffer pins, etc, so we do need to scan
+the plan state tree to find these sorts of resources.
+
+
+The executor can also be used to evaluate simple expressions without any Plan
+tree ("simple" meaning "no aggregates and no sub-selects", though such might
+be hidden inside function calls). This case has a flow of control like
+
+ CreateExecutorState
+ creates per-query context
+
+ CreateExprContext -- or use GetPerTupleExprContext(estate)
+ creates per-tuple context
+
+ ExecPrepareExpr
+ switch to per-query context to run ExecInitExpr
+ ExecInitExpr
+
+ Repeatedly do:
+ ExecEvalExprSwitchContext
+ ExecEvalExpr --- called in per-tuple context
+ ResetExprContext --- to free memory
+
+ FreeExecutorState
+ frees per-query context, as well as ExprContext
+ (a separate FreeExprContext call is not necessary)
+
+
EvalPlanQual (READ COMMITTED update checking)
---------------------------------------------
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index bac7398825e..a25f2f2e296 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.192 2002/12/13 19:45:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.193 2002/12/15 16:17:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -40,7 +40,6 @@
#include "executor/execdebug.h"
#include "executor/execdefs.h"
#include "miscadmin.h"
-#include "optimizer/planmain.h"
#include "optimizer/var.h"
#include "parser/parsetree.h"
#include "utils/acl.h"
@@ -53,7 +52,6 @@ static void initResultRelInfo(ResultRelInfo *resultRelInfo,
Index resultRelationIndex,
List *rangeTable,
CmdType operation);
-static void EndPlan(PlanState *planstate, EState *estate);
static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate,
CmdType operation,
long numberTuples,
@@ -86,27 +84,31 @@ static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
* field of the QueryDesc is filled in to describe the tuples that will be
* returned, and the internal fields (estate and planstate) are set up.
*
- * XXX this will change soon:
- * NB: the CurrentMemoryContext when this is called must be the context
- * to be used as the per-query context for the query plan. ExecutorRun()
- * and ExecutorEnd() must be called in this same memory context.
+ * NB: the CurrentMemoryContext when this is called will become the parent
+ * of the per-query context used for this Executor invocation.
* ----------------------------------------------------------------
*/
void
ExecutorStart(QueryDesc *queryDesc)
{
EState *estate;
+ MemoryContext oldcontext;
/* sanity checks: queryDesc must not be started already */
Assert(queryDesc != NULL);
Assert(queryDesc->estate == NULL);
/*
- * Build EState, fill with parameters from queryDesc
+ * Build EState, switch into per-query memory context for startup.
*/
estate = CreateExecutorState();
queryDesc->estate = estate;
+ oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
+
+ /*
+ * Fill in parameters, if any, from queryDesc
+ */
estate->es_param_list_info = queryDesc->params;
if (queryDesc->plantree->nParamExec > 0)
@@ -128,6 +130,8 @@ ExecutorStart(QueryDesc *queryDesc)
* Initialize the plan state tree
*/
InitPlan(queryDesc);
+
+ MemoryContextSwitchTo(oldcontext);
}
/* ----------------------------------------------------------------
@@ -152,23 +156,30 @@ TupleTableSlot *
ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count)
{
- CmdType operation;
EState *estate;
+ CmdType operation;
CommandDest dest;
DestReceiver *destfunc;
TupleTableSlot *result;
+ MemoryContext oldcontext;
+
+ /* sanity checks */
+ Assert(queryDesc != NULL);
+
+ estate = queryDesc->estate;
+
+ Assert(estate != NULL);
/*
- * sanity checks
+ * Switch into per-query memory context
*/
- Assert(queryDesc != NULL);
+ oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
/*
* extract information from the query descriptor and the query
* feature.
*/
operation = queryDesc->operation;
- estate = queryDesc->estate;
dest = queryDesc->dest;
/*
@@ -199,6 +210,8 @@ ExecutorRun(QueryDesc *queryDesc,
*/
(*destfunc->cleanup) (destfunc);
+ MemoryContextSwitchTo(oldcontext);
+
return result;
}
@@ -213,72 +226,37 @@ void
ExecutorEnd(QueryDesc *queryDesc)
{
EState *estate;
+ MemoryContext oldcontext;
/* sanity checks */
Assert(queryDesc != NULL);
estate = queryDesc->estate;
- EndPlan(queryDesc->planstate, estate);
-
- if (estate->es_snapshot != NULL)
- {
- if (estate->es_snapshot->xcnt > 0)
- pfree(estate->es_snapshot->xip);
- pfree(estate->es_snapshot);
- estate->es_snapshot = NULL;
- }
-
- if (estate->es_param_exec_vals != NULL)
- {
- pfree(estate->es_param_exec_vals);
- estate->es_param_exec_vals = NULL;
- }
-}
-
-
-/*
- * CreateExecutorState
- */
-EState *
-CreateExecutorState(void)
-{
- EState *state;
+ Assert(estate != NULL);
/*
- * create a new executor state
+ * Switch into per-query memory context to run ExecEndPlan
*/
- state = makeNode(EState);
+ oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
+
+ ExecEndPlan(queryDesc->planstate, estate);
/*
- * initialize the Executor State structure
+ * Must switch out of context before destroying it
*/
- state->es_direction = ForwardScanDirection;
- state->es_range_table = NIL;
-
- state->es_result_relations = NULL;
- state->es_num_result_relations = 0;
- state->es_result_relation_info = NULL;
-
- state->es_junkFilter = NULL;
-
- state->es_into_relation_descriptor = NULL;
-
- state->es_param_list_info = NULL;
- state->es_param_exec_vals = NULL;
-
- state->es_tupleTable = NULL;
-
- state->es_query_cxt = CurrentMemoryContext;
-
- state->es_instrument = false;
-
- state->es_per_tuple_exprcontext = NULL;
+ MemoryContextSwitchTo(oldcontext);
/*
- * return the executor state structure
+ * Release EState and per-query memory context. This should release
+ * everything the executor has allocated.
*/
- return state;
+ FreeExecutorState(estate);
+
+ /* Reset queryDesc fields that no longer point to anything */
+ queryDesc->tupDesc = NULL;
+ queryDesc->estate = NULL;
+ queryDesc->planstate = NULL;
}
@@ -794,13 +772,13 @@ initResultRelInfo(ResultRelInfo *resultRelInfo,
}
/* ----------------------------------------------------------------
- * EndPlan
+ * ExecEndPlan
*
* Cleans up the query plan -- closes files and frees up storage
* ----------------------------------------------------------------
*/
-static void
-EndPlan(PlanState *planstate, EState *estate)
+void
+ExecEndPlan(PlanState *planstate, EState *estate)
{
ResultRelInfo *resultRelInfo;
int i;
@@ -1542,9 +1520,8 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
for (i = 0; i < ncheck; i++)
{
qual = (List *) stringToNode(check[i].ccbin);
- fix_opfuncids((Node *) qual);
resultRelInfo->ri_ConstraintExprs[i] = (List *)
- ExecInitExpr((Expr *) qual, NULL);
+ ExecPrepareExpr((Expr *) qual, estate);
}
MemoryContextSwitchTo(oldContext);
}
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index a3f79c3ac80..971773b1212 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.120 2002/12/14 00:17:50 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.121 2002/12/15 16:17:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -40,6 +40,7 @@
#include "executor/functions.h"
#include "executor/nodeSubplan.h"
#include "miscadmin.h"
+#include "optimizer/planmain.h"
#include "parser/parse_expr.h"
#include "utils/acl.h"
#include "utils/array.h"
@@ -1896,9 +1897,11 @@ ExecEvalExprSwitchContext(ExprState *expression,
* cleanup work can register a shutdown callback in the ExprContext.
*
* 'node' is the root of the expression tree to examine
- * 'parent' is the PlanState node that owns the expression,
- * or NULL if we are preparing an expression that is not associated
- * with a plan. (If so, it can't have aggs or subplans.)
+ * 'parent' is the PlanState node that owns the expression.
+ *
+ * 'parent' may be NULL if we are preparing an expression that is not
+ * associated with a plan tree. (If so, it can't have aggs or subplans.)
+ * This case should usually come through ExecPrepareExpr, not directly here.
*/
ExprState *
ExecInitExpr(Expr *node, PlanState *parent)
@@ -2017,6 +2020,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
* parent->subPlan. The subplans will be initialized later.
*/
parent->subPlan = lcons(sstate, parent->subPlan);
+ sstate->sub_estate = NULL;
sstate->planstate = NULL;
sstate->oper = (List *)
@@ -2149,6 +2153,7 @@ ExecInitExprInitPlan(SubPlan *node, PlanState *parent)
elog(ERROR, "ExecInitExpr: SubPlan not expected here");
/* The subplan's state will be initialized later */
+ sstate->sub_estate = NULL;
sstate->planstate = NULL;
sstate->oper = (List *) ExecInitExpr((Expr *) node->oper, parent);
@@ -2159,6 +2164,33 @@ ExecInitExprInitPlan(SubPlan *node, PlanState *parent)
return sstate;
}
+/*
+ * ExecPrepareExpr --- initialize for expression execution outside a normal
+ * Plan tree context.
+ *
+ * This differs from ExecInitExpr in that we don't assume the caller is
+ * already running in the EState's per-query context. Also, we apply
+ * fix_opfuncids() to the passed expression tree to be sure it is ready
+ * to run. (In ordinary Plan trees the planner will have fixed opfuncids,
+ * but callers outside the executor will not have done this.)
+ */
+ExprState *
+ExecPrepareExpr(Expr *node, EState *estate)
+{
+ ExprState *result;
+ MemoryContext oldcontext;
+
+ fix_opfuncids((Node *) node);
+
+ oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
+
+ result = ExecInitExpr(node, NULL);
+
+ MemoryContextSwitchTo(oldcontext);
+
+ return result;
+}
+
/* ----------------------------------------------------------------
* ExecQual / ExecTargetList / ExecProject
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 36997a49103..6c2cece7b6e 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -8,13 +8,20 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.92 2002/12/13 19:45:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.93 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
+ * CreateExecutorState Create/delete executor working state
+ * FreeExecutorState
+ * CreateExprContext
+ * FreeExprContext
+ *
* ExecAssignExprContext Common code for plan node init routines.
+ * ExecAssignResultType
+ * etc
*
* ExecOpenIndices \
* ExecCloseIndices | referenced by InitPlan, EndPlan,
@@ -26,7 +33,6 @@
* NOTES
* This file has traditionally been the place to stick misc.
* executor support stuff that doesn't really go anyplace else.
- *
*/
#include "postgres.h"
@@ -64,6 +70,7 @@ extern int NIndexTupleProcessed; /* have to be defined in the
static void ShutdownExprContext(ExprContext *econtext);
+
/* ----------------------------------------------------------------
* statistic functions
* ----------------------------------------------------------------
@@ -124,137 +131,264 @@ DisplayTupleCount(FILE *statfp)
}
#endif
+
/* ----------------------------------------------------------------
- * miscellaneous node-init support functions
+ * Executor state and memory management functions
* ----------------------------------------------------------------
*/
/* ----------------
- * ExecAssignExprContext
+ * CreateExecutorState
*
- * This initializes the ExprContext field. It is only necessary
- * to do this for nodes which use ExecQual or ExecProject
- * because those routines depend on econtext. Other nodes that
- * don't have to evaluate expressions don't need to do this.
+ * Create and initialize an EState node, which is the root of
+ * working storage for an entire Executor invocation.
*
- * Note: we assume CurrentMemoryContext is the correct per-query context.
- * This should be true during plan node initialization.
+ * Principally, this creates the per-query memory context that will be
+ * used to hold all working data that lives till the end of the query.
+ * Note that the per-query context will become a child of the caller's
+ * CurrentMemoryContext.
* ----------------
*/
-void
-ExecAssignExprContext(EState *estate, PlanState *planstate)
+EState *
+CreateExecutorState(void)
{
- ExprContext *econtext = makeNode(ExprContext);
+ EState *estate;
+ MemoryContext qcontext;
+ MemoryContext oldcontext;
- econtext->ecxt_scantuple = NULL;
- econtext->ecxt_innertuple = NULL;
- econtext->ecxt_outertuple = NULL;
- econtext->ecxt_per_query_memory = CurrentMemoryContext;
+ /*
+ * Create the per-query context for this Executor run.
+ */
+ qcontext = AllocSetContextCreate(CurrentMemoryContext,
+ "ExecutorState",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
/*
- * Create working memory for expression evaluation in this context.
+ * Make the EState node within the per-query context. This way,
+ * we don't need a separate pfree() operation for it at shutdown.
*/
- econtext->ecxt_per_tuple_memory =
- AllocSetContextCreate(CurrentMemoryContext,
- "PlanExprContext",
- ALLOCSET_DEFAULT_MINSIZE,
- ALLOCSET_DEFAULT_INITSIZE,
- ALLOCSET_DEFAULT_MAXSIZE);
- econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
- econtext->ecxt_param_list_info = estate->es_param_list_info;
- econtext->ecxt_aggvalues = NULL;
- econtext->ecxt_aggnulls = NULL;
- econtext->ecxt_callbacks = NULL;
+ oldcontext = MemoryContextSwitchTo(qcontext);
+
+ estate = makeNode(EState);
+
+ /*
+ * Initialize all fields of the Executor State structure
+ */
+ estate->es_direction = ForwardScanDirection;
+ estate->es_snapshot = SnapshotNow;
+ estate->es_range_table = NIL;
+
+ estate->es_result_relations = NULL;
+ estate->es_num_result_relations = 0;
+ estate->es_result_relation_info = NULL;
+
+ estate->es_junkFilter = NULL;
+ estate->es_into_relation_descriptor = NULL;
+
+ estate->es_param_list_info = NULL;
+ estate->es_param_exec_vals = NULL;
+
+ estate->es_query_cxt = qcontext;
+
+ estate->es_tupleTable = NULL;
- planstate->ps_ExprContext = econtext;
+ estate->es_processed = 0;
+ estate->es_lastoid = InvalidOid;
+ estate->es_rowMark = NIL;
+
+ estate->es_instrument = false;
+
+ estate->es_exprcontexts = NIL;
+
+ estate->es_per_tuple_exprcontext = NULL;
+
+ estate->es_origPlan = NULL;
+ estate->es_evalPlanQual = NULL;
+ estate->es_evTupleNull = NULL;
+ estate->es_evTuple = NULL;
+ estate->es_useEvalPlan = false;
+
+ /*
+ * Return the executor state structure
+ */
+ MemoryContextSwitchTo(oldcontext);
+
+ return estate;
+}
+
+/* ----------------
+ * FreeExecutorState
+ *
+ * Release an EState along with all remaining working storage.
+ *
+ * Note: this is not responsible for releasing non-memory resources,
+ * such as open relations or buffer pins. But it will shut down any
+ * still-active ExprContexts within the EState. That is sufficient
+ * cleanup for situations where the EState has only been used for expression
+ * evaluation, and not to run a complete Plan.
+ *
+ * This can be called in any memory context ... so long as it's not one
+ * of the ones to be freed.
+ * ----------------
+ */
+void
+FreeExecutorState(EState *estate)
+{
+ /*
+ * Shut down and free any remaining ExprContexts. We do this
+ * explicitly to ensure that any remaining shutdown callbacks get
+ * called (since they might need to release resources that aren't
+ * simply memory within the per-query memory context).
+ */
+ while (estate->es_exprcontexts)
+ {
+ FreeExprContext((ExprContext *) lfirst(estate->es_exprcontexts));
+ /* FreeExprContext removed the list link for us */
+ }
+ /*
+ * Free the per-query memory context, thereby releasing all working
+ * memory, including the EState node itself.
+ */
+ MemoryContextDelete(estate->es_query_cxt);
}
/* ----------------
- * MakeExprContext
+ * CreateExprContext
+ *
+ * Create a context for expression evaluation within an EState.
+ *
+ * An executor run may require multiple ExprContexts (we usually make one
+ * for each Plan node, and a separate one for per-output-tuple processing
+ * such as constraint checking). Each ExprContext has its own "per-tuple"
+ * memory context.
*
- * Build an expression context for use outside normal plan-node cases.
- * A fake scan-tuple slot can be supplied (pass NULL if not needed).
- * A memory context sufficiently long-lived to use as fcache context
- * must be supplied as well.
+ * Note we make no assumption about the caller's memory context.
* ----------------
*/
ExprContext *
-MakeExprContext(TupleTableSlot *slot,
- MemoryContext queryContext)
+CreateExprContext(EState *estate)
{
- ExprContext *econtext = makeNode(ExprContext);
+ ExprContext *econtext;
+ MemoryContext oldcontext;
- econtext->ecxt_scantuple = slot;
+ /* Create the ExprContext node within the per-query memory context */
+ oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
+
+ econtext = makeNode(ExprContext);
+
+ /* Initialize fields of ExprContext */
+ econtext->ecxt_scantuple = NULL;
econtext->ecxt_innertuple = NULL;
econtext->ecxt_outertuple = NULL;
- econtext->ecxt_per_query_memory = queryContext;
+
+ econtext->ecxt_per_query_memory = estate->es_query_cxt;
/*
- * We make the temporary context a child of current working context,
- * not of the specified queryContext. This seems reasonable but I'm
- * not totally sure about it...
- *
- * Expression contexts made via this routine typically don't live long
- * enough to get reset, so specify a minsize of 0. That avoids
- * alloc'ing any memory in the common case where expr eval doesn't use
- * any.
+ * Create working memory for expression evaluation in this context.
*/
econtext->ecxt_per_tuple_memory =
- AllocSetContextCreate(CurrentMemoryContext,
- "TempExprContext",
- 0,
+ AllocSetContextCreate(estate->es_query_cxt,
+ "ExprContext",
+ ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
- econtext->ecxt_param_exec_vals = NULL;
- econtext->ecxt_param_list_info = NULL;
+
+ econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
+ econtext->ecxt_param_list_info = estate->es_param_list_info;
+
econtext->ecxt_aggvalues = NULL;
econtext->ecxt_aggnulls = NULL;
+
+ econtext->domainValue_datum = (Datum) 0;
+ econtext->domainValue_isNull = true;
+
+ econtext->ecxt_estate = estate;
+
econtext->ecxt_callbacks = NULL;
+ /*
+ * Link the ExprContext into the EState to ensure it is shut down
+ * when the EState is freed. Because we use lcons(), shutdowns will
+ * occur in reverse order of creation, which may not be essential
+ * but can't hurt.
+ */
+ estate->es_exprcontexts = lcons(econtext, estate->es_exprcontexts);
+
+ MemoryContextSwitchTo(oldcontext);
+
return econtext;
}
-/*
- * Free an ExprContext made by MakeExprContext, including the temporary
- * context used for expression evaluation. Note this will cause any
- * pass-by-reference expression result to go away!
+/* ----------------
+ * FreeExprContext
+ *
+ * Free an expression context, including calling any remaining
+ * shutdown callbacks.
+ *
+ * Since we free the temporary context used for expression evaluation,
+ * any previously computed pass-by-reference expression result will go away!
+ *
+ * Note we make no assumption about the caller's memory context.
+ * ----------------
*/
void
FreeExprContext(ExprContext *econtext)
{
+ EState *estate;
+
/* Call any registered callbacks */
ShutdownExprContext(econtext);
/* And clean up the memory used */
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
+ /* Unlink self from owning EState */
+ estate = econtext->ecxt_estate;
+ estate->es_exprcontexts = lremove(econtext, estate->es_exprcontexts);
+ /* And delete the ExprContext node */
pfree(econtext);
}
/*
* Build a per-output-tuple ExprContext for an EState.
*
- * This is normally invoked via GetPerTupleExprContext() macro.
+ * This is normally invoked via GetPerTupleExprContext() macro,
+ * not directly.
*/
ExprContext *
MakePerTupleExprContext(EState *estate)
{
if (estate->es_per_tuple_exprcontext == NULL)
- {
- MemoryContext oldContext;
+ estate->es_per_tuple_exprcontext = CreateExprContext(estate);
- oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
- estate->es_per_tuple_exprcontext =
- MakeExprContext(NULL, estate->es_query_cxt);
- MemoryContextSwitchTo(oldContext);
- }
return estate->es_per_tuple_exprcontext;
}
+
/* ----------------------------------------------------------------
- * Result slot tuple type and ProjectionInfo support
+ * miscellaneous node-init support functions
+ *
+ * Note: all of these are expected to be called with CurrentMemoryContext
+ * equal to the per-query memory context.
* ----------------------------------------------------------------
*/
/* ----------------
+ * ExecAssignExprContext
+ *
+ * This initializes the ps_ExprContext field. It is only necessary
+ * to do this for nodes which use ExecQual or ExecProject
+ * because those routines require an econtext. Other nodes that
+ * don't have to evaluate expressions don't need to do this.
+ * ----------------
+ */
+void
+ExecAssignExprContext(EState *estate, PlanState *planstate)
+{
+ planstate->ps_ExprContext = CreateExprContext(estate);
+}
+
+/* ----------------
* ExecAssignResultType
* ----------------
*/
@@ -368,34 +502,12 @@ ExecAssignProjectionInfo(PlanState *planstate)
/* ----------------
- * ExecFreeProjectionInfo
- * ----------------
- */
-void
-ExecFreeProjectionInfo(PlanState *planstate)
-{
- ProjectionInfo *projInfo;
-
- /*
- * get projection info. if NULL then this node has none so we just
- * return.
- */
- projInfo = planstate->ps_ProjInfo;
- if (projInfo == NULL)
- return;
-
- /*
- * clean up memory used.
- */
- if (projInfo->pi_tupValue != NULL)
- pfree(projInfo->pi_tupValue);
-
- pfree(projInfo);
- planstate->ps_ProjInfo = NULL;
-}
-
-/* ----------------
* ExecFreeExprContext
+ *
+ * A plan node's ExprContext should be freed explicitly during ExecEndNode
+ * because there may be shutdown callbacks to call. (Other resources made
+ * by the above routines, such as projection info, don't need to be freed
+ * explicitly because they're just memory in the per-query memory context.)
* ----------------
*/
void
@@ -411,16 +523,8 @@ ExecFreeExprContext(PlanState *planstate)
if (econtext == NULL)
return;
- /*
- * clean up any registered callbacks
- */
- ShutdownExprContext(econtext);
+ FreeExprContext(econtext);
- /*
- * clean up memory used.
- */
- MemoryContextDelete(econtext->ecxt_per_tuple_memory);
- pfree(econtext);
planstate->ps_ExprContext = NULL;
}
@@ -612,7 +716,8 @@ ExecCloseIndices(ResultRelInfo *resultRelInfo)
}
/*
- * XXX should free indexInfo array here too.
+ * XXX should free indexInfo array here too? Currently we assume that
+ * such stuff will be cleaned up automatically in FreeExecutorState.
*/
}
@@ -674,16 +779,31 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
for (i = 0; i < numIndices; i++)
{
IndexInfo *indexInfo;
- List *predicate;
InsertIndexResult result;
if (relationDescs[i] == NULL)
continue;
indexInfo = indexInfoArray[i];
- predicate = indexInfo->ii_PredicateState;
- if (predicate != NIL)
+
+ /* Check for partial index */
+ if (indexInfo->ii_Predicate != NIL)
{
+ List *predicate;
+
+ /*
+ * If predicate state not set up yet, create it (in the
+ * estate's per-query context)
+ */
+ predicate = indexInfo->ii_PredicateState;
+ if (predicate == NIL)
+ {
+ predicate = (List *)
+ ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,
+ estate);
+ indexInfo->ii_PredicateState = predicate;
+ }
+
/* Skip this index-update if the predicate isn't satisfied */
if (!ExecQual(predicate, econtext, false))
continue;
@@ -811,6 +931,17 @@ static void
ShutdownExprContext(ExprContext *econtext)
{
ExprContext_CB *ecxt_callback;
+ MemoryContext oldcontext;
+
+ /* Fast path in normal case where there's nothing to do. */
+ if (econtext->ecxt_callbacks == NULL)
+ return;
+
+ /*
+ * Call the callbacks in econtext's per-tuple context. This ensures
+ * that any memory they might leak will get cleaned up.
+ */
+ oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
/*
* Call each callback function in reverse registration order.
@@ -821,4 +952,6 @@ ShutdownExprContext(ExprContext *econtext)
(*ecxt_callback->function) (ecxt_callback->arg);
pfree(ecxt_callback);
}
+
+ MemoryContextSwitchTo(oldcontext);
}
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 328aea5f079..d3ccf0dd905 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.61 2002/12/05 15:50:32 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.62 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -284,7 +284,8 @@ postquel_end(execution_state *es)
if (es->qd->operation != CMD_UTILITY)
ExecutorEnd(es->qd);
- pfree(es->qd);
+ FreeQueryDesc(es->qd);
+
es->qd = NULL;
es->status = F_EXEC_DONE;
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index e6ba3887630..769e88a8397 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -45,7 +45,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.100 2002/12/13 19:45:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.101 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1392,8 +1392,6 @@ ExecEndAgg(AggState *node)
tuplesort_end(peraggstate->sortstate);
}
- ExecFreeProjectionInfo(&node->ss.ps);
-
/*
* Free both the expr contexts.
*/
@@ -1401,18 +1399,13 @@ ExecEndAgg(AggState *node)
node->ss.ps.ps_ExprContext = node->tmpcontext;
ExecFreeExprContext(&node->ss.ps);
+ /* clean up tuple table */
+ ExecClearTuple(node->ss.ss_ScanTupleSlot);
+
MemoryContextDelete(node->aggcontext);
outerPlan = outerPlanState(node);
ExecEndNode(outerPlan);
-
- /* clean up tuple table */
- ExecClearTuple(node->ss.ss_ScanTupleSlot);
- if (node->grp_firstTuple != NULL)
- {
- heap_freetuple(node->grp_firstTuple);
- node->grp_firstTuple = NULL;
- }
}
void
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index d0bf78631da..78f66523d51 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.15 2002/12/13 19:45:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.16 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -273,9 +273,8 @@ void
ExecEndFunctionScan(FunctionScanState *node)
{
/*
- * Free the projection info and the scan attribute info
+ * Free the exprcontext
*/
- ExecFreeProjectionInfo(&node->ss.ps);
ExecFreeExprContext(&node->ss.ps);
/*
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index 8bb72ba3438..58f6c1b34e9 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -15,7 +15,7 @@
* locate group boundaries.
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.52 2002/12/13 19:45:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.53 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -218,19 +218,13 @@ ExecEndGroup(GroupState *node)
{
PlanState *outerPlan;
- ExecFreeProjectionInfo(&node->ss.ps);
ExecFreeExprContext(&node->ss.ps);
- outerPlan = outerPlanState(node);
- ExecEndNode(outerPlan);
-
/* clean up tuple table */
ExecClearTuple(node->ss.ss_ScanTupleSlot);
- if (node->grp_firstTuple != NULL)
- {
- heap_freetuple(node->grp_firstTuple);
- node->grp_firstTuple = NULL;
- }
+
+ outerPlan = outerPlanState(node);
+ ExecEndNode(outerPlan);
}
void
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index 45ba826317d..efdd3b3cabb 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.70 2002/12/13 19:45:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.71 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -179,10 +179,8 @@ ExecEndHash(HashState *node)
PlanState *outerPlan;
/*
- * free projection info. no need to free result type info because
- * that came from the outer plan...
+ * free exprcontext
*/
- ExecFreeProjectionInfo(&node->ps);
ExecFreeExprContext(&node->ps);
/*
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index 07de8703812..8f899b577d7 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.44 2002/12/13 19:45:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.45 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -456,24 +456,22 @@ ExecEndHashJoin(HashJoinState *node)
}
/*
- * Free the projection info and the scan attribute info
+ * Free the exprcontext
*/
- ExecFreeProjectionInfo(&node->js.ps);
ExecFreeExprContext(&node->js.ps);
/*
- * clean up subtrees
- */
- ExecEndNode(outerPlanState(node));
- ExecEndNode(innerPlanState(node));
-
- /*
* clean out the tuple table
*/
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
ExecClearTuple(node->hj_OuterTupleSlot);
ExecClearTuple(node->hj_HashTupleSlot);
+ /*
+ * clean up subtrees
+ */
+ ExecEndNode(outerPlanState(node));
+ ExecEndNode(innerPlanState(node));
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 1e36e93113d..7b96723844b 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.74 2002/12/13 19:45:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.75 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -399,45 +399,39 @@ ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt)
/* ----------------------------------------------------------------
* ExecEndIndexScan
- *
- * old comments
- * Releases any storage allocated through C routines.
- * Returns nothing.
* ----------------------------------------------------------------
*/
void
ExecEndIndexScan(IndexScanState *node)
{
- ExprState ***runtimeKeyInfo;
- ScanKey *scanKeys;
- int *numScanKeys;
int numIndices;
- Relation relation;
RelationPtr indexRelationDescs;
IndexScanDescPtr indexScanDescs;
+ Relation relation;
int i;
- runtimeKeyInfo = node->iss_RuntimeKeyInfo;
-
/*
* extract information from the node
*/
numIndices = node->iss_NumIndices;
- scanKeys = node->iss_ScanKeys;
- numScanKeys = node->iss_NumScanKeys;
indexRelationDescs = node->iss_RelationDescs;
indexScanDescs = node->iss_ScanDescs;
relation = node->ss.ss_currentRelation;
/*
- * Free the projection info and the scan attribute info
+ * Free the exprcontext(s)
*/
- ExecFreeProjectionInfo(&node->ss.ps);
ExecFreeExprContext(&node->ss.ps);
if (node->iss_RuntimeContext)
FreeExprContext(node->iss_RuntimeContext);
/*
+ * clear out tuple table slots
+ */
+ ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+ ExecClearTuple(node->ss.ss_ScanTupleSlot);
+
+ /*
* close the index relations
*/
for (i = 0; i < numIndices; i++)
@@ -458,36 +452,6 @@ ExecEndIndexScan(IndexScanState *node)
* locking, however.)
*/
heap_close(relation, NoLock);
-
- /*
- * free the scan keys used in scanning the indices
- */
- for (i = 0; i < numIndices; i++)
- {
- if (scanKeys[i] != NULL)
- pfree(scanKeys[i]);
- }
- pfree(scanKeys);
- pfree(numScanKeys);
-
- if (runtimeKeyInfo)
- {
- for (i = 0; i < numIndices; i++)
- {
- if (runtimeKeyInfo[i] != NULL)
- pfree(runtimeKeyInfo[i]);
- }
- pfree(runtimeKeyInfo);
- }
-
- /*
- * clear out tuple table slots
- */
- ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
- ExecClearTuple(node->ss.ss_ScanTupleSlot);
- pfree(node->iss_RelationDescs);
- pfree(node->iss_ScanDescs);
- pfree(node);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index 6abd83de8aa..39d09331ce2 100644
--- a/src/backend/executor/nodeLimit.c
+++ b/src/backend/executor/nodeLimit.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.13 2002/12/13 19:45:54 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.14 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -349,10 +349,10 @@ ExecEndLimit(LimitState *node)
{
ExecFreeExprContext(&node->ps);
- ExecEndNode(outerPlanState(node));
-
/* clean up tuple table */
ExecClearTuple(node->ps.ps_ResultTupleSlot);
+
+ ExecEndNode(outerPlanState(node));
}
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index cf7ca89f4a9..a1725901a7c 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.39 2002/12/05 15:50:33 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.40 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -197,16 +197,16 @@ ExecEndMaterial(MaterialState *node)
ExecClearTuple(node->ss.ss_ScanTupleSlot);
/*
- * shut down the subplan
- */
- ExecEndNode(outerPlanState(node));
-
- /*
* Release tuplestore resources
*/
if (node->tuplestorestate != NULL)
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
node->tuplestorestate = NULL;
+
+ /*
+ * shut down the subplan
+ */
+ ExecEndNode(outerPlanState(node));
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 1bb5878d819..af6cd8d6f3f 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.54 2002/12/13 19:45:54 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.55 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1551,23 +1551,22 @@ ExecEndMergeJoin(MergeJoinState *node)
"ending node processing");
/*
- * Free the projection info and the scan attribute info
+ * Free the exprcontext
*/
- ExecFreeProjectionInfo(&node->js.ps);
ExecFreeExprContext(&node->js.ps);
/*
- * shut down the subplans
- */
- ExecEndNode(innerPlanState(node));
- ExecEndNode(outerPlanState(node));
-
- /*
* clean out the tuple table
*/
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
ExecClearTuple(node->mj_MarkedTupleSlot);
+ /*
+ * shut down the subplans
+ */
+ ExecEndNode(innerPlanState(node));
+ ExecEndNode(outerPlanState(node));
+
MJ1_printf("ExecEndMergeJoin: %s\n",
"node processing ended");
}
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index 452ed7d70c3..917a7011cbf 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.28 2002/12/13 19:45:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.29 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -364,21 +364,20 @@ ExecEndNestLoop(NestLoopState *node)
"ending node processing");
/*
- * Free the projection info
+ * Free the exprcontext
*/
- ExecFreeProjectionInfo(&node->js.ps);
ExecFreeExprContext(&node->js.ps);
/*
- * close down subplans
+ * clean out the tuple table
*/
- ExecEndNode(outerPlanState(node));
- ExecEndNode(innerPlanState(node));
+ ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
/*
- * clean out the tuple table
+ * close down subplans
*/
- ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
+ ExecEndNode(outerPlanState(node));
+ ExecEndNode(innerPlanState(node));
NL1_printf("ExecEndNestLoop: %s\n",
"node processing ended");
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index 3f2c9927e01..9ea75eb3ce7 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -34,7 +34,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.23 2002/12/13 19:45:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.24 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -248,9 +248,8 @@ void
ExecEndResult(ResultState *node)
{
/*
- * Free the projection info
+ * Free the exprcontext
*/
- ExecFreeProjectionInfo(&node->ps);
ExecFreeExprContext(&node->ps);
/*
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index 6a7393795b2..6628a9eecbe 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.40 2002/12/13 19:45:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.41 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -264,23 +264,22 @@ ExecEndSeqScan(SeqScanState *node)
scanDesc = node->ss_currentScanDesc;
/*
- * Free the projection info and the scan attribute info
+ * Free the exprcontext
*/
- ExecFreeProjectionInfo(&node->ps);
ExecFreeExprContext(&node->ps);
/*
- * close heap scan
- */
- heap_endscan(scanDesc);
-
- /*
* clean out the tuple table
*/
ExecClearTuple(node->ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss_ScanTupleSlot);
/*
+ * close heap scan
+ */
+ heap_endscan(scanDesc);
+
+ /*
* close the heap relation.
*
* Currently, we do not release the AccessShareLock acquired by
diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c
index a81a4a29d91..965a2a6466a 100644
--- a/src/backend/executor/nodeSetOp.c
+++ b/src/backend/executor/nodeSetOp.c
@@ -21,7 +21,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.7 2002/12/05 15:50:33 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.8 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -301,9 +301,9 @@ ExecEndSetOp(SetOpState *node)
ExecClearTuple(node->ps.ps_ResultTupleSlot);
node->ps.ps_OuterTupleSlot = NULL;
- ExecEndNode(outerPlanState(node));
-
MemoryContextDelete(node->tempContext);
+
+ ExecEndNode(outerPlanState(node));
}
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
index e1b4db7a51d..a37583241fb 100644
--- a/src/backend/executor/nodeSort.c
+++ b/src/backend/executor/nodeSort.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.41 2002/12/05 15:50:33 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.42 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -285,17 +285,17 @@ ExecEndSort(SortState *node)
ExecClearTuple(node->ss.ss_ScanTupleSlot);
/*
- * shut down the subplan
- */
- ExecEndNode(outerPlanState(node));
-
- /*
* Release tuplesort resources
*/
if (node->tuplesortstate != NULL)
tuplesort_end((Tuplesortstate *) node->tuplesortstate);
node->tuplesortstate = NULL;
+ /*
+ * shut down the subplan
+ */
+ ExecEndNode(outerPlanState(node));
+
SO1_printf("ExecEndSort: %s\n",
"sort node shutdown");
}
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index 3a2ca974aee..2f5ab52e213 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.38 2002/12/14 00:17:50 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.39 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -47,9 +47,10 @@ ExecSubPlan(SubPlanState *node,
/*
* We are probably in a short-lived expression-evaluation context.
- * Switch to longer-lived per-query context.
+ * Switch to the child plan's per-query context for manipulating its
+ * chgParam, calling ExecProcNode on it, etc.
*/
- oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
+ oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
if (subplan->setParam != NIL)
elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
@@ -132,10 +133,13 @@ ExecSubPlan(SubPlanState *node,
* ExecProcNode() call. node->curTuple keeps track of the
* copied tuple for eventual freeing.
*/
+ MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
tup = heap_copytuple(tup);
if (node->curTuple)
heap_freetuple(node->curTuple);
node->curTuple = tup;
+ MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
+
result = heap_getattr(tup, col, tdesc, isNull);
/* keep scanning subplan to make sure there's only one tuple */
continue;
@@ -295,6 +299,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
{
SubPlan *subplan = (SubPlan *) node->xprstate.expr;
EState *sp_estate;
+ MemoryContext oldcontext;
/*
* Do access checking on the rangetable entries in the subquery.
@@ -303,15 +308,23 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
/*
- * initialize state
+ * initialize my state
*/
node->needShutdown = false;
node->curTuple = NULL;
/*
* create an EState for the subplan
+ *
+ * The subquery needs its own EState because it has its own rangetable.
+ * It shares our Param ID space, however. XXX if rangetable access were
+ * done differently, the subquery could share our EState, which would
+ * eliminate some thrashing about in this module...
*/
sp_estate = CreateExecutorState();
+ node->sub_estate = sp_estate;
+
+ oldcontext = MemoryContextSwitchTo(sp_estate->es_query_cxt);
sp_estate->es_range_table = subplan->rtable;
sp_estate->es_param_list_info = estate->es_param_list_info;
@@ -322,12 +335,14 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
sp_estate->es_instrument = estate->es_instrument;
/*
- * Start up the subplan
+ * Start up the subplan (this is a very cut-down form of InitPlan())
*/
node->planstate = ExecInitNode(subplan->plan, sp_estate);
node->needShutdown = true; /* now we need to shutdown the subplan */
+ MemoryContextSwitchTo(oldcontext);
+
/*
* If this plan is un-correlated or undirect correlated one and want
* to set params for parent plan then prepare parameters.
@@ -376,10 +391,9 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
bool found = false;
/*
- * We are probably in a short-lived expression-evaluation context.
- * Switch to longer-lived per-query context.
+ * Must switch to child query's per-query memory context.
*/
- oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
+ oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
if (subLinkType == ANY_SUBLINK ||
subLinkType == ALL_SUBLINK)
@@ -415,15 +429,18 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
found = true;
/*
- * We need to copy the subplan's tuple in case any of the params
- * are pass-by-ref type --- the pointers stored in the param
- * structs will point at this copied tuple! node->curTuple keeps
- * track of the copied tuple for eventual freeing.
+ * We need to copy the subplan's tuple into our own context,
+ * in case any of the params are pass-by-ref type --- the pointers
+ * stored in the param structs will point at this copied tuple!
+ * node->curTuple keeps track of the copied tuple for eventual
+ * freeing.
*/
+ MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
tup = heap_copytuple(tup);
if (node->curTuple)
heap_freetuple(node->curTuple);
node->curTuple = tup;
+ MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
foreach(lst, subplan->setParam)
{
@@ -460,7 +477,10 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
if (planstate->plan->extParam == NULL) /* un-correlated ... */
{
- ExecEndNode(planstate);
+ ExecEndPlan(planstate, node->sub_estate);
+ /* mustn't free context while still in it... */
+ MemoryContextSwitchTo(oldcontext);
+ FreeExecutorState(node->sub_estate);
node->needShutdown = false;
}
@@ -476,7 +496,12 @@ ExecEndSubPlan(SubPlanState *node)
{
if (node->needShutdown)
{
- ExecEndNode(node->planstate);
+ MemoryContext oldcontext;
+
+ oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
+ ExecEndPlan(node->planstate, node->sub_estate);
+ MemoryContextSwitchTo(oldcontext);
+ FreeExecutorState(node->sub_estate);
node->needShutdown = false;
}
if (node->curTuple)
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
index 68291ba6e34..4466ef34219 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -12,7 +12,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.15 2002/12/13 19:45:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.16 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,7 @@ SubqueryNext(SubqueryScanState *node)
EState *estate;
ScanDirection direction;
TupleTableSlot *slot;
+ MemoryContext oldcontext;
/*
* get information from the estate and scan state
@@ -66,12 +67,17 @@ SubqueryNext(SubqueryScanState *node)
*/
/*
- * get the next tuple from the sub-query
+ * Get the next tuple from the sub-query. We have to be careful to
+ * run it in its appropriate memory context.
*/
node->sss_SubEState->es_direction = direction;
+ oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
+
slot = ExecProcNode(node->subplan);
+ MemoryContextSwitchTo(oldcontext);
+
node->ss.ss_ScanTupleSlot = slot;
return slot;
@@ -106,6 +112,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
SubqueryScanState *subquerystate;
RangeTblEntry *rte;
EState *sp_estate;
+ MemoryContext oldcontext;
/*
* SubqueryScan should not have any "normal" children.
@@ -152,9 +159,17 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
Assert(rte->rtekind == RTE_SUBQUERY);
+ /*
+ * The subquery needs its own EState because it has its own rangetable.
+ * It shares our Param ID space, however. XXX if rangetable access were
+ * done differently, the subquery could share our EState, which would
+ * eliminate some thrashing about in this module...
+ */
sp_estate = CreateExecutorState();
subquerystate->sss_SubEState = sp_estate;
+ oldcontext = MemoryContextSwitchTo(sp_estate->es_query_cxt);
+
sp_estate->es_range_table = rte->subquery->rtable;
sp_estate->es_param_list_info = estate->es_param_list_info;
sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
@@ -163,8 +178,13 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
sp_estate->es_snapshot = estate->es_snapshot;
sp_estate->es_instrument = estate->es_instrument;
+ /*
+ * Start up the subplan (this is a very cut-down form of InitPlan())
+ */
subquerystate->subplan = ExecInitNode(node->subplan, sp_estate);
+ MemoryContextSwitchTo(oldcontext);
+
subquerystate->ss.ss_ScanTupleSlot = NULL;
subquerystate->ss.ps.ps_TupFromTlist = false;
@@ -197,10 +217,11 @@ ExecCountSlotsSubqueryScan(SubqueryScan *node)
void
ExecEndSubqueryScan(SubqueryScanState *node)
{
+ MemoryContext oldcontext;
+
/*
- * Free the projection info and the scan attribute info
+ * Free the exprcontext
*/
- ExecFreeProjectionInfo(&node->ss.ps);
ExecFreeExprContext(&node->ss.ps);
/*
@@ -211,15 +232,13 @@ ExecEndSubqueryScan(SubqueryScanState *node)
/*
* close down subquery
*/
- ExecEndNode(node->subplan);
+ oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
- /*
- * clean up subquery's tuple table
- */
- node->ss.ss_ScanTupleSlot = NULL;
- ExecDropTupleTable(node->sss_SubEState->es_tupleTable, true);
+ ExecEndPlan(node->subplan, node->sss_SubEState);
- /* XXX we seem to be leaking the sub-EState... */
+ MemoryContextSwitchTo(oldcontext);
+
+ FreeExecutorState(node->sss_SubEState);
}
/* ----------------------------------------------------------------
@@ -232,12 +251,17 @@ void
ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
{
EState *estate;
+ MemoryContext oldcontext;
estate = node->ss.ps.state;
+ oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
+
/*
* ExecReScan doesn't know about my subplan, so I have to do
- * changed-parameter signaling myself.
+ * changed-parameter signaling myself. This is just as well,
+ * because the subplan has its own memory context in which its
+ * chgParam lists live.
*/
if (node->ss.ps.chgParam != NULL)
SetChangedParamList(node->subplan, node->ss.ps.chgParam);
@@ -249,5 +273,7 @@ ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
if (node->subplan->chgParam == NULL)
ExecReScan(node->subplan, NULL);
+ MemoryContextSwitchTo(oldcontext);
+
node->ss.ss_ScanTupleSlot = NULL;
}
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index ba2793407ce..7e35bc07cd7 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.29 2002/12/13 19:45:56 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.30 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -278,19 +278,8 @@ void
ExecEndTidScan(TidScanState *node)
{
/*
- * extract information from the node
+ * Free the exprcontext
*/
- if (node && node->tss_TidList)
- pfree(node->tss_TidList);
-
- /*
- * Free the projection info and the scan attribute info
- *
- * Note: we don't ExecFreeResultType(scanstate) because the rule manager
- * depends on the tupType returned by ExecMain(). So for now, this is
- * freed at end-transaction time. -cim 6/2/91
- */
- ExecFreeProjectionInfo(&node->ss.ps);
ExecFreeExprContext(&node->ss.ps);
/*
diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c
index 88b08061f99..415594f92c4 100644
--- a/src/backend/executor/nodeUnique.c
+++ b/src/backend/executor/nodeUnique.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.35 2002/12/05 15:50:34 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.36 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -194,15 +194,10 @@ ExecEndUnique(UniqueState *node)
{
/* clean up tuple table */
ExecClearTuple(node->ps.ps_ResultTupleSlot);
- if (node->priorTuple != NULL)
- {
- heap_freetuple(node->priorTuple);
- node->priorTuple = NULL;
- }
-
- ExecEndNode(outerPlanState(node));
MemoryContextDelete(node->tempContext);
+
+ ExecEndNode(outerPlanState(node));
}
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 147becf6ed8..cde9ab6ff6e 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.79 2002/12/05 15:50:34 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.80 2002/12/15 16:17:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1287,23 +1287,23 @@ _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount)
elog(FATAL, "SPI_select: # of processed tuples check failed");
}
- ExecutorEnd(queryDesc);
-
-#ifdef SPI_EXECUTOR_STATS
- if (ShowExecutorStats)
- ShowUsage("SPI EXECUTOR STATS");
-#endif
-
if (dest == SPI)
{
SPI_processed = _SPI_current->processed;
SPI_lastoid = save_lastoid;
SPI_tuptable = _SPI_current->tuptable;
}
- queryDesc->dest = dest;
- return res;
+ ExecutorEnd(queryDesc);
+
+ FreeQueryDesc(queryDesc);
+
+#ifdef SPI_EXECUTOR_STATS
+ if (ShowExecutorStats)
+ ShowUsage("SPI EXECUTOR STATS");
+#endif
+ return res;
}
/*
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index e4eedd11790..984c930e3a6 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -9,7 +9,7 @@
*
*
* 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;
ScanKeyData entry[1];
Form_pg_amop aform;
- ExprContext *econtext;
+ EState *estate;
+ MemoryContext oldcontext;
/* First try the equal() test */
if (equal((Node *) predicate, clause))
@@ -1267,20 +1268,33 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
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,
BOOLOID,
false,
(Expr *) clause_const,
(Expr *) pred_const);
- set_opfuncid((OpExpr *) test_expr);
- test_exprstate = ExecInitExpr(test_expr, NULL);
- econtext = MakeExprContext(NULL, CurrentMemoryContext);
- test_result = ExecEvalExprSwitchContext(test_exprstate, econtext,
+ /* Prepare it for execution */
+ test_exprstate = ExecPrepareExpr(test_expr, estate);
+
+ /* And execute it. */
+ test_result = ExecEvalExprSwitchContext(test_exprstate,
+ GetPerTupleExprContext(estate),
&isNull, NULL);
- FreeExprContext(econtext);
+
+ /* Get back to outer memory context */
+ MemoryContextSwitchTo(oldcontext);
+
+ /* Release all the junk we just created */
+ FreeExecutorState(estate);
if (isNull)
{
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 1d87afdc42f..4c87a95c3b1 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
*
*
* 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
* AUTHOR DATE MAJOR EVENT
@@ -1684,7 +1684,8 @@ evaluate_function(Oid funcid, List *args, HeapTuple func_tuple)
bool has_null_input = false;
FuncExpr *newexpr;
ExprState *newexprstate;
- ExprContext *econtext;
+ EState *estate;
+ MemoryContext oldcontext;
Datum const_val;
bool const_is_null;
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
* 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.
*/
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->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
* might seem fortuitous, but it's not so unreasonable --- a constant
* expression does not depend on context, by definition, n'est ce pas?
*/
- econtext = MakeExprContext(NULL, CurrentMemoryContext);
+ const_val = ExecEvalExprSwitchContext(newexprstate,
+ GetPerTupleExprContext(estate),
+ &const_is_null, NULL);
- newexprstate = ExecInitExpr((Expr *) newexpr, NULL);
+ /* Get info needed about result datatype */
+ get_typlenbyval(result_typeid, &resultTypLen, &resultTypByVal);
- const_val = ExecEvalExprSwitchContext(newexprstate, econtext,
- &const_is_null, NULL);
+ /* Get back to outer memory context */
+ MemoryContextSwitchTo(oldcontext);
/* Must copy result out of sub-context used by expression eval */
if (!const_is_null)
const_val = datumCopy(const_val, resultTypByVal, resultTypLen);
- FreeExprContext(econtext);
+ /* Release all the junk we just created */
+ FreeExecutorState(estate);
/*
* Make the constant result node.
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 24d4aac8b2c..1e02e42193d 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -8,7 +8,7 @@
*
*
* 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;
}
+/*
+ * 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
* ----------------
@@ -152,9 +164,8 @@ ProcessQuery(Query *parsetree,
* QueryDesc */
/*
- * 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
- * context.
+ * We stay in portal's memory context for now, so that query desc
+ * is also allocated in the portal context.
*/
}
@@ -231,4 +242,6 @@ ProcessQuery(Query *parsetree,
* Now, we close down all the scans and free allocated resources.
*/
ExecutorEnd(queryDesc);
+
+ FreeQueryDesc(queryDesc);
}
diff --git a/src/include/executor/execdesc.h b/src/include/executor/execdesc.h
index 9a95551d7c8..27148bb1d86 100644
--- a/src/include/executor/execdesc.h
+++ b/src/include/executor/execdesc.h
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* 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,
bool doInstrument);
+extern void FreeQueryDesc(QueryDesc *qdesc);
+
#endif /* EXECDESC_H */
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 9b7af6d36fb..571f35c64e3 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* 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,
ScanDirection direction, long count);
extern void ExecutorEnd(QueryDesc *queryDesc);
-extern EState *CreateExecutorState(void);
extern void ExecCheckRTPerms(List *rangeTable, CmdType operation);
+extern void ExecEndPlan(PlanState *planstate, EState *estate);
extern void ExecConstraints(const char *caller, ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate);
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
@@ -93,6 +93,7 @@ extern Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econt
bool *isNull, ExprDoneCond *isDone);
extern ExprState *ExecInitExpr(Expr *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 int ExecTargetListLength(List *targetlist);
extern int ExecCleanTargetListLength(List *targetlist);
@@ -157,23 +158,9 @@ extern void end_tup_output(TupOutputState *tstate);
/*
* prototypes from functions in execUtils.c
*/
-extern void ResetTupleCount(void);
-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 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 EState *CreateExecutorState(void);
+extern void FreeExecutorState(EState *estate);
+extern ExprContext *CreateExprContext(EState *estate);
extern void FreeExprContext(ExprContext *econtext);
#define ResetExprContext(econtext) \
@@ -197,6 +184,19 @@ extern ExprContext *MakePerTupleExprContext(EState *estate);
ResetExprContext((estate)->es_per_tuple_exprcontext); \
} 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 ExecCloseIndices(ResultRelInfo *resultRelInfo);
extern void ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid,
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index f8e1f7cc4c9..65c5f23884d 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* 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.
*
* There are two memory contexts associated with an ExprContext:
- * * ecxt_per_query_memory is a relatively long-lived context (such as
- * TransactionCommandContext); typically it's the same context the
- * ExprContext node itself is allocated in. This context can be
- * used for purposes such as storing function call cache info.
+ * * ecxt_per_query_memory is a query-lifespan context, typically the same
+ * context the ExprContext node itself is allocated in. This context
+ * can be used for purposes such as storing function call cache info.
* * ecxt_per_tuple_memory is a short-term context for expression results.
* As the name suggests, it will typically be reset once per tuple,
* before we begin to evaluate expressions for that tuple. Each
* ExprContext normally has its very own per-tuple memory context.
+ *
* CurrentMemoryContext should be set to ecxt_per_tuple_memory before
* calling ExecEvalExpr() --- see ExecEvalExprSwitchContext().
* ----------------
@@ -118,6 +118,9 @@ typedef struct ExprContext
Datum domainValue_datum;
bool domainValue_isNull;
+ /* Link to containing EState */
+ struct EState *ecxt_estate;
+
/* Functions to call back when ExprContext is shut down */
ExprContext_CB *ecxt_callbacks;
} ExprContext;
@@ -277,45 +280,43 @@ typedef struct ResultRelInfo
/* ----------------
* EState information
*
- * direction direction of the scan
- *
- * 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.
+ * Master working state for an Executor invocation
* ----------------
*/
typedef struct EState
{
NodeTag type;
- ScanDirection es_direction;
- Snapshot es_snapshot;
- List *es_range_table;
+
+ /* Basic state for all query types: */
+ 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 */
int es_num_result_relations; /* length of array */
ResultRelInfo *es_result_relation_info; /* currently active array
* elt */
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 */
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 */
Oid es_lastoid; /* last oid processed (by INSERT) */
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 */
+ List *es_exprcontexts; /* List of ExprContexts within EState */
+
/*
* this ExprContext is for per-output-tuple operations, such as
* constraint checks and index-value computations. It will be reset
@@ -457,6 +458,7 @@ typedef struct BoolExprState
typedef struct SubPlanState
{
ExprState xprstate;
+ EState *sub_estate; /* subselect plan has its own EState */
struct PlanState *planstate; /* subselect plan's state tree */
bool needShutdown; /* TRUE = need to shutdown subplan */
HeapTuple curTuple; /* copy of most recent tuple from subplan */
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 8908a43a786..a569d9ee9da 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -3,7 +3,7 @@
* procedural language
*
* 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.
*
@@ -3227,7 +3227,6 @@ exec_eval_simple_expr(PLpgSQL_execstate * estate,
bool *isNull,
Oid *rettype)
{
- _SPI_plan *spi_plan = (_SPI_plan *) expr->plan;
Datum retval;
PLpgSQL_var *var;
PLpgSQL_rec *rec;
@@ -3242,14 +3241,11 @@ exec_eval_simple_expr(PLpgSQL_execstate * estate,
ParamListInfo paramLI;
/*
- * Create a simple expression context to hold the arguments.
- *
- * NOTE: we pass the SPI plan's context as the query-lifetime context for
- * 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.
+ * Create an expression context to hold the arguments and the result
+ * of this expression evaluation. This must be a child of the EState
+ * we created in the SPI plan's context.
*/
- econtext = MakeExprContext(NULL, spi_plan->plancxt);
+ econtext = CreateExprContext(expr->plan_simple_estate);
/*
* Param list can live in econtext's temporary memory context.
@@ -3691,13 +3687,20 @@ exec_simple_check_plan(PLpgSQL_expr * expr)
return;
/*
- * Yes - this is a simple expression. Prepare to execute it, and
- * stash away the result type. Put the expression state tree in the
- * plan context so it will have appropriate lifespan.
+ * Yes - this is a simple expression. Prepare to execute it.
+ * We need an EState and an expression state tree, which we'll put
+ * into the plan context so they will have appropriate lifespan.
*/
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);
+
+ /* Also stash away the expression result type */
expr->plan_simple_type = exprType((Node *) tle->expr);
}
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 945569b6f6a..f051c015721 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -3,7 +3,7 @@
* procedural language
*
* 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.
*
@@ -166,6 +166,7 @@ typedef struct
char *query;
void *plan;
ExprState *plan_simple_expr;
+ EState *plan_simple_estate;
Oid plan_simple_type;
Oid *plan_argtypes;
int nparams;