]> granicus.if.org Git - postgresql/commitdiff
First stage of reclaiming memory in executor by resetting short-term
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 12 Jul 2000 02:37:39 +0000 (02:37 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 12 Jul 2000 02:37:39 +0000 (02:37 +0000)
memory contexts.  Currently, only leaks in expressions executed as
quals or projections are handled.  Clean up some old dead cruft in
executor while at it --- unused fields in state nodes, that sort of thing.

53 files changed:
src/backend/access/gist/gist.c
src/backend/access/hash/hash.c
src/backend/access/nbtree/nbtcompare.c
src/backend/access/nbtree/nbtree.c
src/backend/access/rtree/rtree.c
src/backend/catalog/index.c
src/backend/commands/copy.c
src/backend/executor/execAmi.c
src/backend/executor/execMain.c
src/backend/executor/execQual.c
src/backend/executor/execScan.c
src/backend/executor/execTuples.c
src/backend/executor/execUtils.c
src/backend/executor/functions.c
src/backend/executor/nodeAgg.c
src/backend/executor/nodeAppend.c
src/backend/executor/nodeGroup.c
src/backend/executor/nodeHash.c
src/backend/executor/nodeHashjoin.c
src/backend/executor/nodeIndexscan.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/nodeSort.c
src/backend/executor/nodeSubplan.c
src/backend/executor/nodeTidscan.c
src/backend/executor/nodeUnique.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/subselect.c
src/backend/optimizer/util/clauses.c
src/backend/tcop/pquery.c
src/backend/utils/adt/datum.c
src/backend/utils/adt/varlena.c
src/backend/utils/cache/fcache.c
src/backend/utils/mmgr/aset.c
src/include/catalog/index.h
src/include/executor/executor.h
src/include/executor/hashjoin.h
src/include/executor/nodeGroup.h
src/include/executor/nodeHash.h
src/include/executor/nodeSubplan.h
src/include/fmgr.h
src/include/nodes/execnodes.h
src/include/nodes/plannodes.h
src/include/utils/datum.h
src/include/utils/fcache.h
src/pl/plpgsql/src/pl_exec.c

index 794685da2e12c6ea7aac72295b15a02fc80400eb..28c547ffe69fc8376bd95835f815e2d8480ddbb4 100644 (file)
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.60 2000/07/03 23:09:11 wieck Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.61 2000/07/12 02:36:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -141,11 +141,10 @@ gistbuild(PG_FUNCTION_ARGS)
        {
                tupleTable = ExecCreateTupleTable(1);
                slot = ExecAllocTableSlot(tupleTable);
-               econtext = makeNode(ExprContext);
-               FillDummyExprContext(econtext, slot, hd, InvalidBuffer);
+               ExecSetSlotDescriptor(slot, hd);
+               econtext = MakeExprContext(slot, TransactionCommandContext);
        }
        else
-/* shut the compiler up */
        {
                tupleTable = NULL;
                slot = NULL;
@@ -161,13 +160,13 @@ gistbuild(PG_FUNCTION_ARGS)
        {
                nh++;
 
+#ifndef OMIT_PARTIAL_INDEX
                /*
                 * If oldPred != NULL, this is an EXTEND INDEX command, so skip
                 * this tuple if it was already in the existing partial index
                 */
                if (oldPred != NULL)
                {
-#ifndef OMIT_PARTIAL_INDEX
                        /* SetSlotContents(slot, htup); */
                        slot->val = htup;
                        if (ExecQual((List *) oldPred, econtext, false))
@@ -175,7 +174,6 @@ gistbuild(PG_FUNCTION_ARGS)
                                ni++;
                                continue;
                        }
-#endif  /* OMIT_PARTIAL_INDEX */
                }
 
                /*
@@ -184,13 +182,12 @@ gistbuild(PG_FUNCTION_ARGS)
                 */
                if (pred != NULL)
                {
-#ifndef OMIT_PARTIAL_INDEX
                        /* SetSlotContents(slot, htup); */
                        slot->val = htup;
                        if (!ExecQual((List *) pred, econtext, false))
                                continue;
-#endif  /* OMIT_PARTIAL_INDEX */
                }
+#endif  /* OMIT_PARTIAL_INDEX */
 
                ni++;
 
@@ -262,13 +259,13 @@ gistbuild(PG_FUNCTION_ARGS)
        /* okay, all heap tuples are indexed */
        heap_endscan(scan);
 
+#ifndef OMIT_PARTIAL_INDEX
        if (pred != NULL || oldPred != NULL)
        {
-#ifndef OMIT_PARTIAL_INDEX
                ExecDropTupleTable(tupleTable, true);
-               pfree(econtext);
-#endif  /* OMIT_PARTIAL_INDEX */
+               FreeExprContext(econtext);
        }
+#endif  /* OMIT_PARTIAL_INDEX */
 
        /*
         * Since we just counted the tuples in the heap, we update its stats
index 9102b75f61b92ebe5f276c09f20e3d031f213638..354d4985723cafa06c48355dd47fffbcf041330b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.40 2000/06/17 23:41:13 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.41 2000/07/12 02:36:46 tgl Exp $
  *
  * NOTES
  *       This file contains only the public interface routines.
@@ -102,15 +102,14 @@ hashbuild(PG_FUNCTION_ARGS)
        {
                tupleTable = ExecCreateTupleTable(1);
                slot = ExecAllocTableSlot(tupleTable);
-               econtext = makeNode(ExprContext);
-               FillDummyExprContext(econtext, slot, htupdesc, InvalidBuffer);
+               ExecSetSlotDescriptor(slot, htupdesc);
+               econtext = MakeExprContext(slot, TransactionCommandContext);
        }
        else
-/* quiet the compiler */
        {
+               tupleTable = NULL;
+               slot = NULL;
                econtext = NULL;
-               tupleTable = 0;
-               slot = 0;
        }
 #endif  /* OMIT_PARTIAL_INDEX */
 
@@ -122,9 +121,9 @@ hashbuild(PG_FUNCTION_ARGS)
 
        while (HeapTupleIsValid(htup = heap_getnext(hscan, 0)))
        {
-
                nhtups++;
 
+#ifndef OMIT_PARTIAL_INDEX
                /*
                 * If oldPred != NULL, this is an EXTEND INDEX command, so skip
                 * this tuple if it was already in the existing partial index
@@ -132,14 +131,12 @@ hashbuild(PG_FUNCTION_ARGS)
                if (oldPred != NULL)
                {
                        /* SetSlotContents(slot, htup); */
-#ifndef OMIT_PARTIAL_INDEX
                        slot->val = htup;
                        if (ExecQual((List *) oldPred, econtext, false))
                        {
                                nitups++;
                                continue;
                        }
-#endif  /* OMIT_PARTIAL_INDEX */
                }
 
                /*
@@ -148,13 +145,12 @@ hashbuild(PG_FUNCTION_ARGS)
                 */
                if (pred != NULL)
                {
-#ifndef OMIT_PARTIAL_INDEX
                        /* SetSlotContents(slot, htup); */
                        slot->val = htup;
                        if (!ExecQual((List *) pred, econtext, false))
                                continue;
-#endif  /* OMIT_PARTIAL_INDEX */
                }
+#endif  /* OMIT_PARTIAL_INDEX */
 
                nitups++;
 
@@ -221,13 +217,13 @@ hashbuild(PG_FUNCTION_ARGS)
        /* okay, all heap tuples are indexed */
        heap_endscan(hscan);
 
+#ifndef OMIT_PARTIAL_INDEX
        if (pred != NULL || oldPred != NULL)
        {
-#ifndef OMIT_PARTIAL_INDEX
                ExecDropTupleTable(tupleTable, true);
-               pfree(econtext);
-#endif  /* OMIT_PARTIAL_INDEX */
+               FreeExprContext(econtext);
        }
+#endif  /* OMIT_PARTIAL_INDEX */
 
        /*
         * Since we just counted the tuples in the heap, we update its stats
index 73f52cb861c80cab0df2b79b6701619db64351ca..411564fb8dbfe63831057c190dfbd93e4d22fcb8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtcompare.c,v 1.38 2000/06/19 03:54:22 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtcompare.c,v 1.39 2000/07/12 02:36:48 tgl Exp $
  *
  * NOTES
  *
  *     that work on 32-bit or wider datatypes can't just return "a - b".
  *     That could overflow and give the wrong answer.
  *
+ *     NOTE: these routines must not leak memory, since memory allocated
+ *     during an index access won't be recovered till end of query.  This
+ *     primarily affects comparison routines for toastable datatypes;
+ *     they have to be careful to free any detoasted copy of an input datum.
  *-------------------------------------------------------------------------
  */
 
@@ -230,18 +234,23 @@ bttextcmp(PG_FUNCTION_ARGS)
                } while (res == 0 && len != 0);
        }
 
+       if (res == 0 && VARSIZE(a) != VARSIZE(b))
+       {
+               /*
+                * The two strings are the same in the first len bytes,
+                * and they are of different lengths.
+                */
+               if (VARSIZE(a) < VARSIZE(b))
+                       res = -1;
+               else
+                       res = 1;
+       }
+
 #endif
 
-       if (res != 0 || VARSIZE(a) == VARSIZE(b))
-               PG_RETURN_INT32(res);
+       /* Avoid leaking memory when handed toasted input. */
+       PG_FREE_IF_COPY(a, 0);
+       PG_FREE_IF_COPY(b, 1);
 
-       /*
-        * The two strings are the same in the first len bytes, and they are
-        * of different lengths.
-        */
-
-       if (VARSIZE(a) < VARSIZE(b))
-               PG_RETURN_INT32(-1);
-       else
-               PG_RETURN_INT32(1);
+       PG_RETURN_INT32(res);
 }
index 59423ccb5f073e2a1b13414eeed0896aedba34f0..3d8ea1a70a8e8e04eb93d2e324b63f7506618ce7 100644 (file)
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.59 2000/06/17 23:41:16 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.60 2000/07/12 02:36:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -121,8 +121,8 @@ btbuild(PG_FUNCTION_ARGS)
        {
                tupleTable = ExecCreateTupleTable(1);
                slot = ExecAllocTableSlot(tupleTable);
-               econtext = makeNode(ExprContext);
-               FillDummyExprContext(econtext, slot, htupdesc, InvalidBuffer);
+               ExecSetSlotDescriptor(slot, htupdesc);
+               econtext = MakeExprContext(slot, TransactionCommandContext);
 
                /*
                 * we never want to use sort/build if we are extending an existing
@@ -151,14 +151,13 @@ btbuild(PG_FUNCTION_ARGS)
        {
                nhtups++;
 
+#ifndef OMIT_PARTIAL_INDEX
                /*
                 * If oldPred != NULL, this is an EXTEND INDEX command, so skip
                 * this tuple if it was already in the existing partial index
                 */
                if (oldPred != NULL)
                {
-#ifndef OMIT_PARTIAL_INDEX
-
                        /* SetSlotContents(slot, htup); */
                        slot->val = htup;
                        if (ExecQual((List *) oldPred, econtext, false))
@@ -166,7 +165,6 @@ btbuild(PG_FUNCTION_ARGS)
                                nitups++;
                                continue;
                        }
-#endif  /* OMIT_PARTIAL_INDEX */
                }
 
                /*
@@ -175,13 +173,12 @@ btbuild(PG_FUNCTION_ARGS)
                 */
                if (pred != NULL)
                {
-#ifndef OMIT_PARTIAL_INDEX
                        /* SetSlotContents(slot, htup); */
                        slot->val = htup;
                        if (!ExecQual((List *) pred, econtext, false))
                                continue;
-#endif  /* OMIT_PARTIAL_INDEX */
                }
+#endif  /* OMIT_PARTIAL_INDEX */
 
                nitups++;
 
@@ -260,13 +257,13 @@ btbuild(PG_FUNCTION_ARGS)
        /* okay, all heap tuples are indexed */
        heap_endscan(hscan);
 
+#ifndef OMIT_PARTIAL_INDEX
        if (pred != NULL || oldPred != NULL)
        {
-#ifndef OMIT_PARTIAL_INDEX
                ExecDropTupleTable(tupleTable, true);
-               pfree(econtext);
-#endif  /* OMIT_PARTIAL_INDEX */
+               FreeExprContext(econtext);
        }
+#endif  /* OMIT_PARTIAL_INDEX */
 
        /*
         * if we are doing bottom-up btree build, finish the build by (1)
index 7e84d456389981673914855cfcae7582367c12d4..badff1ee21bec6f5b172755398a4429f598e61cb 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.50 2000/06/17 23:41:22 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.51 2000/07/12 02:36:52 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -136,14 +136,14 @@ rtbuild(PG_FUNCTION_ARGS)
        {
                tupleTable = ExecCreateTupleTable(1);
                slot = ExecAllocTableSlot(tupleTable);
-               econtext = makeNode(ExprContext);
-               FillDummyExprContext(econtext, slot, hd, InvalidBuffer);
+               ExecSetSlotDescriptor(slot, hd);
+               econtext = MakeExprContext(slot, TransactionCommandContext);
        }
        else
        {
-               econtext = NULL;
                tupleTable = NULL;
                slot = NULL;
+               econtext = NULL;
        }
 #endif  /* OMIT_PARTIAL_INDEX */
 
@@ -156,13 +156,13 @@ rtbuild(PG_FUNCTION_ARGS)
        {
                nh++;
 
+#ifndef OMIT_PARTIAL_INDEX
                /*
                 * If oldPred != NULL, this is an EXTEND INDEX command, so skip
                 * this tuple if it was already in the existing partial index
                 */
                if (oldPred != NULL)
                {
-#ifndef OMIT_PARTIAL_INDEX
                        /* SetSlotContents(slot, htup); */
                        slot->val = htup;
                        if (ExecQual((List *) oldPred, econtext, false))
@@ -170,7 +170,6 @@ rtbuild(PG_FUNCTION_ARGS)
                                ni++;
                                continue;
                        }
-#endif  /* OMIT_PARTIAL_INDEX */
                }
 
                /*
@@ -179,13 +178,12 @@ rtbuild(PG_FUNCTION_ARGS)
                 */
                if (pred != NULL)
                {
-#ifndef OMIT_PARTIAL_INDEX
                        /* SetSlotContents(slot, htup); */
                        slot->val = htup;
                        if (!ExecQual((List *) pred, econtext, false))
                                continue;
-#endif  /* OMIT_PARTIAL_INDEX */
                }
+#endif  /* OMIT_PARTIAL_INDEX */
 
                ni++;
 
@@ -239,13 +237,13 @@ rtbuild(PG_FUNCTION_ARGS)
        /* okay, all heap tuples are indexed */
        heap_endscan(scan);
 
+#ifndef OMIT_PARTIAL_INDEX
        if (pred != NULL || oldPred != NULL)
        {
-#ifndef OMIT_PARTIAL_INDEX
                ExecDropTupleTable(tupleTable, true);
-               pfree(econtext);
-#endif  /* OMIT_PARTIAL_INDEX */
+               FreeExprContext(econtext);
        }
+#endif  /* OMIT_PARTIAL_INDEX */
 
        /*
         * Since we just counted the tuples in the heap, we update its stats
index e1909e4404ccf4da4b6581ce835cf0f2fa7de880..41d747b0dbfe534d8f0bc0bea5846391c2d1718a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.124 2000/07/05 23:11:06 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.125 2000/07/12 02:36:55 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1670,34 +1670,6 @@ UpdateStats(Oid relid, long reltuples, bool inplace)
 }
 
 
-/* -------------------------
- *             FillDummyExprContext
- *                     Sets up dummy ExprContext and TupleTableSlot objects for use
- *                     with ExecQual.
- *
- *                     NOTE: buffer is passed for historical reasons; it should
- *                     almost certainly always be InvalidBuffer.
- * -------------------------
- */
-void
-FillDummyExprContext(ExprContext *econtext,
-                                        TupleTableSlot *slot,
-                                        TupleDesc tupdesc,
-                                        Buffer buffer)
-{
-       econtext->ecxt_scantuple = slot;
-       econtext->ecxt_innertuple = NULL;
-       econtext->ecxt_outertuple = NULL;
-       econtext->ecxt_param_list_info = NULL;
-       econtext->ecxt_range_table = NULL;
-
-       slot->ttc_tupleDescriptor = tupdesc;
-       slot->ttc_buffer = buffer;
-       slot->ttc_shouldFree = false;
-
-}
-
-
 /* ----------------
  *             DefaultBuild
  *
@@ -1777,14 +1749,14 @@ DefaultBuild(Relation heapRelation,
        {
                tupleTable = ExecCreateTupleTable(1);
                slot = ExecAllocTableSlot(tupleTable);
-               econtext = makeNode(ExprContext);
-               FillDummyExprContext(econtext, slot, heapDescriptor, InvalidBuffer);
+               ExecSetSlotDescriptor(slot, heapDescriptor);
+               econtext = MakeExprContext(slot, TransactionCommandContext);
        }
        else
        {
-               econtext = NULL;
-               tupleTable = 0;
+               tupleTable = NULL;
                slot = NULL;
+               econtext = NULL;
        }
 #endif  /* OMIT_PARTIAL_INDEX */
 
@@ -1812,7 +1784,6 @@ DefaultBuild(Relation heapRelation,
                reltuples++;
 
 #ifndef OMIT_PARTIAL_INDEX
-
                /*
                 * If oldPred != NULL, this is an EXTEND INDEX command, so skip
                 * this tuple if it was already in the existing partial index
@@ -1877,6 +1848,7 @@ DefaultBuild(Relation heapRelation,
        {
                /* parameter was 'false', almost certainly wrong --- tgl 9/21/99 */
                ExecDropTupleTable(tupleTable, true);
+               FreeExprContext(econtext);
        }
 #endif  /* OMIT_PARTIAL_INDEX */
 
index 441941762eaac5f5a13076f336f26604d942d9ec..355b218e6409a209fd0f194d24042619a7f9d449 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.117 2000/07/05 23:11:11 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.118 2000/07/12 02:36:58 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -611,13 +611,11 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
        char       *predString;
        Node      **indexPred = NULL;
        TupleDesc       rtupdesc;
-       ExprContext *econtext = NULL;
        EState     *estate = makeNode(EState);          /* for ExecConstraints() */
-
 #ifndef OMIT_PARTIAL_INDEX
+       ExprContext *econtext = NULL;
        TupleTable      tupleTable;
        TupleTableSlot *slot = NULL;
-
 #endif
        int                     natts;
        AttrNumber *attnumP;
@@ -651,7 +649,6 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
                        finfo = (FuncIndexInfo *) palloc(n_indices * sizeof(FuncIndexInfo));
                        finfoP = (FuncIndexInfo **) palloc(n_indices * sizeof(FuncIndexInfo *));
                        indexPred = (Node **) palloc(n_indices * sizeof(Node *));
-                       econtext = NULL;
                        for (i = 0; i < n_indices; i++)
                        {
                                itupdescArr[i] = RelationGetDescr(index_rels[i]);
@@ -680,36 +677,18 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
                                                                        PointerGetDatum(&pgIndexP[i]->indpred)));
                                        indexPred[i] = stringToNode(predString);
                                        pfree(predString);
+#ifndef OMIT_PARTIAL_INDEX
                                        /* make dummy ExprContext for use by ExecQual */
                                        if (econtext == NULL)
                                        {
-#ifndef OMIT_PARTIAL_INDEX
                                                tupleTable = ExecCreateTupleTable(1);
                                                slot = ExecAllocTableSlot(tupleTable);
-                                               econtext = makeNode(ExprContext);
-                                               econtext->ecxt_scantuple = slot;
                                                rtupdesc = RelationGetDescr(rel);
-                                               slot->ttc_tupleDescriptor = rtupdesc;
-
-                                               /*
-                                                * There's no buffer associated with heap tuples
-                                                * here, so I set the slot's buffer to NULL.
-                                                * Currently, it appears that the only way a
-                                                * buffer could be needed would be if the partial
-                                                * index predicate referred to the "lock" system
-                                                * attribute.  If it did, then heap_getattr would
-                                                * call HeapTupleGetRuleLock, which uses the
-                                                * buffer's descriptor to get the relation id.
-                                                * Rather than try to fix this, I'll just disallow
-                                                * partial indexes on "lock", which wouldn't be
-                                                * useful anyway. --Nels, Nov '92
-                                                */
-                                               /* SetSlotBuffer(slot, (Buffer) NULL); */
-                                               /* SetSlotShouldFree(slot, false); */
-                                               slot->ttc_buffer = (Buffer) NULL;
-                                               slot->ttc_shouldFree = false;
-#endif  /* OMIT_PARTIAL_INDEX */
+                                               ExecSetSlotDescriptor(slot, rtupdesc);
+                                               econtext = MakeExprContext(slot,
+                                                                                                  TransactionCommandContext);
                                        }
+#endif  /* OMIT_PARTIAL_INDEX */
                                }
                                else
                                        indexPred[i] = NULL;
@@ -927,10 +906,9 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
                        {
                                for (i = 0; i < n_indices; i++)
                                {
+#ifndef OMIT_PARTIAL_INDEX
                                        if (indexPred[i] != NULL)
                                        {
-#ifndef OMIT_PARTIAL_INDEX
-
                                                /*
                                                 * if tuple doesn't satisfy predicate, don't
                                                 * update index
@@ -939,8 +917,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
                                                /* SetSlotContents(slot, tuple); */
                                                if (!ExecQual((List *) indexPred[i], econtext, false))
                                                        continue;
-#endif  /* OMIT_PARTIAL_INDEX */
                                        }
+#endif  /* OMIT_PARTIAL_INDEX */
                                        FormIndexDatum(indexNatts[i],
                                                                (AttrNumber *) &(pgIndexP[i]->indkey[0]),
                                                                   tuple,
index ff3fa0b6ed12d2f0d7a9d68a8412cfa3a687883f..10478f60ad69340738ec07fb3e7a6a76c199e591 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $Id: execAmi.c,v 1.48 2000/06/18 22:44:03 tgl Exp $
+ *     $Id: execAmi.c,v 1.49 2000/07/12 02:37:00 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -171,8 +171,8 @@ ExecBeginScan(Relation relation,
 /* ----------------------------------------------------------------
  *             ExecCloseR
  *
- *             closes the relation and scan descriptor for a scan or sort
- *             node.  Also closes index relations and scans for index scans.
+ *             closes the relation and scan descriptor for a scan node.
+ *             Also closes index relations and scans for index scans.
  * ----------------------------------------------------------------
  */
 void
@@ -197,20 +197,12 @@ ExecCloseR(Plan *node)
                        state = ((IndexScan *) node)->scan.scanstate;
                        break;
 
-               case T_Sort:
-                       state = &(((Sort *) node)->sortstate->csstate);
-                       break;
-
-               case T_Agg:
-                       state = &(((Agg *) node)->aggstate->csstate);
-                       break;
-
                case T_TidScan:
                        state = ((TidScan *) node)->scan.scanstate;
                        break;
 
                default:
-                       elog(DEBUG, "ExecCloseR: not a scan or sort node!");
+                       elog(DEBUG, "ExecCloseR: not a scan node!");
                        return;
        }
 
@@ -237,13 +229,12 @@ ExecCloseR(Plan *node)
        if (IsA(node, IndexScan))
        {
                IndexScan  *iscan = (IndexScan *) node;
-               IndexScanState *indexstate;
+               IndexScanState *indexstate = iscan->indxstate;
                int                     numIndices;
                RelationPtr indexRelationDescs;
                IndexScanDescPtr indexScanDescs;
                int                     i;
 
-               indexstate = iscan->indxstate;
                numIndices = indexstate->iss_NumIndices;
                indexRelationDescs = indexstate->iss_RelationDescs;
                indexScanDescs = indexstate->iss_ScanDescs;
index 6f161d95c0fae07721b864cb9294b085911ecd3b..3125bf175e9cb18e14e4739fedaa7350e0799683 100644 (file)
@@ -27,7 +27,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.121 2000/07/05 16:17:43 wieck Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.122 2000/07/12 02:37:00 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -86,9 +86,12 @@ static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation,
  *             This routine must be called at the beginning of any execution of any
  *             query plan
  *
- *             returns (AttrInfo*) which describes the attributes of the tuples to
+ *             returns a TupleDesc which describes the attributes of the tuples to
  *             be returned by the query.
  *
+ * 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.
  * ----------------------------------------------------------------
  */
 TupleDesc
@@ -103,7 +106,8 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
        {
                estate->es_param_exec_vals = (ParamExecData *)
                        palloc(queryDesc->plantree->nParamExec * sizeof(ParamExecData));
-               memset(estate->es_param_exec_vals, 0, queryDesc->plantree->nParamExec * sizeof(ParamExecData));
+               MemSet(estate->es_param_exec_vals, 0,
+                          queryDesc->plantree->nParamExec * sizeof(ParamExecData));
        }
 
        /*
@@ -151,7 +155,6 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
  *                      EXEC_RETONE: return one tuple but don't 'retrieve' it
  *                                                used in postquel function processing
  *
- *
  * ----------------------------------------------------------------
  */
 TupleTableSlot *
@@ -687,13 +690,6 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
         */
        estate->es_range_table = rangeTable;
 
-       /*
-        * initialize the BaseId counter so node base_id's are assigned
-        * correctly.  Someday baseid's will have to be stored someplace other
-        * than estate because they should be unique per query planned.
-        */
-       estate->es_BaseId = 1;
-
        /*
         * initialize result relation stuff
         */
@@ -793,7 +789,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
        /*
         * initialize the private state information for all the nodes in the
         * query tree.  This opens files, allocates storage and leaves us
-        * ready to start processing tuples..
+        * ready to start processing tuples.
         */
        ExecInitNode(plan, estate, NULL);
 
@@ -1589,7 +1585,7 @@ ExecAttrDefault(Relation rel, HeapTuple tuple)
 {
        int                     ndef = rel->rd_att->constr->num_defval;
        AttrDefault *attrdef = rel->rd_att->constr->defval;
-       ExprContext *econtext = makeNode(ExprContext);
+       ExprContext *econtext = MakeExprContext(NULL, CurrentMemoryContext);
        HeapTuple       newtuple;
        Node       *expr;
        bool            isnull;
@@ -1600,23 +1596,13 @@ ExecAttrDefault(Relation rel, HeapTuple tuple)
        char       *repl = NULL;
        int                     i;
 
-       econtext->ecxt_scantuple = NULL;        /* scan tuple slot */
-       econtext->ecxt_innertuple = NULL;       /* inner tuple slot */
-       econtext->ecxt_outertuple = NULL;       /* outer tuple slot */
-       econtext->ecxt_relation = NULL;         /* relation */
-       econtext->ecxt_relid = 0;       /* relid */
-       econtext->ecxt_param_list_info = NULL;          /* param list info */
-       econtext->ecxt_param_exec_vals = NULL;          /* exec param values */
-       econtext->ecxt_range_table = NULL;      /* range table */
        for (i = 0; i < ndef; i++)
        {
                if (!heap_attisnull(tuple, attrdef[i].adnum))
                        continue;
                expr = (Node *) stringToNode(attrdef[i].adbin);
 
-               val = ExecEvalExpr(expr, econtext, &isnull, &isdone);
-
-               pfree(expr);
+               val = ExecEvalExprSwitchContext(expr, econtext, &isnull, &isdone);
 
                if (isnull)
                        continue;
@@ -1635,20 +1621,24 @@ ExecAttrDefault(Relation rel, HeapTuple tuple)
 
        }
 
-       pfree(econtext);
-
        if (repl == NULL)
-               return tuple;
+       {
+               /* no changes needed */
+               newtuple = tuple;
+       }
+       else
+       {
+               newtuple = heap_modifytuple(tuple, rel, replValue, replNull, repl);
 
-       newtuple = heap_modifytuple(tuple, rel, replValue, replNull, repl);
+               pfree(repl);
+               pfree(replNull);
+               pfree(replValue);
+               heap_freetuple(tuple);
+       }
 
-       pfree(repl);
-       heap_freetuple(tuple);
-       pfree(replNull);
-       pfree(replValue);
+       FreeMemoryContext(econtext);
 
        return newtuple;
-
 }
 
 #endif
@@ -1658,9 +1648,10 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
 {
        int                     ncheck = rel->rd_att->constr->num_check;
        ConstrCheck *check = rel->rd_att->constr->check;
-       ExprContext *econtext = makeNode(ExprContext);
        TupleTableSlot *slot = makeNode(TupleTableSlot);
        RangeTblEntry *rte = makeNode(RangeTblEntry);
+       ExprContext *econtext = MakeExprContext(slot,
+                                                                                       TransactionCommandContext);
        List       *rtlist;
        List       *qual;
        int                     i;
@@ -1677,17 +1668,21 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
        rte->relid = RelationGetRelid(rel);
        /* inh, inFromCl, inJoinSet, skipAcl won't be used, leave them zero */
        rtlist = lcons(rte, NIL);
-       econtext->ecxt_scantuple = slot;        /* scan tuple slot */
-       econtext->ecxt_innertuple = NULL;       /* inner tuple slot */
-       econtext->ecxt_outertuple = NULL;       /* outer tuple slot */
-       econtext->ecxt_relation = rel;          /* relation */
-       econtext->ecxt_relid = 0;       /* relid */
-       econtext->ecxt_param_list_info = NULL;          /* param list info */
-       econtext->ecxt_param_exec_vals = NULL;          /* exec param values */
-       econtext->ecxt_range_table = rtlist;            /* range table */
+       econtext->ecxt_range_table = rtlist; /* phony range table */
 
+       /*
+        * Save the de-stringized constraint expressions in command-level
+        * memory context.  XXX should build the above stuff there too,
+        * instead of doing it over for each tuple.
+        * XXX Is it sufficient to have just one es_result_relation_constraints
+        * in an inherited insert/update?
+        */
        if (estate->es_result_relation_constraints == NULL)
        {
+               MemoryContext oldContext;
+
+               oldContext = MemoryContextSwitchTo(TransactionCommandContext);
+
                estate->es_result_relation_constraints =
                        (List **) palloc(ncheck * sizeof(List *));
 
@@ -1696,6 +1691,8 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
                        qual = (List *) stringToNode(check[i].ccbin);
                        estate->es_result_relation_constraints[i] = qual;
                }
+
+               MemoryContextSwitchTo(oldContext);
        }
 
        for (i = 0; i < ncheck; i++)
@@ -1714,16 +1711,15 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
        pfree(slot);
        pfree(rte);
        pfree(rtlist);
-       pfree(econtext);
 
-       return (char *) NULL;
+       FreeExprContext(econtext);
 
+       return (char *) NULL;
 }
 
 void
 ExecConstraints(char *caller, Relation rel, HeapTuple tuple, EState *estate)
 {
-
        Assert(rel->rd_att->constr);
 
        if (rel->rd_att->constr->has_not_null)
@@ -1732,9 +1728,10 @@ ExecConstraints(char *caller, Relation rel, HeapTuple tuple, EState *estate)
 
                for (attrChk = 1; attrChk <= rel->rd_att->natts; attrChk++)
                {
-                       if (rel->rd_att->attrs[attrChk - 1]->attnotnull && heap_attisnull(tuple, attrChk))
+                       if (rel->rd_att->attrs[attrChk-1]->attnotnull &&
+                               heap_attisnull(tuple, attrChk))
                                elog(ERROR, "%s: Fail to add null value in not null attribute %s",
-                                        caller, NameStr(rel->rd_att->attrs[attrChk - 1]->attname));
+                                        caller, NameStr(rel->rd_att->attrs[attrChk-1]->attname));
                }
        }
 
@@ -1743,10 +1740,9 @@ ExecConstraints(char *caller, Relation rel, HeapTuple tuple, EState *estate)
                char       *failed;
 
                if ((failed = ExecRelCheck(rel, tuple, estate)) != NULL)
-                       elog(ERROR, "%s: rejected due to CHECK constraint %s", caller, failed);
+                       elog(ERROR, "%s: rejected due to CHECK constraint %s",
+                                caller, failed);
        }
-
-       return;
 }
 
 TupleTableSlot *
index 33bfa88734fd1f2df4f783a5c5c5040856668ae3..fd9d761ffc477bf16392dbe4b496e32ce9200f7d 100644 (file)
@@ -8,15 +8,16 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.72 2000/06/15 04:09:50 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.73 2000/07/12 02:37:00 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  *      INTERFACE ROUTINES
  *             ExecEvalExpr    - evaluate an expression and return a datum
+ *             ExecEvalExprSwitchContext - same, but switch into eval memory context
  *             ExecQual                - return true/false if qualification is satisfied
- *             ExecTargetList  - form a new tuple by projecting the given tuple
+ *             ExecProject             - form a new tuple by projecting the given tuple
  *
  *      NOTES
  *             ExecEvalExpr() and ExecEvalVar() are hotspots.  making these faster
@@ -24,7 +25,7 @@
  *             implemented recursively.  Eliminating the recursion is bound to
  *             improve the speed of the executor.
  *
- *             ExecTargetList() is used to make tuple projections.  Rather then
+ *             ExecProject() is used to make tuple projections.  Rather then
  *             trying to speed it up, the execution plan should be pre-processed
  *             to facilitate attribute sharing between nodes wherever possible,
  *             instead of doing needless copying.      -cim 5/31/91
 #include "utils/fcache2.h"
 
 
-/*
- *             externs and constants
- */
-
-/*
- * XXX Used so we can get rid of use of Const nodes in the executor.
- * Currently only used by ExecHashGetBucket and set only by ExecMakeVarConst
- * and by ExecEvalArrayRef.
- */
-bool           execConstByVal;
-int                    execConstLen;
-
-/* static functions decls */
+/* static function decls */
 static Datum ExecEvalAggref(Aggref *aggref, ExprContext *econtext, bool *isNull);
 static Datum ExecEvalArrayRef(ArrayRef *arrayRef, ExprContext *econtext,
                                 bool *isNull, bool *isDone);
-static Datum ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull);
+static Datum ExecEvalOper(Expr *opClause, ExprContext *econtext,
+                        bool *isNull);
 static Datum ExecEvalFunc(Expr *funcClause, ExprContext *econtext,
                         bool *isNull, bool *isDone);
 static void ExecEvalFuncArgs(FunctionCachePtr fcache, ExprContext *econtext,
                                                         List *argList, FunctionCallInfo fcinfo,
                                                         bool *argIsDone);
 static Datum ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull);
-static Datum ExecEvalOper(Expr *opClause, ExprContext *econtext,
-                        bool *isNull);
+static Datum ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull);
 static Datum ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull);
 static Datum ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull);
 static Datum ExecMakeFunctionResult(Node *node, List *arguments,
@@ -100,10 +89,11 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
 
        if (arrayRef->refexpr != NULL)
        {
-               array_scanner = (ArrayType *) ExecEvalExpr(arrayRef->refexpr,
-                                                                                                  econtext,
-                                                                                                  isNull,
-                                                                                                  isDone);
+               array_scanner = (ArrayType *)
+                       DatumGetPointer(ExecEvalExpr(arrayRef->refexpr,
+                                                                                econtext,
+                                                                                isNull,
+                                                                                isDone));
                /* If refexpr yields NULL, result is always NULL, for now anyway */
                if (*isNull)
                        return (Datum) NULL;
@@ -128,10 +118,10 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
                        elog(ERROR, "ExecEvalArrayRef: can only handle %d dimensions",
                                 MAXDIM);
 
-               upper.indx[i++] = (int32) ExecEvalExpr((Node *) lfirst(elt),
-                                                                                          econtext,
-                                                                                          isNull,
-                                                                                          &dummy);
+               upper.indx[i++] = DatumGetInt32(ExecEvalExpr((Node *) lfirst(elt),
+                                                                                                        econtext,
+                                                                                                        isNull,
+                                                                                                        &dummy));
                /* If any index expr yields NULL, result is NULL */
                if (*isNull)
                        return (Datum) NULL;
@@ -145,10 +135,10 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
                                elog(ERROR, "ExecEvalArrayRef: can only handle %d dimensions",
                                         MAXDIM);
 
-                       lower.indx[j++] = (int32) ExecEvalExpr((Node *) lfirst(elt),
-                                                                                                  econtext,
-                                                                                                  isNull,
-                                                                                                  &dummy);
+                       lower.indx[j++] = DatumGetInt32(ExecEvalExpr((Node *) lfirst(elt),
+                                                                                                                econtext,
+                                                                                                                isNull,
+                                                                                                                &dummy));
                        /* If any index expr yields NULL, result is NULL */
                        if (*isNull)
                                return (Datum) NULL;
@@ -171,9 +161,6 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
                if (*isNull)
                        return (Datum) NULL;
 
-               execConstByVal = arrayRef->refelembyval;
-               execConstLen = arrayRef->refelemlength;
-
                if (array_scanner == NULL)
                        return sourceData;      /* XXX do something else? */
 
@@ -199,9 +186,6 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
                                                                                   isNull));
        }
 
-       execConstByVal = arrayRef->refelembyval;
-       execConstLen = arrayRef->refelemlength;
-
        if (lIndex == NULL)
                return array_ref(array_scanner, i,
                                                 upper.indx,
@@ -325,7 +309,7 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
                ExecSetSlotDescriptor(tempSlot, td);
 
                ExecStoreTuple(tup, tempSlot, InvalidBuffer, true);
-               return (Datum) tempSlot;
+               return PointerGetDatum(tempSlot);
        }
 
        result = heap_getattr(heapTuple,        /* tuple containing attribute */
@@ -338,7 +322,7 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
         * return null if att is null
         */
        if (*isNull)
-               return (Datum) NULL;
+               return (Datum) 0;
 
        /*
         * get length and type information.. ??? what should we do about
@@ -364,9 +348,6 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
                byval = tuple_type->attrs[attnum - 1]->attbyval ? true : false;
        }
 
-       execConstByVal = byval;
-       execConstLen = len;
-
        return result;
 }
 
@@ -397,7 +378,6 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
 Datum
 ExecEvalParam(Param *expression, ExprContext *econtext, bool *isNull)
 {
-
        char       *thisParameterName;
        int                     thisParameterKind = expression->paramkind;
        AttrNumber      thisParameterId = expression->paramid;
@@ -406,11 +386,15 @@ ExecEvalParam(Param *expression, ExprContext *econtext, bool *isNull)
 
        if (thisParameterKind == PARAM_EXEC)
        {
-               ParamExecData *prm = &(econtext->ecxt_param_exec_vals[thisParameterId]);
+               ParamExecData *prm;
 
+               prm = &(econtext->ecxt_param_exec_vals[thisParameterId]);
                if (prm->execPlan != NULL)
-                       ExecSetParamPlan(prm->execPlan);
-               Assert(prm->execPlan == NULL);
+               {
+                       ExecSetParamPlan(prm->execPlan, econtext);
+                       /* ExecSetParamPlan should have processed this param... */
+                       Assert(prm->execPlan == NULL);
+               }
                *isNull = prm->isnull;
                return prm->value;
        }
@@ -493,7 +477,7 @@ ExecEvalParam(Param *expression, ExprContext *econtext, bool *isNull)
        if (paramList->isnull)
        {
                *isNull = true;
-               return (Datum) NULL;
+               return (Datum) 0;
        }
 
        if (expression->param_tlist != NIL)
@@ -526,8 +510,12 @@ ExecEvalParam(Param *expression, ExprContext *econtext, bool *isNull)
  *             named attribute out of the tuple from the arg slot.  User defined
  *             C functions which take a tuple as an argument are expected
  *             to use this.  Ex: overpaid(EMP) might call GetAttributeByNum().
+ *
+ * XXX these two functions are misdeclared: they should be declared to
+ * return Datum.  They are not used anywhere in the backend proper, and
+ * exist only for use by user-defined functions.  Should we change their
+ * definitions, at risk of breaking user code?
  */
-/* static but gets called from external functions */
 char *
 GetAttributeByNum(TupleTableSlot *slot,
                                  AttrNumber attrno,
@@ -559,18 +547,6 @@ GetAttributeByNum(TupleTableSlot *slot,
        return (char *) retval;
 }
 
-/* XXX name for catalogs */
-#ifdef NOT_USED
-char *
-att_by_num(TupleTableSlot *slot,
-                  AttrNumber attrno,
-                  bool *isNull)
-{
-       return GetAttributeByNum(slot, attrno, isNull);
-}
-
-#endif
-
 char *
 GetAttributeByName(TupleTableSlot *slot, char *attname, bool *isNull)
 {
@@ -617,15 +593,6 @@ GetAttributeByName(TupleTableSlot *slot, char *attname, bool *isNull)
        return (char *) retval;
 }
 
-/* XXX name for catalogs */
-#ifdef NOT_USED
-char *
-att_by_name(TupleTableSlot *slot, char *attname, bool *isNull)
-{
-       return GetAttributeByName(slot, attname, isNull);
-}
-
-#endif
 
 static void
 ExecEvalFuncArgs(FunctionCachePtr fcache,
@@ -732,9 +699,8 @@ ExecMakeFunctionResult(Node *node,
                if (fcache->hasSetArg && argDone)
                {
                        /* can only get here if input is an empty set. */
-                       if (isDone)
-                               *isDone = true;
                        *isNull = true;
+                       *isDone = true;
                        return (Datum) 0;
                }
        }
@@ -817,8 +783,8 @@ ExecMakeFunctionResult(Node *node,
                        else
                        {
                                result = (Datum) 0;
-                               *isDone = true;
                                *isNull = true;
+                               *isDone = true;
                        }
 
                        if (!*isDone)
@@ -872,8 +838,8 @@ ExecMakeFunctionResult(Node *node,
        else
        {
                /* A non-SQL function cannot return a set, at present. */
-               if (isDone)
-                       *isDone = true;
+               *isDone = true;
+
                /*
                 * If function is strict, and there are any NULL arguments,
                 * skip calling the function and return NULL.
@@ -904,15 +870,7 @@ ExecMakeFunctionResult(Node *node,
  *             ExecEvalFunc
  *
  *             Evaluate the functional result of a list of arguments by calling the
- *             function manager.  Note that in the case of operator expressions, the
- *             optimizer had better have already replaced the operator OID with the
- *             appropriate function OID or we're hosed.
- *
- * old comments
- *             Presumably the function manager will not take null arguments, so we
- *             check for null arguments before sending the arguments to (fmgr).
- *
- *             Returns the value of the functional expression.
+ *             function manager.
  * ----------------------------------------------------------------
  */
 
@@ -929,8 +887,6 @@ ExecEvalOper(Expr *opClause, ExprContext *econtext, bool *isNull)
        bool            isDone;
 
        /*
-        * an opclause is a list (op args).  (I think)
-        *
         * we extract the oid of the function associated with the op and then
         * pass the work onto ExecMakeFunctionResult which evaluates the
         * arguments and returns the result of calling the function on the
@@ -954,7 +910,8 @@ ExecEvalOper(Expr *opClause, ExprContext *econtext, bool *isNull)
         * call ExecMakeFunctionResult() with a dummy isDone that we ignore.
         * We don't have operator whose arguments are sets.
         */
-       return ExecMakeFunctionResult((Node *) op, argList, econtext, isNull, &isDone);
+       return ExecMakeFunctionResult((Node *) op, argList, econtext,
+                                                                 isNull, &isDone);
 }
 
 /* ----------------------------------------------------------------
@@ -973,8 +930,6 @@ ExecEvalFunc(Expr *funcClause,
        FunctionCachePtr fcache;
 
        /*
-        * an funcclause is a list (func args).  (I think)
-        *
         * we extract the oid of the function associated with the func node and
         * then pass the work onto ExecMakeFunctionResult which evaluates the
         * arguments and returns the result of calling the function on the
@@ -996,7 +951,8 @@ ExecEvalFunc(Expr *funcClause,
                fcache = func->func_fcache;
        }
 
-       return ExecMakeFunctionResult((Node *) func, argList, econtext, isNull, isDone);
+       return ExecMakeFunctionResult((Node *) func, argList, econtext,
+                                                                 isNull, isDone);
 }
 
 /* ----------------------------------------------------------------
@@ -1041,10 +997,7 @@ ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull)
         * evaluation of 'not' is simple.. expr is false, then return 'true'
         * and vice versa.
         */
-       if (DatumGetInt32(expr_value) == 0)
-               return (Datum) true;
-
-       return (Datum) false;
+       return BoolGetDatum(! DatumGetBool(expr_value));
 }
 
 /* ----------------------------------------------------------------
@@ -1094,13 +1047,13 @@ ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull)
                 */
                if (*isNull)
                        AnyNull = true;         /* remember we got a null */
-               else if (DatumGetInt32(clause_value) != 0)
+               else if (DatumGetBool(clause_value))
                        return clause_value;
        }
 
        /* AnyNull is true if at least one clause evaluated to NULL */
        *isNull = AnyNull;
-       return (Datum) false;
+       return BoolGetDatum(false);
 }
 
 /* ----------------------------------------------------------------
@@ -1144,13 +1097,13 @@ ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull)
                 */
                if (*isNull)
                        AnyNull = true;         /* remember we got a null */
-               else if (DatumGetInt32(clause_value) == 0)
+               else if (! DatumGetBool(clause_value))
                        return clause_value;
        }
 
        /* AnyNull is true if at least one clause evaluated to NULL */
        *isNull = AnyNull;
-       return (Datum) (!AnyNull);
+       return BoolGetDatum(!AnyNull);
 }
 
 /* ----------------------------------------------------------------
@@ -1195,7 +1148,7 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull)
                 * case statement is satisfied.  A NULL result from the test is
                 * not considered true.
                 */
-               if (DatumGetInt32(clause_value) != 0 && !*isNull)
+               if (DatumGetBool(clause_value) && !*isNull)
                {
                        return ExecEvalExpr(wclause->result,
                                                                econtext,
@@ -1221,19 +1174,15 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull)
  *
  *             Recursively evaluate a targetlist or qualification expression.
  *
- *             This routine is an inner loop routine and should be as fast
- *             as possible.
+ *             The caller should already have switched into the temporary
+ *             memory context econtext->ecxt_per_tuple_memory.  The convenience
+ *             entry point ExecEvalExprSwitchContext() is provided for callers
+ *             who don't prefer to do the switch in an outer loop.  We do not
+ *             do the switch here because it'd be a waste of cycles during
+ *             recursive entries to ExecEvalExpr().
  *
- *             Node comparison functions were replaced by macros for speed and to plug
- *             memory leaks incurred by using the planner's Lispy stuff for
- *             comparisons.  Order of evaluation of node comparisons IS IMPORTANT;
- *             the macros do no checks.  Order of evaluation:
- *
- *             o an isnull check, largely to avoid coredumps since greg doubts this
- *               routine is called with a null ptr anyway in proper operation, but is
- *               not completely sure...
- *             o ExactNodeType checks.
- *             o clause checks or other checks where we look at the lfirst of something.
+ *             This routine is an inner loop routine and must be as fast
+ *             as possible.
  * ----------------------------------------------------------------
  */
 Datum
@@ -1244,25 +1193,21 @@ ExecEvalExpr(Node *expression,
 {
        Datum           retDatum;
 
+       /* Set default values for result flags: non-null, not a set result */
        *isNull = false;
+       *isDone = true;
 
-       /*
-        * Some callers don't care about is done and only want 1 result.  They
-        * indicate this by passing NULL
-        */
-       if (isDone)
-               *isDone = true;
-
-       /*
-        * here we dispatch the work to the appropriate type of function given
-        * the type of our expression.
-        */
+       /* Is this still necessary?  Doubtful... */
        if (expression == NULL)
        {
                *isNull = true;
-               return (Datum) true;
+               return (Datum) 0;
        }
 
+       /*
+        * here we dispatch the work to the appropriate type of function given
+        * the type of our expression.
+        */
        switch (nodeTag(expression))
        {
                case T_Var:
@@ -1350,8 +1295,27 @@ ExecEvalExpr(Node *expression,
 }      /* ExecEvalExpr() */
 
 
+/*
+ * Same as above, but get into the right allocation context explicitly.
+ */
+Datum
+ExecEvalExprSwitchContext(Node *expression,
+                                                 ExprContext *econtext,
+                                                 bool *isNull,
+                                                 bool *isDone)
+{
+       Datum           retDatum;
+       MemoryContext oldContext;
+
+       oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
+       retDatum = ExecEvalExpr(expression, econtext, isNull, isDone);
+       MemoryContextSwitchTo(oldContext);
+       return retDatum;
+}
+
+
 /* ----------------------------------------------------------------
- *                                      ExecQual / ExecTargetList
+ *                                      ExecQual / ExecTargetList / ExecProject
  * ----------------------------------------------------------------
  */
 
@@ -1386,6 +1350,8 @@ ExecEvalExpr(Node *expression,
 bool
 ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
 {
+       bool            result;
+       MemoryContext oldContext;
        List       *qlist;
 
        /*
@@ -1397,6 +1363,11 @@ ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
 
        IncrProcessed();
 
+       /*
+        * Run in short-lived per-tuple context while computing expressions.
+        */
+       oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
+
        /*
         * Evaluate the qual conditions one at a time.  If we find a FALSE
         * result, we can stop evaluating and return FALSE --- the AND result
@@ -1409,6 +1380,7 @@ ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
         * is NULL (one or more NULL subresult, with all the rest TRUE) and
         * the caller has specified resultForNull = TRUE.
         */
+       result = true;
 
        foreach(qlist, qual)
        {
@@ -1417,14 +1389,6 @@ ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
                bool            isNull;
                bool            isDone;
 
-               /*
-                * If there is a null clause, consider the qualification to fail.
-                * XXX is this still correct for constraints?  It probably
-                * shouldn't happen at all ...
-                */
-               if (clause == NULL)
-                       return false;
-
                /*
                 * pass isDone, but ignore it.  We don't iterate over multiple
                 * returns in the qualifications.
@@ -1434,16 +1398,24 @@ ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
                if (isNull)
                {
                        if (resultForNull == false)
-                               return false;   /* treat NULL as FALSE */
+                       {
+                               result = false; /* treat NULL as FALSE */
+                               break;
+                       }
                }
                else
                {
-                       if (DatumGetInt32(expr_value) == 0)
-                               return false;   /* definitely FALSE */
+                       if (! DatumGetBool(expr_value))
+                       {
+                               result = false; /* definitely FALSE */
+                               break;
+                       }
                }
        }
 
-       return true;
+       MemoryContextSwitchTo(oldContext);
+
+       return result;
 }
 
 int
@@ -1481,6 +1453,7 @@ ExecTargetList(List *targetlist,
                           ExprContext *econtext,
                           bool *isDone)
 {
+       MemoryContext oldContext;
        char            nulls_array[64];
        bool            fjNullArray[64];
        bool            itemIsDoneArray[64];
@@ -1506,6 +1479,11 @@ ExecTargetList(List *targetlist,
        EV_nodeDisplay(targetlist);
        EV_printf("\n");
 
+       /*
+        * Run in short-lived per-tuple context while computing expressions.
+        */
+       oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
+
        /*
         * There used to be some klugy and demonstrably broken code here that
         * special-cased the situation where targetlist == NIL.  Now we just
@@ -1563,10 +1541,10 @@ ExecTargetList(List *targetlist,
                        resdom = tle->resdom;
                        resind = resdom->resno - 1;
 
-                       constvalue = (Datum) ExecEvalExpr(expr,
-                                                                                         econtext,
-                                                                                         &isNull,
-                                                                                         &itemIsDone[resind]);
+                       constvalue = ExecEvalExpr(expr,
+                                                                         econtext,
+                                                                         &isNull,
+                                                                         &itemIsDone[resind]);
 
                        values[resind] = constvalue;
 
@@ -1597,7 +1575,10 @@ ExecTargetList(List *targetlist,
 
                        /* this is probably wrong: */
                        if (*isDone)
-                               return (HeapTuple) NULL;
+                       {
+                               newTuple = NULL;
+                               goto exit;
+                       }
 
                        /*
                         * get the result from the inner node
@@ -1681,10 +1662,10 @@ ExecTargetList(List *targetlist,
 
                                        if (IsA(expr, Iter) &&itemIsDone[resind])
                                        {
-                                               constvalue = (Datum) ExecEvalExpr(expr,
-                                                                                                                 econtext,
-                                                                                                                 &isNull,
-                                                                                                       &itemIsDone[resind]);
+                                               constvalue = ExecEvalExpr(expr,
+                                                                                                 econtext,
+                                                                                                 &isNull,
+                                                                                                 &itemIsDone[resind]);
                                                if (itemIsDone[resind])
                                                {
 
@@ -1710,8 +1691,10 @@ ExecTargetList(List *targetlist,
        }
 
        /*
-        * form the new result tuple (in the "normal" context)
+        * form the new result tuple (in the caller's memory context!)
         */
+       MemoryContextSwitchTo(oldContext);
+
        newTuple = (HeapTuple) heap_formtuple(targettype, values, null_head);
 
 exit:
@@ -1726,6 +1709,9 @@ exit:
                pfree(itemIsDone);
        }
 
+       /* make sure we are in the right context if we did "goto exit" */
+       MemoryContextSwitchTo(oldContext);
+
        return newTuple;
 }
 
index 98345b408a3c7a795b45c8b9c869e31723fe5608..40bbbd916f651a510c45f3ae55dd0be5a6fa25f4 100644 (file)
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.11 2000/01/26 05:56:21 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.12 2000/07/12 02:37:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -30,7 +30,7 @@
  *             returns the next qualifying tuple in the direction specified
  *             in the global variable ExecDirection.
  *             The access method returns the next tuple and execScan() is
- *             responisble for checking the tuple returned against the qual-clause.
+ *             responsible for checking the tuple returned against the qual-clause.
  *
  *             Conditions:
  *               -- the "cursor" maintained by the AMI is positioned at the tuple
  *             Initial States:
  *               -- the relation indicated is opened for scanning so that the
  *                      "cursor" is positioned before the first qualifying tuple.
- *
- *             May need to put startmmgr  and endmmgr in here.
  * ----------------------------------------------------------------
  */
 TupleTableSlot *
 ExecScan(Scan *node,
-                TupleTableSlot *(*accessMtd) ())               /* function returning a
-                                                                                                * tuple */
+                ExecScanAccessMtd accessMtd) /* function returning a tuple */
 {
        CommonScanState *scanstate;
        EState     *estate;
        List       *qual;
        bool            isDone;
-
-       TupleTableSlot *slot;
        TupleTableSlot *resultSlot;
-       HeapTuple       newTuple;
-
        ExprContext *econtext;
        ProjectionInfo *projInfo;
 
-
        /* ----------------
-        *      initialize misc variables
+        *      Fetch data from node
         * ----------------
         */
-       newTuple = NULL;
-       slot = NULL;
-
        estate = node->plan.state;
        scanstate = node->scanstate;
+       econtext = scanstate->cstate.cs_ExprContext;
+       qual = node->plan.qual;
 
        /* ----------------
-        *      get the expression context
+        *      Reset per-tuple memory context to free any expression evaluation
+        *      storage allocated in the previous tuple cycle.
         * ----------------
         */
-       econtext = scanstate->cstate.cs_ExprContext;
+       ResetExprContext(econtext);
 
        /* ----------------
-        *      initialize fields in ExprContext which don't change
-        *      in the course of the scan..
+        *      Check to see if we're still projecting out tuples from a previous
+        *      scan tuple (because there is a function-returning-set in the
+        *      projection expressions).  If so, try to project another one.
         * ----------------
         */
-       qual = node->plan.qual;
-       econtext->ecxt_relation = scanstate->css_currentRelation;
-       econtext->ecxt_relid = node->scanrelid;
-
        if (scanstate->cstate.cs_TupFromTlist)
        {
                projInfo = scanstate->cstate.cs_ProjInfo;
                resultSlot = ExecProject(projInfo, &isDone);
                if (!isDone)
                        return resultSlot;
+               /* Done with that source tuple... */
+               scanstate->cstate.cs_TupFromTlist = false;
        }
 
        /*
@@ -100,27 +91,23 @@ ExecScan(Scan *node,
         */
        for (;;)
        {
-               slot = (TupleTableSlot *) (*accessMtd) (node);
+               TupleTableSlot *slot;
+
+               slot = (*accessMtd) (node);
 
                /* ----------------
                 *      if the slot returned by the accessMtd contains
                 *      NULL, then it means there is nothing more to scan
-                *      so we just return the empty slot...
-                *
-                *      ... with invalid TupleDesc (not the same as in
-                *      projInfo->pi_slot) and break upper MergeJoin node.
-                *      New code below do what ExecProject() does.      - vadim 02/26/98
+                *      so we just return an empty slot, being careful to use
+                *      the projection result slot so it has correct tupleDesc.
                 * ----------------
                 */
                if (TupIsNull(slot))
                {
-                       scanstate->cstate.cs_TupFromTlist = false;
-                       resultSlot = scanstate->cstate.cs_ProjInfo->pi_slot;
-                       return (TupleTableSlot *)
-                               ExecStoreTuple(NULL,
-                                                          resultSlot,
-                                                          InvalidBuffer,
-                                                          true);
+                       return ExecStoreTuple(NULL,
+                                                                 scanstate->cstate.cs_ProjInfo->pi_slot,
+                                                                 InvalidBuffer,
+                                                                 true);
                }
 
                /* ----------------
@@ -131,22 +118,28 @@ ExecScan(Scan *node,
 
                /* ----------------
                 *      check that the current tuple satisfies the qual-clause
-                *      if our qualification succeeds then we
+                *      if our qualification succeeds then we may
                 *      leave the loop.
-                * ----------------
-                */
-
-               /*
-                * add a check for non-nil qual here to avoid a function call to
+                *
+                * check for non-nil qual here to avoid a function call to
                 * ExecQual() when the qual is nil ... saves only a few cycles,
                 * but they add up ...
+                * ----------------
                 */
                if (!qual || ExecQual(qual, econtext, false))
                        break;
+
+               /* ----------------
+                *      Tuple fails qual, so free per-tuple memory and try again.
+                * ----------------
+                */
+               ResetExprContext(econtext);
        }
 
        /* ----------------
-        *      form a projection tuple, store it in the result tuple
+        *      Found a satisfactory scan tuple.
+        *
+        *      Form a projection tuple, store it in the result tuple
         *      slot and return it.
         * ----------------
         */
index 578b8b806812a15bd9f7abaec82cf8a0ce57f7c9..37b092fc20f03201343eaa84e4b53619a41739b3 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.37 2000/04/12 17:15:08 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.38 2000/07/12 02:37:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -76,8 +76,7 @@
  *               by the access methods into the scan tuple slot.
  *
  *             - ExecSeqScan() calls ExecStoreTuple() to take the result
- *               tuple from ExecTargetList() and place it into the result tuple
- *               slot.
+ *               tuple from ExecProject() and place it into the result tuple slot.
  *
  *             - ExecutePlan() calls ExecRetrieve() which gets the tuple out of
  *               the slot passed to it by calling ExecFetchTuple().  this tuple
@@ -182,8 +181,8 @@ ExecCreateTupleTable(int initialSize)       /* initial number of slots in
 /* --------------------------------
  *             ExecDropTupleTable
  *
- *             This pfrees the storage assigned to the tuple table and
- *             optionally pfrees the contents of the table also.
+ *             This frees the storage used by the tuple table itself
+ *             and optionally frees the contents of the table also.
  *             It is expected that this routine be called by EndPlan().
  * --------------------------------
  */
@@ -239,7 +238,6 @@ ExecDropTupleTable(TupleTable table,        /* tuple table */
         */
        pfree(array);
        pfree(table);
-
 }
 
 
@@ -252,13 +250,12 @@ ExecDropTupleTable(TupleTable table,      /* tuple table */
  *
  *             This routine is used to reserve slots in the table for
  *             use by the various plan nodes.  It is expected to be
- *             called by the node init routines (ex: ExecInitNestLoop).
+ *             called by the node init routines (ex: ExecInitNestLoop)
  *             once per slot needed by the node.  Not all nodes need
  *             slots (some just pass tuples around).
  * --------------------------------
  */
-TupleTableSlot *                               /* return: the slot allocated in the tuple
-                                                                * table */
+TupleTableSlot *
 ExecAllocTableSlot(TupleTable table)
 {
        int                     slotnum;                /* new slot number */
@@ -283,22 +280,12 @@ ExecAllocTableSlot(TupleTable table)
         *      pointers into _freed_ memory.  This leads to bad ends.  We
         *      now count the number of slots we will need and create all the
         *      slots we will need ahead of time.  The if below should never
-        *      happen now.  Give a WARN if it does.  -mer 4 Aug 1992
+        *      happen now.  Fail if it does.  -mer 4 Aug 1992
         * ----------------
         */
        if (table->next >= table->size)
-       {
-
-               /*
-                * int newsize = NewTableSize(table->size);
-                *
-                * pfree(table->array); table->array = (Pointer) palloc(newsize *
-                * TableSlotSize); bzero(table->array, newsize * TableSlotSize);
-                * table->size =  newsize;
-                */
-               elog(NOTICE, "Plan requires more slots than are available");
-               elog(ERROR, "send mail to your local executor guru to fix this");
-       }
+               elog(ERROR, "Plan requires more slots than are available"
+                        "\n\tsend mail to your local executor guru to fix this");
 
        /* ----------------
         *      at this point, space in the table is guaranteed so we
@@ -427,7 +414,7 @@ ExecClearTuple(TupleTableSlot *slot)        /* slot in which to store tuple */
 
        slot->val = (HeapTuple) NULL;
 
-       slot->ttc_shouldFree = true;/* probably useless code... */
+       slot->ttc_shouldFree = true;    /* probably useless code... */
 
        /* ----------------
         *      Drop the pin on the referenced buffer, if there is one.
index a023405a2754be53532a77f0c1f4ba97ca75db3a..daa40dccf75e7c188b2ba7c95935949634a56d52 100644 (file)
@@ -1,22 +1,20 @@
 /*-------------------------------------------------------------------------
  *
  * execUtils.c
- *       miscellanious executor utility routines
+ *       miscellaneous executor utility routines
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.62 2000/07/05 23:11:14 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.63 2000/07/12 02:37:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * INTERFACE ROUTINES
- *             ExecAssignNodeBaseInfo  \
- *             ExecAssignDebugHooks     >      preforms misc work done in all the
- *             ExecAssignExprContext   /       init node routines.
+ *             ExecAssignExprContext   Common code for plan node init routines.
  *
  *             ExecGetTypeInfo                   |  old execCStructs interface
  *             ExecMakeTypeInfo                  |  code from the version 1
@@ -53,6 +51,7 @@
 #include "miscadmin.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
+#include "utils/memutils.h"
 #include "utils/relcache.h"
 #include "utils/syscache.h"
 
@@ -137,57 +136,104 @@ DisplayTupleCount(FILE *statfp)
 #endif
 
 /* ----------------------------------------------------------------
- *                              miscellanious init node support functions
+ *                              miscellaneous node-init support functions
  *
- *             ExecAssignNodeBaseInfo  - assigns the baseid field of the node
- *             ExecAssignDebugHooks    - assigns the node's debugging hooks
  *             ExecAssignExprContext   - assigns the node's expression context
  * ----------------------------------------------------------------
  */
 
 /* ----------------
- *             ExecAssignNodeBaseInfo
+ *             ExecAssignExprContext
+ *
+ *             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.
  *
- *             as it says, this assigns the baseid field of the node and
- *             increments the counter in the estate.  In addition, it initializes
- *             the base_parent field of the basenode.
+ * Note: we assume CurrentMemoryContext is the correct per-query context.
+ * This should be true during plan node initialization.
  * ----------------
  */
 void
-ExecAssignNodeBaseInfo(EState *estate, CommonState *cstate, Plan *parent)
+ExecAssignExprContext(EState *estate, CommonState *commonstate)
 {
-       int                     baseId;
+       ExprContext *econtext = makeNode(ExprContext);
 
-       baseId = estate->es_BaseId;
-       cstate->cs_base_id = baseId;
-       estate->es_BaseId = baseId + 1;
+       econtext->ecxt_scantuple = NULL;
+       econtext->ecxt_innertuple = NULL;
+       econtext->ecxt_outertuple = NULL;
+       econtext->ecxt_per_query_memory = CurrentMemoryContext;
+       /*
+        * Create working memory for expression evaluation in this context.
+        */
+       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_range_table = estate->es_range_table;
+
+       commonstate->cs_ExprContext = econtext;
 }
 
 /* ----------------
- *             ExecAssignExprContext
+ *             MakeExprContext
  *
- *             This initializes the ExprContext field.  It is only necessary
- *             to do this for nodes which use ExecQual or ExecTargetList
- *             because those routines depend on econtext.      Other nodes which
- *             dont have to evaluate expressions don't need to do this.
+ *             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.
  * ----------------
  */
-void
-ExecAssignExprContext(EState *estate, CommonState *commonstate)
+ExprContext *
+MakeExprContext(TupleTableSlot *slot,
+                               MemoryContext queryContext)
 {
-       ExprContext *econtext;
+       ExprContext *econtext = makeNode(ExprContext);
 
-       econtext = makeNode(ExprContext);
-       econtext->ecxt_scantuple = NULL;        /* scan tuple slot */
-       econtext->ecxt_innertuple = NULL;       /* inner tuple slot */
-       econtext->ecxt_outertuple = NULL;       /* outer tuple slot */
-       econtext->ecxt_relation = NULL;         /* relation */
-       econtext->ecxt_relid = 0;       /* relid */
-       econtext->ecxt_param_list_info = estate->es_param_list_info;
-       econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
-       econtext->ecxt_range_table = estate->es_range_table;            /* range table */
+       econtext->ecxt_scantuple = slot;
+       econtext->ecxt_innertuple = NULL;
+       econtext->ecxt_outertuple = NULL;
+       econtext->ecxt_per_query_memory = queryContext;
+       /*
+        * We make the temporary context a child of current working context,
+        * not of the specified queryContext.  This seems reasonable but I'm
+        * not totally sure about it...
+        *
+        * Expression contexts made via this routine typically don't live long
+        * enough to get reset, so specify a minsize of 0.  That avoids alloc'ing
+        * any memory in the common case where expr eval doesn't use any.
+        */
+       econtext->ecxt_per_tuple_memory =
+               AllocSetContextCreate(CurrentMemoryContext,
+                                                         "TempExprContext",
+                                                         0,
+                                                         ALLOCSET_DEFAULT_INITSIZE,
+                                                         ALLOCSET_DEFAULT_MAXSIZE);
+       econtext->ecxt_param_exec_vals = NULL;
+       econtext->ecxt_param_list_info = NULL;
+       econtext->ecxt_aggvalues = NULL;
+       econtext->ecxt_aggnulls = NULL;
+       econtext->ecxt_range_table = NIL;
+
+       return econtext;
+}
 
-       commonstate->cs_ExprContext = 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!
+ */
+void
+FreeExprContext(ExprContext *econtext)
+{
+       MemoryContextDelete(econtext->ecxt_per_tuple_memory);
+       pfree(econtext);
 }
 
 /* ----------------------------------------------------------------
@@ -390,6 +436,7 @@ ExecFreeExprContext(CommonState *commonstate)
         *      clean up memory used.
         * ----------------
         */
+       MemoryContextDelete(econtext->ecxt_per_tuple_memory);
        pfree(econtext);
        commonstate->cs_ExprContext = NULL;
 }
@@ -398,6 +445,7 @@ ExecFreeExprContext(CommonState *commonstate)
  *             ExecFreeTypeInfo
  * ----------------
  */
+#ifdef NOT_USED
 void
 ExecFreeTypeInfo(CommonState *commonstate)
 {
@@ -414,6 +462,7 @@ ExecFreeTypeInfo(CommonState *commonstate)
        FreeTupleDesc(tupDesc);
        commonstate->cs_ResultTupleSlot->ttc_tupleDescriptor = NULL;
 }
+#endif
 
 /* ----------------------------------------------------------------
  *             the following scan type support functions are for
@@ -974,8 +1023,8 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
                if (predicate != NULL)
                {
                        if (econtext == NULL)
-                               econtext = makeNode(ExprContext);
-                       econtext->ecxt_scantuple = slot;
+                               econtext = MakeExprContext(slot,
+                                                                                  TransactionCommandContext);
 
                        /* Skip this index-update if the predicate isn't satisfied */
                        if (!ExecQual((List *) predicate, econtext, false))
@@ -1023,7 +1072,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
                        pfree(result);
        }
        if (econtext != NULL)
-               pfree(econtext);
+               FreeExprContext(econtext);
 }
 
 void
index 6d8d93a47f1235c78782b12f889fef9f70ef66ec..a92811d0342a0409d6f6c2c6a409c09ec53e29d9 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.35 2000/06/28 03:31:33 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.36 2000/07/12 02:37:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -57,20 +57,18 @@ ProjectAttribute(TupleDesc TD,
                                 HeapTuple tup,
                                 bool *isnullP)
 {
-       Datum           val,
-                               valueP;
+       Datum           val;
        Var                *attrVar = (Var *) tlist->expr;
        AttrNumber      attrno = attrVar->varattno;
 
        val = heap_getattr(tup, attrno, TD, isnullP);
+
        if (*isnullP)
-               return (Datum) NULL;
+               return (Datum) 0;
 
-       valueP = datumCopy(val,
-                                          TD->attrs[attrno - 1]->atttypid,
-                                          TD->attrs[attrno - 1]->attbyval,
-                                          (Size) TD->attrs[attrno - 1]->attlen);
-       return valueP;
+       return datumCopy(val,
+                                        TD->attrs[attrno - 1]->attbyval,
+                                        TD->attrs[attrno - 1]->attlen);
 }
 
 static execution_state *
@@ -351,10 +349,18 @@ postquel_function(FunctionCallInfo fcinfo,
                                  List *func_tlist,
                                  bool *isDone)
 {
+       MemoryContext oldcontext;
        execution_state *es;
        Datum           result = 0;
        CommandId       savedId;
 
+       /*
+        * Switch to context in which the fcache lives.  This ensures that
+        * parsetrees, plans, etc, will have sufficient lifetime.  The
+        * sub-executor is responsible for deleting per-tuple information.
+        */
+       oldcontext = MemoryContextSwitchTo(fcache->fcacheCxt);
+
        /*
         * Before we start do anything we must save CurrentScanCommandId to
         * restore it before return to upper Executor. Also, we have to set
@@ -416,6 +422,7 @@ postquel_function(FunctionCallInfo fcinfo,
                 * Let caller know we're finished.
                 */
                *isDone = true;
+               MemoryContextSwitchTo(oldcontext);
                return (fcache->oneResult) ? result : (Datum) NULL;
        }
 
@@ -426,5 +433,8 @@ postquel_function(FunctionCallInfo fcinfo,
        Assert(LAST_POSTQUEL_COMMAND(es));
 
        *isDone = false;
+
+       MemoryContextSwitchTo(oldcontext);
+
        return result;
 }
index 0289cf45bd3b4ebff487abbf04a70c965279492a..1ac5c3c9e21e53c88e048afaeb2d50c39ccfbf38 100644 (file)
@@ -32,7 +32,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.68 2000/06/28 03:31:33 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.69 2000/07/12 02:37:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -50,6 +50,7 @@
 #include "parser/parse_type.h"
 #include "utils/syscache.h"
 #include "utils/tuplesort.h"
+#include "utils/datum.h"
 
 /*
  * AggStatePerAggData - per-aggregate working state for the Agg scan
@@ -101,13 +102,15 @@ typedef struct AggStatePerAggData
                                initValue2IsNull;
 
        /*
-        * We need the len and byval info for the agg's input and transition
-        * data types in order to know how to copy/delete values.
+        * We need the len and byval info for the agg's input, result, and
+        * transition data types in order to know how to copy/delete values.
         */
        int                     inputtypeLen,
+                               resulttypeLen,
                                transtype1Len,
                                transtype2Len;
        bool            inputtypeByVal,
+                               resulttypeByVal,
                                transtype1ByVal,
                                transtype2ByVal;
 
@@ -143,13 +146,16 @@ typedef struct AggStatePerAggData
 static void initialize_aggregate(AggStatePerAgg peraggstate);
 static void advance_transition_functions(AggStatePerAgg peraggstate,
                                                         Datum newVal, bool isNull);
+static void process_sorted_aggregate(AggState *aggstate,
+                                                                        AggStatePerAgg peraggstate);
 static void finalize_aggregate(AggStatePerAgg peraggstate,
                                   Datum *resultVal, bool *resultIsNull);
-static Datum copyDatum(Datum val, int typLen, bool typByVal);
 
 
 /*
  * Initialize one aggregate for a new set of input values.
+ *
+ * When called, CurrentMemoryContext should be the per-query context.
  */
 static void
 initialize_aggregate(AggStatePerAgg peraggstate)
@@ -177,23 +183,14 @@ initialize_aggregate(AggStatePerAgg peraggstate)
 
        /*
         * (Re)set value1 and value2 to their initial values.
+        *
+        * Note that when the initial values are pass-by-ref, we just reuse
+        * them without copying for each group.  Hence, transition function
+        * had better not scribble on its input!
         */
-       if (OidIsValid(peraggstate->xfn1_oid) &&
-               !peraggstate->initValue1IsNull)
-               peraggstate->value1 = copyDatum(peraggstate->initValue1,
-                                                                               peraggstate->transtype1Len,
-                                                                               peraggstate->transtype1ByVal);
-       else
-               peraggstate->value1 = (Datum) NULL;
+       peraggstate->value1 = peraggstate->initValue1;
        peraggstate->value1IsNull = peraggstate->initValue1IsNull;
-
-       if (OidIsValid(peraggstate->xfn2_oid) &&
-               !peraggstate->initValue2IsNull)
-               peraggstate->value2 = copyDatum(peraggstate->initValue2,
-                                                                               peraggstate->transtype2Len,
-                                                                               peraggstate->transtype2ByVal);
-       else
-               peraggstate->value2 = (Datum) NULL;
+       peraggstate->value2 = peraggstate->initValue2;
        peraggstate->value2IsNull = peraggstate->initValue2IsNull;
 
        /* ------------------------------------------
@@ -211,6 +208,9 @@ initialize_aggregate(AggStatePerAgg peraggstate)
 /*
  * Given a new input value, advance the transition functions of an aggregate.
  *
+ * When called, CurrentMemoryContext should be the context we want transition
+ * function results to be delivered into on this cycle.
+ *
  * Note: if the agg does not have usenulls set, null inputs will be filtered
  * out before reaching here.
  */
@@ -237,12 +237,13 @@ advance_transition_functions(AggStatePerAgg peraggstate,
                         * XXX We assume, without having checked, that the agg's input
                         * type is binary-compatible with its transtype1!
                         *
-                        * We have to copy the datum since the tuple from which it came
+                        * We had better copy the datum if it is pass-by-ref, since
+                        * the given pointer may be pointing into a scan tuple that
                         * will be freed on the next iteration of the scan.
                         */
-                       peraggstate->value1 = copyDatum(newVal,
-                                                                                       peraggstate->transtype1Len,
-                                                                                       peraggstate->transtype1ByVal);
+                       peraggstate->value1 = datumCopy(newVal,
+                                                                                       peraggstate->transtype1ByVal,
+                                                                                       peraggstate->transtype1Len);
                        peraggstate->value1IsNull = false;
                        peraggstate->noInitValue = false;
                }
@@ -264,8 +265,18 @@ advance_transition_functions(AggStatePerAgg peraggstate,
                        }
                        else
                                newVal = FunctionCallInvoke(&fcinfo);
-                       if (!peraggstate->transtype1ByVal && !peraggstate->value1IsNull)
-                               pfree(DatumGetPointer(peraggstate->value1));
+                       /*
+                        * If the transition function was uncooperative, it may have
+                        * given us a pass-by-ref result that points at the scan tuple
+                        * or the prior-cycle working memory.  Copy it into the active
+                        * context if it doesn't look right.
+                        */
+                       if (!peraggstate->transtype1ByVal && !fcinfo.isnull &&
+                               ! MemoryContextContains(CurrentMemoryContext,
+                                                                               DatumGetPointer(newVal)))
+                               newVal = datumCopy(newVal,
+                                                                  peraggstate->transtype1ByVal,
+                                                                  peraggstate->transtype1Len);
                        peraggstate->value1 = newVal;
                        peraggstate->value1IsNull = fcinfo.isnull;
                }
@@ -287,70 +298,116 @@ advance_transition_functions(AggStatePerAgg peraggstate,
                }
                else
                        newVal = FunctionCallInvoke(&fcinfo);
-               if (!peraggstate->transtype2ByVal && !peraggstate->value2IsNull)
-                       pfree(DatumGetPointer(peraggstate->value2));
+               /*
+                * If the transition function was uncooperative, it may have
+                * given us a pass-by-ref result that points at the scan tuple
+                * or the prior-cycle working memory.  Copy it into the active
+                * context if it doesn't look right.
+                */
+               if (!peraggstate->transtype2ByVal && !fcinfo.isnull &&
+                       ! MemoryContextContains(CurrentMemoryContext,
+                                                                       DatumGetPointer(newVal)))
+                       newVal = datumCopy(newVal,
+                                                          peraggstate->transtype2ByVal,
+                                                          peraggstate->transtype2Len);
                peraggstate->value2 = newVal;
                peraggstate->value2IsNull = fcinfo.isnull;
        }
 }
 
 /*
- * Compute the final value of one aggregate.
+ * Run the transition functions for a DISTINCT aggregate.  This is called
+ * after we have completed entering all the input values into the sort
+ * object.  We complete the sort, read out the value in sorted order, and
+ * run the transition functions on each non-duplicate value.
+ *
+ * When called, CurrentMemoryContext should be the per-query context.
  */
 static void
-finalize_aggregate(AggStatePerAgg peraggstate,
-                                  Datum *resultVal, bool *resultIsNull)
+process_sorted_aggregate(AggState *aggstate,
+                                                AggStatePerAgg peraggstate)
 {
-       Aggref                             *aggref = peraggstate->aggref;
-       FunctionCallInfoData    fcinfo;
+       Datum           oldVal = (Datum) 0;
+       bool            haveOldVal = false;
+       MemoryContext oldContext;
+       Datum           newVal;
+       bool            isNull;
 
-       MemSet(&fcinfo, 0, sizeof(fcinfo));
+       tuplesort_performsort(peraggstate->sortstate);
 
        /*
-        * If it's a DISTINCT aggregate, all we've done so far is to stuff the
-        * input values into the sort object.  Complete the sort, then run the
-        * transition functions on the non-duplicate values.  Note that
-        * DISTINCT always suppresses nulls, per SQL spec, regardless of
-        * usenulls.
+        * Note: if input type is pass-by-ref, the datums returned by the sort
+        * are freshly palloc'd in the per-query context, so we must be careful
+        * to pfree them when they are no longer needed.
         */
-       if (aggref->aggdistinct)
+
+       while (tuplesort_getdatum(peraggstate->sortstate, true,
+                                                         &newVal, &isNull))
        {
-               Datum           oldVal = (Datum) 0;
-               bool            haveOldVal = false;
-               Datum           newVal;
-               bool            isNull;
-
-               tuplesort_performsort(peraggstate->sortstate);
-               while (tuplesort_getdatum(peraggstate->sortstate, true,
-                                                                 &newVal, &isNull))
+               /*
+                * DISTINCT always suppresses nulls, per SQL spec, regardless of
+                * the aggregate's usenulls setting.
+                */
+               if (isNull)
+                       continue;
+               /*
+                * Clear and select the current working context for evaluation of
+                * the equality function and transition functions.
+                */
+               MemoryContextReset(aggstate->agg_cxt[aggstate->which_cxt]);
+               oldContext =
+                       MemoryContextSwitchTo(aggstate->agg_cxt[aggstate->which_cxt]);
+
+               if (haveOldVal &&
+                       DatumGetBool(FunctionCall2(&peraggstate->equalfn,
+                                                                          oldVal, newVal)))
+               {
+                       /* equal to prior, so forget this one */
+                       if (!peraggstate->inputtypeByVal)
+                               pfree(DatumGetPointer(newVal));
+                       /* note we do NOT flip contexts in this case... */
+               }
+               else
                {
-                       if (isNull)
-                               continue;
-                       if (haveOldVal)
-                       {
-                               if (DatumGetBool(FunctionCall2(&peraggstate->equalfn,
-                                                                                          oldVal, newVal)))
-                               {
-                                       /* equal to prior, so forget this one */
-                                       if (!peraggstate->inputtypeByVal)
-                                               pfree(DatumGetPointer(newVal));
-                                       continue;
-                               }
-                       }
                        advance_transition_functions(peraggstate, newVal, false);
+                       /*
+                        * Make the other context current so that this transition
+                        * result is preserved.
+                        */
+                       aggstate->which_cxt = 1 - aggstate->which_cxt;
+                       /* forget the old value, if any */
                        if (haveOldVal && !peraggstate->inputtypeByVal)
                                pfree(DatumGetPointer(oldVal));
                        oldVal = newVal;
                        haveOldVal = true;
                }
-               if (haveOldVal && !peraggstate->inputtypeByVal)
-                       pfree(DatumGetPointer(oldVal));
-               tuplesort_end(peraggstate->sortstate);
-               peraggstate->sortstate = NULL;
+
+               MemoryContextSwitchTo(oldContext);
        }
 
+       if (haveOldVal && !peraggstate->inputtypeByVal)
+               pfree(DatumGetPointer(oldVal));
+
+       tuplesort_end(peraggstate->sortstate);
+       peraggstate->sortstate = NULL;
+}
+
+/*
+ * Compute the final value of one aggregate.
+ *
+ * When called, CurrentMemoryContext should be the context where we want
+ * final values delivered (ie, the per-output-tuple expression context).
+ */
+static void
+finalize_aggregate(AggStatePerAgg peraggstate,
+                                  Datum *resultVal, bool *resultIsNull)
+{
+       FunctionCallInfoData    fcinfo;
+
+       MemSet(&fcinfo, 0, sizeof(fcinfo));
+
        /*
-        * Now apply the agg's finalfn, or substitute the appropriate
+        * Apply the agg's finalfn, or substitute the appropriate
         * transition value if there is no finalfn.
         *
         * XXX For now, only apply finalfn if we got at least one non-null input
@@ -403,35 +460,27 @@ finalize_aggregate(AggStatePerAgg peraggstate,
                /* Return value1 */
                *resultVal = peraggstate->value1;
                *resultIsNull = peraggstate->value1IsNull;
-               /* prevent pfree below */
-               peraggstate->value1IsNull = true;
        }
        else if (OidIsValid(peraggstate->xfn2_oid))
        {
                /* Return value2 */
                *resultVal = peraggstate->value2;
                *resultIsNull = peraggstate->value2IsNull;
-               /* prevent pfree below */
-               peraggstate->value2IsNull = true;
        }
        else
                elog(ERROR, "ExecAgg: no valid transition functions??");
-
        /*
-        * Release any per-group working storage, unless we're passing it back
-        * as the result of the aggregate.
+        * If result is pass-by-ref, make sure it is in the right context.
         */
-       if (OidIsValid(peraggstate->xfn1_oid) &&
-               !peraggstate->value1IsNull &&
-               !peraggstate->transtype1ByVal)
-               pfree(DatumGetPointer(peraggstate->value1));
-
-       if (OidIsValid(peraggstate->xfn2_oid) &&
-               !peraggstate->value2IsNull &&
-               !peraggstate->transtype2ByVal)
-               pfree(DatumGetPointer(peraggstate->value2));
+       if (!peraggstate->resulttypeByVal && ! *resultIsNull &&
+               ! MemoryContextContains(CurrentMemoryContext,
+                                                               DatumGetPointer(*resultVal)))
+               *resultVal = datumCopy(*resultVal,
+                                                          peraggstate->resulttypeByVal,
+                                                          peraggstate->resulttypeLen);
 }
 
+
 /* ---------------------------------------
  *
  * ExecAgg -
@@ -461,6 +510,7 @@ ExecAgg(Agg *node)
        Datum      *aggvalues;
        bool       *aggnulls;
        AggStatePerAgg peragg;
+       MemoryContext oldContext;
        TupleTableSlot *resultSlot;
        HeapTuple       inputTuple;
        int                     aggno;
@@ -481,14 +531,18 @@ ExecAgg(Agg *node)
        peragg = aggstate->peragg;
 
        /*
-        * We loop retrieving groups until we find one matching
-        * node->plan.qual
+        * We loop retrieving groups until we find one matching node->plan.qual
         */
        do
        {
                if (aggstate->agg_done)
                        return NULL;
 
+               /*
+                * Clear the per-output-tuple context for each group
+                */
+               MemoryContextReset(aggstate->tup_cxt);
+
                /*
                 * Initialize working state for a new input tuple group
                 */
@@ -514,6 +568,17 @@ ExecAgg(Agg *node)
                                break;
                        econtext->ecxt_scantuple = outerslot;
 
+                       /*
+                        * Clear and select the current working context for evaluation
+                        * of the input expressions and transition functions at this
+                        * input tuple.
+                        */
+                       econtext->ecxt_per_tuple_memory =
+                               aggstate->agg_cxt[aggstate->which_cxt];
+                       ResetExprContext(econtext);
+                       oldContext =
+                               MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
+
                        for (aggno = 0; aggno < aggstate->numaggs; aggno++)
                        {
                                AggStatePerAgg peraggstate = &peragg[aggno];
@@ -527,13 +592,26 @@ ExecAgg(Agg *node)
                                        continue;       /* ignore this tuple for this agg */
 
                                if (aggref->aggdistinct)
+                               {
+                                       /* putdatum has to be called in per-query context */
+                                       MemoryContextSwitchTo(oldContext);
                                        tuplesort_putdatum(peraggstate->sortstate,
                                                                           newVal, isNull);
+                                       MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
+                               }
                                else
                                        advance_transition_functions(peraggstate,
                                                                                                 newVal, isNull);
                        }
 
+                       /*
+                        * Make the other context current so that these transition
+                        * results are preserved.
+                        */
+                       aggstate->which_cxt = 1 - aggstate->which_cxt;
+
+                       MemoryContextSwitchTo(oldContext);
+
                        /*
                         * Keep a copy of the first input tuple for the projection.
                         * (We only need one since only the GROUP BY columns in it can
@@ -546,14 +624,38 @@ ExecAgg(Agg *node)
 
                /*
                 * Done scanning input tuple group. Finalize each aggregate
-                * calculation.
+                * calculation, and stash results in the per-output-tuple context.
+                *
+                * This is a bit tricky when there are both DISTINCT and plain
+                * aggregates: we must first finalize all the plain aggs and then all
+                * the DISTINCT ones.  This is needed because the last transition
+                * values for the plain aggs are stored in the not-current working
+                * context, and we have to evaluate those aggs (and stash the results
+                * in the output tup_cxt!) before we start flipping contexts again
+                * in process_sorted_aggregate.
                 */
+               oldContext = MemoryContextSwitchTo(aggstate->tup_cxt);
+               for (aggno = 0; aggno < aggstate->numaggs; aggno++)
+               {
+                       AggStatePerAgg peraggstate = &peragg[aggno];
+
+                       if (! peraggstate->aggref->aggdistinct)
+                               finalize_aggregate(peraggstate,
+                                                                  &aggvalues[aggno], &aggnulls[aggno]);
+               }
+               MemoryContextSwitchTo(oldContext);
                for (aggno = 0; aggno < aggstate->numaggs; aggno++)
                {
                        AggStatePerAgg peraggstate = &peragg[aggno];
 
-                       finalize_aggregate(peraggstate,
-                                                          &aggvalues[aggno], &aggnulls[aggno]);
+                       if (peraggstate->aggref->aggdistinct)
+                       {
+                               process_sorted_aggregate(aggstate, peraggstate);
+                               oldContext = MemoryContextSwitchTo(aggstate->tup_cxt);
+                               finalize_aggregate(peraggstate,
+                                                                  &aggvalues[aggno], &aggnulls[aggno]);
+                               MemoryContextSwitchTo(oldContext);
+                       }
                }
 
                /*
@@ -584,7 +686,7 @@ ExecAgg(Agg *node)
                        /*
                         * If inputtuple==NULL (ie, the outerPlan didn't return
                         * anything), create a dummy all-nulls input tuple for use by
-                        * execProject. 99.44% of the time this is a waste of cycles,
+                        * ExecProject. 99.44% of the time this is a waste of cycles,
                         * because ordinarily the projected output tuple's targetlist
                         * cannot contain any direct (non-aggregated) references to
                         * input columns, so the dummy tuple will not be referenced.
@@ -619,7 +721,8 @@ ExecAgg(Agg *node)
 
                /*
                 * Store the representative input tuple in the tuple table slot
-                * reserved for it.
+                * reserved for it.  The tuple will be deleted when it is cleared
+                * from the slot.
                 */
                ExecStoreTuple(inputTuple,
                                           aggstate->csstate.css_ScanTupleSlot,
@@ -627,6 +730,11 @@ ExecAgg(Agg *node)
                                           true);
                econtext->ecxt_scantuple = aggstate->csstate.css_ScanTupleSlot;
 
+               /*
+                * Do projection and qual check in the per-output-tuple context.
+                */
+               econtext->ecxt_per_tuple_memory = aggstate->tup_cxt;
+
                /*
                 * Form a projection tuple using the aggregate results and the
                 * representative input tuple.  Store it in the result tuple slot.
@@ -701,11 +809,33 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
        }
 
        /*
-        * assign node's base id and create expression context
+        * Create expression context
         */
-       ExecAssignNodeBaseInfo(estate, &aggstate->csstate.cstate, (Plan *) parent);
        ExecAssignExprContext(estate, &aggstate->csstate.cstate);
 
+       /*
+        * We actually need three separate expression memory contexts: one
+        * for calculating per-output-tuple values (ie, the finished aggregate
+        * results), and two that we ping-pong between for per-input-tuple
+        * evaluation of input expressions and transition functions.  The
+        * context made by ExecAssignExprContext() is used as the output context.
+        */
+       aggstate->tup_cxt =
+               aggstate->csstate.cstate.cs_ExprContext->ecxt_per_tuple_memory;
+       aggstate->agg_cxt[0] = 
+               AllocSetContextCreate(CurrentMemoryContext,
+                                                         "AggExprContext1",
+                                                         ALLOCSET_DEFAULT_MINSIZE,
+                                                         ALLOCSET_DEFAULT_INITSIZE,
+                                                         ALLOCSET_DEFAULT_MAXSIZE);
+       aggstate->agg_cxt[1] = 
+               AllocSetContextCreate(CurrentMemoryContext,
+                                                         "AggExprContext2",
+                                                         ALLOCSET_DEFAULT_MINSIZE,
+                                                         ALLOCSET_DEFAULT_INITSIZE,
+                                                         ALLOCSET_DEFAULT_MAXSIZE);
+       aggstate->which_cxt = 0;
+
 #define AGG_NSLOTS 2
 
        /*
@@ -769,16 +899,20 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
                /* Fill in the peraggstate data */
                peraggstate->aggref = aggref;
 
-               aggTuple = SearchSysCacheTuple(AGGNAME,
-                                                                          PointerGetDatum(aggname),
-                                                                          ObjectIdGetDatum(aggref->basetype),
-                                                                          0, 0);
+               aggTuple = SearchSysCacheTupleCopy(AGGNAME,
+                                                                                  PointerGetDatum(aggname),
+                                                                                  ObjectIdGetDatum(aggref->basetype),
+                                                                                  0, 0);
                if (!HeapTupleIsValid(aggTuple))
                        elog(ERROR, "ExecAgg: cache lookup failed for aggregate %s(%s)",
                                 aggname,
                                 typeidTypeName(aggref->basetype));
                aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
 
+               typeInfo = typeidType(aggform->aggfinaltype);
+               peraggstate->resulttypeLen = typeLen(typeInfo);
+               peraggstate->resulttypeByVal = typeByVal(typeInfo);
+
                peraggstate->initValue1 =
                        AggNameGetInitVal(aggname,
                                                          aggform->aggbasetype,
@@ -846,6 +980,8 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
                        peraggstate->sortOperator = any_ordering_op(inputType);
                        peraggstate->sortstate = NULL;
                }
+
+               heap_freetuple(aggTuple);
        }
 
        return TRUE;
@@ -866,6 +1002,17 @@ ExecEndAgg(Agg *node)
        Plan       *outerPlan;
 
        ExecFreeProjectionInfo(&aggstate->csstate.cstate);
+       /*
+        * Make sure ExecFreeExprContext() frees the right expr context...
+        */
+       aggstate->csstate.cstate.cs_ExprContext->ecxt_per_tuple_memory =
+               aggstate->tup_cxt;
+       ExecFreeExprContext(&aggstate->csstate.cstate);
+       /*
+        * ... and I free the others.
+        */
+       MemoryContextDelete(aggstate->agg_cxt[0]);
+       MemoryContextDelete(aggstate->agg_cxt[1]);
 
        outerPlan = outerPlan(node);
        ExecEndNode(outerPlan, (Plan *) node);
@@ -890,28 +1037,4 @@ ExecReScanAgg(Agg *node, ExprContext *exprCtxt, Plan *parent)
         */
        if (((Plan *) node)->lefttree->chgParam == NULL)
                ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
-
-}
-
-
-/*
- * Helper routine to make a copy of a Datum.
- *
- * NB: input had better not be a NULL; might cause null-pointer dereference.
- */
-static Datum
-copyDatum(Datum val, int typLen, bool typByVal)
-{
-       if (typByVal)
-               return val;
-       else
-       {
-               char       *newVal;
-
-               if (typLen == -1)               /* variable length type? */
-                       typLen = VARSIZE((struct varlena *) DatumGetPointer(val));
-               newVal = (char *) palloc(typLen);
-               memcpy(newVal, DatumGetPointer(val), typLen);
-               return PointerGetDatum(newVal);
-       }
 }
index 5e34e806e32d3d43abc66118c1dca8beba2978e1..2b1eceb15d909b2aaad1b475bc43b9c6ace524b9 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.34 2000/06/17 21:48:49 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.35 2000/07/12 02:37:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -219,16 +219,12 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
        node->appendstate = appendstate;
 
        /* ----------------
-        *      Miscellanious initialization
-        *
-        *               +      assign node's base_id
-        *               +      assign debugging hooks
+        *      Miscellaneous initialization
         *
         *      Append plans don't have expression contexts because they
-        *      never call ExecQual or ExecTargetList.
+        *      never call ExecQual or ExecProject.
         * ----------------
         */
-       ExecAssignNodeBaseInfo(estate, &appendstate->cstate, parent);
 
 #define APPEND_NSLOTS 1
        /* ----------------
@@ -380,7 +376,7 @@ ExecCountSlotsAppend(Append *node)
  *
  *             Handles the iteration over the multiple scans.
  *
- *        NOTE: Can't call this ExecAppend, that name is used in execMain.l
+ *        NOTE: Can't call this ExecAppend, that name is used in execMain.
  * ----------------------------------------------------------------
  */
 TupleTableSlot *
index d1ae02616c1440493c9ab0eeca2f63c9504a83ab..8a445b53d4197944d0c7bea3eaec850147c79136 100644 (file)
@@ -15,7 +15,7 @@
  *       locate group boundaries.
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.36 2000/05/30 04:24:45 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.37 2000/07/12 02:37:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -68,13 +68,11 @@ ExecGroupEveryTuple(Group *node)
        EState     *estate;
        ExprContext *econtext;
        TupleDesc       tupdesc;
-
        HeapTuple       outerTuple = NULL;
        HeapTuple       firsttuple;
        TupleTableSlot *outerslot;
        ProjectionInfo *projInfo;
        TupleTableSlot *resultSlot;
-
        bool            isDone;
 
        /* ---------------------
@@ -84,14 +82,16 @@ ExecGroupEveryTuple(Group *node)
        grpstate = node->grpstate;
        if (grpstate->grp_done)
                return NULL;
-
        estate = node->plan.state;
-
        econtext = grpstate->csstate.cstate.cs_ExprContext;
-
        tupdesc = ExecGetScanType(&grpstate->csstate);
 
-       /* if we haven't returned first tuple of new group yet ... */
+       /*
+        *      We need not call ResetExprContext here because execTuplesMatch
+        *      will reset the per-tuple memory context once per input tuple.
+        */
+
+       /* if we haven't returned first tuple of a new group yet ... */
        if (grpstate->grp_useFirstTuple)
        {
                grpstate->grp_useFirstTuple = FALSE;
@@ -130,7 +130,8 @@ ExecGroupEveryTuple(Group *node)
                        if (!execTuplesMatch(firsttuple, outerTuple,
                                                                 tupdesc,
                                                                 node->numCols, node->grpColIdx,
-                                                                grpstate->eqfunctions))
+                                                                grpstate->eqfunctions,
+                                                                econtext->ecxt_per_tuple_memory))
                        {
 
                                /*
@@ -179,13 +180,11 @@ ExecGroupOneTuple(Group *node)
        EState     *estate;
        ExprContext *econtext;
        TupleDesc       tupdesc;
-
        HeapTuple       outerTuple = NULL;
        HeapTuple       firsttuple;
        TupleTableSlot *outerslot;
        ProjectionInfo *projInfo;
        TupleTableSlot *resultSlot;
-
        bool            isDone;
 
        /* ---------------------
@@ -195,13 +194,15 @@ ExecGroupOneTuple(Group *node)
        grpstate = node->grpstate;
        if (grpstate->grp_done)
                return NULL;
-
        estate = node->plan.state;
-
        econtext = node->grpstate->csstate.cstate.cs_ExprContext;
-
        tupdesc = ExecGetScanType(&grpstate->csstate);
 
+       /*
+        *      We need not call ResetExprContext here because execTuplesMatch
+        *      will reset the per-tuple memory context once per input tuple.
+        */
+
        firsttuple = grpstate->grp_firstTuple;
        if (firsttuple == NULL)
        {
@@ -237,7 +238,8 @@ ExecGroupOneTuple(Group *node)
                if (!execTuplesMatch(firsttuple, outerTuple,
                                                         tupdesc,
                                                         node->numCols, node->grpColIdx,
-                                                        grpstate->eqfunctions))
+                                                        grpstate->eqfunctions,
+                                                        econtext->ecxt_per_tuple_memory))
                        break;
        }
 
@@ -296,10 +298,8 @@ ExecInitGroup(Group *node, EState *estate, Plan *parent)
        grpstate->grp_firstTuple = NULL;
 
        /*
-        * assign node's base id and create expression context
+        * create expression context
         */
-       ExecAssignNodeBaseInfo(estate, &grpstate->csstate.cstate,
-                                                  (Plan *) parent);
        ExecAssignExprContext(estate, &grpstate->csstate.cstate);
 
 #define GROUP_NSLOTS 2
@@ -360,6 +360,7 @@ ExecEndGroup(Group *node)
        grpstate = node->grpstate;
 
        ExecFreeProjectionInfo(&grpstate->csstate.cstate);
+       ExecFreeExprContext(&grpstate->csstate.cstate);
 
        outerPlan = outerPlan(node);
        ExecEndNode(outerPlan, (Plan *) node);
@@ -406,6 +407,9 @@ ExecReScanGroup(Group *node, ExprContext *exprCtxt, Plan *parent)
  * numCols: the number of attributes to be examined
  * matchColIdx: array of attribute column numbers
  * eqFunctions: array of fmgr lookup info for the equality functions to use
+ * evalContext: short-term memory context for executing the functions
+ *
+ * NB: evalContext is reset each time!
  */
 bool
 execTuplesMatch(HeapTuple tuple1,
@@ -413,16 +417,25 @@ execTuplesMatch(HeapTuple tuple1,
                                TupleDesc tupdesc,
                                int numCols,
                                AttrNumber *matchColIdx,
-                               FmgrInfo *eqfunctions)
+                               FmgrInfo *eqfunctions,
+                               MemoryContext evalContext)
 {
+       MemoryContext oldContext;
+       bool            result;
        int                     i;
 
+       /* Reset and switch into the temp context. */
+       MemoryContextReset(evalContext);
+       oldContext = MemoryContextSwitchTo(evalContext);
+
        /*
         * We cannot report a match without checking all the fields, but we
         * can report a non-match as soon as we find unequal fields.  So,
         * start comparing at the last field (least significant sort key).
         * That's the most likely to be different...
         */
+       result = true;
+
        for (i = numCols; --i >= 0;)
        {
                AttrNumber      att = matchColIdx[i];
@@ -442,7 +455,10 @@ execTuplesMatch(HeapTuple tuple1,
                                                         &isNull2);
 
                if (isNull1 != isNull2)
-                       return FALSE;           /* one null and one not; they aren't equal */
+               {
+                       result = false;         /* one null and one not; they aren't equal */
+                       break;
+               }
 
                if (isNull1)
                        continue;                       /* both are null, treat as equal */
@@ -451,10 +467,15 @@ execTuplesMatch(HeapTuple tuple1,
 
                if (! DatumGetBool(FunctionCall2(&eqfunctions[i],
                                                                                 attr1, attr2)))
-                       return FALSE;
+               {
+                       result = false;         /* they aren't equal */
+                       break;
+               }
        }
 
-       return TRUE;
+       MemoryContextSwitchTo(oldContext);
+
+       return result;
 }
 
 /*
index 34b0a269a5b2dd892ea75d6aaf2c8ffdfcc208c4..9c2d293858ca061c0fd3261bca58b93bb8141878 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
- *     $Id: nodeHash.c,v 1.48 2000/06/28 03:31:34 tgl Exp $
+ *     $Id: nodeHash.c,v 1.49 2000/07/12 02:37:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,7 +28,8 @@
 #include "executor/nodeHash.h"
 #include "executor/nodeHashjoin.h"
 #include "miscadmin.h"
-
+#include "parser/parse_expr.h"
+#include "parser/parse_type.h"
 
 static int     hashFunc(Datum key, int len, bool byVal);
 
@@ -45,7 +46,7 @@ ExecHash(Hash *node)
        EState     *estate;
        HashState  *hashstate;
        Plan       *outerNode;
-       Var                *hashkey;
+       Node       *hashkey;
        HashJoinTable hashtable;
        TupleTableSlot *slot;
        ExprContext *econtext;
@@ -139,12 +140,9 @@ ExecInitHash(Hash *node, EState *estate, Plan *parent)
        /* ----------------
         *      Miscellaneous initialization
         *
-        *               +      assign node's base_id
-        *               +      assign debugging hooks and
         *               +      create expression context for node
         * ----------------
         */
-       ExecAssignNodeBaseInfo(estate, &hashstate->cstate, parent);
        ExecAssignExprContext(estate, &hashstate->cstate);
 
        /* ----------------
@@ -204,6 +202,7 @@ ExecEndHash(Hash *node)
         * ----------------
         */
        ExecFreeProjectionInfo(&hashstate->cstate);
+       ExecFreeExprContext(&hashstate->cstate);
 
        /* ----------------
         *      shut down the subplan
@@ -236,6 +235,7 @@ ExecHashTableCreate(Hash *node)
        int                     totalbuckets;
        int                     bucketsize;
        int                     i;
+       Type            typeInfo;
        MemoryContext oldcxt;
 
        /* ----------------
@@ -346,6 +346,14 @@ ExecHashTableCreate(Hash *node)
        hashtable->innerBatchSize = NULL;
        hashtable->outerBatchSize = NULL;
 
+       /* ----------------
+        *      Get info about the datatype of the hash key.
+        * ----------------
+        */
+       typeInfo = typeidType(exprType(node->hashkey));
+       hashtable->typByVal = typeByVal(typeInfo);
+       hashtable->typLen = typeLen(typeInfo);
+
        /* ----------------
         *      Create temporary memory contexts in which to keep the hashtable
         *      working storage.  See notes in executor/hashjoin.h.
@@ -448,7 +456,7 @@ ExecHashTableDestroy(HashJoinTable hashtable)
 void
 ExecHashTableInsert(HashJoinTable hashtable,
                                        ExprContext *econtext,
-                                       Var *hashkey)
+                                       Node *hashkey)
 {
        int                     bucketno = ExecHashGetBucket(hashtable, econtext, hashkey);
        TupleTableSlot *slot = econtext->ecxt_innertuple;
@@ -508,43 +516,44 @@ ExecHashTableInsert(HashJoinTable hashtable,
 int
 ExecHashGetBucket(HashJoinTable hashtable,
                                  ExprContext *econtext,
-                                 Var *hashkey)
+                                 Node *hashkey)
 {
        int                     bucketno;
        Datum           keyval;
        bool            isNull;
+       bool            isDone;
 
        /* ----------------
         *      Get the join attribute value of the tuple
         *
-        * ...It's quick hack - use ExecEvalExpr instead of ExecEvalVar:
-        * hashkey may be T_ArrayRef, not just T_Var.           - vadim 04/22/97
+        *      We reset the eval context each time to avoid any possibility
+        *      of memory leaks in the hash function.
         * ----------------
         */
-       keyval = ExecEvalExpr((Node *) hashkey, econtext, &isNull, NULL);
+       ResetExprContext(econtext);
 
-       /*
-        * keyval could be null, so we better point it to something valid
-        * before trying to run hashFunc on it. --djm 8/17/96
-        */
-       if (isNull)
-       {
-               execConstByVal = 0;
-               execConstLen = 0;
-               keyval = (Datum) "";
-       }
+       keyval = ExecEvalExprSwitchContext(hashkey, econtext,
+                                                                          &isNull, &isDone);
 
        /* ------------------
         *      compute the hash function
         * ------------------
         */
-       bucketno = hashFunc(keyval, execConstLen, execConstByVal) % hashtable->totalbuckets;
+       if (isNull)
+       {
+               bucketno = 0;
+       }
+       else
+       {
+               bucketno = hashFunc(keyval, hashtable->typLen, hashtable->typByVal)
+                       % hashtable->totalbuckets;
+       }
 
 #ifdef HJDEBUG
        if (bucketno >= hashtable->nbuckets)
-               printf("hash(%d) = %d SAVED\n", keyval, bucketno);
+               printf("hash(%ld) = %d SAVED\n", (long) keyval, bucketno);
        else
-               printf("hash(%d) = %d\n", keyval, bucketno);
+               printf("hash(%ld) = %d\n", (long) keyval, bucketno);
 #endif
 
        return bucketno;
@@ -585,6 +594,9 @@ ExecScanHashBucket(HashJoinState *hjstate,
                                                                  false);               /* do not pfree this tuple */
                econtext->ecxt_innertuple = inntuple;
 
+               /* reset temp memory each time to avoid leaks from qual expression */
+               ResetExprContext(econtext);
+
                if (ExecQual(hjclauses, econtext, false))
                {
                        hjstate->hj_CurTuple = hashTuple;
index d1cb1fe242060d9b8f0263f358a9122a2c22499f..e136c13154165fc6edf8c0e04af32ae214b8761b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.30 2000/01/26 05:56:23 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.31 2000/07/12 02:37:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -51,13 +51,12 @@ ExecHashJoin(HashJoin *node)
        List       *qual;
        ScanDirection dir;
        TupleTableSlot *inntuple;
-       Var                *outerVar;
+       Node       *outerVar;
        ExprContext *econtext;
        HashJoinTable hashtable;
        HeapTuple       curtuple;
        TupleTableSlot *outerTupleSlot;
        TupleTableSlot *innerTupleSlot;
-       Var                *innerhashkey;
        int                     i;
        bool            hashPhaseDone;
 
@@ -73,7 +72,6 @@ ExecHashJoin(HashJoin *node)
        hashNode = (Hash *) innerPlan(node);
        outerNode = outerPlan(node);
        hashPhaseDone = node->hashdone;
-
        dir = estate->es_direction;
 
        /* -----------------
@@ -81,13 +79,21 @@ ExecHashJoin(HashJoin *node)
         * -----------------
         */
        hashtable = hjstate->hj_HashTable;
+       econtext = hjstate->jstate.cs_ExprContext;
 
-       /* --------------------
-        * initialize expression context
-        * --------------------
+       /* ----------------
+        *      Reset per-tuple memory context to free any expression evaluation
+        *      storage allocated in the previous tuple cycle.
+        * ----------------
         */
-       econtext = hjstate->jstate.cs_ExprContext;
+       ResetExprContext(econtext);
 
+       /* ----------------
+        *      Check to see if we're still projecting out tuples from a previous
+        *      join tuple (because there is a function-returning-set in the
+        *      projection expressions).  If so, try to project another one.
+        * ----------------
+        */
        if (hjstate->jstate.cs_TupFromTlist)
        {
                TupleTableSlot *result;
@@ -96,6 +102,8 @@ ExecHashJoin(HashJoin *node)
                result = ExecProject(hjstate->jstate.cs_ProjInfo, &isDone);
                if (!isDone)
                        return result;
+               /* Done with that source tuple... */
+               hjstate->jstate.cs_TupFromTlist = false;
        }
 
        /* ----------------
@@ -112,8 +120,7 @@ ExecHashJoin(HashJoin *node)
                         */
                        hashtable = ExecHashTableCreate(hashNode);
                        hjstate->hj_HashTable = hashtable;
-                       innerhashkey = hashNode->hashkey;
-                       hjstate->hj_InnerHashKey = innerhashkey;
+                       hjstate->hj_InnerHashKey = hashNode->hashkey;
 
                        /* ----------------
                         * execute the Hash node, to build the hash table
@@ -139,7 +146,7 @@ ExecHashJoin(HashJoin *node)
         * ----------------
         */
        outerTupleSlot = hjstate->jstate.cs_OuterTupleSlot;
-       outerVar = get_leftop(clause);
+       outerVar = (Node *) get_leftop(clause);
 
        for (;;)
        {
@@ -220,6 +227,10 @@ ExecHashJoin(HashJoin *node)
                                                                          InvalidBuffer,
                                                                          false);       /* don't pfree this tuple */
                        econtext->ecxt_innertuple = inntuple;
+
+                       /* reset temp memory each time to avoid leaks from qpqual */
+                       ResetExprContext(econtext);
+
                        /* ----------------
                         * if we pass the qual, then save state for next call and
                         * have ExecProject form the projection, store it
@@ -279,12 +290,9 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
        /* ----------------
         *      Miscellaneous initialization
         *
-        *               +      assign node's base_id
-        *               +      assign debugging hooks and
         *               +      create expression context for node
         * ----------------
         */
-       ExecAssignNodeBaseInfo(estate, &hjstate->jstate, parent);
        ExecAssignExprContext(estate, &hjstate->jstate);
 
 #define HASHJOIN_NSLOTS 2
@@ -343,10 +351,10 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
        hjstate->hj_HashTable = (HashJoinTable) NULL;
        hjstate->hj_CurBucketNo = 0;
        hjstate->hj_CurTuple = (HashJoinTuple) NULL;
-       hjstate->hj_InnerHashKey = (Var *) NULL;
+       hjstate->hj_InnerHashKey = (Node *) NULL;
 
        hjstate->jstate.cs_OuterTupleSlot = (TupleTableSlot *) NULL;
-       hjstate->jstate.cs_TupFromTlist = (bool) false;
+       hjstate->jstate.cs_TupFromTlist = false;
 
        return TRUE;
 }
@@ -396,6 +404,7 @@ ExecEndHashJoin(HashJoin *node)
         * ----------------
         */
        ExecFreeProjectionInfo(&hjstate->jstate);
+       ExecFreeExprContext(&hjstate->jstate);
 
        /* ----------------
         * clean up subtrees
@@ -510,7 +519,7 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
        BufFile    *innerFile;
        TupleTableSlot *slot;
        ExprContext *econtext;
-       Var                *innerhashkey;
+       Node       *innerhashkey;
 
        if (newbatch > 1)
        {
@@ -651,10 +660,10 @@ ExecReScanHashJoin(HashJoin *node, ExprContext *exprCtxt, Plan *parent)
 
        hjstate->hj_CurBucketNo = 0;
        hjstate->hj_CurTuple = (HashJoinTuple) NULL;
-       hjstate->hj_InnerHashKey = (Var *) NULL;
+       hjstate->hj_InnerHashKey = (Node *) NULL;
 
        hjstate->jstate.cs_OuterTupleSlot = (TupleTableSlot *) NULL;
-       hjstate->jstate.cs_TupFromTlist = (bool) false;
+       hjstate->jstate.cs_TupFromTlist = false;
 
        /*
         * if chgParam of subnodes is not null then plans will be re-scanned
index be5617d5ef41b50cc41e427eac4f5ead26541f57..0eb3b9f5ae9d8377cceec53da686bfba6cb1fd87 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.51 2000/06/15 04:09:52 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.52 2000/07/12 02:37:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -79,6 +79,7 @@ IndexNext(IndexScan *node)
        EState     *estate;
        CommonScanState *scanstate;
        IndexScanState *indexstate;
+       ExprContext *econtext;
        ScanDirection direction;
        Snapshot        snapshot;
        IndexScanDescPtr scanDescs;
@@ -89,7 +90,6 @@ IndexNext(IndexScan *node)
        TupleTableSlot *slot;
        Buffer          buffer = InvalidBuffer;
        int                     numIndices;
-
        bool            bBackward;
        int                     indexNumber;
 
@@ -112,6 +112,7 @@ IndexNext(IndexScan *node)
        scanDescs = indexstate->iss_ScanDescs;
        heapRelation = scanstate->css_currentRelation;
        numIndices = indexstate->iss_NumIndices;
+       econtext = scanstate->cstate.cs_ExprContext;
        slot = scanstate->css_ScanTupleSlot;
 
        /*
@@ -133,14 +134,15 @@ IndexNext(IndexScan *node)
                slot->val = estate->es_evTuple[node->scan.scanrelid - 1];
                slot->ttc_shouldFree = false;
 
-               scanstate->cstate.cs_ExprContext->ecxt_scantuple = slot;
+               econtext->ecxt_scantuple = slot;
 
                /* Does the tuple meet any of the OR'd indxqual conditions? */
+
+               ResetExprContext(econtext);
+
                foreach(qual, node->indxqualorig)
                {
-                       if (ExecQual((List *) lfirst(qual),
-                                                scanstate->cstate.cs_ExprContext,
-                                                false))
+                       if (ExecQual((List *) lfirst(qual), econtext, false))
                                break;
                }
                if (qual == NIL)                /* would not be returned by indices */
@@ -219,14 +221,13 @@ IndexNext(IndexScan *node)
                                 * and checking for failure with all previous
                                 * qualifications.
                                 */
-                               scanstate->cstate.cs_ExprContext->ecxt_scantuple = slot;
+                               econtext->ecxt_scantuple = slot;
+                               ResetExprContext(econtext);
                                qual = node->indxqualorig;
                                for (prev_index = 0; prev_index < indexstate->iss_IndexPtr;
                                         prev_index++)
                                {
-                                       if (ExecQual((List *) lfirst(qual),
-                                                                scanstate->cstate.cs_ExprContext,
-                                                                false))
+                                       if (ExecQual((List *) lfirst(qual), econtext, false))
                                        {
                                                prev_matches = true;
                                                break;
@@ -234,7 +235,7 @@ IndexNext(IndexScan *node)
                                        qual = lnext(qual);
                                }
                                if (!prev_matches)
-                                       return slot;/* OK to return tuple */
+                                       return slot; /* OK to return tuple */
                                /* Duplicate tuple, so drop it and loop back for another */
                                ExecClearTuple(slot);
                        }
@@ -284,7 +285,7 @@ ExecIndexScan(IndexScan *node)
         *      use IndexNext as access method
         * ----------------
         */
-       return ExecScan(&node->scan, IndexNext);
+       return ExecScan(&node->scan, (ExecScanAccessMtd) IndexNext);
 }
 
 /* ----------------------------------------------------------------
@@ -293,9 +294,8 @@ ExecIndexScan(IndexScan *node)
  *             Recalculates the value of the scan keys whose value depends on
  *             information known at runtime and rescans the indexed relation.
  *             Updating the scan key was formerly done separately in
- *             ExecUpdateIndexScanKeys. Integrating it into ReScan
- *             makes rescans of indices and
- *             relations/general streams more uniform.
+ *             ExecUpdateIndexScanKeys. Integrating it into ReScan makes
+ *             rescans of indices and relations/general streams more uniform.
  *
  * ----------------------------------------------------------------
  */
@@ -304,6 +304,7 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
 {
        EState     *estate;
        IndexScanState *indexstate;
+       ExprContext *econtext;
        ScanDirection direction;
        IndexScanDescPtr scanDescs;
        ScanKey    *scanKeys;
@@ -311,8 +312,7 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
        ScanKey         skey;
        int                     numIndices;
        int                     i;
-
-       Pointer    *runtimeKeyInfo;
+       int               **runtimeKeyInfo;
        int                *numScanKeys;
        List       *indxqual;
        List       *qual;
@@ -326,22 +326,34 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
        bool            isNull;
        bool            isDone;
 
-       indexstate = node->indxstate;
        estate = node->scan.plan.state;
+       indexstate = node->indxstate;
+       econtext = indexstate->iss_RuntimeContext; /* context for runtime keys */
        direction = estate->es_direction;
        numIndices = indexstate->iss_NumIndices;
        scanDescs = indexstate->iss_ScanDescs;
        scanKeys = indexstate->iss_ScanKeys;
-       runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;
+       runtimeKeyInfo = indexstate->iss_RuntimeKeyInfo;
        numScanKeys = indexstate->iss_NumScanKeys;
        indexstate->iss_IndexPtr = -1;
        if (ScanDirectionIsBackward(node->indxorderdir))
                indexstate->iss_IndexPtr = numIndices;
 
-       /* If we are being passed an outer tuple, save it for runtime key calc */
-       if (exprCtxt != NULL)
-               node->scan.scanstate->cstate.cs_ExprContext->ecxt_outertuple =
-                       exprCtxt->ecxt_outertuple;
+       if (econtext)
+       {
+               /*
+                * If we are being passed an outer tuple,
+                * save it for runtime key calc
+                */
+               if (exprCtxt != NULL)
+                       econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
+               /*
+                * Reset the runtime-key context so we don't leak memory as
+                * each outer tuple is scanned.  Note this assumes that we
+                * will recalculate *all* runtime keys on each call.
+                */
+               ResetExprContext(econtext);
+       }
 
        /* If this is re-scanning of PlanQual ... */
        if (estate->es_evTuple != NULL &&
@@ -364,7 +376,7 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
 
                if (runtimeKeyInfo)
                {
-                       run_keys = (int *) runtimeKeyInfo[i];
+                       run_keys = runtimeKeyInfo[i];
                        for (j = 0; j < n_keys; j++)
                        {
 
@@ -373,6 +385,13 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
                                 * expression and evaluate it with respect to the current
                                 * outer tuple.  We then stick the result into the scan
                                 * key.
+                                *
+                                * Note: the result of the eval could be a pass-by-ref
+                                * value that's stored in the outer scan's tuple, not in
+                                * econtext->ecxt_per_tuple_memory.  We assume that the
+                                * outer tuple will stay put throughout our scan.  If this
+                                * is wrong, we could copy the result into our context
+                                * explicitly, but I think that's not necessary...
                                 */
                                if (run_keys[j] != NO_OP)
                                {
@@ -385,10 +404,10 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
                                         * pass in isDone but ignore it.  We don't iterate in
                                         * quals
                                         */
-                                       scanvalue = (Datum)
-                                               ExecEvalExpr(scanexpr,
-                                                        node->scan.scanstate->cstate.cs_ExprContext,
-                                                                        &isNull, &isDone);
+                                       scanvalue = ExecEvalExprSwitchContext(scanexpr,
+                                                                                                                 econtext,
+                                                                                                                 &isNull,
+                                                                                                                 &isDone);
                                        scan_keys[j].sk_argument = scanvalue;
                                        if (isNull)
                                                scan_keys[j].sk_flags |= SK_ISNULL;
@@ -401,11 +420,6 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
                skey = scanKeys[i];
                index_rescan(scan, direction, skey);
        }
-       /* ----------------
-        *      perhaps return something meaningful
-        * ----------------
-        */
-       return;
 }
 
 /* ----------------------------------------------------------------
@@ -421,7 +435,7 @@ ExecEndIndexScan(IndexScan *node)
 {
        CommonScanState *scanstate;
        IndexScanState *indexstate;
-       Pointer    *runtimeKeyInfo;
+       int               **runtimeKeyInfo;
        ScanKey    *scanKeys;
        List       *indxqual;
        int                *numScanKeys;
@@ -431,7 +445,7 @@ ExecEndIndexScan(IndexScan *node)
        scanstate = node->scan.scanstate;
        indexstate = node->indxstate;
        indxqual = node->indxqual;
-       runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;
+       runtimeKeyInfo = indexstate->iss_RuntimeKeyInfo;
 
        /* ----------------
         *      extract information from the node
@@ -451,6 +465,9 @@ ExecEndIndexScan(IndexScan *node)
         * ----------------
         */
        ExecFreeProjectionInfo(&scanstate->cstate);
+       ExecFreeExprContext(&scanstate->cstate);
+       if (indexstate->iss_RuntimeContext)
+               FreeExprContext(indexstate->iss_RuntimeContext);
 
        /* ----------------
         *      close the heap and index relations
@@ -474,12 +491,7 @@ ExecEndIndexScan(IndexScan *node)
        {
                for (i = 0; i < numIndices; i++)
                {
-                       List       *qual;
-                       int                     n_keys;
-
-                       qual = nth(i, indxqual);
-                       n_keys = length(qual);
-                       if (n_keys > 0)
+                       if (runtimeKeyInfo[i] != NULL)
                                pfree(runtimeKeyInfo[i]);
                }
                pfree(runtimeKeyInfo);
@@ -491,7 +503,6 @@ ExecEndIndexScan(IndexScan *node)
         */
        ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
        ExecClearTuple(scanstate->css_ScanTupleSlot);
-/*       ExecClearTuple(scanstate->css_RawTupleSlot); */
 }
 
 /* ----------------------------------------------------------------
@@ -562,7 +573,7 @@ ExecIndexRestrPos(IndexScan *node)
  *
  * old comments
  *             Creates the run-time state information for the node and
- *             sets the relation id to contain relevant decriptors.
+ *             sets the relation id to contain relevant descriptors.
  *
  *             Parameters:
  *               node: IndexNode node produced by the planner.
@@ -583,19 +594,16 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
        int                *numScanKeys;
        RelationPtr relationDescs;
        IndexScanDescPtr scanDescs;
-       Pointer    *runtimeKeyInfo;
+       int               **runtimeKeyInfo;
        bool            have_runtime_keys;
        List       *rangeTable;
        RangeTblEntry *rtentry;
        Index           relid;
        Oid                     reloid;
-
        Relation        currentRelation;
        HeapScanDesc currentScanDesc;
        ScanDirection direction;
-       int                     baseid;
-
-       List       *execParam = NULL;
+       List       *execParam = NIL;
 
        /* ----------------
         *      assign execution state to node
@@ -610,25 +618,12 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
         * --------------------------------
         */
        scanstate = makeNode(CommonScanState);
-/*
-       scanstate->ss_ProcOuterFlag = false;
-       scanstate->ss_OldRelId = 0;
-*/
-
        node->scan.scanstate = scanstate;
 
        /* ----------------
-        *      assign node's base_id .. we don't use AssignNodeBaseid() because
-        *      the increment is done later on after we assign the index scan's
-        *      scanstate.      see below.
-        * ----------------
-        */
-       baseid = estate->es_BaseId;
-/*       scanstate->csstate.cstate.bnode.base_id = baseid; */
-       scanstate->cstate.cs_base_id = baseid;
-
-       /* ----------------
-        *      create expression context for node
+        *      Miscellaneous initialization
+        *
+        *               +      create expression context for node
         * ----------------
         */
        ExecAssignExprContext(estate, &scanstate->cstate);
@@ -640,7 +635,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
         */
        ExecInitResultTupleSlot(estate, &scanstate->cstate);
        ExecInitScanTupleSlot(estate, scanstate);
-/*       ExecInitRawTupleSlot(estate, scanstate); */
 
        /* ----------------
         *      initialize projection info.  result type comes from scan desc
@@ -661,19 +655,12 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
        indexstate->iss_ScanKeys = NULL;
        indexstate->iss_NumScanKeys = NULL;
        indexstate->iss_RuntimeKeyInfo = NULL;
+       indexstate->iss_RuntimeContext = NULL;
        indexstate->iss_RelationDescs = NULL;
        indexstate->iss_ScanDescs = NULL;
 
        node->indxstate = indexstate;
 
-       /* ----------------
-        *      assign base id to index scan state also
-        * ----------------
-        */
-       indexstate->cstate.cs_base_id = baseid;
-       baseid++;
-       estate->es_BaseId = baseid;
-
        /* ----------------
         *      get the index node information
         * ----------------
@@ -696,12 +683,11 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
        scanDescs = (IndexScanDescPtr) palloc(numIndices * sizeof(IndexScanDesc));
 
        /* ----------------
-        *      initialize runtime key info.
+        *      initialize space for runtime key info (may not be needed)
         * ----------------
         */
        have_runtime_keys = false;
-       runtimeKeyInfo = (Pointer *)
-               palloc(numIndices * sizeof(Pointer));
+       runtimeKeyInfo = (int **) palloc(numIndices * sizeof(int *));
 
        /* ----------------
         *      build the index scan keys from the index qualification
@@ -719,9 +705,9 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
                qual = lfirst(indxqual);
                indxqual = lnext(indxqual);
                n_keys = length(qual);
-               scan_keys = (n_keys <= 0) ? NULL :
+               scan_keys = (n_keys <= 0) ? (ScanKey) NULL :
                        (ScanKey) palloc(n_keys * sizeof(ScanKeyData));
-               run_keys = (n_keys <= 0) ? NULL :
+               run_keys = (n_keys <= 0) ? (int *) NULL :
                        (int *) palloc(n_keys * sizeof(int));
 
                CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
@@ -966,12 +952,12 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
                }
 
                /* ----------------
-                *      store the key information into our array.
+                *      store the key information into our arrays.
                 * ----------------
                 */
                numScanKeys[i] = n_keys;
                scanKeys[i] = scan_keys;
-               runtimeKeyInfo[i] = (Pointer) run_keys;
+               runtimeKeyInfo[i] = run_keys;
        }
 
        indexstate->iss_NumIndices = numIndices;
@@ -988,12 +974,35 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
         *      (one for each index) to arrays of flags (one for each key)
         *      which indicate that the qual needs to be evaluated at runtime.
         *      -cim 10/24/89
+        *
+        *      If we do have runtime keys, we need an ExprContext to evaluate them;
+        *      the node's standard context won't do because we want to reset that
+        *      context for every tuple.  So, build another context just like the
+        *      other one...
+        *      -tgl 7/11/00
         * ----------------
         */
        if (have_runtime_keys)
-               indexstate->iss_RuntimeKeyInfo = (Pointer) runtimeKeyInfo;
+       {
+               ExprContext        *stdecontext = scanstate->cstate.cs_ExprContext;
+
+               ExecAssignExprContext(estate, &scanstate->cstate);
+               indexstate->iss_RuntimeKeyInfo = runtimeKeyInfo;
+               indexstate->iss_RuntimeContext = scanstate->cstate.cs_ExprContext;
+               scanstate->cstate.cs_ExprContext = stdecontext;
+       }
        else
+       {
                indexstate->iss_RuntimeKeyInfo = NULL;
+               indexstate->iss_RuntimeContext = NULL;
+               /* Get rid of the speculatively-allocated flag arrays, too */
+               for (i = 0; i < numIndices; i++)
+               {
+                       if (runtimeKeyInfo[i] != NULL)
+                               pfree(runtimeKeyInfo[i]);
+               }
+               pfree(runtimeKeyInfo);
+       }
 
        /* ----------------
         *      get the range table and direction information
@@ -1026,7 +1035,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
        scanstate->css_currentRelation = currentRelation;
        scanstate->css_currentScanDesc = currentScanDesc;
 
-
        /* ----------------
         *      get the scan type from the relation descriptor.
         * ----------------
@@ -1034,12 +1042,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
        ExecAssignScanType(scanstate, RelationGetDescr(currentRelation));
        ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
 
-       /* ----------------
-        *      index scans don't have subtrees..
-        * ----------------
-        */
-/*       scanstate->ss_ProcOuterFlag = false; */
-
        /* ----------------
         *      open the index relations and initialize
         *      relation and scan descriptors.
@@ -1066,10 +1068,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
        indexstate->iss_RelationDescs = relationDescs;
        indexstate->iss_ScanDescs = scanDescs;
 
-       indexstate->cstate.cs_TupFromTlist = false;
-
        /*
-        * if there are some PARAM_EXEC in skankeys then force index rescan on
+        * if there are some PARAM_EXEC in scankeys then force index rescan on
         * first scan.
         */
        ((Plan *) node)->chgParam = execParam;
index 1d5c90424896ac32ff362b9be26056e584da207d..c0a94066bea877268c8b93f5c61d34e8e9ef7096 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.31 2000/06/18 22:44:03 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.32 2000/07/12 02:37:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -158,17 +158,12 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent)
        node->matstate = matstate;
 
        /* ----------------
-        *      Miscellanious initialization
-        *
-        *               +      assign node's base_id
-        *               +      assign debugging hooks and
-        *               +      assign result tuple slot
+        *      Miscellaneous initialization
         *
         *      Materialization nodes don't need ExprContexts because
-        *      they never call ExecQual or ExecTargetList.
+        *      they never call ExecQual or ExecProject.
         * ----------------
         */
-       ExecAssignNodeBaseInfo(estate, &matstate->csstate.cstate, parent);
 
 #define MATERIAL_NSLOTS 1
        /* ----------------
index 0d522f0d5159fdd8011ebcbecc0e7cd7a898d759..a3f92b06901392dec85ab99cb15335a3c09cb394 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.35 2000/06/15 04:09:52 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.36 2000/07/12 02:37:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -202,45 +202,53 @@ MJFormSkipQual(List *qualList, char *replaceopname)
 static bool
 MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
 {
+       bool            result;
+       MemoryContext oldContext;
        List       *clause;
        List       *eqclause;
-       Datum           const_value;
-       bool            isNull;
-       bool            isDone;
 
-       /* ----------------
-        *      if we have no compare qualification, return nil
-        * ----------------
+       /*
+        * Do expression eval in short-lived context.
         */
-       if (compareQual == NIL)
-               return false;
+       oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
 
        /* ----------------
         *      for each pair of clauses, test them until
-        *      our compare conditions are satisfied
+        *      our compare conditions are satisfied.
+        *      if we reach the end of the list, none of our key greater-than
+        *      conditions were satisfied so we return false.
         * ----------------
         */
+       result = false;                         /* assume 'false' result */
+
        eqclause = eqQual;
        foreach(clause, compareQual)
        {
+               Datum           const_value;
+               bool            isNull;
+               bool            isDone;
+
                /* ----------------
                 *       first test if our compare clause is satisfied.
-                *       if so then return true. ignore isDone, don't iterate in
-                *       quals.
+                *       if so then return true.
+                *
+                *       A NULL result is considered false.
+                *       ignore isDone, don't iterate in quals.
                 * ----------------
                 */
-               const_value = (Datum)
-                       ExecEvalExpr((Node *) lfirst(clause), econtext, &isNull, &isDone);
+               const_value = ExecEvalExpr((Node *) lfirst(clause), econtext,
+                                                                  &isNull, &isDone);
 
-               if (DatumGetInt32(const_value) != 0)
-                       return true;
+               if (DatumGetBool(const_value) && !isNull)
+               {
+                       result = true;
+                       break;
+               }
 
                /* ----------------
                 *       ok, the compare clause failed so we test if the keys
                 *       are equal... if key1 != key2, we return false.
                 *       otherwise key1 = key2 so we move on to the next pair of keys.
-                *
-                *       ignore isDone, don't iterate in quals.
                 * ----------------
                 */
                const_value = ExecEvalExpr((Node *) lfirst(eqclause),
@@ -248,17 +256,15 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
                                                                   &isNull,
                                                                   &isDone);
 
-               if (DatumGetInt32(const_value) == 0)
-                       return false;
+               if (! DatumGetBool(const_value) || isNull)
+                       break;                          /* return false */
+
                eqclause = lnext(eqclause);
        }
 
-       /* ----------------
-        *      if we get here then it means none of our key greater-than
-        *      conditions were satisfied so we return false.
-        * ----------------
-        */
-       return false;
+       MemoryContextSwitchTo(oldContext);
+
+       return result;
 }
 
 /* ----------------------------------------------------------------
@@ -403,24 +409,18 @@ ExecMergeJoin(MergeJoin *node)
        List       *qual;
        bool            qualResult;
        bool            compareResult;
-
        Plan       *innerPlan;
        TupleTableSlot *innerTupleSlot;
-
        Plan       *outerPlan;
        TupleTableSlot *outerTupleSlot;
-
        ExprContext *econtext;
-
 #ifdef ENABLE_OUTER_JOINS
-
        /*
         * These should be set from the expression context! - thomas
         * 1999-02-20
         */
        static bool isLeftJoin = true;
        static bool isRightJoin = false;
-
 #endif
 
        /* ----------------
@@ -448,20 +448,34 @@ ExecMergeJoin(MergeJoin *node)
        }
 
        /* ----------------
-        *      ok, everything is setup.. let's go to work
+        *      Reset per-tuple memory context to free any expression evaluation
+        *      storage allocated in the previous tuple cycle.
+        * ----------------
+        */
+       ResetExprContext(econtext);
+
+       /* ----------------
+        *      Check to see if we're still projecting out tuples from a previous
+        *      join tuple (because there is a function-returning-set in the
+        *      projection expressions).  If so, try to project another one.
         * ----------------
         */
        if (mergestate->jstate.cs_TupFromTlist)
        {
                TupleTableSlot *result;
-               ProjectionInfo *projInfo;
                bool            isDone;
 
-               projInfo = mergestate->jstate.cs_ProjInfo;
-               result = ExecProject(projInfo, &isDone);
+               result = ExecProject(mergestate->jstate.cs_ProjInfo, &isDone);
                if (!isDone)
                        return result;
+               /* Done with that source tuple... */
+               mergestate->jstate.cs_TupFromTlist = false;
        }
+
+       /* ----------------
+        *      ok, everything is setup.. let's go to work
+        * ----------------
+        */
        for (;;)
        {
                /* ----------------
@@ -547,6 +561,8 @@ ExecMergeJoin(MergeJoin *node)
                        case EXEC_MJ_JOINTEST:
                                MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTEST\n");
 
+                               ResetExprContext(econtext);
+
                                qualResult = ExecQual((List *) mergeclauses, econtext, false);
                                MJ_DEBUG_QUAL(mergeclauses, qualResult);
 
@@ -565,6 +581,14 @@ ExecMergeJoin(MergeJoin *node)
                                MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTUPLES\n");
                                mergestate->mj_JoinState = EXEC_MJ_NEXTINNER;
 
+                               /*
+                                * Check the qpqual to see if we actually want to return
+                                * this join tuple.  If not, can proceed with merge.
+                                *
+                                * (We don't bother with a ResetExprContext here, on the
+                                * assumption that we just did one before checking the merge
+                                * qual.  One per tuple should be sufficient.)
+                                */
                                qualResult = ExecQual((List *) qual, econtext, false);
                                MJ_DEBUG_QUAL(qual, qualResult);
 
@@ -693,6 +717,8 @@ ExecMergeJoin(MergeJoin *node)
                                innerTupleSlot = econtext->ecxt_innertuple;
                                econtext->ecxt_innertuple = mergestate->mj_MarkedTupleSlot;
 
+                               ResetExprContext(econtext);
+
                                qualResult = ExecQual((List *) mergeclauses, econtext, false);
                                MJ_DEBUG_QUAL(mergeclauses, qualResult);
 
@@ -709,11 +735,7 @@ ExecMergeJoin(MergeJoin *node)
                                         */
 
                                        ExecRestrPos(innerPlan);
-#if 0
-                                       mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
-#endif
                                        mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
-
                                }
                                else
                                {
@@ -777,6 +799,8 @@ ExecMergeJoin(MergeJoin *node)
                                 *      we update the marked tuple and go join them.
                                 * ----------------
                                 */
+                               ResetExprContext(econtext);
+
                                qualResult = ExecQual((List *) mergeclauses, econtext, false);
                                MJ_DEBUG_QUAL(mergeclauses, qualResult);
 
@@ -886,6 +910,8 @@ ExecMergeJoin(MergeJoin *node)
                                 *      we update the marked tuple and go join them.
                                 * ----------------
                                 */
+                               ResetExprContext(econtext);
+
                                qualResult = ExecQual((List *) mergeclauses, econtext, false);
                                MJ_DEBUG_QUAL(mergeclauses, qualResult);
 
@@ -1142,12 +1168,9 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
        /* ----------------
         *      Miscellaneous initialization
         *
-        *               +      assign node's base_id
-        *               +      assign debugging hooks and
         *               +      create expression context for node
         * ----------------
         */
-       ExecAssignNodeBaseInfo(estate, &mergestate->jstate, parent);
        ExecAssignExprContext(estate, &mergestate->jstate);
 
 #define MERGEJOIN_NSLOTS 2
@@ -1251,6 +1274,7 @@ ExecEndMergeJoin(MergeJoin *node)
         * ----------------
         */
        ExecFreeProjectionInfo(&mergestate->jstate);
+       ExecFreeExprContext(&mergestate->jstate);
 
        /* ----------------
         *      shut down the subplans
index ec71ad7ac71fb7449b36fa89e74905d9cf4ea400..0186e394367849505ab660cf2254a1c44427873f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.16 2000/06/15 04:09:52 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.17 2000/07/12 02:37:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
  *
  *             It scans the inner relation to join with current outer tuple.
  *
- *             If none is found, next tuple form the outer relation is retrieved
+ *             If none is found, next tuple from the outer relation is retrieved
  *             and the inner relation is scanned from the beginning again to join
  *             with the outer tuple.
  *
- *             Nil is returned if all the remaining outer tuples are tried and
+ *             NULL is returned if all the remaining outer tuples are tried and
  *             all fail to join with the inner tuples.
  *
- *             Nil is also returned if there is no tuple from inner realtion.
+ *             NULL is also returned if there is no tuple from inner relation.
  *
  *             Conditions:
  *               -- outerTuple contains current tuple from outer relation and
- *                      the right son(inner realtion) maintains "cursor" at the tuple
+ *                      the right son(inner relation) maintains "cursor" at the tuple
  *                      returned previously.
  *                             This is achieved by maintaining a scan position on the outer
  *                             relation.
@@ -60,10 +60,8 @@ ExecNestLoop(NestLoop *node, Plan *parent)
        Plan       *innerPlan;
        Plan       *outerPlan;
        bool            needNewOuterTuple;
-
        TupleTableSlot *outerTupleSlot;
        TupleTableSlot *innerTupleSlot;
-
        List       *qual;
        ExprContext *econtext;
 
@@ -77,11 +75,6 @@ ExecNestLoop(NestLoop *node, Plan *parent)
        qual = node->join.qual;
        outerPlan = outerPlan(&node->join);
        innerPlan = innerPlan(&node->join);
-
-       /* ----------------
-        *      initialize expression context
-        * ----------------
-        */
        econtext = nlstate->jstate.cs_ExprContext;
 
        /* ----------------
@@ -92,11 +85,18 @@ ExecNestLoop(NestLoop *node, Plan *parent)
        econtext->ecxt_outertuple = outerTupleSlot;
 
        /* ----------------
-        *      Ok, everything is setup for the join so now loop until
-        *      we return a qualifying join tuple..
+        *      Reset per-tuple memory context to free any expression evaluation
+        *      storage allocated in the previous tuple cycle.
         * ----------------
         */
+       ResetExprContext(econtext);
 
+       /* ----------------
+        *      Check to see if we're still projecting out tuples from a previous
+        *      join tuple (because there is a function-returning-set in the
+        *      projection expressions).  If so, try to project another one.
+        * ----------------
+        */
        if (nlstate->jstate.cs_TupFromTlist)
        {
                TupleTableSlot *result;
@@ -105,9 +105,17 @@ ExecNestLoop(NestLoop *node, Plan *parent)
                result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
                if (!isDone)
                        return result;
+               /* Done with that source tuple... */
+               nlstate->jstate.cs_TupFromTlist = false;
        }
 
+       /* ----------------
+        *      Ok, everything is setup for the join so now loop until
+        *      we return a qualifying join tuple..
+        * ----------------
+        */
        ENL1_printf("entering main loop");
+
        for (;;)
        {
                /* ----------------
@@ -115,15 +123,7 @@ ExecNestLoop(NestLoop *node, Plan *parent)
                 *      and join it with the current outer tuple.
                 * ----------------
                 */
-               needNewOuterTuple = false;
-
-               if (!TupIsNull(outerTupleSlot))
-                       ENL1_printf("have outer tuple, deal with it");
-               else
-               {
-                       ENL1_printf("outer tuple is nil, need new outer tuple");
-                       needNewOuterTuple = true;
-               }
+               needNewOuterTuple = TupIsNull(outerTupleSlot);
 
                /* ----------------
                 *      if we have an outerTuple, try to get the next inner tuple.
@@ -229,9 +229,11 @@ ExecNestLoop(NestLoop *node, Plan *parent)
                }
 
                /* ----------------
-                *      qualification failed so we have to try again..
+                *      Tuple fails qual, so free per-tuple memory and try again.
                 * ----------------
                 */
+               ResetExprContext(econtext);
+
                ENL1_printf("qualification failed, looping");
        }
 }
@@ -263,18 +265,14 @@ ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
         * ----------------
         */
        nlstate = makeNode(NestLoopState);
-       nlstate->nl_PortalFlag = false;
        node->nlstate = nlstate;
 
        /* ----------------
-        *      Miscellanious initialization
+        *      Miscellaneous initialization
         *
-        *               +      assign node's base_id
-        *               +      assign debugging hooks and
         *               +      create expression context for node
         * ----------------
         */
-       ExecAssignNodeBaseInfo(estate, &nlstate->jstate, parent);
        ExecAssignExprContext(estate, &nlstate->jstate);
 
 #define NESTLOOP_NSLOTS 1
@@ -348,6 +346,7 @@ ExecEndNestLoop(NestLoop *node)
         * ----------------
         */
        ExecFreeProjectionInfo(&nlstate->jstate);
+       ExecFreeExprContext(&nlstate->jstate);
 
        /* ----------------
         *      close down subplans
@@ -386,9 +385,7 @@ ExecReScanNestLoop(NestLoop *node, ExprContext *exprCtxt, Plan *parent)
        if (outerPlan->chgParam == NULL)
                ExecReScan(outerPlan, exprCtxt, (Plan *) node);
 
-       /* let outerPlan to free its result typle ... */
+       /* let outerPlan to free its result tuple ... */
        nlstate->jstate.cs_OuterTupleSlot = NULL;
        nlstate->jstate.cs_TupFromTlist = false;
-
-       return;
 }
index 5bf132520cbae33fb1df1f54ccb1afa49dfb8f5b..a1daaf52c4bccb31ad70f21a32ed3cc87b3ab217 100644 (file)
@@ -3,21 +3,18 @@
  * nodeResult.c
  *       support for constant nodes needing special code.
  *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
  * DESCRIPTION
  *
- *             Example: in constant queries where no relations are scanned,
- *             the planner generates result nodes.  Examples of such queries are:
+ *             Result nodes are used in queries where no relations are scanned.
+ *             Examples of such queries are:
  *
  *                             retrieve (x = 1)
  *             and
  *                             append emp (name = "mike", salary = 15000)
  *
- *             Result nodes are also used to optimise queries
- *             with tautological qualifications like:
+ *             Result nodes are also used to optimise queries with constant
+ *             qualifications (ie, quals that do not depend on the scanned data),
+ *             such as:
  *
  *                             retrieve (emp.all) where 2 > 1
  *
  *                                             /
  *                                SeqScan (emp.all)
  *
+ *             At runtime, the Result node evaluates the constant qual once.
+ *             If it's false, we can return an empty result set without running
+ *             the controlled plan at all.  If it's true, we run the controlled
+ *             plan normally and pass back the results.
+ *
+ *
+ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.13 2000/01/26 05:56:23 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.14 2000/07/12 02:37:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
-#include "postgres.h"
 
+#include "postgres.h"
 
 #include "executor/executor.h"
 #include "executor/nodeResult.h"
@@ -41,7 +47,7 @@
 /* ----------------------------------------------------------------
  *             ExecResult(node)
  *
- *             returns the tuples from the outer plan which satisify the
+ *             returns the tuples from the outer plan which satisfy the
  *             qualification clause.  Since result nodes with right
  *             subtrees are never planned, we ignore the right subtree
  *             entirely (for now).. -cim 10/7/89
@@ -67,15 +73,17 @@ ExecResult(Result *node)
         * ----------------
         */
        resstate = node->resstate;
+       econtext = resstate->cstate.cs_ExprContext;
 
        /* ----------------
-        *      get the expression context
+        *      Reset per-tuple memory context to free any expression evaluation
+        *      storage allocated in the previous tuple cycle.
         * ----------------
         */
-       econtext = resstate->cstate.cs_ExprContext;
+       ResetExprContext(econtext);
 
        /* ----------------
-        *       check tautological qualifications like (2 > 1)
+        *       check constant qualifications like (2 > 1), if not already done
         * ----------------
         */
        if (resstate->rs_checkqual)
@@ -92,74 +100,64 @@ ExecResult(Result *node)
                }
        }
 
+       /* ----------------
+        *      Check to see if we're still projecting out tuples from a previous
+        *      scan tuple (because there is a function-returning-set in the
+        *      projection expressions).  If so, try to project another one.
+        * ----------------
+        */
        if (resstate->cstate.cs_TupFromTlist)
        {
-               ProjectionInfo *projInfo;
-
-               projInfo = resstate->cstate.cs_ProjInfo;
-               resultSlot = ExecProject(projInfo, &isDone);
+               resultSlot = ExecProject(resstate->cstate.cs_ProjInfo, &isDone);
                if (!isDone)
                        return resultSlot;
+               /* Done with that source tuple... */
+               resstate->cstate.cs_TupFromTlist = false;
        }
 
        /* ----------------
-        *      retrieve a tuple that satisfy the qual from the outer plan until
-        *      there are no more.
-        *
-        *      if rs_done is 1 then it means that we were asked to return
-        *      a constant tuple and we alread did the last time ExecResult()
-        *      was called, so now we are through.
+        *      if rs_done is true then it means that we were asked to return
+        *      a constant tuple and we already did the last time ExecResult()
+        *      was called, OR that we failed the constant qual check.
+        *      Either way, now we are through.
         * ----------------
         */
-       outerPlan = outerPlan(node);
-
-       while (!resstate->rs_done)
+       if (!resstate->rs_done)
        {
+               outerPlan = outerPlan(node);
 
-               /* ----------------
-                *        get next outer tuple if necessary.
-                * ----------------
-                */
                if (outerPlan != NULL)
                {
+                       /* ----------------
+                        *      retrieve tuples from the outer plan until there are no more.
+                        * ----------------
+                        */
                        outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
 
                        if (TupIsNull(outerTupleSlot))
                                return NULL;
 
                        resstate->cstate.cs_OuterTupleSlot = outerTupleSlot;
+
+                       /* ----------------
+                        *       XXX gross hack. use outer tuple as scan tuple for projection
+                        * ----------------
+                        */
+                       econtext->ecxt_outertuple = outerTupleSlot;
+                       econtext->ecxt_scantuple = outerTupleSlot;
                }
                else
                {
-
                        /* ----------------
-                        *      if we don't have an outer plan, then it's probably
-                        *      the case that we are doing a retrieve or an append
-                        *      with a constant target list, so we should only return
-                        *      the constant tuple once or never if we fail the qual.
+                        *      if we don't have an outer plan, then we are just generating
+                        *      the results from a constant target list.  Do it only once.
                         * ----------------
                         */
-                       resstate->rs_done = 1;
+                       resstate->rs_done = true;
                }
 
                /* ----------------
-                *        get the information to place into the expr context
-                * ----------------
-                */
-               resstate = node->resstate;
-
-               outerTupleSlot = resstate->cstate.cs_OuterTupleSlot;
-
-               /* ----------------
-                *       fill in the information in the expression context
-                *       XXX gross hack. use outer tuple as scan tuple
-                * ----------------
-                */
-               econtext->ecxt_outertuple = outerTupleSlot;
-               econtext->ecxt_scantuple = outerTupleSlot;
-
-               /* ----------------
-                *       form the result tuple and pass it back using ExecProject()
+                *       form the result tuple using ExecProject(), and return it.
                 * ----------------
                 */
                projInfo = resstate->cstate.cs_ProjInfo;
@@ -200,14 +198,11 @@ ExecInitResult(Result *node, EState *estate, Plan *parent)
        node->resstate = resstate;
 
        /* ----------------
-        *      Miscellanious initialization
+        *      Miscellaneous initialization
         *
-        *               +      assign node's base_id
-        *               +      assign debugging hooks and
         *               +      create expression context for node
         * ----------------
         */
-       ExecAssignNodeBaseInfo(estate, &resstate->cstate, parent);
        ExecAssignExprContext(estate, &resstate->cstate);
 
 #define RESULT_NSLOTS 1
@@ -247,7 +242,7 @@ ExecCountSlotsResult(Result *node)
 /* ----------------------------------------------------------------
  *             ExecEndResult
  *
- *             fees up storage allocated through C routines
+ *             frees up storage allocated through C routines
  * ----------------------------------------------------------------
  */
 void
@@ -266,9 +261,8 @@ ExecEndResult(Result *node)
         *                is freed at end-transaction time.  -cim 6/2/91
         * ----------------
         */
-       ExecFreeExprContext(&resstate->cstate);         /* XXX - new for us - er1p */
-       ExecFreeTypeInfo(&resstate->cstate);            /* XXX - new for us - er1p */
        ExecFreeProjectionInfo(&resstate->cstate);
+       ExecFreeExprContext(&resstate->cstate);
 
        /* ----------------
         *      shut down subplans
@@ -301,5 +295,4 @@ ExecReScanResult(Result *node, ExprContext *exprCtxt, Plan *parent)
        if (((Plan *) node)->lefttree &&
                ((Plan *) node)->lefttree->chgParam == NULL)
                ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
-
 }
index 24de6184010cf8d53199a3e206901dbea8c33263..b953dcd3697bd8d6819ce831fa3b5a90eae53d15 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.23 2000/06/15 04:09:52 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.24 2000/07/12 02:37:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,8 +31,7 @@
 #include "parser/parsetree.h"
 
 static Oid InitScanRelation(SeqScan *node, EState *estate,
-                                CommonScanState *scanstate, Plan *outerPlan);
-
+                                                       CommonScanState *scanstate);
 static TupleTableSlot *SeqNext(SeqScan *node);
 
 /* ----------------------------------------------------------------
@@ -132,25 +131,11 @@ SeqNext(SeqScan *node)
 TupleTableSlot *
 ExecSeqScan(SeqScan *node)
 {
-       TupleTableSlot *slot;
-       Plan       *outerPlan;
-
-       S_printf("ExecSeqScan: scanning node: ");
-       S_nodeDisplay(node);
-
        /* ----------------
-        * if there is an outer subplan, get a tuple from it
-        * else, scan the relation
+        *      use SeqNext as access method
         * ----------------
         */
-       if ((outerPlan = outerPlan((Plan *) node)) != NULL)
-               slot = ExecProcNode(outerPlan, (Plan *) node);
-       else
-               slot = ExecScan(node, SeqNext);
-
-       S1_printf("ExecSeqScan: returned tuple slot: %d\n", slot);
-
-       return slot;
+       return ExecScan(node, (ExecScanAccessMtd) SeqNext);
 }
 
 /* ----------------------------------------------------------------
@@ -162,7 +147,7 @@ ExecSeqScan(SeqScan *node)
  */
 static Oid
 InitScanRelation(SeqScan *node, EState *estate,
-                                CommonScanState *scanstate, Plan *outerPlan)
+                                CommonScanState *scanstate)
 {
        Index           relid;
        List       *rangeTable;
@@ -173,84 +158,56 @@ InitScanRelation(SeqScan *node, EState *estate,
        HeapScanDesc currentScanDesc;
        RelationInfo *resultRelationInfo;
 
-       if (outerPlan == NULL)
-       {
-               /* ----------------
-                * if the outer node is nil then we are doing a simple
-                * sequential scan of a relation...
-                *
-                * get the relation object id from the relid'th entry
-                * in the range table, open that relation and initialize
-                * the scan state...
-                * ----------------
-                */
-               relid = node->scanrelid;
-               rangeTable = estate->es_range_table;
-               rtentry = rt_fetch(relid, rangeTable);
-               reloid = rtentry->relid;
-               direction = estate->es_direction;
-               resultRelationInfo = estate->es_result_relation_info;
-
-               ExecOpenScanR(reloid,   /* relation */
-                                         0,            /* nkeys */
-                                         NULL,         /* scan key */
-                                         0,            /* is index */
-                                         direction,/* scan direction */
-                                         estate->es_snapshot,
-                                         &currentRelation, /* return: rel desc */
-                                         (Pointer *) &currentScanDesc);        /* return: scan desc */
-
-               scanstate->css_currentRelation = currentRelation;
-               scanstate->css_currentScanDesc = currentScanDesc;
-
-               ExecAssignScanType(scanstate,
-                                                  RelationGetDescr(currentRelation));
-       }
-       else
-       {
-               /* ----------------
-                *       otherwise we are scanning tuples from the
-                *       outer subplan so we initialize the outer plan
-                *       and nullify
-                * ----------------
-                */
-               ExecInitNode(outerPlan, estate, (Plan *) node);
-
-               node->scanrelid = 0;
-               scanstate->css_currentRelation = NULL;
-               scanstate->css_currentScanDesc = NULL;
-               ExecAssignScanType(scanstate, NULL);
-               reloid = InvalidOid;
-       }
-
        /* ----------------
-        *      return the relation
+        * get the relation object id from the relid'th entry
+        * in the range table, open that relation and initialize
+        * the scan state...
         * ----------------
         */
+       relid = node->scanrelid;
+       rangeTable = estate->es_range_table;
+       rtentry = rt_fetch(relid, rangeTable);
+       reloid = rtentry->relid;
+       direction = estate->es_direction;
+       resultRelationInfo = estate->es_result_relation_info;
+
+       ExecOpenScanR(reloid,           /* relation */
+                                 0,                    /* nkeys */
+                                 NULL,                 /* scan key */
+                                 0,                    /* is index */
+                                 direction,    /* scan direction */
+                                 estate->es_snapshot,
+                                 &currentRelation, /* return: rel desc */
+                                 (Pointer *) &currentScanDesc); /* return: scan desc */
+
+       scanstate->css_currentRelation = currentRelation;
+       scanstate->css_currentScanDesc = currentScanDesc;
+
+       ExecAssignScanType(scanstate, RelationGetDescr(currentRelation));
+
        return reloid;
 }
 
 
 /* ----------------------------------------------------------------
  *             ExecInitSeqScan
- *
- * old comments
- *             Creates the run-time state information for the seqscan node
- *             and sets the relation id to contain relevant descriptors.
- *
- *             If there is a outer subtree (sort), the outer subtree
- *             is initialized and the relation id is set to the descriptors
- *             returned by the subtree.
  * ----------------------------------------------------------------
  */
 bool
 ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
 {
        CommonScanState *scanstate;
-       Plan       *outerPlan;
        Oid                     reloid;
        HeapScanDesc scandesc;
 
+       /* ----------------
+        *      Once upon a time it was possible to have an outerPlan of a SeqScan,
+        *      but not any more.
+        * ----------------
+        */
+       Assert(outerPlan((Plan *) node) == NULL);
+       Assert(innerPlan((Plan *) node) == NULL);
+
        /* ----------------
         *      assign the node's execution state
         * ----------------
@@ -265,13 +222,11 @@ ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
        node->scanstate = scanstate;
 
        /* ----------------
-        *      Miscellanious initialization
+        *      Miscellaneous initialization
         *
-        *               +      assign node's base_id
         *               +      create expression context for node
         * ----------------
         */
-       ExecAssignNodeBaseInfo(estate, &scanstate->cstate, parent);
        ExecAssignExprContext(estate, &scanstate->cstate);
 
 #define SEQSCAN_NSLOTS 3
@@ -283,12 +238,10 @@ ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
        ExecInitScanTupleSlot(estate, scanstate);
 
        /* ----------------
-        *      initialize scan relation or outer subplan
+        *      initialize scan relation
         * ----------------
         */
-       outerPlan = outerPlan((Plan *) node);
-
-       reloid = InitScanRelation(node, estate, scanstate, outerPlan);
+       reloid = InitScanRelation(node, estate, scanstate);
 
        scandesc = scanstate->css_currentScanDesc;
        scanstate->cstate.cs_TupFromTlist = false;
@@ -315,15 +268,12 @@ ExecCountSlotsSeqScan(SeqScan *node)
  *             ExecEndSeqScan
  *
  *             frees any storage allocated through C routines.
- *|            ...and also closes relations and/or shuts down outer subplan
- *|            -cim 8/14/89
  * ----------------------------------------------------------------
  */
 void
 ExecEndSeqScan(SeqScan *node)
 {
        CommonScanState *scanstate;
-       Plan       *outerPlan;
 
        /* ----------------
         *      get information from node
@@ -341,6 +291,7 @@ ExecEndSeqScan(SeqScan *node)
         * ----------------
         */
        ExecFreeProjectionInfo(&scanstate->cstate);
+       ExecFreeExprContext(&scanstate->cstate);
 
        /* ----------------
         * close scan relation
@@ -348,13 +299,6 @@ ExecEndSeqScan(SeqScan *node)
         */
        ExecCloseR((Plan *) node);
 
-       /* ----------------
-        * clean up outer subtree (does nothing if there is no outerPlan)
-        * ----------------
-        */
-       outerPlan = outerPlan((Plan *) node);
-       ExecEndNode(outerPlan, (Plan *) node);
-
        /* ----------------
         *      clean out the tuple table
         * ----------------
@@ -367,6 +311,7 @@ ExecEndSeqScan(SeqScan *node)
  *                                             Join Support
  * ----------------------------------------------------------------
  */
+
 /* ----------------------------------------------------------------
  *             ExecSeqReScan
  *
@@ -378,7 +323,6 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
 {
        CommonScanState *scanstate;
        EState     *estate;
-       Plan       *outerPlan;
        Relation        rel;
        HeapScanDesc scan;
        ScanDirection direction;
@@ -386,28 +330,18 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
        scanstate = node->scanstate;
        estate = node->plan.state;
 
-       if ((outerPlan = outerPlan((Plan *) node)) != NULL)
-       {
-               /* we are scanning a subplan */
-               outerPlan = outerPlan((Plan *) node);
-               ExecReScan(outerPlan, exprCtxt, parent);
-       }
-       else
-/* otherwise, we are scanning a relation */
+       /* If this is re-scanning of PlanQual ... */
+       if (estate->es_evTuple != NULL &&
+               estate->es_evTuple[node->scanrelid - 1] != NULL)
        {
-               /* If this is re-scanning of PlanQual ... */
-               if (estate->es_evTuple != NULL &&
-                       estate->es_evTuple[node->scanrelid - 1] != NULL)
-               {
-                       estate->es_evTupleNull[node->scanrelid - 1] = false;
-                       return;
-               }
-               rel = scanstate->css_currentRelation;
-               scan = scanstate->css_currentScanDesc;
-               direction = estate->es_direction;
-               scan = ExecReScanR(rel, scan, direction, 0, NULL);
-               scanstate->css_currentScanDesc = scan;
+               estate->es_evTupleNull[node->scanrelid - 1] = false;
+               return;
        }
+       rel = scanstate->css_currentRelation;
+       scan = scanstate->css_currentScanDesc;
+       direction = estate->es_direction;
+       scan = ExecReScanR(rel, scan, direction, 0, NULL);
+       scanstate->css_currentScanDesc = scan;
 }
 
 /* ----------------------------------------------------------------
@@ -420,33 +354,11 @@ void
 ExecSeqMarkPos(SeqScan *node)
 {
        CommonScanState *scanstate;
-       Plan       *outerPlan;
        HeapScanDesc scan;
 
        scanstate = node->scanstate;
-
-       /* ----------------
-        *      if we are scanning a subplan then propagate
-        *      the ExecMarkPos() request to the subplan
-        * ----------------
-        */
-       outerPlan = outerPlan((Plan *) node);
-       if (outerPlan)
-       {
-               ExecMarkPos(outerPlan);
-               return;
-       }
-
-       /* ----------------
-        *      otherwise we are scanning a relation so mark the
-        *      position using the access methods..
-        *
-        * ----------------
-        */
        scan = scanstate->css_currentScanDesc;
        heap_markpos(scan);
-
-       return;
 }
 
 /* ----------------------------------------------------------------
@@ -459,28 +371,9 @@ void
 ExecSeqRestrPos(SeqScan *node)
 {
        CommonScanState *scanstate;
-       Plan       *outerPlan;
        HeapScanDesc scan;
 
        scanstate = node->scanstate;
-
-       /* ----------------
-        *      if we are scanning a subplan then propagate
-        *      the ExecRestrPos() request to the subplan
-        * ----------------
-        */
-       outerPlan = outerPlan((Plan *) node);
-       if (outerPlan)
-       {
-               ExecRestrPos(outerPlan);
-               return;
-       }
-
-       /* ----------------
-        *      otherwise we are scanning a relation so restore the
-        *      position using the access methods..
-        * ----------------
-        */
        scan = scanstate->css_currentScanDesc;
        heap_restrpos(scan);
 }
index f8b5571a578eb1b496cb672034f80bf0f0d53edd..6f2e1f7f47b191258559cefa70666eef41b5481a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.28 2000/07/09 04:17:53 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.29 2000/07/12 02:37:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -255,14 +255,10 @@ ExecInitSort(Sort *node, EState *estate, Plan *parent)
        /* ----------------
         *      Miscellaneous initialization
         *
-        *               +      assign node's base_id
-        *               +      assign debugging hooks
-        *
         *      Sort nodes don't initialize their ExprContexts because
-        *      they never call ExecQual or ExecTargetList.
+        *      they never call ExecQual or ExecProject.
         * ----------------
         */
-       ExecAssignNodeBaseInfo(estate, &sortstate->csstate.cstate, parent);
 
 #define SORT_NSLOTS 1
        /* ----------------
index 99b09f685a0cd21f2bf0748aeb63fe09c1207134..3d331c714f74ef853d3150052499a663ba135bf1 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.25 2000/04/12 17:15:10 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.26 2000/07/12 02:37:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -37,11 +37,19 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
        SubLink    *sublink = node->sublink;
        SubLinkType subLinkType = sublink->subLinkType;
        bool            useor = sublink->useor;
+       MemoryContext oldcontext;
        TupleTableSlot *slot;
        Datum           result;
+       bool            isDone;
        bool            found = false;  /* TRUE if got at least one subplan tuple */
        List       *lst;
 
+       /*
+        * We are probably in a short-lived expression-evaluation context.
+        * Switch to longer-lived per-query context.
+        */
+       oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
+
        if (node->setParam != NIL)
                elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
 
@@ -52,12 +60,16 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
        {
                foreach(lst, node->parParam)
                {
-                       ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]);
+                       ParamExecData *prm;
 
+                       prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]);
                        Assert(pvar != NIL);
-                       prm->value = ExecEvalExpr((Node *) lfirst(pvar),
-                                                                         econtext,
-                                                                         &(prm->isnull), NULL);
+                       prm->value = ExecEvalExprSwitchContext((Node *) lfirst(pvar),
+                                                                                                  econtext,
+                                                                                                  &(prm->isnull),
+                                                                                                  &isDone);
+                       if (!isDone)
+                               elog(ERROR, "ExecSubPlan: set values not supported for params");
                        pvar = lnext(pvar);
                }
                plan->chgParam = nconc(plan->chgParam, listCopy(node->parParam));
@@ -84,7 +96,7 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
         * return NULL.  Assuming we get a tuple, we just return its first
         * column (there can be only one non-junk column in this case).
         */
-       result = (Datum) (subLinkType == ALL_SUBLINK ? true : false);
+       result = BoolGetDatum(subLinkType == ALL_SUBLINK);
        *isNull = false;
 
        for (slot = ExecProcNode(plan, plan);
@@ -93,12 +105,16 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
        {
                HeapTuple       tup = slot->val;
                TupleDesc       tdesc = slot->ttc_tupleDescriptor;
-               Datum           rowresult = (Datum) (useor ? false : true);
+               Datum           rowresult = BoolGetDatum(! useor);
                bool            rownull = false;
                int                     col = 1;
 
                if (subLinkType == EXISTS_SUBLINK)
-                       return (Datum) true;
+               {
+                       found = true;
+                       result = BoolGetDatum(true);
+                       break;
+               }
 
                if (subLinkType == EXPR_SUBLINK)
                {
@@ -172,8 +188,10 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
                        /*
                         * Now we can eval the combining operator for this column.
                         */
-                       expresult = ExecEvalExpr((Node *) expr, econtext, &expnull,
-                                                                        (bool *) NULL);
+                       expresult = ExecEvalExprSwitchContext((Node *) expr, econtext,
+                                                                                                 &expnull, &isDone);
+                       if (!isDone)
+                               elog(ERROR, "ExecSubPlan: set values not supported for combining operators");
 
                        /*
                         * Combine the result into the row result as appropriate.
@@ -188,9 +206,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
                                /* combine within row per OR semantics */
                                if (expnull)
                                        rownull = true;
-                               else if (DatumGetInt32(expresult) != 0)
+                               else if (DatumGetBool(expresult))
                                {
-                                       rowresult = (Datum) true;
+                                       rowresult = BoolGetDatum(true);
                                        rownull = false;
                                        break;          /* needn't look at any more columns */
                                }
@@ -200,9 +218,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
                                /* combine within row per AND semantics */
                                if (expnull)
                                        rownull = true;
-                               else if (DatumGetInt32(expresult) == 0)
+                               else if (! DatumGetBool(expresult))
                                {
-                                       rowresult = (Datum) false;
+                                       rowresult = BoolGetDatum(false);
                                        rownull = false;
                                        break;          /* needn't look at any more columns */
                                }
@@ -215,9 +233,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
                        /* combine across rows per OR semantics */
                        if (rownull)
                                *isNull = true;
-                       else if (DatumGetInt32(rowresult) != 0)
+                       else if (DatumGetBool(rowresult))
                        {
-                               result = (Datum) true;
+                               result = BoolGetDatum(true);
                                *isNull = false;
                                break;                  /* needn't look at any more rows */
                        }
@@ -227,9 +245,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
                        /* combine across rows per AND semantics */
                        if (rownull)
                                *isNull = true;
-                       else if (DatumGetInt32(rowresult) == 0)
+                       else if (! DatumGetBool(rowresult))
                        {
-                               result = (Datum) false;
+                               result = BoolGetDatum(false);
                                *isNull = false;
                                break;                  /* needn't look at any more rows */
                        }
@@ -252,11 +270,13 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
                 */
                if (subLinkType == EXPR_SUBLINK || subLinkType == MULTIEXPR_SUBLINK)
                {
-                       result = (Datum) false;
+                       result = (Datum) 0;
                        *isNull = true;
                }
        }
 
+       MemoryContextSwitchTo(oldcontext);
+
        return result;
 }
 
@@ -277,13 +297,13 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
                ExecCreateTupleTable(ExecCountSlotsNode(node->plan) + 10);
        sp_estate->es_snapshot = estate->es_snapshot;
 
-       node->shutdown = false;
+       node->needShutdown = false;
        node->curTuple = NULL;
 
        if (!ExecInitNode(node->plan, sp_estate, NULL))
                return false;
 
-       node->shutdown = true;          /* now we need to shutdown the subplan */
+       node->needShutdown = true;      /* now we need to shutdown the subplan */
 
        /*
         * If this plan is un-correlated or undirect correlated one and want
@@ -317,14 +337,21 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
  * ----------------------------------------------------------------
  */
 void
-ExecSetParamPlan(SubPlan *node)
+ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
 {
        Plan       *plan = node->plan;
        SubLink    *sublink = node->sublink;
+       MemoryContext oldcontext;
        TupleTableSlot *slot;
        List       *lst;
        bool            found = false;
 
+       /*
+        * We are probably in a short-lived expression-evaluation context.
+        * Switch to longer-lived per-query context.
+        */
+       oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
+
        if (sublink->subLinkType == ANY_SUBLINK ||
                sublink->subLinkType == ALL_SUBLINK)
                elog(ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported");
@@ -345,7 +372,7 @@ ExecSetParamPlan(SubPlan *node)
                        ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
 
                        prm->execPlan = NULL;
-                       prm->value = (Datum) true;
+                       prm->value = BoolGetDatum(true);
                        prm->isnull = false;
                        found = true;
                        break;
@@ -386,7 +413,7 @@ ExecSetParamPlan(SubPlan *node)
                        ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
 
                        prm->execPlan = NULL;
-                       prm->value = (Datum) false;
+                       prm->value = BoolGetDatum(false);
                        prm->isnull = false;
                }
                else
@@ -396,16 +423,18 @@ ExecSetParamPlan(SubPlan *node)
                                ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
 
                                prm->execPlan = NULL;
-                               prm->value = (Datum) NULL;
+                               prm->value = (Datum) 0;
                                prm->isnull = true;
                        }
                }
        }
 
+       MemoryContextSwitchTo(oldcontext);
+
        if (plan->extParam == NULL) /* un-correlated ... */
        {
                ExecEndNode(plan, plan);
-               node->shutdown = false;
+               node->needShutdown = false;
        }
 }
 
@@ -416,10 +445,10 @@ ExecSetParamPlan(SubPlan *node)
 void
 ExecEndSubPlan(SubPlan *node)
 {
-       if (node->shutdown)
+       if (node->needShutdown)
        {
                ExecEndNode(node->plan, node->plan);
-               node->shutdown = false;
+               node->needShutdown = false;
        }
        if (node->curTuple)
        {
index 0978c1ec033d5c79779e210635efa0b3c4ba9f2a..824ead5ec6b0de25f818a8efef8aaca09d0b3273 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.9 2000/06/15 04:09:52 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.10 2000/07/12 02:37:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -38,12 +38,16 @@ TidListCreate(List *evalList, ExprContext *econtext, ItemPointer *tidList)
        List       *lst;
        ItemPointer itemptr;
        bool            isNull;
+       bool            isDone;
        int                     numTids = 0;
 
        foreach(lst, evalList)
        {
-               itemptr = (ItemPointer) ExecEvalExpr(lfirst(lst), econtext,
-                                                                                        &isNull, (bool *) 0);
+               itemptr = (ItemPointer)
+                       DatumGetPointer(ExecEvalExprSwitchContext(lfirst(lst),
+                                                                                                         econtext,
+                                                                                                         &isNull,
+                                                                                                         &isDone));
                if (itemptr && ItemPointerIsValid(itemptr))
                {
                        tidList[numTids] = itemptr;
@@ -243,7 +247,7 @@ ExecTidScan(TidScan *node)
         *      use TidNext as access method
         * ----------------
         */
-       return ExecScan(&node->scan, TidNext);
+       return ExecScan(&node->scan, (ExecScanAccessMtd) TidNext);
 }
 
 /* ----------------------------------------------------------------
@@ -319,6 +323,7 @@ ExecEndTidScan(TidScan *node)
         * ----------------
         */
        ExecFreeProjectionInfo(&scanstate->cstate);
+       ExecFreeExprContext(&scanstate->cstate);
 
        /* ----------------
         *      close the heap and tid relations
@@ -332,7 +337,6 @@ ExecEndTidScan(TidScan *node)
         */
        ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
        ExecClearTuple(scanstate->css_ScanTupleSlot);
-/*       ExecClearTuple(scanstate->css_RawTupleSlot); */
 }
 
 /* ----------------------------------------------------------------
@@ -394,11 +398,8 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
        RangeTblEntry *rtentry;
        Oid                     relid;
        Oid                     reloid;
-
        Relation        currentRelation;
-       int                     baseid;
-
-       List       *execParam = NULL;
+       List       *execParam = NIL;
 
        /* ----------------
         *      assign execution state to node
@@ -413,25 +414,12 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
         * --------------------------------
         */
        scanstate = makeNode(CommonScanState);
-/*
-       scanstate->ss_ProcOuterFlag = false;
-       scanstate->ss_OldRelId = 0;
-*/
-
        node->scan.scanstate = scanstate;
 
        /* ----------------
-        *      assign node's base_id .. we don't use AssignNodeBaseid() because
-        *      the increment is done later on after we assign the tid scan's
-        *      scanstate.      see below.
-        * ----------------
-        */
-       baseid = estate->es_BaseId;
-/*       scanstate->csstate.cstate.bnode.base_id = baseid; */
-       scanstate->cstate.cs_base_id = baseid;
-
-       /* ----------------
-        *      create expression context for node
+        *      Miscellaneous initialization
+        *
+        *               +      create expression context for node
         * ----------------
         */
        ExecAssignExprContext(estate, &scanstate->cstate);
@@ -443,7 +431,6 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
         */
        ExecInitResultTupleSlot(estate, &scanstate->cstate);
        ExecInitScanTupleSlot(estate, scanstate);
-/*       ExecInitRawTupleSlot(estate, scanstate); */
 
        /* ----------------
         *      initialize projection info.  result type comes from scan desc
@@ -461,14 +448,6 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
        tidstate = makeNode(TidScanState);
        node->tidstate = tidstate;
 
-       /* ----------------
-        *      assign base id to tid scan state also
-        * ----------------
-        */
-       tidstate->cstate.cs_base_id = baseid;
-       baseid++;
-       estate->es_BaseId = baseid;
-
        /* ----------------
         *      get the tid node information
         * ----------------
@@ -514,14 +493,6 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
        ExecAssignScanType(scanstate, RelationGetDescr(currentRelation));
        ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
 
-       /* ----------------
-        *      tid scans don't have subtrees..
-        * ----------------
-        */
-/*       scanstate->ss_ProcOuterFlag = false; */
-
-       tidstate->cstate.cs_TupFromTlist = false;
-
        /*
         * if there are some PARAM_EXEC in skankeys then force tid rescan on
         * first scan.
index add569a2c21cb7f2b6b6099542e4c7094e526ea6..29c790b2c7677e6bf88892fb5ff39dca014dd23d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.29 2000/05/30 00:49:45 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.30 2000/07/12 02:37:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -88,27 +88,32 @@ ExecUnique(Unique *node)
                if (!execTuplesMatch(slot->val, uniquestate->priorTuple,
                                                         tupDesc,
                                                         node->numCols, node->uniqColIdx,
-                                                        uniquestate->eqfunctions))
+                                                        uniquestate->eqfunctions,
+                                                        uniquestate->tempContext))
                        break;
        }
 
        /* ----------------
         *      We have a new tuple different from the previous saved tuple (if any).
-        *      Save it and return it.  Note that we make two copies of the tuple:
-        *      one to keep for our own future comparisons, and one to return to the
-        *      caller.  We need to copy the tuple returned by the subplan to avoid
-        *      holding buffer refcounts, and we need our own copy because the caller
-        *      may alter the resultTupleSlot (eg via ExecRemoveJunk).
+        *      Save it and return it.  We must copy it because the source subplan
+        *      won't guarantee that this source tuple is still accessible after
+        *      fetching the next source tuple.
+        *
+        *      Note that we manage the copy ourselves.  We can't rely on the result
+        *      tuple slot to maintain the tuple reference because our caller may
+        *      replace the slot contents with a different tuple (see junk filter
+        *      handling in execMain.c).  We assume that the caller will no longer
+        *      be interested in the current tuple after he next calls us.
         * ----------------
         */
        if (uniquestate->priorTuple != NULL)
                heap_freetuple(uniquestate->priorTuple);
        uniquestate->priorTuple = heap_copytuple(slot->val);
 
-       ExecStoreTuple(heap_copytuple(slot->val),
+       ExecStoreTuple(uniquestate->priorTuple,
                                   resultTupleSlot,
                                   InvalidBuffer,
-                                  true);
+                                  false);              /* tuple does not belong to slot */
 
        return resultTupleSlot;
 }
@@ -143,14 +148,17 @@ ExecInitUnique(Unique *node, EState *estate, Plan *parent)
        /* ----------------
         *      Miscellaneous initialization
         *
-        *               +      assign node's base_id
-        *               +      assign debugging hooks and
-        *
         *      Unique nodes have no ExprContext initialization because
-        *      they never call ExecQual or ExecTargetList.
+        *      they never call ExecQual or ExecProject.  But they do need a
+        *      per-tuple memory context anyway for calling execTuplesMatch.
         * ----------------
         */
-       ExecAssignNodeBaseInfo(estate, &uniquestate->cstate, parent);
+       uniquestate->tempContext =
+               AllocSetContextCreate(CurrentMemoryContext,
+                                                         "Unique",
+                                                         ALLOCSET_DEFAULT_MINSIZE,
+                                                         ALLOCSET_DEFAULT_INITSIZE,
+                                                         ALLOCSET_DEFAULT_MAXSIZE);
 
 #define UNIQUE_NSLOTS 1
        /* ------------
@@ -207,6 +215,8 @@ ExecEndUnique(Unique *node)
 
        ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
 
+       MemoryContextDelete(uniquestate->tempContext);
+
        /* clean up tuple table */
        ExecClearTuple(uniquestate->cstate.cs_ResultTupleSlot);
        if (uniquestate->priorTuple != NULL)
index 605fe70e6c1950cffaae45513c3e2216c7159d8e..bc305382dfea192c957b90832c04a5f0044359de 100644 (file)
@@ -19,7 +19,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.115 2000/06/29 07:35:56 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.116 2000/07/12 02:37:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -578,7 +578,7 @@ _copySubPlan(SubPlan *from)
        Node_Copy(from, newnode, sublink);
 
        /* do not copy execution state */
-       newnode->shutdown = false;
+       newnode->needShutdown = false;
        newnode->curTuple = NULL;
 
        return newnode;
index 308f4d90e87072821ea9d78c8c6932ff665020a1..b8814786180158ae7951368244fd2cc7ebcd5e69 100644 (file)
@@ -24,7 +24,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.67 2000/06/29 07:35:56 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.68 2000/07/12 02:37:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -184,8 +184,8 @@ _equalConst(Const *a, Const *b)
         */
        if (a->constisnull)
                return true;
-       return (datumIsEqual(a->constvalue, b->constvalue,
-                                                a->consttype, a->constbyval, a->constlen));
+       return datumIsEqual(a->constvalue, b->constvalue,
+                                               a->constbyval, a->constlen);
 }
 
 static bool
index b9830edc22ffcf323396393933bb22b174b1e9ae..2999c4263b15bb1826e59cab1c10a93a97b5007c 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.120 2000/06/18 22:44:05 tgl Exp $
+ *     $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.121 2000/07/12 02:37:06 tgl Exp $
  *
  * NOTES
  *       Every (plan) node in POSTGRES has an associated "out" routine which
@@ -1155,10 +1155,10 @@ _outJoinInfo(StringInfo str, JoinInfo *node)
 static void
 _outDatum(StringInfo str, Datum value, Oid type)
 {
-       char       *s;
-       Size            length,
-                               typeLength;
        bool            byValue;
+       int                     typeLength;
+       Size            length;
+       char       *s;
        int                     i;
 
        /*
@@ -1167,12 +1167,12 @@ _outDatum(StringInfo str, Datum value, Oid type)
         */
        byValue = get_typbyval(type);
        typeLength = get_typlen(type);
-       length = datumGetSize(value, type, byValue, typeLength);
+       length = datumGetSize(value, byValue, typeLength);
 
        if (byValue)
        {
                s = (char *) (&value);
-               appendStringInfo(str, " %d [ ", length);
+               appendStringInfo(str, " %u [ ", (unsigned int) length);
                for (i = 0; i < (int) sizeof(Datum); i++)
                        appendStringInfo(str, "%d ", (int) (s[i]));
                appendStringInfo(str, "] ");
@@ -1184,14 +1184,7 @@ _outDatum(StringInfo str, Datum value, Oid type)
                        appendStringInfo(str, " 0 [ ] ");
                else
                {
-
-                       /*
-                        * length is unsigned - very bad to do < comparison to -1
-                        * without casting it to int first!! -mer 8 Jan 1991
-                        */
-                       if (((int) length) <= -1)
-                               length = VARSIZE(s);
-                       appendStringInfo(str, " %d [ ", length);
+                       appendStringInfo(str, " %u [ ", (unsigned int) length);
                        for (i = 0; i < (int) length; i++)
                                appendStringInfo(str, "%d ", (int) (s[i]));
                        appendStringInfo(str, "] ");
index f872d952d03e1bbfcd849d9762709ba07b277493..4754cbc327add461cfec06bc700cda1811013aef 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.91 2000/06/18 22:44:05 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.92 2000/07/12 02:37:06 tgl Exp $
  *
  * NOTES
  *       Most of the read functions for plan nodes are tested. (In fact, they
@@ -608,7 +608,7 @@ _readHash()
        _getPlan((Plan *) local_node);
 
        token = lsptok(NULL, &length);          /* eat :hashkey */
-       local_node->hashkey = (Var *) nodeRead(true);
+       local_node->hashkey = nodeRead(true);
 
        return local_node;
 }
index 4915133d0a6cb14e40dc6519dae61f6e40f96b2b..bf91b8d1a6ce753e3f5a69525e96784a5ec4615f 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.93 2000/06/18 22:44:07 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.94 2000/07/12 02:37:08 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -66,7 +66,7 @@ static NestLoop *make_nestloop(List *qptlist, List *qpqual, Plan *lefttree,
                          Plan *righttree);
 static HashJoin *make_hashjoin(List *tlist, List *qpqual,
                          List *hashclauses, Plan *lefttree, Plan *righttree);
-static Hash *make_hash(List *tlist, Var *hashkey, Plan *lefttree);
+static Hash *make_hash(List *tlist, Node *hashkey, Plan *lefttree);
 static MergeJoin *make_mergejoin(List *tlist, List *qpqual,
                           List *mergeclauses, Plan *righttree, Plan *lefttree);
 static void copy_path_costsize(Plan *dest, Path *src);
@@ -664,7 +664,7 @@ create_hashjoin_node(HashPath *best_path,
        List       *hashclauses;
        HashJoin   *join_node;
        Hash       *hash_node;
-       Var                *innerhashkey;
+       Node       *innerhashkey;
 
        /*
         * NOTE: there will always be exactly one hashclause in the list
@@ -694,7 +694,7 @@ create_hashjoin_node(HashPath *best_path,
                                                                                           (Index) 0));
 
        /* Now the righthand op of the sole hashclause is the inner hash key. */
-       innerhashkey = get_rightop(lfirst(hashclauses));
+       innerhashkey = (Node *) get_rightop(lfirst(hashclauses));
 
        /*
         * Build the hash node and hash join node.
@@ -1103,7 +1103,7 @@ make_hashjoin(List *tlist,
 }
 
 static Hash *
-make_hash(List *tlist, Var *hashkey, Plan *lefttree)
+make_hash(List *tlist, Node *hashkey, Plan *lefttree)
 {
        Hash       *node = makeNode(Hash);
        Plan       *plan = &node->plan;
index cd624fb111d41b9a8f3d8d562dbe175806847363..6d69171f1b47dbfe43707b4b92c8e3f14ed281e1 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.38 2000/06/18 22:44:09 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.39 2000/07/12 02:37:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -649,7 +649,7 @@ SS_finalize_plan(Plan *plan)
                        break;
 
                case T_Hash:
-                       finalize_primnode((Node *) ((Hash *) plan)->hashkey,
+                       finalize_primnode(((Hash *) plan)->hashkey,
                                                          &results);
                        break;
 
index f1963d229662cc777ae821b5b4d45ea90c346ac4..d3a813fb86c134f9f4c1ef21e64edb05fd2cf481 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.68 2000/05/30 00:49:49 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.69 2000/07/12 02:37:11 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -30,6 +30,7 @@
 #include "optimizer/var.h"
 #include "parser/parse_type.h"
 #include "parser/parsetree.h"
+#include "utils/datum.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
@@ -1317,7 +1318,10 @@ simplify_op_or_func(Expr *expr, List *args)
        HeapTuple       func_tuple;
        Form_pg_proc funcform;
        Type            resultType;
+       bool            resultTypByVal;
+       int                     resultTypLen;
        Expr       *newexpr;
+       ExprContext *econtext;
        Datum           const_val;
        bool            has_nonconst_input = false;
        bool            has_null_input = false;
@@ -1424,25 +1428,35 @@ simplify_op_or_func(Expr *expr, List *args)
        newexpr->oper = expr->oper;
        newexpr->args = args;
 
+       /* Get info needed about result datatype */
+       resultType = typeidType(result_typeid);
+       resultTypByVal = typeByVal(resultType);
+       resultTypLen = typeLen(resultType);
+
        /*
-        * It is OK to pass econtext = NULL because none of the ExecEvalExpr()
+        * It is OK to pass a dummy 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?
         */
-       const_val = ExecEvalExpr((Node *) newexpr, NULL,
-                                                        &const_is_null, &isDone);
+       econtext = MakeExprContext(NULL, CurrentMemoryContext);
+
+       const_val = ExecEvalExprSwitchContext((Node *) newexpr, econtext,
+                                                                                 &const_is_null, &isDone);
        Assert(isDone);                         /* if this isn't set, we blew it... */
+
+       /* Must copy result out of sub-context used by expression eval */
+       const_val = datumCopy(const_val, resultTypByVal, resultTypLen);
+
+       FreeExprContext(econtext);
        pfree(newexpr);
 
        /*
         * Make the constant result node.
         */
-       resultType = typeidType(result_typeid);
-       return (Expr *) makeConst(result_typeid, typeLen(resultType),
+       return (Expr *) makeConst(result_typeid, resultTypLen,
                                                          const_val, const_is_null,
-                                                         typeByVal(resultType),
-                                                         false, false);
+                                                         resultTypByVal, false, false);
 }
 
 
index 9e52930e20f8dc4c16d145038822bca6787e11fe..57818afb9edadcdebad9afd6add333f18da3a353 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.35 2000/06/28 03:32:22 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.36 2000/07/12 02:37:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -72,7 +72,6 @@ CreateExecutorState(void)
        state->es_param_list_info = NULL;
        state->es_param_exec_vals = NULL;
 
-       state->es_BaseId = 0;
        state->es_tupleTable = NULL;
 
        state->es_junkFilter = NULL;
index a86ec87067bb004509108fec6b0e51f227ccb184..7f590e06e46436a1b1a37e974df98ed23cbc458b 100644 (file)
@@ -1,13 +1,14 @@
 /*-------------------------------------------------------------------------
  *
  * datum.c
+ *       POSTGRES Datum (abstract data type) manipulation routines.
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/datum.c,v 1.17 2000/01/26 05:57:13 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/datum.c,v 1.18 2000/07/12 02:37:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,7 +17,7 @@
  *
  * A) if a type is "byVal" then all the information is stored in the
  * Datum itself (i.e. no pointers involved!). In this case the
- * length of the type is always greater than zero and less than
+ * length of the type is always greater than zero and not more than
  * "sizeof(Datum)"
  * B) if a type is not "byVal" and it has a fixed length, then
  * the "Datum" always contain a pointer to a stream of bytes.
  * This varlena structure has information about the actual length of this
  * particular instance of the type and about its value.
  *
+ * Note that we do not treat "toasted" datums specially; therefore what
+ * will be copied or compared is the compressed data or toast reference.
  */
+
 #include "postgres.h"
+
 #include "utils/datum.h"
 
 /*-------------------------------------------------------------------------
  * datumGetSize
  *
  * Find the "real" size of a datum, given the datum value,
- * its type, whether it is a "by value", and its length.
+ * whether it is a "by value", and its length.
  *
  * To cut a long story short, usually the real size is equal to the
  * type length, with the exception of variable length types which have
  *-------------------------------------------------------------------------
  */
 Size
-datumGetSize(Datum value, Oid type, bool byVal, Size len)
+datumGetSize(Datum value, bool typByVal, int typLen)
 {
+       Size            size;
 
-       struct varlena *s;
-       Size            size = 0;
-
-       if (byVal)
+       if (typByVal)
        {
-               if (len <= sizeof(Datum))
-                       size = len;
-               else
-               {
-                       elog(ERROR,
-                                "datumGetSize: Error: type=%ld, byVaL with len=%d",
-                                (long) type, len);
-               }
+               /* Pass-by-value types are always fixed-length */
+               Assert(typLen > 0 && typLen <= sizeof(Datum));
+               size = (Size) typLen;
        }
        else
-       {                                                       /* not byValue */
-               if (len == -1)
+       {
+               if (typLen == -1)
                {
+                       /* Assume it is a varlena datatype */
+                       struct varlena *s = (struct varlena *) DatumGetPointer(value);
 
-                       /*
-                        * variable length type Look at the varlena struct for its
-                        * real length...
-                        */
-                       s = (struct varlena *) DatumGetPointer(value);
                        if (!PointerIsValid(s))
-                       {
-                               elog(ERROR,
-                                        "datumGetSize: Invalid Datum Pointer");
-                       }
+                               elog(ERROR, "datumGetSize: Invalid Datum Pointer");
                        size = (Size) VARSIZE(s);
                }
                else
                {
-
-                       /*
-                        * fixed length type
-                        */
-                       size = len;
+                       /* Fixed-length pass-by-ref type */
+                       size = (Size) typLen;
                }
        }
 
@@ -97,37 +86,29 @@ datumGetSize(Datum value, Oid type, bool byVal, Size len)
  *
  * make a copy of a datum
  *
- * If the type of the datum is not passed by value (i.e. "byVal=false")
- * then we assume that the datum contains a pointer and we copy all the
- * bytes pointed by this pointer
+ * If the datatype is pass-by-reference, memory is obtained with palloc().
  *-------------------------------------------------------------------------
  */
 Datum
-datumCopy(Datum value, Oid type, bool byVal, Size len)
+datumCopy(Datum value, bool typByVal, int typLen)
 {
-
-       Size            realSize;
        Datum           res;
-       char       *s;
-
 
-       if (byVal)
+       if (typByVal)
                res = value;
        else
        {
-               if (value == 0)
-                       return (Datum) NULL;
-               realSize = datumGetSize(value, type, byVal, len);
+               Size            realSize;
+               char       *s;
+
+               if (DatumGetPointer(value) == NULL)
+                       return PointerGetDatum(NULL);
+
+               realSize = datumGetSize(value, typByVal, typLen);
 
-               /*
-                * the value is a pointer. Allocate enough space and copy the
-                * pointed data.
-                */
                s = (char *) palloc(realSize);
-               if (s == NULL)
-                       elog(ERROR, "datumCopy: out of memory\n");
-               memmove(s, DatumGetPointer(value), realSize);
-               res = (Datum) s;
+               memcpy(s, DatumGetPointer(value), realSize);
+               res = PointerGetDatum(s);
        }
        return res;
 }
@@ -143,21 +124,12 @@ datumCopy(Datum value, Oid type, bool byVal, Size len)
  */
 #ifdef NOT_USED
 void
-datumFree(Datum value, Oid type, bool byVal, Size len)
+datumFree(Datum value, bool typByVal, int typLen)
 {
-
-       Size            realSize;
-       Pointer         s;
-
-       realSize = datumGetSize(value, type, byVal, len);
-
-       if (!byVal)
+       if (!typByVal)
        {
+               Pointer         s = DatumGetPointer(value);
 
-               /*
-                * free the space palloced by "datumCopy()"
-                */
-               s = DatumGetPointer(value);
                pfree(s);
        }
 }
@@ -174,46 +146,41 @@ datumFree(Datum value, Oid type, bool byVal, Size len)
  * This routine will return false if there are 2 different
  * representations of the same value (something along the lines
  * of say the representation of zero in one's complement arithmetic).
- *
+ * Also, it will probably not give the answer you want if either
+ * datum has been "toasted".
  *-------------------------------------------------------------------------
  */
 bool
-datumIsEqual(Datum value1, Datum value2, Oid type, bool byVal, Size len)
+datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
 {
-       Size            size1,
-                               size2;
-       char       *s1,
-                          *s2;
+       bool    res;
 
-       if (byVal)
+       if (typByVal)
        {
-
                /*
                 * just compare the two datums. NOTE: just comparing "len" bytes
                 * will not do the work, because we do not know how these bytes
                 * are aligned inside the "Datum".
                 */
-               if (value1 == value2)
-                       return true;
-               else
-                       return false;
+               res = (value1 == value2);
        }
        else
        {
+               Size            size1,
+                                       size2;
+               char       *s1,
+                                  *s2;
 
                /*
-                * byVal = false Compare the bytes pointed by the pointers stored
-                * in the datums.
+                * Compare the bytes pointed by the pointers stored in the datums.
                 */
-               size1 = datumGetSize(value1, type, byVal, len);
-               size2 = datumGetSize(value2, type, byVal, len);
+               size1 = datumGetSize(value1, typByVal, typLen);
+               size2 = datumGetSize(value2, typByVal, typLen);
                if (size1 != size2)
                        return false;
                s1 = (char *) DatumGetPointer(value1);
                s2 = (char *) DatumGetPointer(value2);
-               if (!memcmp(s1, s2, size1))
-                       return true;
-               else
-                       return false;
+               res = (memcmp(s1, s2, size1) == 0);
        }
+       return res;
 }
index 8247e16812dfc1c9d95fb1df327d4e7a42a65576..b5380a8c52a56e27fa75d8ae452cd7776d9238f8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.63 2000/07/06 05:48:11 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.64 2000/07/12 02:37:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -436,25 +436,38 @@ textpos(PG_FUNCTION_ARGS)
 /*
  *             texteq                  - returns true iff arguments are equal
  *             textne                  - returns true iff arguments are not equal
+ *
+ * Note: btree indexes need these routines not to leak memory; therefore,
+ * be careful to free working copies of toasted datums.  Most places don't
+ * need to be so careful.
  */
 Datum
 texteq(PG_FUNCTION_ARGS)
 {
        text       *arg1 = PG_GETARG_TEXT_P(0);
        text       *arg2 = PG_GETARG_TEXT_P(1);
-       int                     len;
-       char       *a1p,
-                          *a2p;
+       bool            result;
 
        if (VARSIZE(arg1) != VARSIZE(arg2))
-               PG_RETURN_BOOL(false);
+               result = false;
+       else
+       {
+               int                     len;
+               char       *a1p,
+                                  *a2p;
 
-       len = VARSIZE(arg1) - VARHDRSZ;
+               len = VARSIZE(arg1) - VARHDRSZ;
 
-       a1p = VARDATA(arg1);
-       a2p = VARDATA(arg2);
+               a1p = VARDATA(arg1);
+               a2p = VARDATA(arg2);
 
-       PG_RETURN_BOOL(memcmp(a1p, a2p, len) == 0);
+               result = (memcmp(a1p, a2p, len) == 0);
+       }
+
+       PG_FREE_IF_COPY(arg1, 0);
+       PG_FREE_IF_COPY(arg2, 1);
+
+       PG_RETURN_BOOL(result);
 }
 
 Datum
@@ -462,19 +475,28 @@ textne(PG_FUNCTION_ARGS)
 {
        text       *arg1 = PG_GETARG_TEXT_P(0);
        text       *arg2 = PG_GETARG_TEXT_P(1);
-       int                     len;
-       char       *a1p,
-                          *a2p;
+       bool            result;
 
        if (VARSIZE(arg1) != VARSIZE(arg2))
-               PG_RETURN_BOOL(true);
+               result = true;
+       else
+       {
+               int                     len;
+               char       *a1p,
+                                  *a2p;
 
-       len = VARSIZE(arg1) - VARHDRSZ;
+               len = VARSIZE(arg1) - VARHDRSZ;
 
-       a1p = VARDATA(arg1);
-       a2p = VARDATA(arg2);
+               a1p = VARDATA(arg1);
+               a2p = VARDATA(arg2);
+
+               result = (memcmp(a1p, a2p, len) != 0);
+       }
 
-       PG_RETURN_BOOL(memcmp(a1p, a2p, len) != 0);
+       PG_FREE_IF_COPY(arg1, 0);
+       PG_FREE_IF_COPY(arg2, 1);
+
+       PG_RETURN_BOOL(result);
 }
 
 /* varstr_cmp()
@@ -545,6 +567,10 @@ text_cmp(text *arg1, text *arg2)
 
 /*
  * Comparison functions for text strings.
+ *
+ * Note: btree indexes need these routines not to leak memory; therefore,
+ * be careful to free working copies of toasted datums.  Most places don't
+ * need to be so careful.
  */
 
 Datum
@@ -552,8 +578,14 @@ text_lt(PG_FUNCTION_ARGS)
 {
        text       *arg1 = PG_GETARG_TEXT_P(0);
        text       *arg2 = PG_GETARG_TEXT_P(1);
+       bool            result;
 
-       PG_RETURN_BOOL(text_cmp(arg1, arg2) < 0);
+       result = (text_cmp(arg1, arg2) < 0);
+
+       PG_FREE_IF_COPY(arg1, 0);
+       PG_FREE_IF_COPY(arg2, 1);
+
+       PG_RETURN_BOOL(result);
 }
 
 Datum
@@ -561,8 +593,14 @@ text_le(PG_FUNCTION_ARGS)
 {
        text       *arg1 = PG_GETARG_TEXT_P(0);
        text       *arg2 = PG_GETARG_TEXT_P(1);
+       bool            result;
+
+       result = (text_cmp(arg1, arg2) <= 0);
+
+       PG_FREE_IF_COPY(arg1, 0);
+       PG_FREE_IF_COPY(arg2, 1);
 
-       PG_RETURN_BOOL(text_cmp(arg1, arg2) <= 0);
+       PG_RETURN_BOOL(result);
 }
 
 Datum
@@ -570,8 +608,14 @@ text_gt(PG_FUNCTION_ARGS)
 {
        text       *arg1 = PG_GETARG_TEXT_P(0);
        text       *arg2 = PG_GETARG_TEXT_P(1);
+       bool            result;
 
-       PG_RETURN_BOOL(text_cmp(arg1, arg2) > 0);
+       result = (text_cmp(arg1, arg2) > 0);
+
+       PG_FREE_IF_COPY(arg1, 0);
+       PG_FREE_IF_COPY(arg2, 1);
+
+       PG_RETURN_BOOL(result);
 }
 
 Datum
@@ -579,8 +623,14 @@ text_ge(PG_FUNCTION_ARGS)
 {
        text       *arg1 = PG_GETARG_TEXT_P(0);
        text       *arg2 = PG_GETARG_TEXT_P(1);
+       bool            result;
+
+       result = (text_cmp(arg1, arg2) >= 0);
+
+       PG_FREE_IF_COPY(arg1, 0);
+       PG_FREE_IF_COPY(arg2, 1);
 
-       PG_RETURN_BOOL(text_cmp(arg1, arg2) >= 0);
+       PG_RETURN_BOOL(result);
 }
 
 Datum
@@ -589,14 +639,8 @@ text_larger(PG_FUNCTION_ARGS)
        text       *arg1 = PG_GETARG_TEXT_P(0);
        text       *arg2 = PG_GETARG_TEXT_P(1);
        text       *result;
-       text       *temp;
 
-       temp = ((text_cmp(arg1, arg2) > 0) ? arg1 : arg2);
-
-       /* Make a copy --- temporary hack until nodeAgg.c is smarter */
-
-       result = (text *) palloc(VARSIZE(temp));
-       memcpy((char *) result, (char *) temp, VARSIZE(temp));
+       result = ((text_cmp(arg1, arg2) > 0) ? arg1 : arg2);
 
        PG_RETURN_TEXT_P(result);
 }
@@ -607,14 +651,8 @@ text_smaller(PG_FUNCTION_ARGS)
        text       *arg1 = PG_GETARG_TEXT_P(0);
        text       *arg2 = PG_GETARG_TEXT_P(1);
        text       *result;
-       text       *temp;
-
-       temp = ((text_cmp(arg1, arg2) < 0) ? arg1 : arg2);
-
-       /* Make a copy --- temporary hack until nodeAgg.c is smarter */
 
-       result = (text *) palloc(VARSIZE(temp));
-       memcpy((char *) result, (char *) temp, VARSIZE(temp));
+       result = ((text_cmp(arg1, arg2) < 0) ? arg1 : arg2);
 
        PG_RETURN_TEXT_P(result);
 }
index 7e9d18c7e27727627044effa4806107cbc81ffb5..ba34dfd03dc9448f40bf78800396d3c405828870 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.33 2000/07/05 23:11:39 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.34 2000/07/12 02:37:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -75,6 +75,7 @@ init_fcache(Oid foid,
 
        retval = (FunctionCachePtr) palloc(sizeof(FunctionCache));
        MemSet(retval, 0, sizeof(FunctionCache));
+       retval->fcacheCxt = CurrentMemoryContext;
 
        /* ----------------
         *       get the procedure tuple corresponding to the given functionOid
@@ -256,22 +257,26 @@ init_fcache(Oid foid,
 void
 setFcache(Node *node, Oid foid, List *argList, ExprContext *econtext)
 {
-       Func       *fnode;
-       Oper       *onode;
+       MemoryContext oldcontext;
        FunctionCachePtr fcache;
 
+       /* Switch to a context long-lived enough for the fcache entry */
+       oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
+
        fcache = init_fcache(foid, argList, econtext);
 
        if (IsA(node, Oper))
        {
-               onode = (Oper *) node;
+               Oper       *onode = (Oper *) node;
                onode->op_fcache = fcache;
        }
        else if (IsA(node, Func))
        {
-               fnode = (Func *) node;
+               Func       *fnode = (Func *) node;
                fnode->func_fcache = fcache;
        }
        else
                elog(ERROR, "init_fcache: node must be Oper or Func!");
+
+       MemoryContextSwitchTo(oldcontext);
 }
index bf212ff7bb5f5da4d46684d75d5d7b42a2e08ff0..6c6f58b0222b355e8a25a6fafa879ea346796d86 100644 (file)
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.29 2000/07/11 14:30:28 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.30 2000/07/12 02:37:23 tgl Exp $
  *
  * NOTE:
  *     This is a new (Feb. 05, 1999) implementation of the allocation set
@@ -349,20 +349,21 @@ AllocSetReset(MemoryContext context)
                if (block == set->keeper)
                {
                        /* Reset the block, but don't return it to malloc */
-                       block->next = NULL;
-                       block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
+                       char   *datastart = ((char *) block) + ALLOC_BLOCKHDRSZ;
+
 #ifdef CLOBBER_FREED_MEMORY
                        /* Wipe freed memory for debugging purposes */
-                       memset(block->freeptr, 0x7F,
-                                  ((char *) block->endptr) - ((char *) block->freeptr));
+                       memset(datastart, 0x7F, ((char *) block->freeptr) - datastart);
 #endif
+                       block->freeptr = datastart;
+                       block->next = NULL;
                }
                else
                {
                        /* Normal case, release the block */
 #ifdef CLOBBER_FREED_MEMORY
                        /* Wipe freed memory for debugging purposes */
-                       memset(block, 0x7F, ((char *) block->endptr) - ((char *) block));
+                       memset(block, 0x7F, ((char *) block->freeptr) - ((char *) block));
 #endif
                        free(block);
                }
index dd495517d30c5dee3fdf804a8274b67b1897381f..66b4f601be36d061065470636f7bdba0b998181e 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: index.h,v 1.27 2000/07/04 06:11:54 tgl Exp $
+ * $Id: index.h,v 1.28 2000/07/12 02:37:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,9 +53,6 @@ extern void setRelhasindexInplace(Oid relid, bool hasindex, bool immediate);
 extern bool SetReindexProcessing(bool processing);
 extern bool IsReindexProcessing(void);
 
-extern void FillDummyExprContext(ExprContext *econtext, TupleTableSlot *slot,
-                                        TupleDesc tupdesc, Buffer buffer);
-
 extern void index_build(Relation heapRelation, Relation indexRelation,
                                                int numberOfAttributes, AttrNumber *attributeNumber,
                                                FuncIndexInfo *funcInfo, PredInfo *predInfo,
index 703c907e127ccd14fc5f230af32268b47d358690..b835b29044007ded607451fbbc5ce50843d567be 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: executor.h,v 1.45 2000/06/18 22:44:28 tgl Exp $
+ * $Id: executor.h,v 1.46 2000/07/12 02:37:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -72,19 +72,16 @@ extern void ExecEndNode(Plan *node, Plan *parent);
 /*
  * prototypes from functions in execQual.c
  */
-extern bool execConstByVal;
-extern int     execConstLen;
-
-extern Datum ExecExtractResult(TupleTableSlot *slot, AttrNumber attnum,
-                                 bool *isNull);
 extern Datum ExecEvalParam(Param *expression, ExprContext *econtext,
                          bool *isNull);
-
 extern char *GetAttributeByNum(TupleTableSlot *slot, AttrNumber attrno,
                                  bool *isNull);
-extern char *GetAttributeByName(TupleTableSlot *slot, char *attname, bool *isNull);
-extern Datum ExecEvalExpr(Node *expression, ExprContext *econtext, bool *isNull,
-                        bool *isDone);
+extern char *GetAttributeByName(TupleTableSlot *slot, char *attname,
+                                                               bool *isNull);
+extern Datum ExecEvalExpr(Node *expression, ExprContext *econtext,
+                                                 bool *isNull, bool *isDone);
+extern Datum ExecEvalExprSwitchContext(Node *expression, ExprContext *econtext,
+                                                                          bool *isNull, bool *isDone);
 extern bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull);
 extern int     ExecTargetListLength(List *targetlist);
 extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo, bool *isDone);
@@ -92,7 +89,9 @@ extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo, bool *isDone);
 /*
  * prototypes from functions in execScan.c
  */
-extern TupleTableSlot *ExecScan(Scan *node, TupleTableSlot *(*accessMtd) ());
+typedef TupleTableSlot *(*ExecScanAccessMtd) (Scan *node);
+
+extern TupleTableSlot *ExecScan(Scan *node, ExecScanAccessMtd accessMtd);
 
 /*
  * prototypes from functions in execTuples.c
@@ -121,8 +120,6 @@ extern void SetChangedParamList(Plan *node, List *newchg);
  * prototypes from functions in execUtils.c
  */
 extern void ResetTupleCount(void);
-extern void ExecAssignNodeBaseInfo(EState *estate, CommonState *basenode,
-                                          Plan *parent);
 extern void ExecAssignExprContext(EState *estate, CommonState *commonstate);
 extern void ExecAssignResultType(CommonState *commonstate,
                                         TupleDesc tupDesc);
@@ -133,7 +130,6 @@ extern TupleDesc ExecGetResultType(CommonState *commonstate);
 extern void ExecAssignProjectionInfo(Plan *node, CommonState *commonstate);
 extern void ExecFreeProjectionInfo(CommonState *commonstate);
 extern void ExecFreeExprContext(CommonState *commonstate);
-extern void ExecFreeTypeInfo(CommonState *commonstate);
 extern TupleDesc ExecGetScanType(CommonScanState *csstate);
 extern void ExecAssignScanType(CommonScanState *csstate,
                                   TupleDesc tupDesc);
@@ -141,6 +137,13 @@ extern void ExecAssignScanTypeFromOuterPlan(Plan *node,
                                                                CommonScanState *csstate);
 extern Form_pg_attribute ExecGetTypeInfo(Relation relDesc);
 
+extern ExprContext *MakeExprContext(TupleTableSlot *slot,
+                                                                       MemoryContext queryContext);
+extern void FreeExprContext(ExprContext *econtext);
+
+#define ResetExprContext(econtext) \
+       MemoryContextReset((econtext)->ecxt_per_tuple_memory)
+
 extern void ExecOpenIndices(RelationInfo *resultRelationInfo);
 extern void ExecCloseIndices(RelationInfo *resultRelationInfo);
 extern void ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid,
index 285bb314d3dd66895bad4fc079c7bf0e6241496d..8d4cb98469fd7336941cee618aa44810cb7d27c4 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: hashjoin.h,v 1.17 2000/06/28 03:33:05 tgl Exp $
+ * $Id: hashjoin.h,v 1.18 2000/07/12 02:37:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,8 +21,8 @@
  *                             hash-join hash table structures
  *
  * Each active hashjoin has a HashJoinTable control block which is
- * palloc'd in the executor's context. All other storage needed for
- * the hashjoin is kept in private memory contexts, two for each hashjoin.
+ * palloc'd in the executor's per-query context.  All other storage needed
+ * for the hashjoin is kept in private memory contexts, two for each hashjoin.
  * This makes it easy and fast to release the storage when we don't need it
  * anymore.
  *
@@ -68,6 +68,14 @@ typedef struct HashTableData
        long       *innerBatchSize; /* count of tuples in each inner batch
                                                                 * file */
 
+       /*
+        * Info about the datatype being hashed.  We assume that the inner
+        * and outer sides of the hash are the same type, or at least
+        * binary-compatible types.
+        */
+       bool            typByVal;
+       int                     typLen;
+
        /*
         * During 1st scan of inner relation, we get tuples from executor. If
         * nbatch > 0 then tuples that don't belong in first nbuckets logical
index 303516b167e94776f331457b52580db36a4f0b8a..71bd3b52ff563d5c2bfb977d7f5b382c5726a4ae 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodeGroup.h,v 1.16 2000/04/12 17:16:33 momjian Exp $
+ * $Id: nodeGroup.h,v 1.17 2000/07/12 02:37:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,7 +27,8 @@ extern bool execTuplesMatch(HeapTuple tuple1,
                                TupleDesc tupdesc,
                                int numCols,
                                AttrNumber *matchColIdx,
-                               FmgrInfo *eqfunctions);
+                               FmgrInfo *eqfunctions,
+                               MemoryContext evalContext);
 extern FmgrInfo *execTuplesMatchPrepare(TupleDesc tupdesc,
                                           int numCols,
                                           AttrNumber *matchColIdx);
index b61ced7cdc1900c09f11391d2df3eafcb03ea271..5fabe7d253af2f4fc61d6fc5054f93240f49d776 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodeHash.h,v 1.16 2000/04/18 05:43:00 tgl Exp $
+ * $Id: nodeHash.h,v 1.17 2000/07/12 02:37:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -25,10 +25,12 @@ extern int  ExecCountSlotsHash(Hash *node);
 extern void ExecEndHash(Hash *node);
 extern HashJoinTable ExecHashTableCreate(Hash *node);
 extern void ExecHashTableDestroy(HashJoinTable hashtable);
-extern void ExecHashTableInsert(HashJoinTable hashtable, ExprContext *econtext,
-                                       Var *hashkey);
-extern int ExecHashGetBucket(HashJoinTable hashtable, ExprContext *econtext,
-                                 Var *hashkey);
+extern void ExecHashTableInsert(HashJoinTable hashtable,
+                                                               ExprContext *econtext,
+                                                               Node *hashkey);
+extern int ExecHashGetBucket(HashJoinTable hashtable,
+                                                        ExprContext *econtext,
+                                                        Node *hashkey);
 extern HeapTuple ExecScanHashBucket(HashJoinState *hjstate, List *hjclauses,
                                   ExprContext *econtext);
 extern void ExecHashTableReset(HashJoinTable hashtable, long ntuples);
index a56ae216f5edeb6384835509f80323cf26acdad3..f7c46c3ca9241db1bed5517249705fb8c38f8e2e 100644 (file)
@@ -13,7 +13,7 @@ extern Datum ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext,
                        bool *isNull);
 extern bool ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent);
 extern void ExecReScanSetParamPlan(SubPlan *node, Plan *parent);
-extern void ExecSetParamPlan(SubPlan *node);
+extern void ExecSetParamPlan(SubPlan *node, ExprContext *econtext);
 extern void ExecEndSubPlan(SubPlan *node);
 
 #endif  /* NODESUBPLAN_H */
index b0aea5df09e67b77a904028a1b789ccc52fbee5a..03d13e3d4ed2548fb179c45b011cdcbbee139280 100644 (file)
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: fmgr.h,v 1.7 2000/07/06 05:48:17 tgl Exp $
+ * $Id: fmgr.h,v 1.8 2000/07/12 02:37:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -119,6 +119,21 @@ extern struct varlena * pg_detoast_datum_copy(struct varlena * datum);
 #define PG_DETOAST_DATUM_COPY(datum) \
        pg_detoast_datum_copy((struct varlena *) DatumGetPointer(datum))
 
+/*
+ * Support for cleaning up detoasted copies of inputs.  This must only
+ * be used for pass-by-ref datatypes, and normally would only be used
+ * for toastable types.  If the given pointer is different from the
+ * original argument, assume it's a palloc'd detoasted copy, and pfree it.
+ * NOTE: most functions on toastable types do not have to worry about this,
+ * but we currently require that support functions for indexes not leak
+ * memory.
+ */
+#define PG_FREE_IF_COPY(ptr,n) \
+       do { \
+               if ((Pointer) (ptr) != PG_GETARG_POINTER(n)) \
+                       pfree(ptr); \
+       } while (0)
+
 /* Macros for fetching arguments of standard types */
 
 #define PG_GETARG_DATUM(n)   (fcinfo->arg[n])
index a74f16348d27f31258bcbea1277a9580297b91ea..2c21dba9c237acfcc1735b41630a44e62a388878 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: execnodes.h,v 1.42 2000/06/18 22:44:29 tgl Exp $
+ * $Id: execnodes.h,v 1.43 2000/07/12 02:37:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -76,29 +76,46 @@ typedef struct RelationInfo
  *             to an attribute in the current inner tuple then we need to know
  *             what the current inner tuple is and so we look at the expression
  *             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 operator/function fcache nodes.
+ *     * 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().
  * ----------------
  */
 typedef struct ExprContext
 {
        NodeTag         type;
+       /* Tuples that Var nodes in expression may refer to */
        TupleTableSlot *ecxt_scantuple;
        TupleTableSlot *ecxt_innertuple;
        TupleTableSlot *ecxt_outertuple;
-       Relation        ecxt_relation;
-       Index           ecxt_relid;
-       ParamListInfo ecxt_param_list_info;
-       ParamExecData *ecxt_param_exec_vals;            /* this is for subselects */
-       List       *ecxt_range_table;
+       /* Memory contexts for expression evaluation --- see notes above */
+       MemoryContext ecxt_per_query_memory;
+       MemoryContext ecxt_per_tuple_memory;
+       /* Values to substitute for Param nodes in expression */
+       ParamExecData *ecxt_param_exec_vals;    /* for PARAM_EXEC params */
+       ParamListInfo ecxt_param_list_info;             /* for other param types */
+       /* Values to substitute for Aggref nodes in expression */
        Datum      *ecxt_aggvalues; /* precomputed values for Aggref nodes */
        bool       *ecxt_aggnulls;      /* null flags for Aggref nodes */
+       /* Range table that Vars in expression refer to --- seldom needed */
+       List       *ecxt_range_table;
 } ExprContext;
 
 /* ----------------
  *             ProjectionInfo node information
  *
- *             This is all the information needed to preform projections
+ *             This is all the information needed to perform projections
  *             on a tuple.  Nodes which need to do projections create one
- *             of these.  In theory, when a node wants to preform a projection
+ *             of these.  In theory, when a node wants to perform a projection
  *             it should just update this information as necessary and then
  *             call ExecProject().  -cim 6/3/91
  *
@@ -122,18 +139,16 @@ typedef struct ProjectionInfo
 /* ----------------
  *       JunkFilter
  *
- *       this class is used to store information regarding junk attributes.
+ *       This class is used to store information regarding junk attributes.
  *       A junk attribute is an attribute in a tuple that is needed only for
  *       storing intermediate information in the executor, and does not belong
- *       in the tuple proper.  For example, when we do a delete or replace
- *       query, the planner adds an entry to the targetlist so that the tuples
- *       returned to ExecutePlan() contain an extra attribute: the t_ctid of
- *       the tuple to be deleted/replaced.  This is needed for amdelete() and
- *       amreplace().  In doing a delete this does not make much of a
- *       difference, but in doing a replace we have to make sure we disgard
- *       all the junk in a tuple before calling amreplace().  Otherwise the
- *       inserted tuple will not have the correct schema.      This solves a
- *       problem with hash-join and merge-sort replace plans.  -cim 10/10/90
+ *       in emitted tuples.    For example, when we do an UPDATE query,
+ *       the planner adds a "junk" entry to the targetlist so that the tuples
+ *       returned to ExecutePlan() contain an extra attribute: the ctid of
+ *       the tuple to be updated.  This is needed to do the update, but we
+ *       don't want the ctid to be part of the stored new tuple!  So, we
+ *       apply a "junk filter" to remove the junk attributes and form the
+ *       real output tuple.
  *
  *       targetList:           the original target list (including junk attributes).
  *       length:                       the length of 'targetList'.
@@ -174,10 +189,6 @@ typedef struct JunkFilter
  *             param_list_info                                 information needed to transform
  *                                                                             Param nodes into Const nodes
  *
- *             BaseId                                                  during InitPlan(), each node is
- *                                                                             given a number.  this is the next
- *                                                                             number to be assigned.
- *
  *             tupleTable                                              this is a pointer to an array
  *                                                                             of pointers to tuples used by
  *                                                                             the executor at any given moment.
@@ -185,11 +196,6 @@ typedef struct JunkFilter
  *             junkFilter                                              contains information used to
  *                                                                             extract junk attributes from a tuple.
  *                                                                             (see JunkFilter above)
- *
- *             refcount                                                local buffer refcounts used in
- *                                                                             an ExecMain cycle.      this is introduced
- *                                                                             to avoid ExecStart's unpinning each
- *                                                                             other's buffers when called recursively
  * ----------------
  */
 typedef struct EState
@@ -203,7 +209,6 @@ typedef struct EState
        Relation        es_into_relation_descriptor;
        ParamListInfo es_param_list_info;
        ParamExecData *es_param_exec_vals;      /* this is for subselects */
-       int                     es_BaseId;
        TupleTable      es_tupleTable;
        JunkFilter *es_junkFilter;
        uint32          es_processed;   /* # of tuples processed */
@@ -249,27 +254,21 @@ typedef struct EState
  * ----------------------------------------------------------------
  */
 
-/* BaseNode removed -- base_id moved into CommonState          - jolly */
-
 /* ----------------
  *      CommonState information
  *
- *|            this is a bogus class used to hold slots so other
- *|            nodes can inherit them...
+ *             Superclass for all executor node-state object types.
  *
  *             OuterTupleSlot     pointer to slot containing current "outer" tuple
  *             ResultTupleSlot    pointer to slot in tuple table for projected tuple
- *             ExprContext                node's current expression context
+ *             ExprContext                node's expression-evaluation context
  *             ProjInfo                   info this node uses to form tuple projections
- *             NumScanAttributes  size of ScanAttributes array
- *             ScanAttributes     attribute numbers of interest in this tuple
- *
+ *             TupFromTlist       state flag used by some node types (why kept here?)
  * ----------------
  */
 typedef struct CommonState
 {
        NodeTag         type;                   /* its first field is NodeTag */
-       int                     cs_base_id;
        TupleTableSlot *cs_OuterTupleSlot;
        TupleTableSlot *cs_ResultTupleSlot;
        ExprContext *cs_ExprContext;
@@ -288,15 +287,6 @@ typedef struct CommonState
  *
  *             done                       flag which tells us to quit when we
  *                                                have already returned a constant tuple.
- *
- *      CommonState information
- *
- *             OuterTupleSlot     pointer to slot containing current "outer" tuple
- *             ResultTupleSlot    pointer to slot in tuple table for projected tuple
- *             ExprContext                node's current expression context
- *             ProjInfo                   info this node uses to form tuple projections
- *             NumScanAttributes  size of ScanAttributes array
- *             ScanAttributes     attribute numbers of interest in this tuple
  * ----------------
  */
 typedef struct ResultState
@@ -319,15 +309,6 @@ typedef struct ResultState
  *             rtentries               range table for the current plan
  *             result_relation_info_list  array of each subplan's result relation info
  *             junkFilter_list  array of each subplan's junk filter
- *
- *      CommonState information
- *
- *             OuterTupleSlot     pointer to slot containing current "outer" tuple
- *             ResultTupleSlot    pointer to slot in tuple table for projected tuple
- *             ExprContext                node's current expression context
- *             ProjInfo                   info this node uses to form tuple projections
- *             NumScanAttributes  size of ScanAttributes array
- *             ScanAttributes     attribute numbers of interest in this tuple
  * ----------------
  */
 typedef struct AppendState
@@ -349,22 +330,15 @@ typedef struct AppendState
 /* ----------------
  *      CommonScanState information
  *
- *             CommonScanState is a class like CommonState, but is used more
- *             by the nodes like SeqScan and Sort which want to
- *             keep track of an underlying relation.
+ *             CommonScanState extends CommonState for node types that represent
+ *             scans of an underlying relation.  It can also be used for nodes
+ *             that scan the output of an underlying plan node --- in that case,
+ *             only ScanTupleSlot is actually useful, and it refers to the tuple
+ *             retrieved from the subplan.
  *
- *             currentRelation    relation being scanned
- *             currentScanDesc    current scan descriptor for scan
+ *             currentRelation    relation being scanned (NULL if none)
+ *             currentScanDesc    current scan descriptor for scan (NULL if none)
  *             ScanTupleSlot      pointer to slot in tuple table holding scan tuple
- *
- *      CommonState information
- *
- *             OuterTupleSlot     pointer to slot containing current "outer" tuple
- *             ResultTupleSlot    pointer to slot in tuple table for projected tuple
- *             ExprContext                node's current expression context
- *             ProjInfo                   info this node uses to form tuple projections
- *             NumScanAttributes  size of ScanAttributes array
- *             ScanAttributes     attribute numbers of interest in this tuple
  * ----------------
  */
 typedef struct CommonScanState
@@ -375,41 +349,39 @@ typedef struct CommonScanState
        TupleTableSlot *css_ScanTupleSlot;
 } CommonScanState;
 
+/*
+ * SeqScan uses a bare CommonScanState as its state item, since it needs
+ * no additional fields.
+ */
+
 /* ----------------
  *      IndexScanState information
  *
- *|            index scans don't use CommonScanState because
- *|            the underlying AM abstractions for heap scans and
- *|            index scans are too different..  It would be nice
- *|            if the current abstraction was more useful but ... -cim 10/15/89
+ *             Note that an IndexScan node *also* has a CommonScanState state item.
+ *             IndexScanState stores the info needed specifically for indexing.
+ *             There's probably no good reason why this is a separate node type
+ *             rather than an extension of CommonScanState.
  *
- *             IndexPtr                   current index in use
  *             NumIndices                 number of indices in this scan
+ *             IndexPtr                   current index in use
  *             ScanKeys                   Skey structures to scan index rels
  *             NumScanKeys                array of no of keys in each Skey struct
  *             RuntimeKeyInfo     array of array of flags for Skeys evaled at runtime
+ *             RuntimeContext     expr context for evaling runtime Skeys
  *             RelationDescs      ptr to array of relation descriptors
  *             ScanDescs                  ptr to array of scan descriptors
- *
- *      CommonState information
- *
- *             OuterTupleSlot     pointer to slot containing current "outer" tuple
- *             ResultTupleSlot    pointer to slot in tuple table for projected tuple
- *             ExprContext                node's current expression context
- *             ProjInfo                   info this node uses to form tuple projections
- *             NumScanAttributes  size of ScanAttributes array
- *             ScanAttributes     attribute numbers of interest in this tuple
  * ----------------
  */
 typedef struct IndexScanState
 {
-       CommonState cstate;                     /* its first field is NodeTag */
+       NodeTag         type;
        int                     iss_NumIndices;
        int                     iss_IndexPtr;
        int                     iss_MarkIndexPtr;
        ScanKey    *iss_ScanKeys;
        int                *iss_NumScanKeys;
-       Pointer         iss_RuntimeKeyInfo;
+       int               **iss_RuntimeKeyInfo;
+       ExprContext *iss_RuntimeContext;
        RelationPtr iss_RelationDescs;
        IndexScanDescPtr iss_ScanDescs;
        HeapTupleData iss_htup;
@@ -418,28 +390,18 @@ typedef struct IndexScanState
 /* ----------------
  *      TidScanState information
  *
- *|            tid scans don't use CommonScanState because
- *|            the underlying AM abstractions for heap scans and
- *|            tid scans are too different..  It would be nice
- *|            if the current abstraction was more useful but ... -cim 10/15/89
+ *             Note that a TidScan node *also* has a CommonScanState state item.
+ *             There's probably no good reason why this is a separate node type
+ *             rather than an extension of CommonScanState.
  *
- *             TidPtr             current tid in use
  *             NumTids            number of tids in this scan
- *             tidList            evaluated item pointers
- *
- *      CommonState information
- *
- *             OuterTupleSlot     pointer to slot containing current "outer" tuple
- *             ResultTupleSlot    pointer to slot in tuple table for projected tuple
- *             ExprContext                node's current expression context
- *             ProjInfo                   info this node uses to form tuple projections
- *             NumScanAttributes  size of ScanAttributes array
- *             ScanAttributes     attribute numbers of interest in this tuple
+ *             TidPtr             current tid in use
+ *             TidList            evaluated item pointers
  * ----------------
  */
 typedef struct TidScanState
 {
-       CommonState cstate;                     /* its first field is NodeTag */
+       NodeTag         type;
        int                     tss_NumTids;
        int                     tss_TidPtr;
        int                     tss_MarkTidPtr;
@@ -455,39 +417,19 @@ typedef struct TidScanState
 /* ----------------
  *      JoinState information
  *
- *      CommonState information
- *
- *             OuterTupleSlot     pointer to slot containing current "outer" tuple
- *             ResultTupleSlot    pointer to slot in tuple table for projected tuple
- *             ExprContext                node's current expression context
- *             ProjInfo                   info this node uses to form tuple projections
- *             NumScanAttributes  size of ScanAttributes array
- *             ScanAttributes     attribute numbers of interest in this tuple
+ *             Superclass for state items of join nodes.
+ *             Currently this is the same as CommonState.
  * ----------------
  */
 typedef CommonState JoinState;
 
 /* ----------------
  *      NestLoopState information
- *
- *             PortalFlag                 Set to enable portals to work.
- *
- *      JoinState information
- *
- *      CommonState information
- *
- *             OuterTupleSlot     pointer to slot containing current "outer" tuple
- *             ResultTupleSlot    pointer to slot in tuple table for projected tuple
- *             ExprContext                node's current expression context
- *             ProjInfo                   info this node uses to form tuple projections
- *             NumScanAttributes  size of ScanAttributes array
- *             ScanAttributes     attribute numbers of interest in this tuple
  * ----------------
  */
 typedef struct NestLoopState
 {
        JoinState       jstate;                 /* its first field is NodeTag */
-       bool            nl_PortalFlag;
 } NestLoopState;
 
 /* ----------------
@@ -497,17 +439,6 @@ typedef struct NestLoopState
  *             InnerSkipQual      outerKey1 > innerKey1 ...
  *             JoinState                  current "state" of join. see executor.h
  *             MarkedTupleSlot    pointer to slot in tuple table for marked tuple
- *
- *      JoinState information
- *
- *      CommonState information
- *
- *             OuterTupleSlot     pointer to slot containing current "outer" tuple
- *             ResultTupleSlot    pointer to slot in tuple table for projected tuple
- *             ExprContext                node's current expression context
- *             ProjInfo                   info this node uses to form tuple projections
- *             NumScanAttributes  size of ScanAttributes array
- *             ScanAttributes     attribute numbers of interest in this tuple
  * ----------------
  */
 typedef struct MergeJoinState
@@ -531,17 +462,6 @@ typedef struct MergeJoinState
  *             hj_InnerHashKey                 the inner hash key in the hashjoin condition
  *             hj_OuterTupleSlot               tuple slot for outer tuples
  *             hj_HashTupleSlot                tuple slot for hashed tuples
- *
- *      JoinState information
- *
- *      CommonState information
- *
- *             OuterTupleSlot     pointer to slot containing current "outer" tuple
- *             ResultTupleSlot    pointer to slot in tuple table for projected tuple
- *             ExprContext                node's current expression context
- *             ProjInfo                   info this node uses to form tuple projections
- *             NumScanAttributes  size of ScanAttributes array
- *             ScanAttributes     attribute numbers of interest in this tuple
  * ----------------
  */
 typedef struct HashJoinState
@@ -550,7 +470,7 @@ typedef struct HashJoinState
        HashJoinTable hj_HashTable;
        int                     hj_CurBucketNo;
        HashJoinTuple hj_CurTuple;
-       Var                *hj_InnerHashKey;
+       Node       *hj_InnerHashKey;
        TupleTableSlot *hj_OuterTupleSlot;
        TupleTableSlot *hj_HashTupleSlot;
 } HashJoinState;
@@ -567,22 +487,9 @@ typedef struct HashJoinState
  *             materialize nodes are used to materialize the results
  *             of a subplan into a temporary file.
  *
- *             tuplestorestate         private state of tuplestore.c
- *
- *      CommonScanState information
- *
- *             currentRelation    relation descriptor of sorted relation
- *             currentScanDesc    current scan descriptor for scan
- *             ScanTupleSlot      pointer to slot in tuple table holding scan tuple
- *
- *      CommonState information
+ *             csstate.css_ScanTupleSlot refers to output of underlying plan.
  *
- *             OuterTupleSlot     pointer to slot containing current "outer" tuple
- *             ResultTupleSlot    pointer to slot in tuple table for projected tuple
- *             ExprContext                node's current expression context
- *             ProjInfo                   info this node uses to form tuple projections
- *             NumScanAttributes  size of ScanAttributes array
- *             ScanAttributes     attribute numbers of interest in this tuple
+ *             tuplestorestate         private state of tuplestore.c
  * ----------------
  */
 typedef struct MaterialState
@@ -594,12 +501,14 @@ typedef struct MaterialState
 /* ---------------------
  *     AggregateState information
  *
+ *     csstate.css_ScanTupleSlot refers to output of underlying plan.
+ *
  *     Note: the associated ExprContext contains ecxt_aggvalues and ecxt_aggnulls
  *     arrays, which hold the computed agg values for the current input group
  *     during evaluation of an Agg node's output tuple(s).
  * -------------------------
  */
-typedef struct AggStatePerAggData *AggStatePerAgg;             /* private in nodeAgg.c */
+typedef struct AggStatePerAggData *AggStatePerAgg;     /* private in nodeAgg.c */
 
 typedef struct AggState
 {
@@ -607,12 +516,14 @@ typedef struct AggState
        List       *aggs;                       /* all Aggref nodes in targetlist & quals */
        int                     numaggs;                /* length of list (could be zero!) */
        AggStatePerAgg peragg;          /* per-Aggref working state */
+       MemoryContext tup_cxt;          /* context for per-output-tuple expressions */
+       MemoryContext agg_cxt[2];       /* pair of expression eval memory contexts */
+       int                     which_cxt;              /* 0 or 1, indicates current agg_cxt */
        bool            agg_done;               /* indicates completion of Agg scan */
 } AggState;
 
 /* ---------------------
  *     GroupState information
- *
  * -------------------------
  */
 typedef struct GroupState
@@ -630,21 +541,6 @@ typedef struct GroupState
  *             sort_Done               indicates whether sort has been performed yet
  *             sort_Keys               scan key structures describing the sort keys
  *             tuplesortstate  private state of tuplesort.c
- *
- *      CommonScanState information
- *
- *             currentRelation    relation descriptor of sorted relation
- *             currentScanDesc    current scan descriptor for scan
- *             ScanTupleSlot      pointer to slot in tuple table holding scan tuple
- *
- *      CommonState information
- *
- *             OuterTupleSlot     pointer to slot containing current "outer" tuple
- *             ResultTupleSlot    pointer to slot in tuple table for projected tuple
- *             ExprContext                node's current expression context
- *             ProjInfo                   info this node uses to form tuple projections
- *             NumScanAttributes  size of ScanAttributes array
- *             ScanAttributes     attribute numbers of interest in this tuple
  * ----------------
  */
 typedef struct SortState
@@ -664,15 +560,6 @@ typedef struct SortState
  *             with the previously fetched tuple stored in priorTuple.
  *             If the two are identical in all interesting fields, then
  *             we just fetch another tuple from the sort and try again.
- *
- *      CommonState information
- *
- *             OuterTupleSlot     pointer to slot containing current "outer" tuple
- *             ResultTupleSlot    pointer to slot in tuple table for projected tuple
- *             ExprContext                node's current expression context
- *             ProjInfo                   info this node uses to form tuple projections
- *             NumScanAttributes  size of ScanAttributes array
- *             ScanAttributes     attribute numbers of interest in this tuple
  * ----------------
  */
 typedef struct UniqueState
@@ -680,6 +567,7 @@ typedef struct UniqueState
        CommonState cstate;                     /* its first field is NodeTag */
        FmgrInfo   *eqfunctions;        /* per-field lookup data for equality fns */
        HeapTuple       priorTuple;             /* most recently returned tuple, or NULL */
+       MemoryContext tempContext;      /* short-term context for comparisons */
 } UniqueState;
 
 
@@ -687,15 +575,6 @@ typedef struct UniqueState
  *      HashState information
  *
  *             hashtable                       hash table for the hashjoin
- *
- *      CommonState information
- *
- *             OuterTupleSlot     pointer to slot containing current "outer" tuple
- *             ResultTupleSlot    pointer to slot in tuple table for projected tuple
- *             ExprContext                node's current expression context
- *             ProjInfo                   info this node uses to form tuple projections
- *             NumScanAttributes  size of ScanAttributes array
- *             ScanAttributes     attribute numbers of interest in this tuple
  * ----------------
  */
 typedef struct HashState
index 37006e621f488ce889675c43c86d20855c1fb132..e348d25b2baca11299f0c2ad06ca057f019d172d 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: plannodes.h,v 1.40 2000/06/18 22:44:31 tgl Exp $
+ * $Id: plannodes.h,v 1.41 2000/07/12 02:37:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -318,7 +318,7 @@ typedef struct Unique
 typedef struct Hash
 {
        Plan            plan;
-       Var                *hashkey;
+       Node       *hashkey;
        HashState  *hashstate;
 } Hash;
 
@@ -370,7 +370,7 @@ typedef struct SubPlan
         * Remaining fields are working state for executor; not used in
         * planning
         */
-       bool            shutdown;               /* TRUE = need to shutdown plan */
+       bool            needShutdown;   /* TRUE = need to shutdown subplan */
        HeapTuple       curTuple;               /* copy of most recent tuple from subplan */
 } SubPlan;
 
index 9079919fa06f2a3f904da5bb9412f5be19005eff..199cf3109e11eaa6d9cdaca10c52d7726cf089d5 100644 (file)
@@ -1,64 +1,49 @@
 /*-------------------------------------------------------------------------
  *
  * datum.h
- *       POSTGRES abstract data type datum representation definitions.
+ *       POSTGRES Datum (abstract data type) manipulation routines.
  *
+ * These routines are driven by the 'typbyval' and 'typlen' information,
+ * which must previously have been obtained by the caller for the datatype
+ * of the Datum.  (We do it this way because in most situations the caller
+ * can look up the info just once and use it for many per-datum operations.)
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: datum.h,v 1.10 2000/01/26 05:58:37 momjian Exp $
+ * $Id: datum.h,v 1.11 2000/07/12 02:37:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef DATUM_H
 #define DATUM_H
 
-
-/*--------------------------------------------------------
- * SOME NOT VERY PORTABLE ROUTINES ???
- *--------------------------------------------------------
- *
- * In the implementation of the next routines we assume the following:
- *
- * A) if a type is "byVal" then all the information is stored in the
- * Datum itself (i.e. no pointers involved!). In this case the
- * length of the type is always greater than zero and less than
- * "sizeof(Datum)"
- * B) if a type is not "byVal" and it has a fixed length, then
- * the "Datum" always contain a pointer to a stream of bytes.
- * The number of significant bytes are always equal to the length of thr
- * type.
- * C) if a type is not "byVal" and is of variable length (i.e. it has
- * length == -1) then "Datum" always points to a "struct varlena".
- * This varlena structure has information about the actual length of this
- * particular instance of the type and about its value.
- */
-
-/*---------------
- * datumGetSize
- * find the "real" length of a datum
+/*
+ * datumGetSize - find the "real" length of a datum
  */
-extern Size datumGetSize(Datum value, Oid type, bool byVal, Size len);
+extern Size datumGetSize(Datum value, bool typByVal, int typLen);
 
-/*---------------
- * datumCopy
- * make a copy of a datum.
+/*
+ * datumCopy - make a copy of a datum.
+ *
+ * If the datatype is pass-by-reference, memory is obtained with palloc().
  */
-extern Datum datumCopy(Datum value, Oid type, bool byVal, Size len);
+extern Datum datumCopy(Datum value, bool typByVal, int typLen);
 
-/*---------------
- * datumFree
- * free space that *might* have been palloced by "datumCopy"
+/*
+ * datumFree - free a datum previously allocated by datumCopy, if any.
+ *
+ * Does nothing if datatype is pass-by-value.
  */
-extern void datumFree(Datum value, Oid type, bool byVal, Size len);
+extern void datumFree(Datum value, bool typByVal, int typLen);
 
-/*---------------
+/*
  * datumIsEqual
- * return true if thwo datums are equal, false otherwise.
+ * return true if two datums of the same type are equal, false otherwise.
+ *
  * XXX : See comments in the code for restrictions!
  */
-extern bool datumIsEqual(Datum value1, Datum value2, Oid type,
-                        bool byVal, Size len);
+extern bool datumIsEqual(Datum value1, Datum value2,
+                                                bool typByVal, int typLen);
 
 #endif  /* DATUM_H */
index db3a05baf4b8c37ae560b4214b7f6762254ce3cf..59f35867a72b278cc2fd24db1fb450a38cb91dce 100644 (file)
@@ -1,13 +1,17 @@
 /*-------------------------------------------------------------------------
  *
  * fcache.h
+ *             Declarations for function cache records.
  *
- *
+ * The first time any Oper or Func node is evaluated, we compute a cache
+ * record for the function being invoked, and save a pointer to the cache
+ * record in the Oper or Func node.  This saves repeated lookup of info
+ * about the function.
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: fcache.h,v 1.11 2000/05/28 17:56:20 tgl Exp $
+ * $Id: fcache.h,v 1.12 2000/07/12 02:37:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,6 +35,11 @@ typedef struct
                                                                 * expr whose argument is func returning a
                                                                 * set ugh! */
 
+       /* If additional info is added to an existing fcache, be sure to
+        * allocate it in the fcacheCxt.
+        */
+       MemoryContext fcacheCxt;        /* context the fcache lives in */
+
        int                     nargs;                  /* actual number of arguments */
        Oid                *argOidVect;         /* oids of all the argument types */
 
index 5b8c6d773f4931d285621554a9f6641f2b9ba1e2..8268299f2f38d268a9d7391f96a69540dc632a14 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.24 2000/07/05 23:11:58 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.25 2000/07/12 02:37:39 tgl Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
 #include "plpgsql.h"
 #include "pl.tab.h"
 
+#include "access/heapam.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_type.h"
+#include "commands/trigger.h"
 #include "executor/spi.h"
 #include "executor/spi_priv.h"
-#include "commands/trigger.h"
-#include "utils/builtins.h"
 #include "fmgr.h"
-#include "access/heapam.h"
-
 #include "tcop/tcopprot.h"
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
-#include "catalog/pg_proc.h"
-#include "catalog/pg_type.h"
 
 
 static PLpgSQL_function *error_info_func = NULL;
@@ -2205,7 +2205,7 @@ exec_eval_simple_expr(PLpgSQL_execstate * estate,
         * Create a simple expression context to hold the arguments
         * ----------
         */
-       econtext = makeNode(ExprContext);
+       econtext = MakeExprContext(NULL, TransactionCommandContext);
        paramLI = (ParamListInfo) palloc((expr->nparams + 1) *
                                                                         sizeof(ParamListInfoData));
        econtext->ecxt_param_list_info = paramLI;
@@ -2286,12 +2286,20 @@ exec_eval_simple_expr(PLpgSQL_execstate * estate,
         * ----------
         */
        SPI_push();
-       retval = ExecEvalExpr(expr->plan_simple_expr,
-                                                 econtext,
-                                                 isNull,
-                                                 &isdone);
+       retval = ExecEvalExprSwitchContext(expr->plan_simple_expr,
+                                                                          econtext,
+                                                                          isNull,
+                                                                          &isdone);
        SPI_pop();
 
+       /*
+        * Copy the result out of the expression-evaluation memory context,
+        * so that we can free the expression context.
+        */
+       retval = datumCopy(retval, get_typbyval(*rettype), get_typlen(*rettype));
+
+       FreeExprContext(econtext);
+
        /* ----------
         * That's it.
         * ----------