Commit badce86a authored by Tom Lane's avatar Tom Lane

First stage of reclaiming memory in executor by resetting short-term

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.
parent 46fb9c29
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -141,11 +141,10 @@ gistbuild(PG_FUNCTION_ARGS)
{ {
tupleTable = ExecCreateTupleTable(1); tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable); slot = ExecAllocTableSlot(tupleTable);
econtext = makeNode(ExprContext); ExecSetSlotDescriptor(slot, hd);
FillDummyExprContext(econtext, slot, hd, InvalidBuffer); econtext = MakeExprContext(slot, TransactionCommandContext);
} }
else else
/* shut the compiler up */
{ {
tupleTable = NULL; tupleTable = NULL;
slot = NULL; slot = NULL;
...@@ -161,13 +160,13 @@ gistbuild(PG_FUNCTION_ARGS) ...@@ -161,13 +160,13 @@ gistbuild(PG_FUNCTION_ARGS)
{ {
nh++; nh++;
#ifndef OMIT_PARTIAL_INDEX
/* /*
* If oldPred != NULL, this is an EXTEND INDEX command, so skip * If oldPred != NULL, this is an EXTEND INDEX command, so skip
* this tuple if it was already in the existing partial index * this tuple if it was already in the existing partial index
*/ */
if (oldPred != NULL) if (oldPred != NULL)
{ {
#ifndef OMIT_PARTIAL_INDEX
/* SetSlotContents(slot, htup); */ /* SetSlotContents(slot, htup); */
slot->val = htup; slot->val = htup;
if (ExecQual((List *) oldPred, econtext, false)) if (ExecQual((List *) oldPred, econtext, false))
...@@ -175,7 +174,6 @@ gistbuild(PG_FUNCTION_ARGS) ...@@ -175,7 +174,6 @@ gistbuild(PG_FUNCTION_ARGS)
ni++; ni++;
continue; continue;
} }
#endif /* OMIT_PARTIAL_INDEX */
} }
/* /*
...@@ -184,13 +182,12 @@ gistbuild(PG_FUNCTION_ARGS) ...@@ -184,13 +182,12 @@ gistbuild(PG_FUNCTION_ARGS)
*/ */
if (pred != NULL) if (pred != NULL)
{ {
#ifndef OMIT_PARTIAL_INDEX
/* SetSlotContents(slot, htup); */ /* SetSlotContents(slot, htup); */
slot->val = htup; slot->val = htup;
if (!ExecQual((List *) pred, econtext, false)) if (!ExecQual((List *) pred, econtext, false))
continue; continue;
#endif /* OMIT_PARTIAL_INDEX */
} }
#endif /* OMIT_PARTIAL_INDEX */
ni++; ni++;
...@@ -262,13 +259,13 @@ gistbuild(PG_FUNCTION_ARGS) ...@@ -262,13 +259,13 @@ gistbuild(PG_FUNCTION_ARGS)
/* okay, all heap tuples are indexed */ /* okay, all heap tuples are indexed */
heap_endscan(scan); heap_endscan(scan);
#ifndef OMIT_PARTIAL_INDEX
if (pred != NULL || oldPred != NULL) if (pred != NULL || oldPred != NULL)
{ {
#ifndef OMIT_PARTIAL_INDEX
ExecDropTupleTable(tupleTable, true); ExecDropTupleTable(tupleTable, true);
pfree(econtext); FreeExprContext(econtext);
#endif /* OMIT_PARTIAL_INDEX */
} }
#endif /* OMIT_PARTIAL_INDEX */
/* /*
* Since we just counted the tuples in the heap, we update its stats * Since we just counted the tuples in the heap, we update its stats
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* This file contains only the public interface routines. * This file contains only the public interface routines.
...@@ -102,15 +102,14 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -102,15 +102,14 @@ hashbuild(PG_FUNCTION_ARGS)
{ {
tupleTable = ExecCreateTupleTable(1); tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable); slot = ExecAllocTableSlot(tupleTable);
econtext = makeNode(ExprContext); ExecSetSlotDescriptor(slot, htupdesc);
FillDummyExprContext(econtext, slot, htupdesc, InvalidBuffer); econtext = MakeExprContext(slot, TransactionCommandContext);
} }
else else
/* quiet the compiler */
{ {
tupleTable = NULL;
slot = NULL;
econtext = NULL; econtext = NULL;
tupleTable = 0;
slot = 0;
} }
#endif /* OMIT_PARTIAL_INDEX */ #endif /* OMIT_PARTIAL_INDEX */
...@@ -122,9 +121,9 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -122,9 +121,9 @@ hashbuild(PG_FUNCTION_ARGS)
while (HeapTupleIsValid(htup = heap_getnext(hscan, 0))) while (HeapTupleIsValid(htup = heap_getnext(hscan, 0)))
{ {
nhtups++; nhtups++;
#ifndef OMIT_PARTIAL_INDEX
/* /*
* If oldPred != NULL, this is an EXTEND INDEX command, so skip * If oldPred != NULL, this is an EXTEND INDEX command, so skip
* this tuple if it was already in the existing partial index * this tuple if it was already in the existing partial index
...@@ -132,14 +131,12 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -132,14 +131,12 @@ hashbuild(PG_FUNCTION_ARGS)
if (oldPred != NULL) if (oldPred != NULL)
{ {
/* SetSlotContents(slot, htup); */ /* SetSlotContents(slot, htup); */
#ifndef OMIT_PARTIAL_INDEX
slot->val = htup; slot->val = htup;
if (ExecQual((List *) oldPred, econtext, false)) if (ExecQual((List *) oldPred, econtext, false))
{ {
nitups++; nitups++;
continue; continue;
} }
#endif /* OMIT_PARTIAL_INDEX */
} }
/* /*
...@@ -148,13 +145,12 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -148,13 +145,12 @@ hashbuild(PG_FUNCTION_ARGS)
*/ */
if (pred != NULL) if (pred != NULL)
{ {
#ifndef OMIT_PARTIAL_INDEX
/* SetSlotContents(slot, htup); */ /* SetSlotContents(slot, htup); */
slot->val = htup; slot->val = htup;
if (!ExecQual((List *) pred, econtext, false)) if (!ExecQual((List *) pred, econtext, false))
continue; continue;
#endif /* OMIT_PARTIAL_INDEX */
} }
#endif /* OMIT_PARTIAL_INDEX */
nitups++; nitups++;
...@@ -221,13 +217,13 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -221,13 +217,13 @@ hashbuild(PG_FUNCTION_ARGS)
/* okay, all heap tuples are indexed */ /* okay, all heap tuples are indexed */
heap_endscan(hscan); heap_endscan(hscan);
#ifndef OMIT_PARTIAL_INDEX
if (pred != NULL || oldPred != NULL) if (pred != NULL || oldPred != NULL)
{ {
#ifndef OMIT_PARTIAL_INDEX
ExecDropTupleTable(tupleTable, true); ExecDropTupleTable(tupleTable, true);
pfree(econtext); FreeExprContext(econtext);
#endif /* OMIT_PARTIAL_INDEX */
} }
#endif /* OMIT_PARTIAL_INDEX */
/* /*
* Since we just counted the tuples in the heap, we update its stats * Since we just counted the tuples in the heap, we update its stats
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* *
...@@ -27,6 +27,10 @@ ...@@ -27,6 +27,10 @@
* that work on 32-bit or wider datatypes can't just return "a - b". * that work on 32-bit or wider datatypes can't just return "a - b".
* That could overflow and give the wrong answer. * 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) ...@@ -230,18 +234,23 @@ bttextcmp(PG_FUNCTION_ARGS)
} while (res == 0 && len != 0); } while (res == 0 && len != 0);
} }
#endif if (res == 0 && VARSIZE(a) != VARSIZE(b))
{
if (res != 0 || VARSIZE(a) == VARSIZE(b))
PG_RETURN_INT32(res);
/* /*
* The two strings are the same in the first len bytes, and they are * The two strings are the same in the first len bytes,
* of different lengths. * and they are of different lengths.
*/ */
if (VARSIZE(a) < VARSIZE(b)) if (VARSIZE(a) < VARSIZE(b))
PG_RETURN_INT32(-1); res = -1;
else else
PG_RETURN_INT32(1); res = 1;
}
#endif
/* Avoid leaking memory when handed toasted input. */
PG_FREE_IF_COPY(a, 0);
PG_FREE_IF_COPY(b, 1);
PG_RETURN_INT32(res);
} }
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/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) ...@@ -121,8 +121,8 @@ btbuild(PG_FUNCTION_ARGS)
{ {
tupleTable = ExecCreateTupleTable(1); tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable); slot = ExecAllocTableSlot(tupleTable);
econtext = makeNode(ExprContext); ExecSetSlotDescriptor(slot, htupdesc);
FillDummyExprContext(econtext, slot, htupdesc, InvalidBuffer); econtext = MakeExprContext(slot, TransactionCommandContext);
/* /*
* we never want to use sort/build if we are extending an existing * we never want to use sort/build if we are extending an existing
...@@ -151,14 +151,13 @@ btbuild(PG_FUNCTION_ARGS) ...@@ -151,14 +151,13 @@ btbuild(PG_FUNCTION_ARGS)
{ {
nhtups++; nhtups++;
#ifndef OMIT_PARTIAL_INDEX
/* /*
* If oldPred != NULL, this is an EXTEND INDEX command, so skip * If oldPred != NULL, this is an EXTEND INDEX command, so skip
* this tuple if it was already in the existing partial index * this tuple if it was already in the existing partial index
*/ */
if (oldPred != NULL) if (oldPred != NULL)
{ {
#ifndef OMIT_PARTIAL_INDEX
/* SetSlotContents(slot, htup); */ /* SetSlotContents(slot, htup); */
slot->val = htup; slot->val = htup;
if (ExecQual((List *) oldPred, econtext, false)) if (ExecQual((List *) oldPred, econtext, false))
...@@ -166,7 +165,6 @@ btbuild(PG_FUNCTION_ARGS) ...@@ -166,7 +165,6 @@ btbuild(PG_FUNCTION_ARGS)
nitups++; nitups++;
continue; continue;
} }
#endif /* OMIT_PARTIAL_INDEX */
} }
/* /*
...@@ -175,13 +173,12 @@ btbuild(PG_FUNCTION_ARGS) ...@@ -175,13 +173,12 @@ btbuild(PG_FUNCTION_ARGS)
*/ */
if (pred != NULL) if (pred != NULL)
{ {
#ifndef OMIT_PARTIAL_INDEX
/* SetSlotContents(slot, htup); */ /* SetSlotContents(slot, htup); */
slot->val = htup; slot->val = htup;
if (!ExecQual((List *) pred, econtext, false)) if (!ExecQual((List *) pred, econtext, false))
continue; continue;
#endif /* OMIT_PARTIAL_INDEX */
} }
#endif /* OMIT_PARTIAL_INDEX */
nitups++; nitups++;
...@@ -260,13 +257,13 @@ btbuild(PG_FUNCTION_ARGS) ...@@ -260,13 +257,13 @@ btbuild(PG_FUNCTION_ARGS)
/* okay, all heap tuples are indexed */ /* okay, all heap tuples are indexed */
heap_endscan(hscan); heap_endscan(hscan);
#ifndef OMIT_PARTIAL_INDEX
if (pred != NULL || oldPred != NULL) if (pred != NULL || oldPred != NULL)
{ {
#ifndef OMIT_PARTIAL_INDEX
ExecDropTupleTable(tupleTable, true); ExecDropTupleTable(tupleTable, true);
pfree(econtext); FreeExprContext(econtext);
#endif /* OMIT_PARTIAL_INDEX */
} }
#endif /* OMIT_PARTIAL_INDEX */
/* /*
* if we are doing bottom-up btree build, finish the build by (1) * if we are doing bottom-up btree build, finish the build by (1)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -136,14 +136,14 @@ rtbuild(PG_FUNCTION_ARGS)
{ {
tupleTable = ExecCreateTupleTable(1); tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable); slot = ExecAllocTableSlot(tupleTable);
econtext = makeNode(ExprContext); ExecSetSlotDescriptor(slot, hd);
FillDummyExprContext(econtext, slot, hd, InvalidBuffer); econtext = MakeExprContext(slot, TransactionCommandContext);
} }
else else
{ {
econtext = NULL;
tupleTable = NULL; tupleTable = NULL;
slot = NULL; slot = NULL;
econtext = NULL;
} }
#endif /* OMIT_PARTIAL_INDEX */ #endif /* OMIT_PARTIAL_INDEX */
...@@ -156,13 +156,13 @@ rtbuild(PG_FUNCTION_ARGS) ...@@ -156,13 +156,13 @@ rtbuild(PG_FUNCTION_ARGS)
{ {
nh++; nh++;
#ifndef OMIT_PARTIAL_INDEX
/* /*
* If oldPred != NULL, this is an EXTEND INDEX command, so skip * If oldPred != NULL, this is an EXTEND INDEX command, so skip
* this tuple if it was already in the existing partial index * this tuple if it was already in the existing partial index
*/ */
if (oldPred != NULL) if (oldPred != NULL)
{ {
#ifndef OMIT_PARTIAL_INDEX
/* SetSlotContents(slot, htup); */ /* SetSlotContents(slot, htup); */
slot->val = htup; slot->val = htup;
if (ExecQual((List *) oldPred, econtext, false)) if (ExecQual((List *) oldPred, econtext, false))
...@@ -170,7 +170,6 @@ rtbuild(PG_FUNCTION_ARGS) ...@@ -170,7 +170,6 @@ rtbuild(PG_FUNCTION_ARGS)
ni++; ni++;
continue; continue;
} }
#endif /* OMIT_PARTIAL_INDEX */
} }
/* /*
...@@ -179,13 +178,12 @@ rtbuild(PG_FUNCTION_ARGS) ...@@ -179,13 +178,12 @@ rtbuild(PG_FUNCTION_ARGS)
*/ */
if (pred != NULL) if (pred != NULL)
{ {
#ifndef OMIT_PARTIAL_INDEX
/* SetSlotContents(slot, htup); */ /* SetSlotContents(slot, htup); */
slot->val = htup; slot->val = htup;
if (!ExecQual((List *) pred, econtext, false)) if (!ExecQual((List *) pred, econtext, false))
continue; continue;
#endif /* OMIT_PARTIAL_INDEX */
} }
#endif /* OMIT_PARTIAL_INDEX */
ni++; ni++;
...@@ -239,13 +237,13 @@ rtbuild(PG_FUNCTION_ARGS) ...@@ -239,13 +237,13 @@ rtbuild(PG_FUNCTION_ARGS)
/* okay, all heap tuples are indexed */ /* okay, all heap tuples are indexed */
heap_endscan(scan); heap_endscan(scan);
#ifndef OMIT_PARTIAL_INDEX
if (pred != NULL || oldPred != NULL) if (pred != NULL || oldPred != NULL)
{ {
#ifndef OMIT_PARTIAL_INDEX
ExecDropTupleTable(tupleTable, true); ExecDropTupleTable(tupleTable, true);
pfree(econtext); FreeExprContext(econtext);
#endif /* OMIT_PARTIAL_INDEX */
} }
#endif /* OMIT_PARTIAL_INDEX */
/* /*
* Since we just counted the tuples in the heap, we update its stats * Since we just counted the tuples in the heap, we update its stats
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
...@@ -1670,34 +1670,6 @@ UpdateStats(Oid relid, long reltuples, bool inplace) ...@@ -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 * DefaultBuild
* *
...@@ -1777,14 +1749,14 @@ DefaultBuild(Relation heapRelation, ...@@ -1777,14 +1749,14 @@ DefaultBuild(Relation heapRelation,
{ {
tupleTable = ExecCreateTupleTable(1); tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable); slot = ExecAllocTableSlot(tupleTable);
econtext = makeNode(ExprContext); ExecSetSlotDescriptor(slot, heapDescriptor);
FillDummyExprContext(econtext, slot, heapDescriptor, InvalidBuffer); econtext = MakeExprContext(slot, TransactionCommandContext);
} }
else else
{ {
econtext = NULL; tupleTable = NULL;
tupleTable = 0;
slot = NULL; slot = NULL;
econtext = NULL;
} }
#endif /* OMIT_PARTIAL_INDEX */ #endif /* OMIT_PARTIAL_INDEX */
...@@ -1812,7 +1784,6 @@ DefaultBuild(Relation heapRelation, ...@@ -1812,7 +1784,6 @@ DefaultBuild(Relation heapRelation,
reltuples++; reltuples++;
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
/* /*
* If oldPred != NULL, this is an EXTEND INDEX command, so skip * If oldPred != NULL, this is an EXTEND INDEX command, so skip
* this tuple if it was already in the existing partial index * this tuple if it was already in the existing partial index
...@@ -1877,6 +1848,7 @@ DefaultBuild(Relation heapRelation, ...@@ -1877,6 +1848,7 @@ DefaultBuild(Relation heapRelation,
{ {
/* parameter was 'false', almost certainly wrong --- tgl 9/21/99 */ /* parameter was 'false', almost certainly wrong --- tgl 9/21/99 */
ExecDropTupleTable(tupleTable, true); ExecDropTupleTable(tupleTable, true);
FreeExprContext(econtext);
} }
#endif /* OMIT_PARTIAL_INDEX */ #endif /* OMIT_PARTIAL_INDEX */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 ...@@ -611,13 +611,11 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
char *predString; char *predString;
Node **indexPred = NULL; Node **indexPred = NULL;
TupleDesc rtupdesc; TupleDesc rtupdesc;
ExprContext *econtext = NULL;
EState *estate = makeNode(EState); /* for ExecConstraints() */ EState *estate = makeNode(EState); /* for ExecConstraints() */
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
ExprContext *econtext = NULL;
TupleTable tupleTable; TupleTable tupleTable;
TupleTableSlot *slot = NULL; TupleTableSlot *slot = NULL;
#endif #endif
int natts; int natts;
AttrNumber *attnumP; AttrNumber *attnumP;
...@@ -651,7 +649,6 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null ...@@ -651,7 +649,6 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
finfo = (FuncIndexInfo *) palloc(n_indices * sizeof(FuncIndexInfo)); finfo = (FuncIndexInfo *) palloc(n_indices * sizeof(FuncIndexInfo));
finfoP = (FuncIndexInfo **) palloc(n_indices * sizeof(FuncIndexInfo *)); finfoP = (FuncIndexInfo **) palloc(n_indices * sizeof(FuncIndexInfo *));
indexPred = (Node **) palloc(n_indices * sizeof(Node *)); indexPred = (Node **) palloc(n_indices * sizeof(Node *));
econtext = NULL;
for (i = 0; i < n_indices; i++) for (i = 0; i < n_indices; i++)
{ {
itupdescArr[i] = RelationGetDescr(index_rels[i]); itupdescArr[i] = RelationGetDescr(index_rels[i]);
...@@ -680,36 +677,18 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null ...@@ -680,36 +677,18 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
PointerGetDatum(&pgIndexP[i]->indpred))); PointerGetDatum(&pgIndexP[i]->indpred)));
indexPred[i] = stringToNode(predString); indexPred[i] = stringToNode(predString);
pfree(predString); pfree(predString);
#ifndef OMIT_PARTIAL_INDEX
/* make dummy ExprContext for use by ExecQual */ /* make dummy ExprContext for use by ExecQual */
if (econtext == NULL) if (econtext == NULL)
{ {
#ifndef OMIT_PARTIAL_INDEX
tupleTable = ExecCreateTupleTable(1); tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable); slot = ExecAllocTableSlot(tupleTable);
econtext = makeNode(ExprContext);
econtext->ecxt_scantuple = slot;
rtupdesc = RelationGetDescr(rel); rtupdesc = RelationGetDescr(rel);
slot->ttc_tupleDescriptor = rtupdesc; ExecSetSlotDescriptor(slot, rtupdesc);
econtext = MakeExprContext(slot,
/* TransactionCommandContext);
* 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 */
} }
#endif /* OMIT_PARTIAL_INDEX */
} }
else else
indexPred[i] = NULL; indexPred[i] = NULL;
...@@ -927,10 +906,9 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *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++) for (i = 0; i < n_indices; i++)
{ {
#ifndef OMIT_PARTIAL_INDEX
if (indexPred[i] != NULL) if (indexPred[i] != NULL)
{ {
#ifndef OMIT_PARTIAL_INDEX
/* /*
* if tuple doesn't satisfy predicate, don't * if tuple doesn't satisfy predicate, don't
* update index * update index
...@@ -939,8 +917,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null ...@@ -939,8 +917,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
/* SetSlotContents(slot, tuple); */ /* SetSlotContents(slot, tuple); */
if (!ExecQual((List *) indexPred[i], econtext, false)) if (!ExecQual((List *) indexPred[i], econtext, false))
continue; continue;
#endif /* OMIT_PARTIAL_INDEX */
} }
#endif /* OMIT_PARTIAL_INDEX */
FormIndexDatum(indexNatts[i], FormIndexDatum(indexNatts[i],
(AttrNumber *) &(pgIndexP[i]->indkey[0]), (AttrNumber *) &(pgIndexP[i]->indkey[0]),
tuple, tuple,
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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, ...@@ -171,8 +171,8 @@ ExecBeginScan(Relation relation,
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* ExecCloseR * ExecCloseR
* *
* closes the relation and scan descriptor for a scan or sort * closes the relation and scan descriptor for a scan node.
* node. Also closes index relations and scans for index scans. * Also closes index relations and scans for index scans.
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
void void
...@@ -197,20 +197,12 @@ ExecCloseR(Plan *node) ...@@ -197,20 +197,12 @@ ExecCloseR(Plan *node)
state = ((IndexScan *) node)->scan.scanstate; state = ((IndexScan *) node)->scan.scanstate;
break; break;
case T_Sort:
state = &(((Sort *) node)->sortstate->csstate);
break;
case T_Agg:
state = &(((Agg *) node)->aggstate->csstate);
break;
case T_TidScan: case T_TidScan:
state = ((TidScan *) node)->scan.scanstate; state = ((TidScan *) node)->scan.scanstate;
break; break;
default: default:
elog(DEBUG, "ExecCloseR: not a scan or sort node!"); elog(DEBUG, "ExecCloseR: not a scan node!");
return; return;
} }
...@@ -237,13 +229,12 @@ ExecCloseR(Plan *node) ...@@ -237,13 +229,12 @@ ExecCloseR(Plan *node)
if (IsA(node, IndexScan)) if (IsA(node, IndexScan))
{ {
IndexScan *iscan = (IndexScan *) node; IndexScan *iscan = (IndexScan *) node;
IndexScanState *indexstate; IndexScanState *indexstate = iscan->indxstate;
int numIndices; int numIndices;
RelationPtr indexRelationDescs; RelationPtr indexRelationDescs;
IndexScanDescPtr indexScanDescs; IndexScanDescPtr indexScanDescs;
int i; int i;
indexstate = iscan->indxstate;
numIndices = indexstate->iss_NumIndices; numIndices = indexstate->iss_NumIndices;
indexRelationDescs = indexstate->iss_RelationDescs; indexRelationDescs = indexstate->iss_RelationDescs;
indexScanDescs = indexstate->iss_ScanDescs; indexScanDescs = indexstate->iss_ScanDescs;
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -86,9 +86,12 @@ static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation,
* This routine must be called at the beginning of any execution of any * This routine must be called at the beginning of any execution of any
* query plan * 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. * 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 TupleDesc
...@@ -103,7 +106,8 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate) ...@@ -103,7 +106,8 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
{ {
estate->es_param_exec_vals = (ParamExecData *) estate->es_param_exec_vals = (ParamExecData *)
palloc(queryDesc->plantree->nParamExec * sizeof(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) ...@@ -151,7 +155,6 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
* EXEC_RETONE: return one tuple but don't 'retrieve' it * EXEC_RETONE: return one tuple but don't 'retrieve' it
* used in postquel function processing * used in postquel function processing
* *
*
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
TupleTableSlot * TupleTableSlot *
...@@ -687,13 +690,6 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate) ...@@ -687,13 +690,6 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
*/ */
estate->es_range_table = rangeTable; 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 * initialize result relation stuff
*/ */
...@@ -793,7 +789,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate) ...@@ -793,7 +789,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
/* /*
* initialize the private state information for all the nodes in the * initialize the private state information for all the nodes in the
* query tree. This opens files, allocates storage and leaves us * query tree. This opens files, allocates storage and leaves us
* ready to start processing tuples.. * ready to start processing tuples.
*/ */
ExecInitNode(plan, estate, NULL); ExecInitNode(plan, estate, NULL);
...@@ -1589,7 +1585,7 @@ ExecAttrDefault(Relation rel, HeapTuple tuple) ...@@ -1589,7 +1585,7 @@ ExecAttrDefault(Relation rel, HeapTuple tuple)
{ {
int ndef = rel->rd_att->constr->num_defval; int ndef = rel->rd_att->constr->num_defval;
AttrDefault *attrdef = rel->rd_att->constr->defval; AttrDefault *attrdef = rel->rd_att->constr->defval;
ExprContext *econtext = makeNode(ExprContext); ExprContext *econtext = MakeExprContext(NULL, CurrentMemoryContext);
HeapTuple newtuple; HeapTuple newtuple;
Node *expr; Node *expr;
bool isnull; bool isnull;
...@@ -1600,23 +1596,13 @@ ExecAttrDefault(Relation rel, HeapTuple tuple) ...@@ -1600,23 +1596,13 @@ ExecAttrDefault(Relation rel, HeapTuple tuple)
char *repl = NULL; char *repl = NULL;
int i; 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++) for (i = 0; i < ndef; i++)
{ {
if (!heap_attisnull(tuple, attrdef[i].adnum)) if (!heap_attisnull(tuple, attrdef[i].adnum))
continue; continue;
expr = (Node *) stringToNode(attrdef[i].adbin); expr = (Node *) stringToNode(attrdef[i].adbin);
val = ExecEvalExpr(expr, econtext, &isnull, &isdone); val = ExecEvalExprSwitchContext(expr, econtext, &isnull, &isdone);
pfree(expr);
if (isnull) if (isnull)
continue; continue;
...@@ -1635,20 +1621,24 @@ ExecAttrDefault(Relation rel, HeapTuple tuple) ...@@ -1635,20 +1621,24 @@ ExecAttrDefault(Relation rel, HeapTuple tuple)
} }
pfree(econtext);
if (repl == NULL) 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(repl);
heap_freetuple(tuple);
pfree(replNull); pfree(replNull);
pfree(replValue); pfree(replValue);
heap_freetuple(tuple);
}
return newtuple; FreeMemoryContext(econtext);
return newtuple;
} }
#endif #endif
...@@ -1658,9 +1648,10 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate) ...@@ -1658,9 +1648,10 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
{ {
int ncheck = rel->rd_att->constr->num_check; int ncheck = rel->rd_att->constr->num_check;
ConstrCheck *check = rel->rd_att->constr->check; ConstrCheck *check = rel->rd_att->constr->check;
ExprContext *econtext = makeNode(ExprContext);
TupleTableSlot *slot = makeNode(TupleTableSlot); TupleTableSlot *slot = makeNode(TupleTableSlot);
RangeTblEntry *rte = makeNode(RangeTblEntry); RangeTblEntry *rte = makeNode(RangeTblEntry);
ExprContext *econtext = MakeExprContext(slot,
TransactionCommandContext);
List *rtlist; List *rtlist;
List *qual; List *qual;
int i; int i;
...@@ -1677,17 +1668,21 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate) ...@@ -1677,17 +1668,21 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
rte->relid = RelationGetRelid(rel); rte->relid = RelationGetRelid(rel);
/* inh, inFromCl, inJoinSet, skipAcl won't be used, leave them zero */ /* inh, inFromCl, inJoinSet, skipAcl won't be used, leave them zero */
rtlist = lcons(rte, NIL); rtlist = lcons(rte, NIL);
econtext->ecxt_scantuple = slot; /* scan tuple slot */ econtext->ecxt_range_table = rtlist; /* phony range table */
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 */
/*
* 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) if (estate->es_result_relation_constraints == NULL)
{ {
MemoryContext oldContext;
oldContext = MemoryContextSwitchTo(TransactionCommandContext);
estate->es_result_relation_constraints = estate->es_result_relation_constraints =
(List **) palloc(ncheck * sizeof(List *)); (List **) palloc(ncheck * sizeof(List *));
...@@ -1696,6 +1691,8 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate) ...@@ -1696,6 +1691,8 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
qual = (List *) stringToNode(check[i].ccbin); qual = (List *) stringToNode(check[i].ccbin);
estate->es_result_relation_constraints[i] = qual; estate->es_result_relation_constraints[i] = qual;
} }
MemoryContextSwitchTo(oldContext);
} }
for (i = 0; i < ncheck; i++) for (i = 0; i < ncheck; i++)
...@@ -1714,16 +1711,15 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate) ...@@ -1714,16 +1711,15 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
pfree(slot); pfree(slot);
pfree(rte); pfree(rte);
pfree(rtlist); pfree(rtlist);
pfree(econtext);
return (char *) NULL; FreeExprContext(econtext);
return (char *) NULL;
} }
void void
ExecConstraints(char *caller, Relation rel, HeapTuple tuple, EState *estate) ExecConstraints(char *caller, Relation rel, HeapTuple tuple, EState *estate)
{ {
Assert(rel->rd_att->constr); Assert(rel->rd_att->constr);
if (rel->rd_att->constr->has_not_null) if (rel->rd_att->constr->has_not_null)
...@@ -1732,9 +1728,10 @@ ExecConstraints(char *caller, Relation rel, HeapTuple tuple, EState *estate) ...@@ -1732,9 +1728,10 @@ ExecConstraints(char *caller, Relation rel, HeapTuple tuple, EState *estate)
for (attrChk = 1; attrChk <= rel->rd_att->natts; attrChk++) 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", 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) ...@@ -1743,10 +1740,9 @@ ExecConstraints(char *caller, Relation rel, HeapTuple tuple, EState *estate)
char *failed; char *failed;
if ((failed = ExecRelCheck(rel, tuple, estate)) != NULL) 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 * TupleTableSlot *
......
This diff is collapsed.
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -30,7 +30,7 @@
* returns the next qualifying tuple in the direction specified * returns the next qualifying tuple in the direction specified
* in the global variable ExecDirection. * in the global variable ExecDirection.
* The access method returns the next tuple and execScan() is * 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: * Conditions:
* -- the "cursor" maintained by the AMI is positioned at the tuple * -- the "cursor" maintained by the AMI is positioned at the tuple
...@@ -39,59 +39,50 @@ ...@@ -39,59 +39,50 @@
* Initial States: * Initial States:
* -- the relation indicated is opened for scanning so that the * -- the relation indicated is opened for scanning so that the
* "cursor" is positioned before the first qualifying tuple. * "cursor" is positioned before the first qualifying tuple.
*
* May need to put startmmgr and endmmgr in here.
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
TupleTableSlot * TupleTableSlot *
ExecScan(Scan *node, ExecScan(Scan *node,
TupleTableSlot *(*accessMtd) ()) /* function returning a ExecScanAccessMtd accessMtd) /* function returning a tuple */
* tuple */
{ {
CommonScanState *scanstate; CommonScanState *scanstate;
EState *estate; EState *estate;
List *qual; List *qual;
bool isDone; bool isDone;
TupleTableSlot *slot;
TupleTableSlot *resultSlot; TupleTableSlot *resultSlot;
HeapTuple newTuple;
ExprContext *econtext; ExprContext *econtext;
ProjectionInfo *projInfo; ProjectionInfo *projInfo;
/* ---------------- /* ----------------
* initialize misc variables * Fetch data from node
* ---------------- * ----------------
*/ */
newTuple = NULL;
slot = NULL;
estate = node->plan.state; estate = node->plan.state;
scanstate = node->scanstate; 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 * Check to see if we're still projecting out tuples from a previous
* in the course of the scan.. * 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) if (scanstate->cstate.cs_TupFromTlist)
{ {
projInfo = scanstate->cstate.cs_ProjInfo; projInfo = scanstate->cstate.cs_ProjInfo;
resultSlot = ExecProject(projInfo, &isDone); resultSlot = ExecProject(projInfo, &isDone);
if (!isDone) if (!isDone)
return resultSlot; return resultSlot;
/* Done with that source tuple... */
scanstate->cstate.cs_TupFromTlist = false;
} }
/* /*
...@@ -100,25 +91,21 @@ ExecScan(Scan *node, ...@@ -100,25 +91,21 @@ ExecScan(Scan *node,
*/ */
for (;;) for (;;)
{ {
slot = (TupleTableSlot *) (*accessMtd) (node); TupleTableSlot *slot;
slot = (*accessMtd) (node);
/* ---------------- /* ----------------
* if the slot returned by the accessMtd contains * if the slot returned by the accessMtd contains
* NULL, then it means there is nothing more to scan * NULL, then it means there is nothing more to scan
* so we just return the empty slot... * so we just return an empty slot, being careful to use
* * the projection result slot so it has correct tupleDesc.
* ... 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
* ---------------- * ----------------
*/ */
if (TupIsNull(slot)) if (TupIsNull(slot))
{ {
scanstate->cstate.cs_TupFromTlist = false; return ExecStoreTuple(NULL,
resultSlot = scanstate->cstate.cs_ProjInfo->pi_slot; scanstate->cstate.cs_ProjInfo->pi_slot,
return (TupleTableSlot *)
ExecStoreTuple(NULL,
resultSlot,
InvalidBuffer, InvalidBuffer,
true); true);
} }
...@@ -131,22 +118,28 @@ ExecScan(Scan *node, ...@@ -131,22 +118,28 @@ ExecScan(Scan *node,
/* ---------------- /* ----------------
* check that the current tuple satisfies the qual-clause * 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. * leave the loop.
* ---------------- *
*/ * check for non-nil qual here to avoid a function call to
/*
* add a check for non-nil qual here to avoid a function call to
* ExecQual() when the qual is nil ... saves only a few cycles, * ExecQual() when the qual is nil ... saves only a few cycles,
* but they add up ... * but they add up ...
* ----------------
*/ */
if (!qual || ExecQual(qual, econtext, false)) if (!qual || ExecQual(qual, econtext, false))
break; 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. * slot and return it.
* ---------------- * ----------------
*/ */
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -76,8 +76,7 @@
* by the access methods into the scan tuple slot. * by the access methods into the scan tuple slot.
* *
* - ExecSeqScan() calls ExecStoreTuple() to take the result * - ExecSeqScan() calls ExecStoreTuple() to take the result
* tuple from ExecTargetList() and place it into the result tuple * tuple from ExecProject() and place it into the result tuple slot.
* slot.
* *
* - ExecutePlan() calls ExecRetrieve() which gets the tuple out of * - ExecutePlan() calls ExecRetrieve() which gets the tuple out of
* the slot passed to it by calling ExecFetchTuple(). this tuple * the slot passed to it by calling ExecFetchTuple(). this tuple
...@@ -182,8 +181,8 @@ ExecCreateTupleTable(int initialSize) /* initial number of slots in ...@@ -182,8 +181,8 @@ ExecCreateTupleTable(int initialSize) /* initial number of slots in
/* -------------------------------- /* --------------------------------
* ExecDropTupleTable * ExecDropTupleTable
* *
* This pfrees the storage assigned to the tuple table and * This frees the storage used by the tuple table itself
* optionally pfrees the contents of the table also. * and optionally frees the contents of the table also.
* It is expected that this routine be called by EndPlan(). * It is expected that this routine be called by EndPlan().
* -------------------------------- * --------------------------------
*/ */
...@@ -239,7 +238,6 @@ ExecDropTupleTable(TupleTable table, /* tuple table */ ...@@ -239,7 +238,6 @@ ExecDropTupleTable(TupleTable table, /* tuple table */
*/ */
pfree(array); pfree(array);
pfree(table); pfree(table);
} }
...@@ -252,13 +250,12 @@ ExecDropTupleTable(TupleTable table, /* tuple table */ ...@@ -252,13 +250,12 @@ ExecDropTupleTable(TupleTable table, /* tuple table */
* *
* This routine is used to reserve slots in the table for * This routine is used to reserve slots in the table for
* use by the various plan nodes. It is expected to be * 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 * once per slot needed by the node. Not all nodes need
* slots (some just pass tuples around). * slots (some just pass tuples around).
* -------------------------------- * --------------------------------
*/ */
TupleTableSlot * /* return: the slot allocated in the tuple TupleTableSlot *
* table */
ExecAllocTableSlot(TupleTable table) ExecAllocTableSlot(TupleTable table)
{ {
int slotnum; /* new slot number */ int slotnum; /* new slot number */
...@@ -283,22 +280,12 @@ ExecAllocTableSlot(TupleTable table) ...@@ -283,22 +280,12 @@ ExecAllocTableSlot(TupleTable table)
* pointers into _freed_ memory. This leads to bad ends. We * pointers into _freed_ memory. This leads to bad ends. We
* now count the number of slots we will need and create all the * 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 * 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) if (table->next >= table->size)
{ elog(ERROR, "Plan requires more slots than are available"
"\n\tsend mail to your local executor guru to fix this");
/*
* 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");
}
/* ---------------- /* ----------------
* at this point, space in the table is guaranteed so we * at this point, space in the table is guaranteed so we
...@@ -427,7 +414,7 @@ ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */ ...@@ -427,7 +414,7 @@ ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */
slot->val = (HeapTuple) NULL; 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. * Drop the pin on the referenced buffer, if there is one.
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* execUtils.c * execUtils.c
* miscellanious executor utility routines * miscellaneous executor utility routines
* *
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/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 * INTERFACE ROUTINES
* ExecAssignNodeBaseInfo \ * ExecAssignExprContext Common code for plan node init routines.
* ExecAssignDebugHooks > preforms misc work done in all the
* ExecAssignExprContext / init node routines.
* *
* ExecGetTypeInfo | old execCStructs interface * ExecGetTypeInfo | old execCStructs interface
* ExecMakeTypeInfo | code from the version 1 * ExecMakeTypeInfo | code from the version 1
...@@ -53,6 +51,7 @@ ...@@ -53,6 +51,7 @@
#include "miscadmin.h" #include "miscadmin.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/memutils.h"
#include "utils/relcache.h" #include "utils/relcache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
...@@ -137,57 +136,104 @@ DisplayTupleCount(FILE *statfp) ...@@ -137,57 +136,104 @@ DisplayTupleCount(FILE *statfp)
#endif #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 * 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 * Note: we assume CurrentMemoryContext is the correct per-query context.
* increments the counter in the estate. In addition, it initializes * This should be true during plan node initialization.
* the base_parent field of the basenode.
* ---------------- * ----------------
*/ */
void void
ExecAssignNodeBaseInfo(EState *estate, CommonState *cstate, Plan *parent) ExecAssignExprContext(EState *estate, CommonState *commonstate)
{ {
int baseId; ExprContext *econtext = makeNode(ExprContext);
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;
baseId = estate->es_BaseId; commonstate->cs_ExprContext = econtext;
cstate->cs_base_id = baseId;
estate->es_BaseId = baseId + 1;
} }
/* ---------------- /* ----------------
* ExecAssignExprContext * MakeExprContext
* *
* This initializes the ExprContext field. It is only necessary * Build an expression context for use outside normal plan-node cases.
* to do this for nodes which use ExecQual or ExecTargetList * A fake scan-tuple slot can be supplied (pass NULL if not needed).
* because those routines depend on econtext. Other nodes which * A memory context sufficiently long-lived to use as fcache context
* dont have to evaluate expressions don't need to do this. * must be supplied as well.
* ---------------- * ----------------
*/ */
void ExprContext *
ExecAssignExprContext(EState *estate, CommonState *commonstate) MakeExprContext(TupleTableSlot *slot,
MemoryContext queryContext)
{ {
ExprContext *econtext; ExprContext *econtext = makeNode(ExprContext);
econtext = makeNode(ExprContext); econtext->ecxt_scantuple = slot;
econtext->ecxt_scantuple = NULL; /* scan tuple slot */ econtext->ecxt_innertuple = NULL;
econtext->ecxt_innertuple = NULL; /* inner tuple slot */ econtext->ecxt_outertuple = NULL;
econtext->ecxt_outertuple = NULL; /* outer tuple slot */ econtext->ecxt_per_query_memory = queryContext;
econtext->ecxt_relation = NULL; /* relation */ /*
econtext->ecxt_relid = 0; /* relid */ * We make the temporary context a child of current working context,
econtext->ecxt_param_list_info = estate->es_param_list_info; * not of the specified queryContext. This seems reasonable but I'm
econtext->ecxt_param_exec_vals = estate->es_param_exec_vals; * not totally sure about it...
econtext->ecxt_range_table = estate->es_range_table; /* range table */ *
* 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) ...@@ -390,6 +436,7 @@ ExecFreeExprContext(CommonState *commonstate)
* clean up memory used. * clean up memory used.
* ---------------- * ----------------
*/ */
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
pfree(econtext); pfree(econtext);
commonstate->cs_ExprContext = NULL; commonstate->cs_ExprContext = NULL;
} }
...@@ -398,6 +445,7 @@ ExecFreeExprContext(CommonState *commonstate) ...@@ -398,6 +445,7 @@ ExecFreeExprContext(CommonState *commonstate)
* ExecFreeTypeInfo * ExecFreeTypeInfo
* ---------------- * ----------------
*/ */
#ifdef NOT_USED
void void
ExecFreeTypeInfo(CommonState *commonstate) ExecFreeTypeInfo(CommonState *commonstate)
{ {
...@@ -414,6 +462,7 @@ ExecFreeTypeInfo(CommonState *commonstate) ...@@ -414,6 +462,7 @@ ExecFreeTypeInfo(CommonState *commonstate)
FreeTupleDesc(tupDesc); FreeTupleDesc(tupDesc);
commonstate->cs_ResultTupleSlot->ttc_tupleDescriptor = NULL; commonstate->cs_ResultTupleSlot->ttc_tupleDescriptor = NULL;
} }
#endif
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* the following scan type support functions are for * the following scan type support functions are for
...@@ -974,8 +1023,8 @@ ExecInsertIndexTuples(TupleTableSlot *slot, ...@@ -974,8 +1023,8 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
if (predicate != NULL) if (predicate != NULL)
{ {
if (econtext == NULL) if (econtext == NULL)
econtext = makeNode(ExprContext); econtext = MakeExprContext(slot,
econtext->ecxt_scantuple = slot; TransactionCommandContext);
/* Skip this index-update if the predicate isn't satisfied */ /* Skip this index-update if the predicate isn't satisfied */
if (!ExecQual((List *) predicate, econtext, false)) if (!ExecQual((List *) predicate, econtext, false))
...@@ -1023,7 +1072,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot, ...@@ -1023,7 +1072,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
pfree(result); pfree(result);
} }
if (econtext != NULL) if (econtext != NULL)
pfree(econtext); FreeExprContext(econtext);
} }
void void
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -57,20 +57,18 @@ ProjectAttribute(TupleDesc TD,
HeapTuple tup, HeapTuple tup,
bool *isnullP) bool *isnullP)
{ {
Datum val, Datum val;
valueP;
Var *attrVar = (Var *) tlist->expr; Var *attrVar = (Var *) tlist->expr;
AttrNumber attrno = attrVar->varattno; AttrNumber attrno = attrVar->varattno;
val = heap_getattr(tup, attrno, TD, isnullP); val = heap_getattr(tup, attrno, TD, isnullP);
if (*isnullP) if (*isnullP)
return (Datum) NULL; return (Datum) 0;
valueP = datumCopy(val, return datumCopy(val,
TD->attrs[attrno - 1]->atttypid,
TD->attrs[attrno - 1]->attbyval, TD->attrs[attrno - 1]->attbyval,
(Size) TD->attrs[attrno - 1]->attlen); TD->attrs[attrno - 1]->attlen);
return valueP;
} }
static execution_state * static execution_state *
...@@ -351,10 +349,18 @@ postquel_function(FunctionCallInfo fcinfo, ...@@ -351,10 +349,18 @@ postquel_function(FunctionCallInfo fcinfo,
List *func_tlist, List *func_tlist,
bool *isDone) bool *isDone)
{ {
MemoryContext oldcontext;
execution_state *es; execution_state *es;
Datum result = 0; Datum result = 0;
CommandId savedId; 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 * Before we start do anything we must save CurrentScanCommandId to
* restore it before return to upper Executor. Also, we have to set * restore it before return to upper Executor. Also, we have to set
...@@ -416,6 +422,7 @@ postquel_function(FunctionCallInfo fcinfo, ...@@ -416,6 +422,7 @@ postquel_function(FunctionCallInfo fcinfo,
* Let caller know we're finished. * Let caller know we're finished.
*/ */
*isDone = true; *isDone = true;
MemoryContextSwitchTo(oldcontext);
return (fcache->oneResult) ? result : (Datum) NULL; return (fcache->oneResult) ? result : (Datum) NULL;
} }
...@@ -426,5 +433,8 @@ postquel_function(FunctionCallInfo fcinfo, ...@@ -426,5 +433,8 @@ postquel_function(FunctionCallInfo fcinfo,
Assert(LAST_POSTQUEL_COMMAND(es)); Assert(LAST_POSTQUEL_COMMAND(es));
*isDone = false; *isDone = false;
MemoryContextSwitchTo(oldcontext);
return result; return result;
} }
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -219,16 +219,12 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
node->appendstate = appendstate; node->appendstate = appendstate;
/* ---------------- /* ----------------
* Miscellanious initialization * Miscellaneous initialization
*
* + assign node's base_id
* + assign debugging hooks
* *
* Append plans don't have expression contexts because they * 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 #define APPEND_NSLOTS 1
/* ---------------- /* ----------------
...@@ -380,7 +376,7 @@ ExecCountSlotsAppend(Append *node) ...@@ -380,7 +376,7 @@ ExecCountSlotsAppend(Append *node)
* *
* Handles the iteration over the multiple scans. * 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 * TupleTableSlot *
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* locate group boundaries. * locate group boundaries.
* *
* IDENTIFICATION * 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) ...@@ -68,13 +68,11 @@ ExecGroupEveryTuple(Group *node)
EState *estate; EState *estate;
ExprContext *econtext; ExprContext *econtext;
TupleDesc tupdesc; TupleDesc tupdesc;
HeapTuple outerTuple = NULL; HeapTuple outerTuple = NULL;
HeapTuple firsttuple; HeapTuple firsttuple;
TupleTableSlot *outerslot; TupleTableSlot *outerslot;
ProjectionInfo *projInfo; ProjectionInfo *projInfo;
TupleTableSlot *resultSlot; TupleTableSlot *resultSlot;
bool isDone; bool isDone;
/* --------------------- /* ---------------------
...@@ -84,14 +82,16 @@ ExecGroupEveryTuple(Group *node) ...@@ -84,14 +82,16 @@ ExecGroupEveryTuple(Group *node)
grpstate = node->grpstate; grpstate = node->grpstate;
if (grpstate->grp_done) if (grpstate->grp_done)
return NULL; return NULL;
estate = node->plan.state; estate = node->plan.state;
econtext = grpstate->csstate.cstate.cs_ExprContext; econtext = grpstate->csstate.cstate.cs_ExprContext;
tupdesc = ExecGetScanType(&grpstate->csstate); 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) if (grpstate->grp_useFirstTuple)
{ {
grpstate->grp_useFirstTuple = FALSE; grpstate->grp_useFirstTuple = FALSE;
...@@ -130,7 +130,8 @@ ExecGroupEveryTuple(Group *node) ...@@ -130,7 +130,8 @@ ExecGroupEveryTuple(Group *node)
if (!execTuplesMatch(firsttuple, outerTuple, if (!execTuplesMatch(firsttuple, outerTuple,
tupdesc, tupdesc,
node->numCols, node->grpColIdx, node->numCols, node->grpColIdx,
grpstate->eqfunctions)) grpstate->eqfunctions,
econtext->ecxt_per_tuple_memory))
{ {
/* /*
...@@ -179,13 +180,11 @@ ExecGroupOneTuple(Group *node) ...@@ -179,13 +180,11 @@ ExecGroupOneTuple(Group *node)
EState *estate; EState *estate;
ExprContext *econtext; ExprContext *econtext;
TupleDesc tupdesc; TupleDesc tupdesc;
HeapTuple outerTuple = NULL; HeapTuple outerTuple = NULL;
HeapTuple firsttuple; HeapTuple firsttuple;
TupleTableSlot *outerslot; TupleTableSlot *outerslot;
ProjectionInfo *projInfo; ProjectionInfo *projInfo;
TupleTableSlot *resultSlot; TupleTableSlot *resultSlot;
bool isDone; bool isDone;
/* --------------------- /* ---------------------
...@@ -195,13 +194,15 @@ ExecGroupOneTuple(Group *node) ...@@ -195,13 +194,15 @@ ExecGroupOneTuple(Group *node)
grpstate = node->grpstate; grpstate = node->grpstate;
if (grpstate->grp_done) if (grpstate->grp_done)
return NULL; return NULL;
estate = node->plan.state; estate = node->plan.state;
econtext = node->grpstate->csstate.cstate.cs_ExprContext; econtext = node->grpstate->csstate.cstate.cs_ExprContext;
tupdesc = ExecGetScanType(&grpstate->csstate); 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; firsttuple = grpstate->grp_firstTuple;
if (firsttuple == NULL) if (firsttuple == NULL)
{ {
...@@ -237,7 +238,8 @@ ExecGroupOneTuple(Group *node) ...@@ -237,7 +238,8 @@ ExecGroupOneTuple(Group *node)
if (!execTuplesMatch(firsttuple, outerTuple, if (!execTuplesMatch(firsttuple, outerTuple,
tupdesc, tupdesc,
node->numCols, node->grpColIdx, node->numCols, node->grpColIdx,
grpstate->eqfunctions)) grpstate->eqfunctions,
econtext->ecxt_per_tuple_memory))
break; break;
} }
...@@ -296,10 +298,8 @@ ExecInitGroup(Group *node, EState *estate, Plan *parent) ...@@ -296,10 +298,8 @@ ExecInitGroup(Group *node, EState *estate, Plan *parent)
grpstate->grp_firstTuple = NULL; 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); ExecAssignExprContext(estate, &grpstate->csstate.cstate);
#define GROUP_NSLOTS 2 #define GROUP_NSLOTS 2
...@@ -360,6 +360,7 @@ ExecEndGroup(Group *node) ...@@ -360,6 +360,7 @@ ExecEndGroup(Group *node)
grpstate = node->grpstate; grpstate = node->grpstate;
ExecFreeProjectionInfo(&grpstate->csstate.cstate); ExecFreeProjectionInfo(&grpstate->csstate.cstate);
ExecFreeExprContext(&grpstate->csstate.cstate);
outerPlan = outerPlan(node); outerPlan = outerPlan(node);
ExecEndNode(outerPlan, (Plan *) node); ExecEndNode(outerPlan, (Plan *) node);
...@@ -406,6 +407,9 @@ ExecReScanGroup(Group *node, ExprContext *exprCtxt, Plan *parent) ...@@ -406,6 +407,9 @@ ExecReScanGroup(Group *node, ExprContext *exprCtxt, Plan *parent)
* numCols: the number of attributes to be examined * numCols: the number of attributes to be examined
* matchColIdx: array of attribute column numbers * matchColIdx: array of attribute column numbers
* eqFunctions: array of fmgr lookup info for the equality functions to use * 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 bool
execTuplesMatch(HeapTuple tuple1, execTuplesMatch(HeapTuple tuple1,
...@@ -413,16 +417,25 @@ execTuplesMatch(HeapTuple tuple1, ...@@ -413,16 +417,25 @@ execTuplesMatch(HeapTuple tuple1,
TupleDesc tupdesc, TupleDesc tupdesc,
int numCols, int numCols,
AttrNumber *matchColIdx, AttrNumber *matchColIdx,
FmgrInfo *eqfunctions) FmgrInfo *eqfunctions,
MemoryContext evalContext)
{ {
MemoryContext oldContext;
bool result;
int i; 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 * 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, * can report a non-match as soon as we find unequal fields. So,
* start comparing at the last field (least significant sort key). * start comparing at the last field (least significant sort key).
* That's the most likely to be different... * That's the most likely to be different...
*/ */
result = true;
for (i = numCols; --i >= 0;) for (i = numCols; --i >= 0;)
{ {
AttrNumber att = matchColIdx[i]; AttrNumber att = matchColIdx[i];
...@@ -442,7 +455,10 @@ execTuplesMatch(HeapTuple tuple1, ...@@ -442,7 +455,10 @@ execTuplesMatch(HeapTuple tuple1,
&isNull2); &isNull2);
if (isNull1 != 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) if (isNull1)
continue; /* both are null, treat as equal */ continue; /* both are null, treat as equal */
...@@ -451,10 +467,15 @@ execTuplesMatch(HeapTuple tuple1, ...@@ -451,10 +467,15 @@ execTuplesMatch(HeapTuple tuple1,
if (! DatumGetBool(FunctionCall2(&eqfunctions[i], if (! DatumGetBool(FunctionCall2(&eqfunctions[i],
attr1, attr2))) attr1, attr2)))
return FALSE; {
result = false; /* they aren't equal */
break;
}
} }
return TRUE; MemoryContextSwitchTo(oldContext);
return result;
} }
/* /*
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -28,7 +28,8 @@
#include "executor/nodeHash.h" #include "executor/nodeHash.h"
#include "executor/nodeHashjoin.h" #include "executor/nodeHashjoin.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "parser/parse_expr.h"
#include "parser/parse_type.h"
static int hashFunc(Datum key, int len, bool byVal); static int hashFunc(Datum key, int len, bool byVal);
...@@ -45,7 +46,7 @@ ExecHash(Hash *node) ...@@ -45,7 +46,7 @@ ExecHash(Hash *node)
EState *estate; EState *estate;
HashState *hashstate; HashState *hashstate;
Plan *outerNode; Plan *outerNode;
Var *hashkey; Node *hashkey;
HashJoinTable hashtable; HashJoinTable hashtable;
TupleTableSlot *slot; TupleTableSlot *slot;
ExprContext *econtext; ExprContext *econtext;
...@@ -139,12 +140,9 @@ ExecInitHash(Hash *node, EState *estate, Plan *parent) ...@@ -139,12 +140,9 @@ ExecInitHash(Hash *node, EState *estate, Plan *parent)
/* ---------------- /* ----------------
* Miscellaneous initialization * Miscellaneous initialization
* *
* + assign node's base_id
* + assign debugging hooks and
* + create expression context for node * + create expression context for node
* ---------------- * ----------------
*/ */
ExecAssignNodeBaseInfo(estate, &hashstate->cstate, parent);
ExecAssignExprContext(estate, &hashstate->cstate); ExecAssignExprContext(estate, &hashstate->cstate);
/* ---------------- /* ----------------
...@@ -204,6 +202,7 @@ ExecEndHash(Hash *node) ...@@ -204,6 +202,7 @@ ExecEndHash(Hash *node)
* ---------------- * ----------------
*/ */
ExecFreeProjectionInfo(&hashstate->cstate); ExecFreeProjectionInfo(&hashstate->cstate);
ExecFreeExprContext(&hashstate->cstate);
/* ---------------- /* ----------------
* shut down the subplan * shut down the subplan
...@@ -236,6 +235,7 @@ ExecHashTableCreate(Hash *node) ...@@ -236,6 +235,7 @@ ExecHashTableCreate(Hash *node)
int totalbuckets; int totalbuckets;
int bucketsize; int bucketsize;
int i; int i;
Type typeInfo;
MemoryContext oldcxt; MemoryContext oldcxt;
/* ---------------- /* ----------------
...@@ -346,6 +346,14 @@ ExecHashTableCreate(Hash *node) ...@@ -346,6 +346,14 @@ ExecHashTableCreate(Hash *node)
hashtable->innerBatchSize = NULL; hashtable->innerBatchSize = NULL;
hashtable->outerBatchSize = 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 * Create temporary memory contexts in which to keep the hashtable
* working storage. See notes in executor/hashjoin.h. * working storage. See notes in executor/hashjoin.h.
...@@ -448,7 +456,7 @@ ExecHashTableDestroy(HashJoinTable hashtable) ...@@ -448,7 +456,7 @@ ExecHashTableDestroy(HashJoinTable hashtable)
void void
ExecHashTableInsert(HashJoinTable hashtable, ExecHashTableInsert(HashJoinTable hashtable,
ExprContext *econtext, ExprContext *econtext,
Var *hashkey) Node *hashkey)
{ {
int bucketno = ExecHashGetBucket(hashtable, econtext, hashkey); int bucketno = ExecHashGetBucket(hashtable, econtext, hashkey);
TupleTableSlot *slot = econtext->ecxt_innertuple; TupleTableSlot *slot = econtext->ecxt_innertuple;
...@@ -508,43 +516,44 @@ ExecHashTableInsert(HashJoinTable hashtable, ...@@ -508,43 +516,44 @@ ExecHashTableInsert(HashJoinTable hashtable,
int int
ExecHashGetBucket(HashJoinTable hashtable, ExecHashGetBucket(HashJoinTable hashtable,
ExprContext *econtext, ExprContext *econtext,
Var *hashkey) Node *hashkey)
{ {
int bucketno; int bucketno;
Datum keyval; Datum keyval;
bool isNull; bool isNull;
bool isDone;
/* ---------------- /* ----------------
* Get the join attribute value of the tuple * Get the join attribute value of the tuple
* *
* ...It's quick hack - use ExecEvalExpr instead of ExecEvalVar: * We reset the eval context each time to avoid any possibility
* hashkey may be T_ArrayRef, not just T_Var. - vadim 04/22/97 * of memory leaks in the hash function.
* ---------------- * ----------------
*/ */
keyval = ExecEvalExpr((Node *) hashkey, econtext, &isNull, NULL); ResetExprContext(econtext);
/* keyval = ExecEvalExprSwitchContext(hashkey, econtext,
* keyval could be null, so we better point it to something valid &isNull, &isDone);
* before trying to run hashFunc on it. --djm 8/17/96
*/
if (isNull)
{
execConstByVal = 0;
execConstLen = 0;
keyval = (Datum) "";
}
/* ------------------ /* ------------------
* compute the hash function * 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 #ifdef HJDEBUG
if (bucketno >= hashtable->nbuckets) if (bucketno >= hashtable->nbuckets)
printf("hash(%d) = %d SAVED\n", keyval, bucketno); printf("hash(%ld) = %d SAVED\n", (long) keyval, bucketno);
else else
printf("hash(%d) = %d\n", keyval, bucketno); printf("hash(%ld) = %d\n", (long) keyval, bucketno);
#endif #endif
return bucketno; return bucketno;
...@@ -585,6 +594,9 @@ ExecScanHashBucket(HashJoinState *hjstate, ...@@ -585,6 +594,9 @@ ExecScanHashBucket(HashJoinState *hjstate,
false); /* do not pfree this tuple */ false); /* do not pfree this tuple */
econtext->ecxt_innertuple = inntuple; econtext->ecxt_innertuple = inntuple;
/* reset temp memory each time to avoid leaks from qual expression */
ResetExprContext(econtext);
if (ExecQual(hjclauses, econtext, false)) if (ExecQual(hjclauses, econtext, false))
{ {
hjstate->hj_CurTuple = hashTuple; hjstate->hj_CurTuple = hashTuple;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -51,13 +51,12 @@ ExecHashJoin(HashJoin *node)
List *qual; List *qual;
ScanDirection dir; ScanDirection dir;
TupleTableSlot *inntuple; TupleTableSlot *inntuple;
Var *outerVar; Node *outerVar;
ExprContext *econtext; ExprContext *econtext;
HashJoinTable hashtable; HashJoinTable hashtable;
HeapTuple curtuple; HeapTuple curtuple;
TupleTableSlot *outerTupleSlot; TupleTableSlot *outerTupleSlot;
TupleTableSlot *innerTupleSlot; TupleTableSlot *innerTupleSlot;
Var *innerhashkey;
int i; int i;
bool hashPhaseDone; bool hashPhaseDone;
...@@ -73,7 +72,6 @@ ExecHashJoin(HashJoin *node) ...@@ -73,7 +72,6 @@ ExecHashJoin(HashJoin *node)
hashNode = (Hash *) innerPlan(node); hashNode = (Hash *) innerPlan(node);
outerNode = outerPlan(node); outerNode = outerPlan(node);
hashPhaseDone = node->hashdone; hashPhaseDone = node->hashdone;
dir = estate->es_direction; dir = estate->es_direction;
/* ----------------- /* -----------------
...@@ -81,13 +79,21 @@ ExecHashJoin(HashJoin *node) ...@@ -81,13 +79,21 @@ ExecHashJoin(HashJoin *node)
* ----------------- * -----------------
*/ */
hashtable = hjstate->hj_HashTable; 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) if (hjstate->jstate.cs_TupFromTlist)
{ {
TupleTableSlot *result; TupleTableSlot *result;
...@@ -96,6 +102,8 @@ ExecHashJoin(HashJoin *node) ...@@ -96,6 +102,8 @@ ExecHashJoin(HashJoin *node)
result = ExecProject(hjstate->jstate.cs_ProjInfo, &isDone); result = ExecProject(hjstate->jstate.cs_ProjInfo, &isDone);
if (!isDone) if (!isDone)
return result; return result;
/* Done with that source tuple... */
hjstate->jstate.cs_TupFromTlist = false;
} }
/* ---------------- /* ----------------
...@@ -112,8 +120,7 @@ ExecHashJoin(HashJoin *node) ...@@ -112,8 +120,7 @@ ExecHashJoin(HashJoin *node)
*/ */
hashtable = ExecHashTableCreate(hashNode); hashtable = ExecHashTableCreate(hashNode);
hjstate->hj_HashTable = hashtable; hjstate->hj_HashTable = hashtable;
innerhashkey = hashNode->hashkey; hjstate->hj_InnerHashKey = hashNode->hashkey;
hjstate->hj_InnerHashKey = innerhashkey;
/* ---------------- /* ----------------
* execute the Hash node, to build the hash table * execute the Hash node, to build the hash table
...@@ -139,7 +146,7 @@ ExecHashJoin(HashJoin *node) ...@@ -139,7 +146,7 @@ ExecHashJoin(HashJoin *node)
* ---------------- * ----------------
*/ */
outerTupleSlot = hjstate->jstate.cs_OuterTupleSlot; outerTupleSlot = hjstate->jstate.cs_OuterTupleSlot;
outerVar = get_leftop(clause); outerVar = (Node *) get_leftop(clause);
for (;;) for (;;)
{ {
...@@ -220,6 +227,10 @@ ExecHashJoin(HashJoin *node) ...@@ -220,6 +227,10 @@ ExecHashJoin(HashJoin *node)
InvalidBuffer, InvalidBuffer,
false); /* don't pfree this tuple */ false); /* don't pfree this tuple */
econtext->ecxt_innertuple = inntuple; 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 * if we pass the qual, then save state for next call and
* have ExecProject form the projection, store it * have ExecProject form the projection, store it
...@@ -279,12 +290,9 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent) ...@@ -279,12 +290,9 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
/* ---------------- /* ----------------
* Miscellaneous initialization * Miscellaneous initialization
* *
* + assign node's base_id
* + assign debugging hooks and
* + create expression context for node * + create expression context for node
* ---------------- * ----------------
*/ */
ExecAssignNodeBaseInfo(estate, &hjstate->jstate, parent);
ExecAssignExprContext(estate, &hjstate->jstate); ExecAssignExprContext(estate, &hjstate->jstate);
#define HASHJOIN_NSLOTS 2 #define HASHJOIN_NSLOTS 2
...@@ -343,10 +351,10 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent) ...@@ -343,10 +351,10 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
hjstate->hj_HashTable = (HashJoinTable) NULL; hjstate->hj_HashTable = (HashJoinTable) NULL;
hjstate->hj_CurBucketNo = 0; hjstate->hj_CurBucketNo = 0;
hjstate->hj_CurTuple = (HashJoinTuple) NULL; hjstate->hj_CurTuple = (HashJoinTuple) NULL;
hjstate->hj_InnerHashKey = (Var *) NULL; hjstate->hj_InnerHashKey = (Node *) NULL;
hjstate->jstate.cs_OuterTupleSlot = (TupleTableSlot *) NULL; hjstate->jstate.cs_OuterTupleSlot = (TupleTableSlot *) NULL;
hjstate->jstate.cs_TupFromTlist = (bool) false; hjstate->jstate.cs_TupFromTlist = false;
return TRUE; return TRUE;
} }
...@@ -396,6 +404,7 @@ ExecEndHashJoin(HashJoin *node) ...@@ -396,6 +404,7 @@ ExecEndHashJoin(HashJoin *node)
* ---------------- * ----------------
*/ */
ExecFreeProjectionInfo(&hjstate->jstate); ExecFreeProjectionInfo(&hjstate->jstate);
ExecFreeExprContext(&hjstate->jstate);
/* ---------------- /* ----------------
* clean up subtrees * clean up subtrees
...@@ -510,7 +519,7 @@ ExecHashJoinNewBatch(HashJoinState *hjstate) ...@@ -510,7 +519,7 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
BufFile *innerFile; BufFile *innerFile;
TupleTableSlot *slot; TupleTableSlot *slot;
ExprContext *econtext; ExprContext *econtext;
Var *innerhashkey; Node *innerhashkey;
if (newbatch > 1) if (newbatch > 1)
{ {
...@@ -651,10 +660,10 @@ ExecReScanHashJoin(HashJoin *node, ExprContext *exprCtxt, Plan *parent) ...@@ -651,10 +660,10 @@ ExecReScanHashJoin(HashJoin *node, ExprContext *exprCtxt, Plan *parent)
hjstate->hj_CurBucketNo = 0; hjstate->hj_CurBucketNo = 0;
hjstate->hj_CurTuple = (HashJoinTuple) NULL; hjstate->hj_CurTuple = (HashJoinTuple) NULL;
hjstate->hj_InnerHashKey = (Var *) NULL; hjstate->hj_InnerHashKey = (Node *) NULL;
hjstate->jstate.cs_OuterTupleSlot = (TupleTableSlot *) 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 * if chgParam of subnodes is not null then plans will be re-scanned
......
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -158,17 +158,12 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent)
node->matstate = matstate; node->matstate = matstate;
/* ---------------- /* ----------------
* Miscellanious initialization * Miscellaneous initialization
*
* + assign node's base_id
* + assign debugging hooks and
* + assign result tuple slot
* *
* Materialization nodes don't need ExprContexts because * 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 #define MATERIAL_NSLOTS 1
/* ---------------- /* ----------------
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -202,45 +202,53 @@ MJFormSkipQual(List *qualList, char *replaceopname)
static bool static bool
MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext) MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
{ {
bool result;
MemoryContext oldContext;
List *clause; List *clause;
List *eqclause; 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) oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
return false;
/* ---------------- /* ----------------
* for each pair of clauses, test them until * 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; eqclause = eqQual;
foreach(clause, compareQual) foreach(clause, compareQual)
{ {
Datum const_value;
bool isNull;
bool isDone;
/* ---------------- /* ----------------
* first test if our compare clause is satisfied. * first test if our compare clause is satisfied.
* if so then return true. ignore isDone, don't iterate in * if so then return true.
* quals. *
* A NULL result is considered false.
* ignore isDone, don't iterate in quals.
* ---------------- * ----------------
*/ */
const_value = (Datum) const_value = ExecEvalExpr((Node *) lfirst(clause), econtext,
ExecEvalExpr((Node *) lfirst(clause), econtext, &isNull, &isDone); &isNull, &isDone);
if (DatumGetInt32(const_value) != 0) if (DatumGetBool(const_value) && !isNull)
return true; {
result = true;
break;
}
/* ---------------- /* ----------------
* ok, the compare clause failed so we test if the keys * ok, the compare clause failed so we test if the keys
* are equal... if key1 != key2, we return false. * are equal... if key1 != key2, we return false.
* otherwise key1 = key2 so we move on to the next pair of keys. * 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), const_value = ExecEvalExpr((Node *) lfirst(eqclause),
...@@ -248,17 +256,15 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext) ...@@ -248,17 +256,15 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
&isNull, &isNull,
&isDone); &isDone);
if (DatumGetInt32(const_value) == 0) if (! DatumGetBool(const_value) || isNull)
return false; break; /* return false */
eqclause = lnext(eqclause); eqclause = lnext(eqclause);
} }
/* ---------------- MemoryContextSwitchTo(oldContext);
* if we get here then it means none of our key greater-than
* conditions were satisfied so we return false. return result;
* ----------------
*/
return false;
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -403,24 +409,18 @@ ExecMergeJoin(MergeJoin *node) ...@@ -403,24 +409,18 @@ ExecMergeJoin(MergeJoin *node)
List *qual; List *qual;
bool qualResult; bool qualResult;
bool compareResult; bool compareResult;
Plan *innerPlan; Plan *innerPlan;
TupleTableSlot *innerTupleSlot; TupleTableSlot *innerTupleSlot;
Plan *outerPlan; Plan *outerPlan;
TupleTableSlot *outerTupleSlot; TupleTableSlot *outerTupleSlot;
ExprContext *econtext; ExprContext *econtext;
#ifdef ENABLE_OUTER_JOINS #ifdef ENABLE_OUTER_JOINS
/* /*
* These should be set from the expression context! - thomas * These should be set from the expression context! - thomas
* 1999-02-20 * 1999-02-20
*/ */
static bool isLeftJoin = true; static bool isLeftJoin = true;
static bool isRightJoin = false; static bool isRightJoin = false;
#endif #endif
/* ---------------- /* ----------------
...@@ -448,20 +448,34 @@ ExecMergeJoin(MergeJoin *node) ...@@ -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) if (mergestate->jstate.cs_TupFromTlist)
{ {
TupleTableSlot *result; TupleTableSlot *result;
ProjectionInfo *projInfo;
bool isDone; bool isDone;
projInfo = mergestate->jstate.cs_ProjInfo; result = ExecProject(mergestate->jstate.cs_ProjInfo, &isDone);
result = ExecProject(projInfo, &isDone);
if (!isDone) if (!isDone)
return result; return result;
/* Done with that source tuple... */
mergestate->jstate.cs_TupFromTlist = false;
} }
/* ----------------
* ok, everything is setup.. let's go to work
* ----------------
*/
for (;;) for (;;)
{ {
/* ---------------- /* ----------------
...@@ -547,6 +561,8 @@ ExecMergeJoin(MergeJoin *node) ...@@ -547,6 +561,8 @@ ExecMergeJoin(MergeJoin *node)
case EXEC_MJ_JOINTEST: case EXEC_MJ_JOINTEST:
MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTEST\n"); MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTEST\n");
ResetExprContext(econtext);
qualResult = ExecQual((List *) mergeclauses, econtext, false); qualResult = ExecQual((List *) mergeclauses, econtext, false);
MJ_DEBUG_QUAL(mergeclauses, qualResult); MJ_DEBUG_QUAL(mergeclauses, qualResult);
...@@ -565,6 +581,14 @@ ExecMergeJoin(MergeJoin *node) ...@@ -565,6 +581,14 @@ ExecMergeJoin(MergeJoin *node)
MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTUPLES\n"); MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTUPLES\n");
mergestate->mj_JoinState = EXEC_MJ_NEXTINNER; 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); qualResult = ExecQual((List *) qual, econtext, false);
MJ_DEBUG_QUAL(qual, qualResult); MJ_DEBUG_QUAL(qual, qualResult);
...@@ -693,6 +717,8 @@ ExecMergeJoin(MergeJoin *node) ...@@ -693,6 +717,8 @@ ExecMergeJoin(MergeJoin *node)
innerTupleSlot = econtext->ecxt_innertuple; innerTupleSlot = econtext->ecxt_innertuple;
econtext->ecxt_innertuple = mergestate->mj_MarkedTupleSlot; econtext->ecxt_innertuple = mergestate->mj_MarkedTupleSlot;
ResetExprContext(econtext);
qualResult = ExecQual((List *) mergeclauses, econtext, false); qualResult = ExecQual((List *) mergeclauses, econtext, false);
MJ_DEBUG_QUAL(mergeclauses, qualResult); MJ_DEBUG_QUAL(mergeclauses, qualResult);
...@@ -709,11 +735,7 @@ ExecMergeJoin(MergeJoin *node) ...@@ -709,11 +735,7 @@ ExecMergeJoin(MergeJoin *node)
*/ */
ExecRestrPos(innerPlan); ExecRestrPos(innerPlan);
#if 0
mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
#endif
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES; mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
} }
else else
{ {
...@@ -777,6 +799,8 @@ ExecMergeJoin(MergeJoin *node) ...@@ -777,6 +799,8 @@ ExecMergeJoin(MergeJoin *node)
* we update the marked tuple and go join them. * we update the marked tuple and go join them.
* ---------------- * ----------------
*/ */
ResetExprContext(econtext);
qualResult = ExecQual((List *) mergeclauses, econtext, false); qualResult = ExecQual((List *) mergeclauses, econtext, false);
MJ_DEBUG_QUAL(mergeclauses, qualResult); MJ_DEBUG_QUAL(mergeclauses, qualResult);
...@@ -886,6 +910,8 @@ ExecMergeJoin(MergeJoin *node) ...@@ -886,6 +910,8 @@ ExecMergeJoin(MergeJoin *node)
* we update the marked tuple and go join them. * we update the marked tuple and go join them.
* ---------------- * ----------------
*/ */
ResetExprContext(econtext);
qualResult = ExecQual((List *) mergeclauses, econtext, false); qualResult = ExecQual((List *) mergeclauses, econtext, false);
MJ_DEBUG_QUAL(mergeclauses, qualResult); MJ_DEBUG_QUAL(mergeclauses, qualResult);
...@@ -1142,12 +1168,9 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent) ...@@ -1142,12 +1168,9 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
/* ---------------- /* ----------------
* Miscellaneous initialization * Miscellaneous initialization
* *
* + assign node's base_id
* + assign debugging hooks and
* + create expression context for node * + create expression context for node
* ---------------- * ----------------
*/ */
ExecAssignNodeBaseInfo(estate, &mergestate->jstate, parent);
ExecAssignExprContext(estate, &mergestate->jstate); ExecAssignExprContext(estate, &mergestate->jstate);
#define MERGEJOIN_NSLOTS 2 #define MERGEJOIN_NSLOTS 2
...@@ -1251,6 +1274,7 @@ ExecEndMergeJoin(MergeJoin *node) ...@@ -1251,6 +1274,7 @@ ExecEndMergeJoin(MergeJoin *node)
* ---------------- * ----------------
*/ */
ExecFreeProjectionInfo(&mergestate->jstate); ExecFreeProjectionInfo(&mergestate->jstate);
ExecFreeExprContext(&mergestate->jstate);
/* ---------------- /* ----------------
* shut down the subplans * shut down the subplans
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -32,18 +32,18 @@ ...@@ -32,18 +32,18 @@
* *
* It scans the inner relation to join with current outer tuple. * 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 * and the inner relation is scanned from the beginning again to join
* with the outer tuple. * 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. * 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: * Conditions:
* -- outerTuple contains current tuple from outer relation and * -- 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. * returned previously.
* This is achieved by maintaining a scan position on the outer * This is achieved by maintaining a scan position on the outer
* relation. * relation.
...@@ -60,10 +60,8 @@ ExecNestLoop(NestLoop *node, Plan *parent) ...@@ -60,10 +60,8 @@ ExecNestLoop(NestLoop *node, Plan *parent)
Plan *innerPlan; Plan *innerPlan;
Plan *outerPlan; Plan *outerPlan;
bool needNewOuterTuple; bool needNewOuterTuple;
TupleTableSlot *outerTupleSlot; TupleTableSlot *outerTupleSlot;
TupleTableSlot *innerTupleSlot; TupleTableSlot *innerTupleSlot;
List *qual; List *qual;
ExprContext *econtext; ExprContext *econtext;
...@@ -77,11 +75,6 @@ ExecNestLoop(NestLoop *node, Plan *parent) ...@@ -77,11 +75,6 @@ ExecNestLoop(NestLoop *node, Plan *parent)
qual = node->join.qual; qual = node->join.qual;
outerPlan = outerPlan(&node->join); outerPlan = outerPlan(&node->join);
innerPlan = innerPlan(&node->join); innerPlan = innerPlan(&node->join);
/* ----------------
* initialize expression context
* ----------------
*/
econtext = nlstate->jstate.cs_ExprContext; econtext = nlstate->jstate.cs_ExprContext;
/* ---------------- /* ----------------
...@@ -92,11 +85,18 @@ ExecNestLoop(NestLoop *node, Plan *parent) ...@@ -92,11 +85,18 @@ ExecNestLoop(NestLoop *node, Plan *parent)
econtext->ecxt_outertuple = outerTupleSlot; econtext->ecxt_outertuple = outerTupleSlot;
/* ---------------- /* ----------------
* Ok, everything is setup for the join so now loop until * Reset per-tuple memory context to free any expression evaluation
* we return a qualifying join tuple.. * 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) if (nlstate->jstate.cs_TupFromTlist)
{ {
TupleTableSlot *result; TupleTableSlot *result;
...@@ -105,9 +105,17 @@ ExecNestLoop(NestLoop *node, Plan *parent) ...@@ -105,9 +105,17 @@ ExecNestLoop(NestLoop *node, Plan *parent)
result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone); result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
if (!isDone) if (!isDone)
return result; 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"); ENL1_printf("entering main loop");
for (;;) for (;;)
{ {
/* ---------------- /* ----------------
...@@ -115,15 +123,7 @@ ExecNestLoop(NestLoop *node, Plan *parent) ...@@ -115,15 +123,7 @@ ExecNestLoop(NestLoop *node, Plan *parent)
* and join it with the current outer tuple. * and join it with the current outer tuple.
* ---------------- * ----------------
*/ */
needNewOuterTuple = false; needNewOuterTuple = TupIsNull(outerTupleSlot);
if (!TupIsNull(outerTupleSlot))
ENL1_printf("have outer tuple, deal with it");
else
{
ENL1_printf("outer tuple is nil, need new outer tuple");
needNewOuterTuple = true;
}
/* ---------------- /* ----------------
* if we have an outerTuple, try to get the next inner tuple. * if we have an outerTuple, try to get the next inner tuple.
...@@ -229,9 +229,11 @@ ExecNestLoop(NestLoop *node, Plan *parent) ...@@ -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"); ENL1_printf("qualification failed, looping");
} }
} }
...@@ -263,18 +265,14 @@ ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent) ...@@ -263,18 +265,14 @@ ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
* ---------------- * ----------------
*/ */
nlstate = makeNode(NestLoopState); nlstate = makeNode(NestLoopState);
nlstate->nl_PortalFlag = false;
node->nlstate = nlstate; node->nlstate = nlstate;
/* ---------------- /* ----------------
* Miscellanious initialization * Miscellaneous initialization
* *
* + assign node's base_id
* + assign debugging hooks and
* + create expression context for node * + create expression context for node
* ---------------- * ----------------
*/ */
ExecAssignNodeBaseInfo(estate, &nlstate->jstate, parent);
ExecAssignExprContext(estate, &nlstate->jstate); ExecAssignExprContext(estate, &nlstate->jstate);
#define NESTLOOP_NSLOTS 1 #define NESTLOOP_NSLOTS 1
...@@ -348,6 +346,7 @@ ExecEndNestLoop(NestLoop *node) ...@@ -348,6 +346,7 @@ ExecEndNestLoop(NestLoop *node)
* ---------------- * ----------------
*/ */
ExecFreeProjectionInfo(&nlstate->jstate); ExecFreeProjectionInfo(&nlstate->jstate);
ExecFreeExprContext(&nlstate->jstate);
/* ---------------- /* ----------------
* close down subplans * close down subplans
...@@ -386,9 +385,7 @@ ExecReScanNestLoop(NestLoop *node, ExprContext *exprCtxt, Plan *parent) ...@@ -386,9 +385,7 @@ ExecReScanNestLoop(NestLoop *node, ExprContext *exprCtxt, Plan *parent)
if (outerPlan->chgParam == NULL) if (outerPlan->chgParam == NULL)
ExecReScan(outerPlan, exprCtxt, (Plan *) node); 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_OuterTupleSlot = NULL;
nlstate->jstate.cs_TupFromTlist = false; nlstate->jstate.cs_TupFromTlist = false;
return;
} }
...@@ -3,21 +3,18 @@ ...@@ -3,21 +3,18 @@
* nodeResult.c * nodeResult.c
* support for constant nodes needing special code. * 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 * DESCRIPTION
* *
* Example: in constant queries where no relations are scanned, * Result nodes are used in queries where no relations are scanned.
* the planner generates result nodes. Examples of such queries are: * Examples of such queries are:
* *
* retrieve (x = 1) * retrieve (x = 1)
* and * and
* append emp (name = "mike", salary = 15000) * append emp (name = "mike", salary = 15000)
* *
* Result nodes are also used to optimise queries * Result nodes are also used to optimise queries with constant
* with tautological qualifications like: * qualifications (ie, quals that do not depend on the scanned data),
* such as:
* *
* retrieve (emp.all) where 2 > 1 * retrieve (emp.all) where 2 > 1
* *
...@@ -27,13 +24,22 @@ ...@@ -27,13 +24,22 @@
* / * /
* SeqScan (emp.all) * 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 * 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/executor.h"
#include "executor/nodeResult.h" #include "executor/nodeResult.h"
...@@ -41,7 +47,7 @@ ...@@ -41,7 +47,7 @@
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* ExecResult(node) * 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 * qualification clause. Since result nodes with right
* subtrees are never planned, we ignore the right subtree * subtrees are never planned, we ignore the right subtree
* entirely (for now).. -cim 10/7/89 * entirely (for now).. -cim 10/7/89
...@@ -67,15 +73,17 @@ ExecResult(Result *node) ...@@ -67,15 +73,17 @@ ExecResult(Result *node)
* ---------------- * ----------------
*/ */
resstate = node->resstate; 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) if (resstate->rs_checkqual)
...@@ -92,74 +100,64 @@ ExecResult(Result *node) ...@@ -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) if (resstate->cstate.cs_TupFromTlist)
{ {
ProjectionInfo *projInfo; resultSlot = ExecProject(resstate->cstate.cs_ProjInfo, &isDone);
projInfo = resstate->cstate.cs_ProjInfo;
resultSlot = ExecProject(projInfo, &isDone);
if (!isDone) if (!isDone)
return resultSlot; return resultSlot;
/* Done with that source tuple... */
resstate->cstate.cs_TupFromTlist = false;
} }
/* ---------------- /* ----------------
* retrieve a tuple that satisfy the qual from the outer plan until * if rs_done is true then it means that we were asked to return
* there are no more. * a constant tuple and we already did the last time ExecResult()
* * was called, OR that we failed the constant qual check.
* if rs_done is 1 then it means that we were asked to return * Either way, now we are through.
* a constant tuple and we alread did the last time ExecResult()
* was called, so now we are through.
* ---------------- * ----------------
*/ */
if (!resstate->rs_done)
{
outerPlan = outerPlan(node); outerPlan = outerPlan(node);
while (!resstate->rs_done) if (outerPlan != NULL)
{ {
/* ---------------- /* ----------------
* get next outer tuple if necessary. * retrieve tuples from the outer plan until there are no more.
* ---------------- * ----------------
*/ */
if (outerPlan != NULL)
{
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node); outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
if (TupIsNull(outerTupleSlot)) if (TupIsNull(outerTupleSlot))
return NULL; return NULL;
resstate->cstate.cs_OuterTupleSlot = outerTupleSlot; resstate->cstate.cs_OuterTupleSlot = outerTupleSlot;
}
else
{
/* ---------------- /* ----------------
* if we don't have an outer plan, then it's probably * XXX gross hack. use outer tuple as scan tuple for projection
* 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.
* ---------------- * ----------------
*/ */
resstate->rs_done = 1; econtext->ecxt_outertuple = outerTupleSlot;
econtext->ecxt_scantuple = outerTupleSlot;
} }
else
/* ---------------- {
* 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 * if we don't have an outer plan, then we are just generating
* XXX gross hack. use outer tuple as scan tuple * the results from a constant target list. Do it only once.
* ---------------- * ----------------
*/ */
econtext->ecxt_outertuple = outerTupleSlot; resstate->rs_done = true;
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; projInfo = resstate->cstate.cs_ProjInfo;
...@@ -200,14 +198,11 @@ ExecInitResult(Result *node, EState *estate, Plan *parent) ...@@ -200,14 +198,11 @@ ExecInitResult(Result *node, EState *estate, Plan *parent)
node->resstate = resstate; node->resstate = resstate;
/* ---------------- /* ----------------
* Miscellanious initialization * Miscellaneous initialization
* *
* + assign node's base_id
* + assign debugging hooks and
* + create expression context for node * + create expression context for node
* ---------------- * ----------------
*/ */
ExecAssignNodeBaseInfo(estate, &resstate->cstate, parent);
ExecAssignExprContext(estate, &resstate->cstate); ExecAssignExprContext(estate, &resstate->cstate);
#define RESULT_NSLOTS 1 #define RESULT_NSLOTS 1
...@@ -247,7 +242,7 @@ ExecCountSlotsResult(Result *node) ...@@ -247,7 +242,7 @@ ExecCountSlotsResult(Result *node)
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* ExecEndResult * ExecEndResult
* *
* fees up storage allocated through C routines * frees up storage allocated through C routines
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
void void
...@@ -266,9 +261,8 @@ ExecEndResult(Result *node) ...@@ -266,9 +261,8 @@ ExecEndResult(Result *node)
* is freed at end-transaction time. -cim 6/2/91 * 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); ExecFreeProjectionInfo(&resstate->cstate);
ExecFreeExprContext(&resstate->cstate);
/* ---------------- /* ----------------
* shut down subplans * shut down subplans
...@@ -301,5 +295,4 @@ ExecReScanResult(Result *node, ExprContext *exprCtxt, Plan *parent) ...@@ -301,5 +295,4 @@ ExecReScanResult(Result *node, ExprContext *exprCtxt, Plan *parent)
if (((Plan *) node)->lefttree && if (((Plan *) node)->lefttree &&
((Plan *) node)->lefttree->chgParam == NULL) ((Plan *) node)->lefttree->chgParam == NULL)
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node); ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -31,8 +31,7 @@
#include "parser/parsetree.h" #include "parser/parsetree.h"
static Oid InitScanRelation(SeqScan *node, EState *estate, static Oid InitScanRelation(SeqScan *node, EState *estate,
CommonScanState *scanstate, Plan *outerPlan); CommonScanState *scanstate);
static TupleTableSlot *SeqNext(SeqScan *node); static TupleTableSlot *SeqNext(SeqScan *node);
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -132,25 +131,11 @@ SeqNext(SeqScan *node) ...@@ -132,25 +131,11 @@ SeqNext(SeqScan *node)
TupleTableSlot * TupleTableSlot *
ExecSeqScan(SeqScan *node) 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 * use SeqNext as access method
* else, scan the relation
* ---------------- * ----------------
*/ */
if ((outerPlan = outerPlan((Plan *) node)) != NULL) return ExecScan(node, (ExecScanAccessMtd) SeqNext);
slot = ExecProcNode(outerPlan, (Plan *) node);
else
slot = ExecScan(node, SeqNext);
S1_printf("ExecSeqScan: returned tuple slot: %d\n", slot);
return slot;
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -162,7 +147,7 @@ ExecSeqScan(SeqScan *node) ...@@ -162,7 +147,7 @@ ExecSeqScan(SeqScan *node)
*/ */
static Oid static Oid
InitScanRelation(SeqScan *node, EState *estate, InitScanRelation(SeqScan *node, EState *estate,
CommonScanState *scanstate, Plan *outerPlan) CommonScanState *scanstate)
{ {
Index relid; Index relid;
List *rangeTable; List *rangeTable;
...@@ -173,12 +158,7 @@ InitScanRelation(SeqScan *node, EState *estate, ...@@ -173,12 +158,7 @@ InitScanRelation(SeqScan *node, EState *estate,
HeapScanDesc currentScanDesc; HeapScanDesc currentScanDesc;
RelationInfo *resultRelationInfo; 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 * get the relation object id from the relid'th entry
* in the range table, open that relation and initialize * in the range table, open that relation and initialize
* the scan state... * the scan state...
...@@ -195,7 +175,7 @@ InitScanRelation(SeqScan *node, EState *estate, ...@@ -195,7 +175,7 @@ InitScanRelation(SeqScan *node, EState *estate,
0, /* nkeys */ 0, /* nkeys */
NULL, /* scan key */ NULL, /* scan key */
0, /* is index */ 0, /* is index */
direction,/* scan direction */ direction, /* scan direction */
estate->es_snapshot, estate->es_snapshot,
&currentRelation, /* return: rel desc */ &currentRelation, /* return: rel desc */
(Pointer *) &currentScanDesc); /* return: scan desc */ (Pointer *) &currentScanDesc); /* return: scan desc */
...@@ -203,54 +183,31 @@ InitScanRelation(SeqScan *node, EState *estate, ...@@ -203,54 +183,31 @@ InitScanRelation(SeqScan *node, EState *estate,
scanstate->css_currentRelation = currentRelation; scanstate->css_currentRelation = currentRelation;
scanstate->css_currentScanDesc = currentScanDesc; scanstate->css_currentScanDesc = currentScanDesc;
ExecAssignScanType(scanstate, ExecAssignScanType(scanstate, RelationGetDescr(currentRelation));
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
* ----------------
*/
return reloid; return reloid;
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* ExecInitSeqScan * 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 bool
ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent) ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
{ {
CommonScanState *scanstate; CommonScanState *scanstate;
Plan *outerPlan;
Oid reloid; Oid reloid;
HeapScanDesc scandesc; 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 * assign the node's execution state
* ---------------- * ----------------
...@@ -265,13 +222,11 @@ ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent) ...@@ -265,13 +222,11 @@ ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
node->scanstate = scanstate; node->scanstate = scanstate;
/* ---------------- /* ----------------
* Miscellanious initialization * Miscellaneous initialization
* *
* + assign node's base_id
* + create expression context for node * + create expression context for node
* ---------------- * ----------------
*/ */
ExecAssignNodeBaseInfo(estate, &scanstate->cstate, parent);
ExecAssignExprContext(estate, &scanstate->cstate); ExecAssignExprContext(estate, &scanstate->cstate);
#define SEQSCAN_NSLOTS 3 #define SEQSCAN_NSLOTS 3
...@@ -283,12 +238,10 @@ ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent) ...@@ -283,12 +238,10 @@ ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
ExecInitScanTupleSlot(estate, scanstate); ExecInitScanTupleSlot(estate, scanstate);
/* ---------------- /* ----------------
* initialize scan relation or outer subplan * initialize scan relation
* ---------------- * ----------------
*/ */
outerPlan = outerPlan((Plan *) node); reloid = InitScanRelation(node, estate, scanstate);
reloid = InitScanRelation(node, estate, scanstate, outerPlan);
scandesc = scanstate->css_currentScanDesc; scandesc = scanstate->css_currentScanDesc;
scanstate->cstate.cs_TupFromTlist = false; scanstate->cstate.cs_TupFromTlist = false;
...@@ -315,15 +268,12 @@ ExecCountSlotsSeqScan(SeqScan *node) ...@@ -315,15 +268,12 @@ ExecCountSlotsSeqScan(SeqScan *node)
* ExecEndSeqScan * ExecEndSeqScan
* *
* frees any storage allocated through C routines. * frees any storage allocated through C routines.
*| ...and also closes relations and/or shuts down outer subplan
*| -cim 8/14/89
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
void void
ExecEndSeqScan(SeqScan *node) ExecEndSeqScan(SeqScan *node)
{ {
CommonScanState *scanstate; CommonScanState *scanstate;
Plan *outerPlan;
/* ---------------- /* ----------------
* get information from node * get information from node
...@@ -341,6 +291,7 @@ ExecEndSeqScan(SeqScan *node) ...@@ -341,6 +291,7 @@ ExecEndSeqScan(SeqScan *node)
* ---------------- * ----------------
*/ */
ExecFreeProjectionInfo(&scanstate->cstate); ExecFreeProjectionInfo(&scanstate->cstate);
ExecFreeExprContext(&scanstate->cstate);
/* ---------------- /* ----------------
* close scan relation * close scan relation
...@@ -348,13 +299,6 @@ ExecEndSeqScan(SeqScan *node) ...@@ -348,13 +299,6 @@ ExecEndSeqScan(SeqScan *node)
*/ */
ExecCloseR((Plan *) 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 * clean out the tuple table
* ---------------- * ----------------
...@@ -367,6 +311,7 @@ ExecEndSeqScan(SeqScan *node) ...@@ -367,6 +311,7 @@ ExecEndSeqScan(SeqScan *node)
* Join Support * Join Support
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* ExecSeqReScan * ExecSeqReScan
* *
...@@ -378,7 +323,6 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent) ...@@ -378,7 +323,6 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
{ {
CommonScanState *scanstate; CommonScanState *scanstate;
EState *estate; EState *estate;
Plan *outerPlan;
Relation rel; Relation rel;
HeapScanDesc scan; HeapScanDesc scan;
ScanDirection direction; ScanDirection direction;
...@@ -386,15 +330,6 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent) ...@@ -386,15 +330,6 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
scanstate = node->scanstate; scanstate = node->scanstate;
estate = node->plan.state; 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 this is re-scanning of PlanQual ... */
if (estate->es_evTuple != NULL && if (estate->es_evTuple != NULL &&
estate->es_evTuple[node->scanrelid - 1] != NULL) estate->es_evTuple[node->scanrelid - 1] != NULL)
...@@ -407,7 +342,6 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent) ...@@ -407,7 +342,6 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
direction = estate->es_direction; direction = estate->es_direction;
scan = ExecReScanR(rel, scan, direction, 0, NULL); scan = ExecReScanR(rel, scan, direction, 0, NULL);
scanstate->css_currentScanDesc = scan; scanstate->css_currentScanDesc = scan;
}
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -420,33 +354,11 @@ void ...@@ -420,33 +354,11 @@ void
ExecSeqMarkPos(SeqScan *node) ExecSeqMarkPos(SeqScan *node)
{ {
CommonScanState *scanstate; CommonScanState *scanstate;
Plan *outerPlan;
HeapScanDesc scan; HeapScanDesc scan;
scanstate = node->scanstate; 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; scan = scanstate->css_currentScanDesc;
heap_markpos(scan); heap_markpos(scan);
return;
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -459,28 +371,9 @@ void ...@@ -459,28 +371,9 @@ void
ExecSeqRestrPos(SeqScan *node) ExecSeqRestrPos(SeqScan *node)
{ {
CommonScanState *scanstate; CommonScanState *scanstate;
Plan *outerPlan;
HeapScanDesc scan; HeapScanDesc scan;
scanstate = node->scanstate; 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; scan = scanstate->css_currentScanDesc;
heap_restrpos(scan); heap_restrpos(scan);
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -255,14 +255,10 @@ ExecInitSort(Sort *node, EState *estate, Plan *parent)
/* ---------------- /* ----------------
* Miscellaneous initialization * Miscellaneous initialization
* *
* + assign node's base_id
* + assign debugging hooks
*
* Sort nodes don't initialize their ExprContexts because * 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 #define SORT_NSLOTS 1
/* ---------------- /* ----------------
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.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) ...@@ -37,11 +37,19 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
SubLink *sublink = node->sublink; SubLink *sublink = node->sublink;
SubLinkType subLinkType = sublink->subLinkType; SubLinkType subLinkType = sublink->subLinkType;
bool useor = sublink->useor; bool useor = sublink->useor;
MemoryContext oldcontext;
TupleTableSlot *slot; TupleTableSlot *slot;
Datum result; Datum result;
bool isDone;
bool found = false; /* TRUE if got at least one subplan tuple */ bool found = false; /* TRUE if got at least one subplan tuple */
List *lst; 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) if (node->setParam != NIL)
elog(ERROR, "ExecSubPlan: can't set parent params from subquery"); elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
...@@ -52,12 +60,16 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull) ...@@ -52,12 +60,16 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
{ {
foreach(lst, node->parParam) 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); Assert(pvar != NIL);
prm->value = ExecEvalExpr((Node *) lfirst(pvar), prm->value = ExecEvalExprSwitchContext((Node *) lfirst(pvar),
econtext, econtext,
&(prm->isnull), NULL); &(prm->isnull),
&isDone);
if (!isDone)
elog(ERROR, "ExecSubPlan: set values not supported for params");
pvar = lnext(pvar); pvar = lnext(pvar);
} }
plan->chgParam = nconc(plan->chgParam, listCopy(node->parParam)); plan->chgParam = nconc(plan->chgParam, listCopy(node->parParam));
...@@ -84,7 +96,7 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull) ...@@ -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 * return NULL. Assuming we get a tuple, we just return its first
* column (there can be only one non-junk column in this case). * 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; *isNull = false;
for (slot = ExecProcNode(plan, plan); for (slot = ExecProcNode(plan, plan);
...@@ -93,12 +105,16 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull) ...@@ -93,12 +105,16 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
{ {
HeapTuple tup = slot->val; HeapTuple tup = slot->val;
TupleDesc tdesc = slot->ttc_tupleDescriptor; TupleDesc tdesc = slot->ttc_tupleDescriptor;
Datum rowresult = (Datum) (useor ? false : true); Datum rowresult = BoolGetDatum(! useor);
bool rownull = false; bool rownull = false;
int col = 1; int col = 1;
if (subLinkType == EXISTS_SUBLINK) if (subLinkType == EXISTS_SUBLINK)
return (Datum) true; {
found = true;
result = BoolGetDatum(true);
break;
}
if (subLinkType == EXPR_SUBLINK) if (subLinkType == EXPR_SUBLINK)
{ {
...@@ -172,8 +188,10 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull) ...@@ -172,8 +188,10 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
/* /*
* Now we can eval the combining operator for this column. * Now we can eval the combining operator for this column.
*/ */
expresult = ExecEvalExpr((Node *) expr, econtext, &expnull, expresult = ExecEvalExprSwitchContext((Node *) expr, econtext,
(bool *) NULL); &expnull, &isDone);
if (!isDone)
elog(ERROR, "ExecSubPlan: set values not supported for combining operators");
/* /*
* Combine the result into the row result as appropriate. * Combine the result into the row result as appropriate.
...@@ -188,9 +206,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull) ...@@ -188,9 +206,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
/* combine within row per OR semantics */ /* combine within row per OR semantics */
if (expnull) if (expnull)
rownull = true; rownull = true;
else if (DatumGetInt32(expresult) != 0) else if (DatumGetBool(expresult))
{ {
rowresult = (Datum) true; rowresult = BoolGetDatum(true);
rownull = false; rownull = false;
break; /* needn't look at any more columns */ break; /* needn't look at any more columns */
} }
...@@ -200,9 +218,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull) ...@@ -200,9 +218,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
/* combine within row per AND semantics */ /* combine within row per AND semantics */
if (expnull) if (expnull)
rownull = true; rownull = true;
else if (DatumGetInt32(expresult) == 0) else if (! DatumGetBool(expresult))
{ {
rowresult = (Datum) false; rowresult = BoolGetDatum(false);
rownull = false; rownull = false;
break; /* needn't look at any more columns */ break; /* needn't look at any more columns */
} }
...@@ -215,9 +233,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull) ...@@ -215,9 +233,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
/* combine across rows per OR semantics */ /* combine across rows per OR semantics */
if (rownull) if (rownull)
*isNull = true; *isNull = true;
else if (DatumGetInt32(rowresult) != 0) else if (DatumGetBool(rowresult))
{ {
result = (Datum) true; result = BoolGetDatum(true);
*isNull = false; *isNull = false;
break; /* needn't look at any more rows */ break; /* needn't look at any more rows */
} }
...@@ -227,9 +245,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull) ...@@ -227,9 +245,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
/* combine across rows per AND semantics */ /* combine across rows per AND semantics */
if (rownull) if (rownull)
*isNull = true; *isNull = true;
else if (DatumGetInt32(rowresult) == 0) else if (! DatumGetBool(rowresult))
{ {
result = (Datum) false; result = BoolGetDatum(false);
*isNull = false; *isNull = false;
break; /* needn't look at any more rows */ break; /* needn't look at any more rows */
} }
...@@ -252,11 +270,13 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull) ...@@ -252,11 +270,13 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
*/ */
if (subLinkType == EXPR_SUBLINK || subLinkType == MULTIEXPR_SUBLINK) if (subLinkType == EXPR_SUBLINK || subLinkType == MULTIEXPR_SUBLINK)
{ {
result = (Datum) false; result = (Datum) 0;
*isNull = true; *isNull = true;
} }
} }
MemoryContextSwitchTo(oldcontext);
return result; return result;
} }
...@@ -277,13 +297,13 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent) ...@@ -277,13 +297,13 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
ExecCreateTupleTable(ExecCountSlotsNode(node->plan) + 10); ExecCreateTupleTable(ExecCountSlotsNode(node->plan) + 10);
sp_estate->es_snapshot = estate->es_snapshot; sp_estate->es_snapshot = estate->es_snapshot;
node->shutdown = false; node->needShutdown = false;
node->curTuple = NULL; node->curTuple = NULL;
if (!ExecInitNode(node->plan, sp_estate, NULL)) if (!ExecInitNode(node->plan, sp_estate, NULL))
return false; 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 * If this plan is un-correlated or undirect correlated one and want
...@@ -317,14 +337,21 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent) ...@@ -317,14 +337,21 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
void void
ExecSetParamPlan(SubPlan *node) ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
{ {
Plan *plan = node->plan; Plan *plan = node->plan;
SubLink *sublink = node->sublink; SubLink *sublink = node->sublink;
MemoryContext oldcontext;
TupleTableSlot *slot; TupleTableSlot *slot;
List *lst; List *lst;
bool found = false; 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 || if (sublink->subLinkType == ANY_SUBLINK ||
sublink->subLinkType == ALL_SUBLINK) sublink->subLinkType == ALL_SUBLINK)
elog(ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported"); elog(ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported");
...@@ -345,7 +372,7 @@ ExecSetParamPlan(SubPlan *node) ...@@ -345,7 +372,7 @@ ExecSetParamPlan(SubPlan *node)
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]); ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
prm->execPlan = NULL; prm->execPlan = NULL;
prm->value = (Datum) true; prm->value = BoolGetDatum(true);
prm->isnull = false; prm->isnull = false;
found = true; found = true;
break; break;
...@@ -386,7 +413,7 @@ ExecSetParamPlan(SubPlan *node) ...@@ -386,7 +413,7 @@ ExecSetParamPlan(SubPlan *node)
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]); ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
prm->execPlan = NULL; prm->execPlan = NULL;
prm->value = (Datum) false; prm->value = BoolGetDatum(false);
prm->isnull = false; prm->isnull = false;
} }
else else
...@@ -396,16 +423,18 @@ ExecSetParamPlan(SubPlan *node) ...@@ -396,16 +423,18 @@ ExecSetParamPlan(SubPlan *node)
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]); ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
prm->execPlan = NULL; prm->execPlan = NULL;
prm->value = (Datum) NULL; prm->value = (Datum) 0;
prm->isnull = true; prm->isnull = true;
} }
} }
} }
MemoryContextSwitchTo(oldcontext);
if (plan->extParam == NULL) /* un-correlated ... */ if (plan->extParam == NULL) /* un-correlated ... */
{ {
ExecEndNode(plan, plan); ExecEndNode(plan, plan);
node->shutdown = false; node->needShutdown = false;
} }
} }
...@@ -416,10 +445,10 @@ ExecSetParamPlan(SubPlan *node) ...@@ -416,10 +445,10 @@ ExecSetParamPlan(SubPlan *node)
void void
ExecEndSubPlan(SubPlan *node) ExecEndSubPlan(SubPlan *node)
{ {
if (node->shutdown) if (node->needShutdown)
{ {
ExecEndNode(node->plan, node->plan); ExecEndNode(node->plan, node->plan);
node->shutdown = false; node->needShutdown = false;
} }
if (node->curTuple) if (node->curTuple)
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -38,12 +38,16 @@ TidListCreate(List *evalList, ExprContext *econtext, ItemPointer *tidList)
List *lst; List *lst;
ItemPointer itemptr; ItemPointer itemptr;
bool isNull; bool isNull;
bool isDone;
int numTids = 0; int numTids = 0;
foreach(lst, evalList) foreach(lst, evalList)
{ {
itemptr = (ItemPointer) ExecEvalExpr(lfirst(lst), econtext, itemptr = (ItemPointer)
&isNull, (bool *) 0); DatumGetPointer(ExecEvalExprSwitchContext(lfirst(lst),
econtext,
&isNull,
&isDone));
if (itemptr && ItemPointerIsValid(itemptr)) if (itemptr && ItemPointerIsValid(itemptr))
{ {
tidList[numTids] = itemptr; tidList[numTids] = itemptr;
...@@ -243,7 +247,7 @@ ExecTidScan(TidScan *node) ...@@ -243,7 +247,7 @@ ExecTidScan(TidScan *node)
* use TidNext as access method * use TidNext as access method
* ---------------- * ----------------
*/ */
return ExecScan(&node->scan, TidNext); return ExecScan(&node->scan, (ExecScanAccessMtd) TidNext);
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -319,6 +323,7 @@ ExecEndTidScan(TidScan *node) ...@@ -319,6 +323,7 @@ ExecEndTidScan(TidScan *node)
* ---------------- * ----------------
*/ */
ExecFreeProjectionInfo(&scanstate->cstate); ExecFreeProjectionInfo(&scanstate->cstate);
ExecFreeExprContext(&scanstate->cstate);
/* ---------------- /* ----------------
* close the heap and tid relations * close the heap and tid relations
...@@ -332,7 +337,6 @@ ExecEndTidScan(TidScan *node) ...@@ -332,7 +337,6 @@ ExecEndTidScan(TidScan *node)
*/ */
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot); ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
ExecClearTuple(scanstate->css_ScanTupleSlot); ExecClearTuple(scanstate->css_ScanTupleSlot);
/* ExecClearTuple(scanstate->css_RawTupleSlot); */
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -394,11 +398,8 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent) ...@@ -394,11 +398,8 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
RangeTblEntry *rtentry; RangeTblEntry *rtentry;
Oid relid; Oid relid;
Oid reloid; Oid reloid;
Relation currentRelation; Relation currentRelation;
int baseid; List *execParam = NIL;
List *execParam = NULL;
/* ---------------- /* ----------------
* assign execution state to node * assign execution state to node
...@@ -413,25 +414,12 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent) ...@@ -413,25 +414,12 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
* -------------------------------- * --------------------------------
*/ */
scanstate = makeNode(CommonScanState); scanstate = makeNode(CommonScanState);
/*
scanstate->ss_ProcOuterFlag = false;
scanstate->ss_OldRelId = 0;
*/
node->scan.scanstate = scanstate; node->scan.scanstate = scanstate;
/* ---------------- /* ----------------
* assign node's base_id .. we don't use AssignNodeBaseid() because * Miscellaneous initialization
* the increment is done later on after we assign the tid scan's *
* scanstate. see below. * + create expression context for node
* ----------------
*/
baseid = estate->es_BaseId;
/* scanstate->csstate.cstate.bnode.base_id = baseid; */
scanstate->cstate.cs_base_id = baseid;
/* ----------------
* create expression context for node
* ---------------- * ----------------
*/ */
ExecAssignExprContext(estate, &scanstate->cstate); ExecAssignExprContext(estate, &scanstate->cstate);
...@@ -443,7 +431,6 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent) ...@@ -443,7 +431,6 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
*/ */
ExecInitResultTupleSlot(estate, &scanstate->cstate); ExecInitResultTupleSlot(estate, &scanstate->cstate);
ExecInitScanTupleSlot(estate, scanstate); ExecInitScanTupleSlot(estate, scanstate);
/* ExecInitRawTupleSlot(estate, scanstate); */
/* ---------------- /* ----------------
* initialize projection info. result type comes from scan desc * initialize projection info. result type comes from scan desc
...@@ -461,14 +448,6 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent) ...@@ -461,14 +448,6 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
tidstate = makeNode(TidScanState); tidstate = makeNode(TidScanState);
node->tidstate = tidstate; 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 * get the tid node information
* ---------------- * ----------------
...@@ -514,14 +493,6 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent) ...@@ -514,14 +493,6 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
ExecAssignScanType(scanstate, RelationGetDescr(currentRelation)); ExecAssignScanType(scanstate, RelationGetDescr(currentRelation));
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate); 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 * if there are some PARAM_EXEC in skankeys then force tid rescan on
* first scan. * first scan.
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -88,27 +88,32 @@ ExecUnique(Unique *node)
if (!execTuplesMatch(slot->val, uniquestate->priorTuple, if (!execTuplesMatch(slot->val, uniquestate->priorTuple,
tupDesc, tupDesc,
node->numCols, node->uniqColIdx, node->numCols, node->uniqColIdx,
uniquestate->eqfunctions)) uniquestate->eqfunctions,
uniquestate->tempContext))
break; break;
} }
/* ---------------- /* ----------------
* We have a new tuple different from the previous saved tuple (if any). * 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: * Save it and return it. We must copy it because the source subplan
* one to keep for our own future comparisons, and one to return to the * won't guarantee that this source tuple is still accessible after
* caller. We need to copy the tuple returned by the subplan to avoid * fetching the next source tuple.
* holding buffer refcounts, and we need our own copy because the caller *
* may alter the resultTupleSlot (eg via ExecRemoveJunk). * 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) if (uniquestate->priorTuple != NULL)
heap_freetuple(uniquestate->priorTuple); heap_freetuple(uniquestate->priorTuple);
uniquestate->priorTuple = heap_copytuple(slot->val); uniquestate->priorTuple = heap_copytuple(slot->val);
ExecStoreTuple(heap_copytuple(slot->val), ExecStoreTuple(uniquestate->priorTuple,
resultTupleSlot, resultTupleSlot,
InvalidBuffer, InvalidBuffer,
true); false); /* tuple does not belong to slot */
return resultTupleSlot; return resultTupleSlot;
} }
...@@ -143,14 +148,17 @@ ExecInitUnique(Unique *node, EState *estate, Plan *parent) ...@@ -143,14 +148,17 @@ ExecInitUnique(Unique *node, EState *estate, Plan *parent)
/* ---------------- /* ----------------
* Miscellaneous initialization * Miscellaneous initialization
* *
* + assign node's base_id
* + assign debugging hooks and
*
* Unique nodes have no ExprContext initialization because * 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 #define UNIQUE_NSLOTS 1
/* ------------ /* ------------
...@@ -207,6 +215,8 @@ ExecEndUnique(Unique *node) ...@@ -207,6 +215,8 @@ ExecEndUnique(Unique *node)
ExecEndNode(outerPlan((Plan *) node), (Plan *) node); ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
MemoryContextDelete(uniquestate->tempContext);
/* clean up tuple table */ /* clean up tuple table */
ExecClearTuple(uniquestate->cstate.cs_ResultTupleSlot); ExecClearTuple(uniquestate->cstate.cs_ResultTupleSlot);
if (uniquestate->priorTuple != NULL) if (uniquestate->priorTuple != NULL)
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/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) ...@@ -578,7 +578,7 @@ _copySubPlan(SubPlan *from)
Node_Copy(from, newnode, sublink); Node_Copy(from, newnode, sublink);
/* do not copy execution state */ /* do not copy execution state */
newnode->shutdown = false; newnode->needShutdown = false;
newnode->curTuple = NULL; newnode->curTuple = NULL;
return newnode; return newnode;
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/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) ...@@ -184,8 +184,8 @@ _equalConst(Const *a, Const *b)
*/ */
if (a->constisnull) if (a->constisnull)
return true; return true;
return (datumIsEqual(a->constvalue, b->constvalue, return datumIsEqual(a->constvalue, b->constvalue,
a->consttype, a->constbyval, a->constlen)); a->constbyval, a->constlen);
} }
static bool static bool
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which * Every (plan) node in POSTGRES has an associated "out" routine which
...@@ -1155,10 +1155,10 @@ _outJoinInfo(StringInfo str, JoinInfo *node) ...@@ -1155,10 +1155,10 @@ _outJoinInfo(StringInfo str, JoinInfo *node)
static void static void
_outDatum(StringInfo str, Datum value, Oid type) _outDatum(StringInfo str, Datum value, Oid type)
{ {
char *s;
Size length,
typeLength;
bool byValue; bool byValue;
int typeLength;
Size length;
char *s;
int i; int i;
/* /*
...@@ -1167,12 +1167,12 @@ _outDatum(StringInfo str, Datum value, Oid type) ...@@ -1167,12 +1167,12 @@ _outDatum(StringInfo str, Datum value, Oid type)
*/ */
byValue = get_typbyval(type); byValue = get_typbyval(type);
typeLength = get_typlen(type); typeLength = get_typlen(type);
length = datumGetSize(value, type, byValue, typeLength); length = datumGetSize(value, byValue, typeLength);
if (byValue) if (byValue)
{ {
s = (char *) (&value); s = (char *) (&value);
appendStringInfo(str, " %d [ ", length); appendStringInfo(str, " %u [ ", (unsigned int) length);
for (i = 0; i < (int) sizeof(Datum); i++) for (i = 0; i < (int) sizeof(Datum); i++)
appendStringInfo(str, "%d ", (int) (s[i])); appendStringInfo(str, "%d ", (int) (s[i]));
appendStringInfo(str, "] "); appendStringInfo(str, "] ");
...@@ -1184,14 +1184,7 @@ _outDatum(StringInfo str, Datum value, Oid type) ...@@ -1184,14 +1184,7 @@ _outDatum(StringInfo str, Datum value, Oid type)
appendStringInfo(str, " 0 [ ] "); appendStringInfo(str, " 0 [ ] ");
else else
{ {
appendStringInfo(str, " %u [ ", (unsigned int) length);
/*
* 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);
for (i = 0; i < (int) length; i++) for (i = 0; i < (int) length; i++)
appendStringInfo(str, "%d ", (int) (s[i])); appendStringInfo(str, "%d ", (int) (s[i]));
appendStringInfo(str, "] "); appendStringInfo(str, "] ");
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Most of the read functions for plan nodes are tested. (In fact, they * Most of the read functions for plan nodes are tested. (In fact, they
...@@ -608,7 +608,7 @@ _readHash() ...@@ -608,7 +608,7 @@ _readHash()
_getPlan((Plan *) local_node); _getPlan((Plan *) local_node);
token = lsptok(NULL, &length); /* eat :hashkey */ token = lsptok(NULL, &length); /* eat :hashkey */
local_node->hashkey = (Var *) nodeRead(true); local_node->hashkey = nodeRead(true);
return local_node; return local_node;
} }
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -66,7 +66,7 @@ static NestLoop *make_nestloop(List *qptlist, List *qpqual, Plan *lefttree,
Plan *righttree); Plan *righttree);
static HashJoin *make_hashjoin(List *tlist, List *qpqual, static HashJoin *make_hashjoin(List *tlist, List *qpqual,
List *hashclauses, Plan *lefttree, Plan *righttree); 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, static MergeJoin *make_mergejoin(List *tlist, List *qpqual,
List *mergeclauses, Plan *righttree, Plan *lefttree); List *mergeclauses, Plan *righttree, Plan *lefttree);
static void copy_path_costsize(Plan *dest, Path *src); static void copy_path_costsize(Plan *dest, Path *src);
...@@ -664,7 +664,7 @@ create_hashjoin_node(HashPath *best_path, ...@@ -664,7 +664,7 @@ create_hashjoin_node(HashPath *best_path,
List *hashclauses; List *hashclauses;
HashJoin *join_node; HashJoin *join_node;
Hash *hash_node; Hash *hash_node;
Var *innerhashkey; Node *innerhashkey;
/* /*
* NOTE: there will always be exactly one hashclause in the list * NOTE: there will always be exactly one hashclause in the list
...@@ -694,7 +694,7 @@ create_hashjoin_node(HashPath *best_path, ...@@ -694,7 +694,7 @@ create_hashjoin_node(HashPath *best_path,
(Index) 0)); (Index) 0));
/* Now the righthand op of the sole hashclause is the inner hash key. */ /* 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. * Build the hash node and hash join node.
...@@ -1103,7 +1103,7 @@ make_hashjoin(List *tlist, ...@@ -1103,7 +1103,7 @@ make_hashjoin(List *tlist,
} }
static Hash * static Hash *
make_hash(List *tlist, Var *hashkey, Plan *lefttree) make_hash(List *tlist, Node *hashkey, Plan *lefttree)
{ {
Hash *node = makeNode(Hash); Hash *node = makeNode(Hash);
Plan *plan = &node->plan; Plan *plan = &node->plan;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/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) ...@@ -649,7 +649,7 @@ SS_finalize_plan(Plan *plan)
break; break;
case T_Hash: case T_Hash:
finalize_primnode((Node *) ((Hash *) plan)->hashkey, finalize_primnode(((Hash *) plan)->hashkey,
&results); &results);
break; break;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "optimizer/var.h" #include "optimizer/var.h"
#include "parser/parse_type.h" #include "parser/parse_type.h"
#include "parser/parsetree.h" #include "parser/parsetree.h"
#include "utils/datum.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
...@@ -1317,7 +1318,10 @@ simplify_op_or_func(Expr *expr, List *args) ...@@ -1317,7 +1318,10 @@ simplify_op_or_func(Expr *expr, List *args)
HeapTuple func_tuple; HeapTuple func_tuple;
Form_pg_proc funcform; Form_pg_proc funcform;
Type resultType; Type resultType;
bool resultTypByVal;
int resultTypLen;
Expr *newexpr; Expr *newexpr;
ExprContext *econtext;
Datum const_val; Datum const_val;
bool has_nonconst_input = false; bool has_nonconst_input = false;
bool has_null_input = false; bool has_null_input = false;
...@@ -1424,25 +1428,35 @@ simplify_op_or_func(Expr *expr, List *args) ...@@ -1424,25 +1428,35 @@ simplify_op_or_func(Expr *expr, List *args)
newexpr->oper = expr->oper; newexpr->oper = expr->oper;
newexpr->args = args; 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 * code used in this situation will use econtext. That might seem
* fortuitous, but it's not so unreasonable --- a constant expression * fortuitous, but it's not so unreasonable --- a constant expression
* does not depend on context, by definition, n'est ce pas? * does not depend on context, by definition, n'est ce pas?
*/ */
const_val = ExecEvalExpr((Node *) newexpr, NULL, econtext = MakeExprContext(NULL, CurrentMemoryContext);
const_val = ExecEvalExprSwitchContext((Node *) newexpr, econtext,
&const_is_null, &isDone); &const_is_null, &isDone);
Assert(isDone); /* if this isn't set, we blew it... */ 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); pfree(newexpr);
/* /*
* Make the constant result node. * Make the constant result node.
*/ */
resultType = typeidType(result_typeid); return (Expr *) makeConst(result_typeid, resultTypLen,
return (Expr *) makeConst(result_typeid, typeLen(resultType),
const_val, const_is_null, const_val, const_is_null,
typeByVal(resultType), resultTypByVal, false, false);
false, false);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -72,7 +72,6 @@ CreateExecutorState(void)
state->es_param_list_info = NULL; state->es_param_list_info = NULL;
state->es_param_exec_vals = NULL; state->es_param_exec_vals = NULL;
state->es_BaseId = 0;
state->es_tupleTable = NULL; state->es_tupleTable = NULL;
state->es_junkFilter = NULL; state->es_junkFilter = NULL;
......
This diff is collapsed.
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -75,6 +75,7 @@ init_fcache(Oid foid,
retval = (FunctionCachePtr) palloc(sizeof(FunctionCache)); retval = (FunctionCachePtr) palloc(sizeof(FunctionCache));
MemSet(retval, 0, sizeof(FunctionCache)); MemSet(retval, 0, sizeof(FunctionCache));
retval->fcacheCxt = CurrentMemoryContext;
/* ---------------- /* ----------------
* get the procedure tuple corresponding to the given functionOid * get the procedure tuple corresponding to the given functionOid
...@@ -256,22 +257,26 @@ init_fcache(Oid foid, ...@@ -256,22 +257,26 @@ init_fcache(Oid foid,
void void
setFcache(Node *node, Oid foid, List *argList, ExprContext *econtext) setFcache(Node *node, Oid foid, List *argList, ExprContext *econtext)
{ {
Func *fnode; MemoryContext oldcontext;
Oper *onode;
FunctionCachePtr fcache; 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); fcache = init_fcache(foid, argList, econtext);
if (IsA(node, Oper)) if (IsA(node, Oper))
{ {
onode = (Oper *) node; Oper *onode = (Oper *) node;
onode->op_fcache = fcache; onode->op_fcache = fcache;
} }
else if (IsA(node, Func)) else if (IsA(node, Func))
{ {
fnode = (Func *) node; Func *fnode = (Func *) node;
fnode->func_fcache = fcache; fnode->func_fcache = fcache;
} }
else else
elog(ERROR, "init_fcache: node must be Oper or Func!"); elog(ERROR, "init_fcache: node must be Oper or Func!");
MemoryContextSwitchTo(oldcontext);
} }
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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); ...@@ -53,9 +53,6 @@ extern void setRelhasindexInplace(Oid relid, bool hasindex, bool immediate);
extern bool SetReindexProcessing(bool processing); extern bool SetReindexProcessing(bool processing);
extern bool IsReindexProcessing(void); extern bool IsReindexProcessing(void);
extern void FillDummyExprContext(ExprContext *econtext, TupleTableSlot *slot,
TupleDesc tupdesc, Buffer buffer);
extern void index_build(Relation heapRelation, Relation indexRelation, extern void index_build(Relation heapRelation, Relation indexRelation,
int numberOfAttributes, AttrNumber *attributeNumber, int numberOfAttributes, AttrNumber *attributeNumber,
FuncIndexInfo *funcInfo, PredInfo *predInfo, FuncIndexInfo *funcInfo, PredInfo *predInfo,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment