]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Revise executor APIs so that all per-query state structure is built in
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 15 Dec 2002 16:17:59 +0000 (16:17 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 15 Dec 2002 16:17:59 +0000 (16:17 +0000)
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.

42 files changed:
src/backend/bootstrap/bootstrap.c
src/backend/catalog/index.c
src/backend/commands/copy.c
src/backend/commands/explain.c
src/backend/commands/indexcmds.c
src/backend/commands/portalcmds.c
src/backend/commands/prepare.c
src/backend/commands/tablecmds.c
src/backend/commands/typecmds.c
src/backend/commands/vacuum.c
src/backend/executor/README
src/backend/executor/execMain.c
src/backend/executor/execQual.c
src/backend/executor/execUtils.c
src/backend/executor/functions.c
src/backend/executor/nodeAgg.c
src/backend/executor/nodeFunctionscan.c
src/backend/executor/nodeGroup.c
src/backend/executor/nodeHash.c
src/backend/executor/nodeHashjoin.c
src/backend/executor/nodeIndexscan.c
src/backend/executor/nodeLimit.c
src/backend/executor/nodeMaterial.c
src/backend/executor/nodeMergejoin.c
src/backend/executor/nodeNestloop.c
src/backend/executor/nodeResult.c
src/backend/executor/nodeSeqscan.c
src/backend/executor/nodeSetOp.c
src/backend/executor/nodeSort.c
src/backend/executor/nodeSubplan.c
src/backend/executor/nodeSubqueryscan.c
src/backend/executor/nodeTidscan.c
src/backend/executor/nodeUnique.c
src/backend/executor/spi.c
src/backend/optimizer/path/indxpath.c
src/backend/optimizer/util/clauses.c
src/backend/tcop/pquery.c
src/include/executor/execdesc.h
src/include/executor/executor.h
src/include/nodes/execnodes.h
src/pl/plpgsql/src/pl_exec.c
src/pl/plpgsql/src/plpgsql.h

index a2180b3466fd8663597b22a92aaf4b2e974c6a2c..cf0c1de7c6284c2ecb8e52dd02a81ac354dbd753 100644 (file)
@@ -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;
index 4e72fc53f0222ce2a952cecbf7cfcaf09a2c9096..5ccb70aee758b8071c48e6631116d2e580b1e9d6 100644 (file)
@@ -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;
@@ -1503,28 +1500,42 @@ 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;
 }
index 9e8f7a46be40850fdfa1d67201cfbd453a0a2792..fd8c6b83a82d3aa37f63cff00f1350db54ef6803 100644 (file)
@@ -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);
 }
 
 
index 05815a2201bbe87935aee168050882b8574c9c7b..3820dd8b4628d9a9bdf3decb2f6d72f3f7368d1c 100644 (file)
@@ -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);
index 7b66eea0b0bced3f3c23ce5f3a0d030bc11d838a..d46b7a389a387d48752f5d966a7d59a7b9b6b926 100644 (file)
@@ -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;
 
index c8607fcf3244dbbf1a6e9f7453bc886cbd041b52..b1799e49f8cddf65342f7f3cedbcd4d911b80107 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 void
 PortalCleanup(Portal portal)
 {
-       MemoryContext oldcontext;
-
        /*
         * sanity checks
         */
        AssertArg(PortalIsValid(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));
 }
 
 
index 98894372fa75d3e2be5597e6215d33d998f7f177..ece9802dc41d7837bc2c24c0023d838d357ec17c 100644 (file)
@@ -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 */
 }
 
 /*
@@ -333,17 +343,6 @@ FetchQueryParams(const char *plan_name)
        return entry->argtype_list;
 }
 
-/*
- * Actually execute a prepared query.
- */
-static void
-RunQuery(QueryDesc *qdesc)
-{
-       ExecutorStart(qdesc);
-       ExecutorRun(qdesc, ForwardScanDirection, 0L);
-       ExecutorEnd(qdesc);
-}
-
 /*
  * Implements the 'DEALLOCATE' utility statement: deletes the
  * specified plan from storage.
index a7a19c6f74154a9503f8fae5d5223b5f04df41b4..09c60bdf3f9e60e6bb3ce246e2fee27767053004 100644 (file)
@@ -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",
index fc0030fe7623dce9be090b0263c4896c26344e18..c088aaac9910ac13013a509773b5d44518961601 100644 (file)
@@ -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);
index 51082689250d264a96a7c340b0399a1bdcea8817..48870b4bca125ea9a1291dcf80919a1d20359f46 100644 (file)
@@ -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);
 }
 
 /*
index d9b0ea1275a1c2f1f44d6d27748c6eabe695792b..ebdbe2d9d0c5598948b8859207c7160856e2d219 100644 (file)
@@ -1,4 +1,4 @@
-$Header: /cvsroot/pgsql/src/backend/executor/README,v 1.2 2002/12/05 15:50:30 tgl Exp $
+$Header: /cvsroot/pgsql/src/backend/executor/README,v 1.3 2002/12/15 16:17:45 tgl Exp $
 
 The Postgres Executor
 ---------------------
@@ -60,6 +60,83 @@ ExprState nodes.  (Actually, there are also List nodes, which are used as
 "glue" in all four kinds of tree.)
 
 
+Memory Management
+-----------------
+
+A "per query" memory context is created during CreateExecutorState();
+all storage allocated during an executor invocation is allocated in that
+context or a child context.  This allows easy reclamation of storage
+during executor shutdown --- rather than messing with retail pfree's and
+probable storage leaks, we just destroy the memory context.
+
+In particular, the plan state trees and expression state trees described
+in the previous section are allocated in the per-query memory context.
+
+To avoid intra-query memory leaks, most processing while a query runs
+is done in "per tuple" memory contexts, which are so-called because they
+are typically reset to empty once per tuple.  Per-tuple contexts are usually
+associated with ExprContexts, and commonly each PlanState node has its own
+ExprContext to evaluate its qual and targetlist expressions in.
+
+
+Query Processing Control Flow
+-----------------------------
+
+This is a sketch of control flow for full query processing:
+
+       CreateQueryDesc
+
+       ExecutorStart
+               CreateExecutorState
+                       creates per-query context
+               switch to per-query context to run ExecInitNode
+               ExecInitNode --- recursively scans plan tree
+                       CreateExprContext
+                               creates per-tuple context
+                       ExecInitExpr
+
+       ExecutorRun
+               ExecProcNode --- recursively called in per-query context
+                       ExecEvalExpr --- called in per-tuple context
+                       ResetExprContext --- to free memory
+
+       ExecutorEnd
+               ExecEndNode --- recursively releases resources
+               FreeExecutorState
+                       frees per-query context and child contexts
+
+       FreeQueryDesc
+
+Per above comments, it's not really critical for ExecEndNode to free any
+memory; it'll all go away in FreeExecutorState anyway.  However, we do need to
+be careful to close relations, drop buffer pins, etc, so we do need to scan
+the plan state tree to find these sorts of resources.
+
+
+The executor can also be used to evaluate simple expressions without any Plan
+tree ("simple" meaning "no aggregates and no sub-selects", though such might
+be hidden inside function calls).  This case has a flow of control like
+
+       CreateExecutorState
+               creates per-query context
+
+       CreateExprContext       -- or use GetPerTupleExprContext(estate)
+               creates per-tuple context
+
+       ExecPrepareExpr
+               switch to per-query context to run ExecInitExpr
+               ExecInitExpr
+
+       Repeatedly do:
+               ExecEvalExprSwitchContext
+                       ExecEvalExpr --- called in per-tuple context
+               ResetExprContext --- to free memory
+
+       FreeExecutorState
+               frees per-query context, as well as ExprContext
+               (a separate FreeExprContext call is not necessary)
+
+
 EvalPlanQual (READ COMMITTED update checking)
 ---------------------------------------------
 
index bac7398825e981e4af2b2498b947469750f97add..a25f2f2e296b41866f7bc7315622f1365f55903e 100644 (file)
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.192 2002/12/13 19:45:52 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.193 2002/12/15 16:17:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,7 +40,6 @@
 #include "executor/execdebug.h"
 #include "executor/execdefs.h"
 #include "miscadmin.h"
-#include "optimizer/planmain.h"
 #include "optimizer/var.h"
 #include "parser/parsetree.h"
 #include "utils/acl.h"
@@ -53,7 +52,6 @@ static void initResultRelInfo(ResultRelInfo *resultRelInfo,
                                  Index resultRelationIndex,
                                  List *rangeTable,
                                  CmdType operation);
-static void EndPlan(PlanState *planstate, EState *estate);
 static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate,
                        CmdType operation,
                        long numberTuples,
@@ -86,27 +84,31 @@ static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
  * field of the QueryDesc is filled in to describe the tuples that will be
  * returned, and the internal fields (estate and planstate) are set up.
  *
- * XXX this will change soon:
- * NB: the CurrentMemoryContext when this is called must be the context
- * to be used as the per-query context for the query plan.     ExecutorRun()
- * and ExecutorEnd() must be called in this same memory context.
+ * NB: the CurrentMemoryContext when this is called will become the parent
+ * of the per-query context used for this Executor invocation.
  * ----------------------------------------------------------------
  */
 void
 ExecutorStart(QueryDesc *queryDesc)
 {
        EState     *estate;
+       MemoryContext oldcontext;
 
        /* sanity checks: queryDesc must not be started already */
        Assert(queryDesc != NULL);
        Assert(queryDesc->estate == NULL);
 
        /*
-        * Build EState, fill with parameters from queryDesc
+        * Build EState, switch into per-query memory context for startup.
         */
        estate = CreateExecutorState();
        queryDesc->estate = estate;
 
+       oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
+
+       /*
+        * Fill in parameters, if any, from queryDesc
+        */
        estate->es_param_list_info = queryDesc->params;
 
        if (queryDesc->plantree->nParamExec > 0)
@@ -128,6 +130,8 @@ ExecutorStart(QueryDesc *queryDesc)
         * Initialize the plan state tree
         */
        InitPlan(queryDesc);
+
+       MemoryContextSwitchTo(oldcontext);
 }
 
 /* ----------------------------------------------------------------
@@ -152,23 +156,30 @@ TupleTableSlot *
 ExecutorRun(QueryDesc *queryDesc,
                        ScanDirection direction, long count)
 {
-       CmdType         operation;
        EState     *estate;
+       CmdType         operation;
        CommandDest dest;
        DestReceiver *destfunc;
        TupleTableSlot *result;
+       MemoryContext oldcontext;
+
+       /* sanity checks */
+       Assert(queryDesc != NULL);
+
+       estate = queryDesc->estate;
+
+       Assert(estate != NULL);
 
        /*
-        * sanity checks
+        * Switch into per-query memory context
         */
-       Assert(queryDesc != NULL);
+       oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
 
        /*
         * extract information from the query descriptor and the query
         * feature.
         */
        operation = queryDesc->operation;
-       estate = queryDesc->estate;
        dest = queryDesc->dest;
 
        /*
@@ -199,6 +210,8 @@ ExecutorRun(QueryDesc *queryDesc,
         */
        (*destfunc->cleanup) (destfunc);
 
+       MemoryContextSwitchTo(oldcontext);
+
        return result;
 }
 
@@ -213,72 +226,37 @@ void
 ExecutorEnd(QueryDesc *queryDesc)
 {
        EState     *estate;
+       MemoryContext oldcontext;
 
        /* sanity checks */
        Assert(queryDesc != NULL);
 
        estate = queryDesc->estate;
 
-       EndPlan(queryDesc->planstate, estate);
-
-       if (estate->es_snapshot != NULL)
-       {
-               if (estate->es_snapshot->xcnt > 0)
-                       pfree(estate->es_snapshot->xip);
-               pfree(estate->es_snapshot);
-               estate->es_snapshot = NULL;
-       }
-
-       if (estate->es_param_exec_vals != NULL)
-       {
-               pfree(estate->es_param_exec_vals);
-               estate->es_param_exec_vals = NULL;
-       }
-}
-
-
-/*
- * CreateExecutorState
- */
-EState *
-CreateExecutorState(void)
-{
-       EState     *state;
+       Assert(estate != NULL);
 
        /*
-        * create a new executor state
+        * Switch into per-query memory context to run ExecEndPlan
         */
-       state = makeNode(EState);
+       oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
+
+       ExecEndPlan(queryDesc->planstate, estate);
 
        /*
-        * initialize the Executor State structure
+        * Must switch out of context before destroying it
         */
-       state->es_direction = ForwardScanDirection;
-       state->es_range_table = NIL;
-
-       state->es_result_relations = NULL;
-       state->es_num_result_relations = 0;
-       state->es_result_relation_info = NULL;
-
-       state->es_junkFilter = NULL;
-
-       state->es_into_relation_descriptor = NULL;
-
-       state->es_param_list_info = NULL;
-       state->es_param_exec_vals = NULL;
-
-       state->es_tupleTable = NULL;
-
-       state->es_query_cxt = CurrentMemoryContext;
-
-       state->es_instrument = false;
-
-       state->es_per_tuple_exprcontext = NULL;
+       MemoryContextSwitchTo(oldcontext);
 
        /*
-        * return the executor state structure
+        * Release EState and per-query memory context.  This should release
+        * everything the executor has allocated.
         */
-       return state;
+       FreeExecutorState(estate);
+
+       /* Reset queryDesc fields that no longer point to anything */
+       queryDesc->tupDesc = NULL;
+       queryDesc->estate = NULL;
+       queryDesc->planstate = NULL;
 }
 
 
@@ -794,13 +772,13 @@ initResultRelInfo(ResultRelInfo *resultRelInfo,
 }
 
 /* ----------------------------------------------------------------
- *             EndPlan
+ *             ExecEndPlan
  *
  *             Cleans up the query plan -- closes files and frees up storage
  * ----------------------------------------------------------------
  */
-static void
-EndPlan(PlanState *planstate, EState *estate)
+void
+ExecEndPlan(PlanState *planstate, EState *estate)
 {
        ResultRelInfo *resultRelInfo;
        int                     i;
@@ -1542,9 +1520,8 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
                for (i = 0; i < ncheck; i++)
                {
                        qual = (List *) stringToNode(check[i].ccbin);
-                       fix_opfuncids((Node *) qual);
                        resultRelInfo->ri_ConstraintExprs[i] = (List *)
-                               ExecInitExpr((Expr *) qual, NULL);
+                               ExecPrepareExpr((Expr *) qual, estate);
                }
                MemoryContextSwitchTo(oldContext);
        }
index a3f79c3ac80b08b89323f29bff14c40537bf6c7a..971773b1212299b83a7a1872a76893de143172e3 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.120 2002/12/14 00:17:50 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.121 2002/12/15 16:17:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,6 +40,7 @@
 #include "executor/functions.h"
 #include "executor/nodeSubplan.h"
 #include "miscadmin.h"
+#include "optimizer/planmain.h"
 #include "parser/parse_expr.h"
 #include "utils/acl.h"
 #include "utils/array.h"
@@ -1896,9 +1897,11 @@ ExecEvalExprSwitchContext(ExprState *expression,
  * cleanup work can register a shutdown callback in the ExprContext.
  *
  *     'node' is the root of the expression tree to examine
- *     'parent' is the PlanState node that owns the expression,
- *             or NULL if we are preparing an expression that is not associated
- *             with a plan.  (If so, it can't have aggs or subplans.)
+ *     'parent' is the PlanState node that owns the expression.
+ *
+ * 'parent' may be NULL if we are preparing an expression that is not
+ * associated with a plan tree.  (If so, it can't have aggs or subplans.)
+ * This case should usually come through ExecPrepareExpr, not directly here.
  */
 ExprState *
 ExecInitExpr(Expr *node, PlanState *parent)
@@ -2017,6 +2020,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
                                 * parent->subPlan.  The subplans will be initialized later.
                                 */
                                parent->subPlan = lcons(sstate, parent->subPlan);
+                               sstate->sub_estate = NULL;
                                sstate->planstate = NULL;
 
                                sstate->oper = (List *)
@@ -2149,6 +2153,7 @@ ExecInitExprInitPlan(SubPlan *node, PlanState *parent)
                elog(ERROR, "ExecInitExpr: SubPlan not expected here");
 
        /* The subplan's state will be initialized later */
+       sstate->sub_estate = NULL;
        sstate->planstate = NULL;
 
        sstate->oper = (List *) ExecInitExpr((Expr *) node->oper, parent);
@@ -2159,6 +2164,33 @@ ExecInitExprInitPlan(SubPlan *node, PlanState *parent)
        return sstate;
 }
 
+/*
+ * ExecPrepareExpr --- initialize for expression execution outside a normal
+ * Plan tree context.
+ *
+ * This differs from ExecInitExpr in that we don't assume the caller is
+ * already running in the EState's per-query context.  Also, we apply
+ * fix_opfuncids() to the passed expression tree to be sure it is ready
+ * to run.  (In ordinary Plan trees the planner will have fixed opfuncids,
+ * but callers outside the executor will not have done this.)
+ */
+ExprState *
+ExecPrepareExpr(Expr *node, EState *estate)
+{
+       ExprState  *result;
+       MemoryContext oldcontext;
+
+       fix_opfuncids((Node *) node);
+
+       oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
+
+       result = ExecInitExpr(node, NULL);
+
+       MemoryContextSwitchTo(oldcontext);
+
+       return result;
+}
+
 
 /* ----------------------------------------------------------------
  *                                      ExecQual / ExecTargetList / ExecProject
index 36997a49103a4ce6a206d22350480595d2c71d42..6c2cece7b6eb629f8e9aed43590a5a6bd980addf 100644 (file)
@@ -8,13 +8,20 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.92 2002/12/13 19:45:52 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.93 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * INTERFACE ROUTINES
+ *             CreateExecutorState             Create/delete executor working state
+ *             FreeExecutorState
+ *             CreateExprContext
+ *             FreeExprContext
+ *
  *             ExecAssignExprContext   Common code for plan node init routines.
+ *             ExecAssignResultType
+ *             etc
  *
  *             ExecOpenIndices                 \
  *             ExecCloseIndices                 | referenced by InitPlan, EndPlan,
@@ -26,7 +33,6 @@
  *      NOTES
  *             This file has traditionally been the place to stick misc.
  *             executor support stuff that doesn't really go anyplace else.
- *
  */
 
 #include "postgres.h"
@@ -64,6 +70,7 @@ extern int    NIndexTupleProcessed;           /* have to be defined in the
 
 static void ShutdownExprContext(ExprContext *econtext);
 
+
 /* ----------------------------------------------------------------
  *                                             statistic functions
  * ----------------------------------------------------------------
@@ -124,136 +131,263 @@ DisplayTupleCount(FILE *statfp)
 }
 #endif
 
+
 /* ----------------------------------------------------------------
- *                              miscellaneous node-init support functions
+ *                              Executor state and memory management functions
  * ----------------------------------------------------------------
  */
 
 /* ----------------
- *             ExecAssignExprContext
+ *             CreateExecutorState
  *
- *             This initializes the ExprContext field.  It is only necessary
- *             to do this for nodes which use ExecQual or ExecProject
- *             because those routines depend on econtext.      Other nodes that
- *             don't have to evaluate expressions don't need to do this.
+ *             Create and initialize an EState node, which is the root of
+ *             working storage for an entire Executor invocation.
  *
- * Note: we assume CurrentMemoryContext is the correct per-query context.
- * This should be true during plan node initialization.
+ * Principally, this creates the per-query memory context that will be
+ * used to hold all working data that lives till the end of the query.
+ * Note that the per-query context will become a child of the caller's
+ * CurrentMemoryContext.
  * ----------------
  */
-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
  * ----------------
@@ -367,35 +501,13 @@ ExecAssignProjectionInfo(PlanState *planstate)
 }
 
 
-/* ----------------
- *             ExecFreeProjectionInfo
- * ----------------
- */
-void
-ExecFreeProjectionInfo(PlanState *planstate)
-{
-       ProjectionInfo *projInfo;
-
-       /*
-        * get projection info.  if NULL then this node has none so we just
-        * return.
-        */
-       projInfo = planstate->ps_ProjInfo;
-       if (projInfo == NULL)
-               return;
-
-       /*
-        * clean up memory used.
-        */
-       if (projInfo->pi_tupValue != NULL)
-               pfree(projInfo->pi_tupValue);
-
-       pfree(projInfo);
-       planstate->ps_ProjInfo = NULL;
-}
-
 /* ----------------
  *             ExecFreeExprContext
+ *
+ * A plan node's ExprContext should be freed explicitly during ExecEndNode
+ * because there may be shutdown callbacks to call.  (Other resources made
+ * by the above routines, such as projection info, don't need to be freed
+ * explicitly because they're just memory in the per-query memory context.)
  * ----------------
  */
 void
@@ -411,16 +523,8 @@ ExecFreeExprContext(PlanState *planstate)
        if (econtext == NULL)
                return;
 
-       /*
-        * clean up any registered callbacks
-        */
-       ShutdownExprContext(econtext);
+       FreeExprContext(econtext);
 
-       /*
-        * clean up memory used.
-        */
-       MemoryContextDelete(econtext->ecxt_per_tuple_memory);
-       pfree(econtext);
        planstate->ps_ExprContext = NULL;
 }
 
@@ -612,7 +716,8 @@ ExecCloseIndices(ResultRelInfo *resultRelInfo)
        }
 
        /*
-        * XXX should free indexInfo array here too.
+        * XXX should free indexInfo array here too?  Currently we assume that
+        * such stuff will be cleaned up automatically in FreeExecutorState.
         */
 }
 
@@ -674,16 +779,31 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
        for (i = 0; i < numIndices; i++)
        {
                IndexInfo  *indexInfo;
-               List       *predicate;
                InsertIndexResult result;
 
                if (relationDescs[i] == NULL)
                        continue;
 
                indexInfo = indexInfoArray[i];
-               predicate = indexInfo->ii_PredicateState;
-               if (predicate != NIL)
+
+               /* Check for partial index */
+               if (indexInfo->ii_Predicate != NIL)
                {
+                       List       *predicate;
+
+                       /*
+                        * If predicate state not set up yet, create it (in the
+                        * estate's per-query context)
+                        */
+                       predicate = indexInfo->ii_PredicateState;
+                       if (predicate == NIL)
+                       {
+                               predicate = (List *)
+                                       ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,
+                                                                       estate);
+                               indexInfo->ii_PredicateState = predicate;
+                       }
+
                        /* Skip this index-update if the predicate isn't satisfied */
                        if (!ExecQual(predicate, econtext, false))
                                continue;
@@ -811,6 +931,17 @@ static void
 ShutdownExprContext(ExprContext *econtext)
 {
        ExprContext_CB *ecxt_callback;
+       MemoryContext oldcontext;
+
+       /* Fast path in normal case where there's nothing to do. */
+       if (econtext->ecxt_callbacks == NULL)
+               return;
+
+       /*
+        * Call the callbacks in econtext's per-tuple context.  This ensures
+        * that any memory they might leak will get cleaned up.
+        */
+       oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
 
        /*
         * Call each callback function in reverse registration order.
@@ -821,4 +952,6 @@ ShutdownExprContext(ExprContext *econtext)
                (*ecxt_callback->function) (ecxt_callback->arg);
                pfree(ecxt_callback);
        }
+
+       MemoryContextSwitchTo(oldcontext);
 }
index 328aea5f07992c19b4c1d273f6023d3978c692dc..d3ccf0dd90576b0c265555843350c6166b03d2f3 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.61 2002/12/05 15:50:32 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.62 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -284,7 +284,8 @@ postquel_end(execution_state *es)
        if (es->qd->operation != CMD_UTILITY)
                ExecutorEnd(es->qd);
 
-       pfree(es->qd);
+       FreeQueryDesc(es->qd);
+
        es->qd = NULL;
 
        es->status = F_EXEC_DONE;
index e6ba3887630d70b98cc39abe9bcf04a4d9f5659b..769e88a839779347305416088488ba8e20ce24fa 100644 (file)
@@ -45,7 +45,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.100 2002/12/13 19:45:52 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.101 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1392,8 +1392,6 @@ ExecEndAgg(AggState *node)
                        tuplesort_end(peraggstate->sortstate);
        }
 
-       ExecFreeProjectionInfo(&node->ss.ps);
-
        /*
         * Free both the expr contexts.
         */
@@ -1401,18 +1399,13 @@ ExecEndAgg(AggState *node)
        node->ss.ps.ps_ExprContext = node->tmpcontext;
        ExecFreeExprContext(&node->ss.ps);
 
+       /* clean up tuple table */
+       ExecClearTuple(node->ss.ss_ScanTupleSlot);
+
        MemoryContextDelete(node->aggcontext);
 
        outerPlan = outerPlanState(node);
        ExecEndNode(outerPlan);
-
-       /* clean up tuple table */
-       ExecClearTuple(node->ss.ss_ScanTupleSlot);
-       if (node->grp_firstTuple != NULL)
-       {
-               heap_freetuple(node->grp_firstTuple);
-               node->grp_firstTuple = NULL;
-       }
 }
 
 void
index d0bf78631da1b1bc5afed52d92566e506dbdd184..78f66523d51d7170b55b851c8aabcb4223ce8f58 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.15 2002/12/13 19:45:52 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.16 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -273,9 +273,8 @@ void
 ExecEndFunctionScan(FunctionScanState *node)
 {
        /*
-        * Free the projection info and the scan attribute info
+        * Free the exprcontext
         */
-       ExecFreeProjectionInfo(&node->ss.ps);
        ExecFreeExprContext(&node->ss.ps);
 
        /*
index 8bb72ba34385c24b19be918ca806bfb5f4f55968..58f6c1b34e906d97f156ecb826ce745b571121a7 100644 (file)
@@ -15,7 +15,7 @@
  *       locate group boundaries.
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.52 2002/12/13 19:45:52 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.53 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -218,19 +218,13 @@ ExecEndGroup(GroupState *node)
 {
        PlanState  *outerPlan;
 
-       ExecFreeProjectionInfo(&node->ss.ps);
        ExecFreeExprContext(&node->ss.ps);
 
-       outerPlan = outerPlanState(node);
-       ExecEndNode(outerPlan);
-
        /* clean up tuple table */
        ExecClearTuple(node->ss.ss_ScanTupleSlot);
-       if (node->grp_firstTuple != NULL)
-       {
-               heap_freetuple(node->grp_firstTuple);
-               node->grp_firstTuple = NULL;
-       }
+
+       outerPlan = outerPlanState(node);
+       ExecEndNode(outerPlan);
 }
 
 void
index 45ba826317d8e3b47f3f28021087809d05cc7d35..efdd3b3cabbdbdec7d311c803ff72339a00a7dd2 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.70 2002/12/13 19:45:52 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.71 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -179,10 +179,8 @@ ExecEndHash(HashState *node)
        PlanState  *outerPlan;
 
        /*
-        * free projection info.  no need to free result type info because
-        * that came from the outer plan...
+        * free exprcontext
         */
-       ExecFreeProjectionInfo(&node->ps);
        ExecFreeExprContext(&node->ps);
 
        /*
index 07de8703812c93995557cce32f98c47f1859d3ce..8f899b577d7f1cb5c8001c4257f1d561ba04cd8d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.44 2002/12/13 19:45:52 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.45 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -456,17 +456,10 @@ ExecEndHashJoin(HashJoinState *node)
        }
 
        /*
-        * Free the projection info and the scan attribute info
+        * Free the exprcontext
         */
-       ExecFreeProjectionInfo(&node->js.ps);
        ExecFreeExprContext(&node->js.ps);
 
-       /*
-        * clean up subtrees
-        */
-       ExecEndNode(outerPlanState(node));
-       ExecEndNode(innerPlanState(node));
-
        /*
         * clean out the tuple table
         */
@@ -474,6 +467,11 @@ ExecEndHashJoin(HashJoinState *node)
        ExecClearTuple(node->hj_OuterTupleSlot);
        ExecClearTuple(node->hj_HashTupleSlot);
 
+       /*
+        * clean up subtrees
+        */
+       ExecEndNode(outerPlanState(node));
+       ExecEndNode(innerPlanState(node));
 }
 
 /* ----------------------------------------------------------------
index 1e36e93113dd51df4e1aaa589a16c61240860e29..7b96723844bd93f7450c6ad2e2a3df7f4831a1ad 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.74 2002/12/13 19:45:52 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.75 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -399,44 +399,38 @@ ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt)
 
 /* ----------------------------------------------------------------
  *             ExecEndIndexScan
- *
- * old comments
- *             Releases any storage allocated through C routines.
- *             Returns nothing.
  * ----------------------------------------------------------------
  */
 void
 ExecEndIndexScan(IndexScanState *node)
 {
-       ExprState ***runtimeKeyInfo;
-       ScanKey    *scanKeys;
-       int                *numScanKeys;
        int                     numIndices;
-       Relation        relation;
        RelationPtr indexRelationDescs;
        IndexScanDescPtr indexScanDescs;
+       Relation        relation;
        int                     i;
 
-       runtimeKeyInfo = node->iss_RuntimeKeyInfo;
-
        /*
         * extract information from the node
         */
        numIndices = node->iss_NumIndices;
-       scanKeys = node->iss_ScanKeys;
-       numScanKeys = node->iss_NumScanKeys;
        indexRelationDescs = node->iss_RelationDescs;
        indexScanDescs = node->iss_ScanDescs;
        relation = node->ss.ss_currentRelation;
 
        /*
-        * Free the projection info and the scan attribute info
+        * Free the exprcontext(s)
         */
-       ExecFreeProjectionInfo(&node->ss.ps);
        ExecFreeExprContext(&node->ss.ps);
        if (node->iss_RuntimeContext)
                FreeExprContext(node->iss_RuntimeContext);
 
+       /*
+        * clear out tuple table slots
+        */
+       ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+       ExecClearTuple(node->ss.ss_ScanTupleSlot);
+
        /*
         * close the index relations
         */
@@ -458,36 +452,6 @@ ExecEndIndexScan(IndexScanState *node)
         * locking, however.)
         */
        heap_close(relation, NoLock);
-
-       /*
-        * free the scan keys used in scanning the indices
-        */
-       for (i = 0; i < numIndices; i++)
-       {
-               if (scanKeys[i] != NULL)
-                       pfree(scanKeys[i]);
-       }
-       pfree(scanKeys);
-       pfree(numScanKeys);
-
-       if (runtimeKeyInfo)
-       {
-               for (i = 0; i < numIndices; i++)
-               {
-                       if (runtimeKeyInfo[i] != NULL)
-                               pfree(runtimeKeyInfo[i]);
-               }
-               pfree(runtimeKeyInfo);
-       }
-
-       /*
-        * clear out tuple table slots
-        */
-       ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
-       ExecClearTuple(node->ss.ss_ScanTupleSlot);
-       pfree(node->iss_RelationDescs);
-       pfree(node->iss_ScanDescs);
-       pfree(node);
 }
 
 /* ----------------------------------------------------------------
index 6abd83de8aa970a0f3b906aaafd931d48dce87aa..39d09331ce2a45501ed62a9f5d612fc45d911f3c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.13 2002/12/13 19:45:54 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.14 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -349,10 +349,10 @@ ExecEndLimit(LimitState *node)
 {
        ExecFreeExprContext(&node->ps);
 
-       ExecEndNode(outerPlanState(node));
-
        /* clean up tuple table */
        ExecClearTuple(node->ps.ps_ResultTupleSlot);
+
+       ExecEndNode(outerPlanState(node));
 }
 
 
index cf7ca89f4a94910d889e25e7ccb3dbb601cdb04b..a1725901a7c937cc71046d5354f8b782b9eb178c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.39 2002/12/05 15:50:33 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.40 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -196,17 +196,17 @@ ExecEndMaterial(MaterialState *node)
         */
        ExecClearTuple(node->ss.ss_ScanTupleSlot);
 
-       /*
-        * shut down the subplan
-        */
-       ExecEndNode(outerPlanState(node));
-
        /*
         * Release tuplestore resources
         */
        if (node->tuplestorestate != NULL)
                tuplestore_end((Tuplestorestate *) node->tuplestorestate);
        node->tuplestorestate = NULL;
+
+       /*
+        * shut down the subplan
+        */
+       ExecEndNode(outerPlanState(node));
 }
 
 /* ----------------------------------------------------------------
index 1bb5878d819a28c27be58ea69ad03f55a863b4b1..af6cd8d6f3f9e9c68918760eb39961d8dea065af 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.54 2002/12/13 19:45:54 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.55 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1551,23 +1551,22 @@ ExecEndMergeJoin(MergeJoinState *node)
                           "ending node processing");
 
        /*
-        * Free the projection info and the scan attribute info
+        * Free the exprcontext
         */
-       ExecFreeProjectionInfo(&node->js.ps);
        ExecFreeExprContext(&node->js.ps);
 
-       /*
-        * shut down the subplans
-        */
-       ExecEndNode(innerPlanState(node));
-       ExecEndNode(outerPlanState(node));
-
        /*
         * clean out the tuple table
         */
        ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
        ExecClearTuple(node->mj_MarkedTupleSlot);
 
+       /*
+        * shut down the subplans
+        */
+       ExecEndNode(innerPlanState(node));
+       ExecEndNode(outerPlanState(node));
+
        MJ1_printf("ExecEndMergeJoin: %s\n",
                           "node processing ended");
 }
index 452ed7d70c3fcb4c25f942cb8524a6291e902622..917a7011cbf72ff7e1f78553c3be1ac2d9dd7152 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.28 2002/12/13 19:45:55 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.29 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -364,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");
index 3f2c9927e01165daef8b758b5b455e26ae5283f5..9ea75eb3ce77ed295ac22633ac737ec719c10c49 100644 (file)
@@ -34,7 +34,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.23 2002/12/13 19:45:55 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.24 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -248,9 +248,8 @@ void
 ExecEndResult(ResultState *node)
 {
        /*
-        * Free the projection info
+        * Free the exprcontext
         */
-       ExecFreeProjectionInfo(&node->ps);
        ExecFreeExprContext(&node->ps);
 
        /*
index 6a7393795b2d94e53686e8abf772e0e61ffe7ee9..6628a9eecbe2552bac3e68d28b2019b55a51d7ea 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.40 2002/12/13 19:45:55 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.41 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -264,22 +264,21 @@ ExecEndSeqScan(SeqScanState *node)
        scanDesc = node->ss_currentScanDesc;
 
        /*
-        * Free the projection info and the scan attribute info
+        * Free the exprcontext
         */
-       ExecFreeProjectionInfo(&node->ps);
        ExecFreeExprContext(&node->ps);
 
-       /*
-        * close heap scan
-        */
-       heap_endscan(scanDesc);
-
        /*
         * clean out the tuple table
         */
        ExecClearTuple(node->ps.ps_ResultTupleSlot);
        ExecClearTuple(node->ss_ScanTupleSlot);
 
+       /*
+        * close heap scan
+        */
+       heap_endscan(scanDesc);
+
        /*
         * close the heap relation.
         *
index a81a4a29d9117e714e278e6c6b8ba8f3133f36a0..965a2a6466aff80572eba0189e56853e972b1d21 100644 (file)
@@ -21,7 +21,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.7 2002/12/05 15:50:33 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.8 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -301,9 +301,9 @@ ExecEndSetOp(SetOpState *node)
        ExecClearTuple(node->ps.ps_ResultTupleSlot);
        node->ps.ps_OuterTupleSlot = NULL;
 
-       ExecEndNode(outerPlanState(node));
-
        MemoryContextDelete(node->tempContext);
+
+       ExecEndNode(outerPlanState(node));
 }
 
 
index e1b4db7a51d5922e89f33c2daeb6859f0e90f73c..a37583241fb878ce69631741de3f67f6546581de 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.41 2002/12/05 15:50:33 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.42 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -284,11 +284,6 @@ ExecEndSort(SortState *node)
         */
        ExecClearTuple(node->ss.ss_ScanTupleSlot);
 
-       /*
-        * shut down the subplan
-        */
-       ExecEndNode(outerPlanState(node));
-
        /*
         * Release tuplesort resources
         */
@@ -296,6 +291,11 @@ ExecEndSort(SortState *node)
                tuplesort_end((Tuplesortstate *) node->tuplesortstate);
        node->tuplesortstate = NULL;
 
+       /*
+        * shut down the subplan
+        */
+       ExecEndNode(outerPlanState(node));
+
        SO1_printf("ExecEndSort: %s\n",
                           "sort node shutdown");
 }
