Revise executor APIs so that all per-query state structure is built in
authorTom Lane
Sun, 15 Dec 2002 16:17:59 +0000 (16:17 +0000)
committerTom Lane
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;