index 3a2ca974aee174c7f1dc97ea29f88741faad3147..2f5ab52e213bcd41a56d592f050e9ae655b0ef85 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.38 2002/12/14 00:17:50 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.39 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,9 +47,10 @@ ExecSubPlan(SubPlanState *node,
 
        /*
         * We are probably in a short-lived expression-evaluation context.
-        * Switch to longer-lived per-query context.
+        * Switch to the child plan's per-query context for manipulating its
+        * chgParam, calling ExecProcNode on it, etc.
         */
-       oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
+       oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
 
        if (subplan->setParam != NIL)
                elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
@@ -132,10 +133,13 @@ ExecSubPlan(SubPlanState *node,
                         * ExecProcNode() call. node->curTuple keeps track of the
                         * copied tuple for eventual freeing.
                         */
+                       MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
                        tup = heap_copytuple(tup);
                        if (node->curTuple)
                                heap_freetuple(node->curTuple);
                        node->curTuple = tup;
+                       MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
+
                        result = heap_getattr(tup, col, tdesc, isNull);
                        /* keep scanning subplan to make sure there's only one tuple */
                        continue;
@@ -295,6 +299,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
 {
        SubPlan    *subplan = (SubPlan *) node->xprstate.expr;
        EState     *sp_estate;
+       MemoryContext oldcontext;
 
        /*
         * Do access checking on the rangetable entries in the subquery.
@@ -303,15 +308,23 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
        ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
 
        /*
-        * initialize state
+        * initialize my state
         */
        node->needShutdown = false;
        node->curTuple = NULL;
 
        /*
         * create an EState for the subplan
+        *
+        * The subquery needs its own EState because it has its own rangetable.
+        * It shares our Param ID space, however.  XXX if rangetable access were
+        * done differently, the subquery could share our EState, which would
+        * eliminate some thrashing about in this module...
         */
        sp_estate = CreateExecutorState();
+       node->sub_estate = sp_estate;
+
+       oldcontext = MemoryContextSwitchTo(sp_estate->es_query_cxt);
 
        sp_estate->es_range_table = subplan->rtable;
        sp_estate->es_param_list_info = estate->es_param_list_info;
@@ -322,12 +335,14 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
        sp_estate->es_instrument = estate->es_instrument;
 
        /*
-        * Start up the subplan
+        * Start up the subplan (this is a very cut-down form of InitPlan())
         */
        node->planstate = ExecInitNode(subplan->plan, sp_estate);
 
        node->needShutdown = true;      /* now we need to shutdown the subplan */
 
+       MemoryContextSwitchTo(oldcontext);
+
        /*
         * If this plan is un-correlated or undirect correlated one and want
         * to set params for parent plan then prepare parameters.
@@ -376,10 +391,9 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
        bool            found = false;
 
        /*
-        * We are probably in a short-lived expression-evaluation context.
-        * Switch to longer-lived per-query context.
+        * Must switch to child query's per-query memory context.
         */
-       oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
+       oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
 
        if (subLinkType == ANY_SUBLINK ||
                subLinkType == ALL_SUBLINK)
@@ -415,15 +429,18 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
                found = true;
 
                /*
-                * We need to copy the subplan's tuple in case any of the params
-                * are pass-by-ref type --- the pointers stored in the param
-                * structs will point at this copied tuple!  node->curTuple keeps
-                * track of the copied tuple for eventual freeing.
+                * We need to copy the subplan's tuple into our own context,
+                * in case any of the params are pass-by-ref type --- the pointers
+                * stored in the param structs will point at this copied tuple!
+                * node->curTuple keeps track of the copied tuple for eventual
+                * freeing.
                 */
+               MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
                tup = heap_copytuple(tup);
                if (node->curTuple)
                        heap_freetuple(node->curTuple);
                node->curTuple = tup;
+               MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
 
                foreach(lst, subplan->setParam)
                {
@@ -460,7 +477,10 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
 
        if (planstate->plan->extParam == NULL) /* un-correlated ... */
        {
-               ExecEndNode(planstate);
+               ExecEndPlan(planstate, node->sub_estate);
+               /* mustn't free context while still in it... */
+               MemoryContextSwitchTo(oldcontext);
+               FreeExecutorState(node->sub_estate);
                node->needShutdown = false;
        }
 
@@ -476,7 +496,12 @@ ExecEndSubPlan(SubPlanState *node)
 {
        if (node->needShutdown)
        {
-               ExecEndNode(node->planstate);
+               MemoryContext oldcontext;
+
+               oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
+               ExecEndPlan(node->planstate, node->sub_estate);
+               MemoryContextSwitchTo(oldcontext);
+               FreeExecutorState(node->sub_estate);
                node->needShutdown = false;
        }
        if (node->curTuple)
index 68291ba6e347c3e79c1403b1de7183a87e9c307b..4466ef342193f5b231df66a1ae541e0c52f99652 100644 (file)
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.15 2002/12/13 19:45:55 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.16 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,7 @@ SubqueryNext(SubqueryScanState *node)
        EState     *estate;
        ScanDirection direction;
        TupleTableSlot *slot;
+       MemoryContext oldcontext;
 
        /*
         * get information from the estate and scan state
@@ -66,12 +67,17 @@ SubqueryNext(SubqueryScanState *node)
         */
 
        /*
-        * get the next tuple from the sub-query
+        * Get the next tuple from the sub-query.  We have to be careful to
+        * run it in its appropriate memory context.
         */
        node->sss_SubEState->es_direction = direction;
 
+       oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
+
        slot = ExecProcNode(node->subplan);
 
+       MemoryContextSwitchTo(oldcontext);
+
        node->ss.ss_ScanTupleSlot = slot;
 
        return slot;
@@ -106,6 +112,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
        SubqueryScanState *subquerystate;
        RangeTblEntry *rte;
        EState     *sp_estate;
+       MemoryContext oldcontext;
 
        /*
         * SubqueryScan should not have any "normal" children.
@@ -152,9 +159,17 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
        rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
        Assert(rte->rtekind == RTE_SUBQUERY);
 
+       /*
+        * The subquery needs its own EState because it has its own rangetable.
+        * It shares our Param ID space, however.  XXX if rangetable access were
+        * done differently, the subquery could share our EState, which would
+        * eliminate some thrashing about in this module...
+        */
        sp_estate = CreateExecutorState();
        subquerystate->sss_SubEState = sp_estate;
 
+       oldcontext = MemoryContextSwitchTo(sp_estate->es_query_cxt);
+
        sp_estate->es_range_table = rte->subquery->rtable;
        sp_estate->es_param_list_info = estate->es_param_list_info;
        sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
@@ -163,8 +178,13 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
        sp_estate->es_snapshot = estate->es_snapshot;
        sp_estate->es_instrument = estate->es_instrument;
 
+       /*
+        * Start up the subplan (this is a very cut-down form of InitPlan())
+        */
        subquerystate->subplan = ExecInitNode(node->subplan, sp_estate);
 
+       MemoryContextSwitchTo(oldcontext);
+
        subquerystate->ss.ss_ScanTupleSlot = NULL;
        subquerystate->ss.ps.ps_TupFromTlist = false;
 
@@ -197,10 +217,11 @@ ExecCountSlotsSubqueryScan(SubqueryScan *node)
 void
 ExecEndSubqueryScan(SubqueryScanState *node)
 {
+       MemoryContext oldcontext;
+
        /*
-        * Free the projection info and the scan attribute info
+        * Free the exprcontext
         */
-       ExecFreeProjectionInfo(&node->ss.ps);
        ExecFreeExprContext(&node->ss.ps);
 
        /*
@@ -211,15 +232,13 @@ ExecEndSubqueryScan(SubqueryScanState *node)
        /*
         * close down subquery
         */
-       ExecEndNode(node->subplan);
+       oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
 
-       /*
-        * clean up subquery's tuple table
-        */
-       node->ss.ss_ScanTupleSlot = NULL;
-       ExecDropTupleTable(node->sss_SubEState->es_tupleTable, true);
+       ExecEndPlan(node->subplan, node->sss_SubEState);
 
-       /* XXX we seem to be leaking the sub-EState... */
+       MemoryContextSwitchTo(oldcontext);
+
+       FreeExecutorState(node->sss_SubEState);
 }
 
 /* ----------------------------------------------------------------
@@ -232,12 +251,17 @@ void
 ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
 {
        EState     *estate;
+       MemoryContext oldcontext;
 
        estate = node->ss.ps.state;
 
+       oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
+
        /*
         * ExecReScan doesn't know about my subplan, so I have to do
-        * changed-parameter signaling myself.
+        * changed-parameter signaling myself.  This is just as well,
+        * because the subplan has its own memory context in which its
+        * chgParam lists live.
         */
        if (node->ss.ps.chgParam != NULL)
                SetChangedParamList(node->subplan, node->ss.ps.chgParam);
@@ -249,5 +273,7 @@ ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
        if (node->subplan->chgParam == NULL)
                ExecReScan(node->subplan, NULL);
 
+       MemoryContextSwitchTo(oldcontext);
+
        node->ss.ss_ScanTupleSlot = NULL;
 }
index ba2793407ce5e21a6f9995b9e0702bbfdf204106..7e35bc07cd71375b161bbc324ae021e553269eca 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.29 2002/12/13 19:45:56 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.30 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -278,19 +278,8 @@ void
 ExecEndTidScan(TidScanState *node)
 {
        /*
-        * extract information from the node
+        * Free the exprcontext
         */
-       if (node && node->tss_TidList)
-               pfree(node->tss_TidList);
-
-       /*
-        * Free the projection info and the scan attribute info
-        *
-        * Note: we don't ExecFreeResultType(scanstate) because the rule manager
-        * depends on the tupType returned by ExecMain().  So for now, this is
-        * freed at end-transaction time.  -cim 6/2/91
-        */
-       ExecFreeProjectionInfo(&node->ss.ps);
        ExecFreeExprContext(&node->ss.ps);
 
        /*
index 88b08061f99803e3b2cebfb57ba217ae0226cf81..415594f92c4ddc2a6d6a9a18142a8fba04769bcd 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.35 2002/12/05 15:50:34 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.36 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -194,15 +194,10 @@ ExecEndUnique(UniqueState *node)
 {
        /* clean up tuple table */
        ExecClearTuple(node->ps.ps_ResultTupleSlot);
-       if (node->priorTuple != NULL)
-       {
-               heap_freetuple(node->priorTuple);
-               node->priorTuple = NULL;
-       }
-
-       ExecEndNode(outerPlanState(node));
 
        MemoryContextDelete(node->tempContext);
+
+       ExecEndNode(outerPlanState(node));
 }
 
 
index 147becf6ed86eec9e89d4f9371c2b928df9bb8f0..cde9ab6ff6ee2f2cdd79093baa152a9a7e467a36 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.79 2002/12/05 15:50:34 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.80 2002/12/15 16:17:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1287,23 +1287,23 @@ _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount)
                        elog(FATAL, "SPI_select: # of processed tuples check failed");
        }
 
-       ExecutorEnd(queryDesc);
-
-#ifdef SPI_EXECUTOR_STATS
-       if (ShowExecutorStats)
-               ShowUsage("SPI EXECUTOR STATS");
-#endif
-
        if (dest == SPI)
        {
                SPI_processed = _SPI_current->processed;
                SPI_lastoid = save_lastoid;
                SPI_tuptable = _SPI_current->tuptable;
        }
-       queryDesc->dest = dest;
 
-       return res;
+       ExecutorEnd(queryDesc);
+
+       FreeQueryDesc(queryDesc);
+
+#ifdef SPI_EXECUTOR_STATS
+       if (ShowExecutorStats)
+               ShowUsage("SPI EXECUTOR STATS");
+#endif
 
+       return res;
 }
 
 /*
index e4eedd1179037f62ca5b8c843f6fb915edb3649b..984c930e3a652949fc4f6740b64cbce65bbc4d0b 100644 (file)
@@ -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)
        {
index 1d87afdc42f56106f3de1f1395aee7a9a0a4cfc3..4c87a95c3b1ebd3d750b8d669a9b7535d7307a18 100644 (file)
@@ -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.
index 24d4aac8b2cbd348414cf069271b7f249a852bc1..1e02e42193df31e0a30307b0b173b0fa1153ef85 100644 (file)
@@ -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);
 }
index 9a95551d7c86d1ebfa9a67ea4faf48a0637ec98f..27148bb1d867d0d360dbdeca1c31481de3b4510f 100644 (file)
@@ -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  */
index 9b7af6d36fb76c962c238032c0ac204c52163637..571f35c64e3ae9fa5c91a391d8bd71817625944f 100644 (file)
@@ -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,
index f8e1f7cc4c9e8af9967a2cd08793a7663e695827..65c5f23884dca2476a4876351cb73f003144997c 100644 (file)
@@ -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 */
index 8908a43a78695ffe050360d51124c055d6a4fe79..a569d9ee9da1a51068ff6757781d7c4f894b102b 100644 (file)
@@ -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);
 }
 
index 945569b6f6a416f9628a86cfa469442cc31e388e..f051c0157217fdd3ff7db276b294e78a4c7f3f5a 100644 (file)
@@ -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;