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 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.60 2000/07/03 23:09:11 wieck Exp $
* $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.61 2000/07/12 02:36:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -141,11 +141,10 @@ gistbuild(PG_FUNCTION_ARGS)
{
tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable);
econtext = makeNode(ExprContext);
FillDummyExprContext(econtext, slot, hd, InvalidBuffer);
ExecSetSlotDescriptor(slot, hd);
econtext = MakeExprContext(slot, TransactionCommandContext);
}
else
/* shut the compiler up */
{
tupleTable = NULL;
slot = NULL;
......@@ -161,13 +160,13 @@ gistbuild(PG_FUNCTION_ARGS)
{
nh++;
#ifndef OMIT_PARTIAL_INDEX
/*
* If oldPred != NULL, this is an EXTEND INDEX command, so skip
* this tuple if it was already in the existing partial index
*/
if (oldPred != NULL)
{
#ifndef OMIT_PARTIAL_INDEX
/* SetSlotContents(slot, htup); */
slot->val = htup;
if (ExecQual((List *) oldPred, econtext, false))
......@@ -175,7 +174,6 @@ gistbuild(PG_FUNCTION_ARGS)
ni++;
continue;
}
#endif /* OMIT_PARTIAL_INDEX */
}
/*
......@@ -184,13 +182,12 @@ gistbuild(PG_FUNCTION_ARGS)
*/
if (pred != NULL)
{
#ifndef OMIT_PARTIAL_INDEX
/* SetSlotContents(slot, htup); */
slot->val = htup;
if (!ExecQual((List *) pred, econtext, false))
continue;
#endif /* OMIT_PARTIAL_INDEX */
}
#endif /* OMIT_PARTIAL_INDEX */
ni++;
......@@ -262,13 +259,13 @@ gistbuild(PG_FUNCTION_ARGS)
/* okay, all heap tuples are indexed */
heap_endscan(scan);
#ifndef OMIT_PARTIAL_INDEX
if (pred != NULL || oldPred != NULL)
{
#ifndef OMIT_PARTIAL_INDEX
ExecDropTupleTable(tupleTable, true);
pfree(econtext);
#endif /* OMIT_PARTIAL_INDEX */
FreeExprContext(econtext);
}
#endif /* OMIT_PARTIAL_INDEX */
/*
* Since we just counted the tuples in the heap, we update its stats
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.40 2000/06/17 23:41:13 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.41 2000/07/12 02:36:46 tgl Exp $
*
* NOTES
* This file contains only the public interface routines.
......@@ -102,15 +102,14 @@ hashbuild(PG_FUNCTION_ARGS)
{
tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable);
econtext = makeNode(ExprContext);
FillDummyExprContext(econtext, slot, htupdesc, InvalidBuffer);
ExecSetSlotDescriptor(slot, htupdesc);
econtext = MakeExprContext(slot, TransactionCommandContext);
}
else
/* quiet the compiler */
{
tupleTable = NULL;
slot = NULL;
econtext = NULL;
tupleTable = 0;
slot = 0;
}
#endif /* OMIT_PARTIAL_INDEX */
......@@ -122,9 +121,9 @@ hashbuild(PG_FUNCTION_ARGS)
while (HeapTupleIsValid(htup = heap_getnext(hscan, 0)))
{
nhtups++;
#ifndef OMIT_PARTIAL_INDEX
/*
* If oldPred != NULL, this is an EXTEND INDEX command, so skip
* this tuple if it was already in the existing partial index
......@@ -132,14 +131,12 @@ hashbuild(PG_FUNCTION_ARGS)
if (oldPred != NULL)
{
/* SetSlotContents(slot, htup); */
#ifndef OMIT_PARTIAL_INDEX
slot->val = htup;
if (ExecQual((List *) oldPred, econtext, false))
{
nitups++;
continue;
}
#endif /* OMIT_PARTIAL_INDEX */
}
/*
......@@ -148,13 +145,12 @@ hashbuild(PG_FUNCTION_ARGS)
*/
if (pred != NULL)
{
#ifndef OMIT_PARTIAL_INDEX
/* SetSlotContents(slot, htup); */
slot->val = htup;
if (!ExecQual((List *) pred, econtext, false))
continue;
#endif /* OMIT_PARTIAL_INDEX */
}
#endif /* OMIT_PARTIAL_INDEX */
nitups++;
......@@ -221,13 +217,13 @@ hashbuild(PG_FUNCTION_ARGS)
/* okay, all heap tuples are indexed */
heap_endscan(hscan);
#ifndef OMIT_PARTIAL_INDEX
if (pred != NULL || oldPred != NULL)
{
#ifndef OMIT_PARTIAL_INDEX
ExecDropTupleTable(tupleTable, true);
pfree(econtext);
#endif /* OMIT_PARTIAL_INDEX */
FreeExprContext(econtext);
}
#endif /* OMIT_PARTIAL_INDEX */
/*
* Since we just counted the tuples in the heap, we update its stats
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtcompare.c,v 1.38 2000/06/19 03:54:22 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtcompare.c,v 1.39 2000/07/12 02:36:48 tgl Exp $
*
* NOTES
*
......@@ -27,6 +27,10 @@
* that work on 32-bit or wider datatypes can't just return "a - b".
* That could overflow and give the wrong answer.
*
* NOTE: these routines must not leak memory, since memory allocated
* during an index access won't be recovered till end of query. This
* primarily affects comparison routines for toastable datatypes;
* they have to be careful to free any detoasted copy of an input datum.
*-------------------------------------------------------------------------
*/
......@@ -230,18 +234,23 @@ bttextcmp(PG_FUNCTION_ARGS)
} while (res == 0 && len != 0);
}
if (res == 0 && VARSIZE(a) != VARSIZE(b))
{
/*
* The two strings are the same in the first len bytes,
* and they are of different lengths.
*/
if (VARSIZE(a) < VARSIZE(b))
res = -1;
else
res = 1;
}
#endif
if (res != 0 || VARSIZE(a) == VARSIZE(b))
PG_RETURN_INT32(res);
/* Avoid leaking memory when handed toasted input. */
PG_FREE_IF_COPY(a, 0);
PG_FREE_IF_COPY(b, 1);
/*
* The two strings are the same in the first len bytes, and they are
* of different lengths.
*/
if (VARSIZE(a) < VARSIZE(b))
PG_RETURN_INT32(-1);
else
PG_RETURN_INT32(1);
PG_RETURN_INT32(res);
}
......@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.59 2000/06/17 23:41:16 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.60 2000/07/12 02:36:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -121,8 +121,8 @@ btbuild(PG_FUNCTION_ARGS)
{
tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable);
econtext = makeNode(ExprContext);
FillDummyExprContext(econtext, slot, htupdesc, InvalidBuffer);
ExecSetSlotDescriptor(slot, htupdesc);
econtext = MakeExprContext(slot, TransactionCommandContext);
/*
* we never want to use sort/build if we are extending an existing
......@@ -151,14 +151,13 @@ btbuild(PG_FUNCTION_ARGS)
{
nhtups++;
#ifndef OMIT_PARTIAL_INDEX
/*
* If oldPred != NULL, this is an EXTEND INDEX command, so skip
* this tuple if it was already in the existing partial index
*/
if (oldPred != NULL)
{
#ifndef OMIT_PARTIAL_INDEX
/* SetSlotContents(slot, htup); */
slot->val = htup;
if (ExecQual((List *) oldPred, econtext, false))
......@@ -166,7 +165,6 @@ btbuild(PG_FUNCTION_ARGS)
nitups++;
continue;
}
#endif /* OMIT_PARTIAL_INDEX */
}
/*
......@@ -175,13 +173,12 @@ btbuild(PG_FUNCTION_ARGS)
*/
if (pred != NULL)
{
#ifndef OMIT_PARTIAL_INDEX
/* SetSlotContents(slot, htup); */
slot->val = htup;
if (!ExecQual((List *) pred, econtext, false))
continue;
#endif /* OMIT_PARTIAL_INDEX */
}
#endif /* OMIT_PARTIAL_INDEX */
nitups++;
......@@ -260,13 +257,13 @@ btbuild(PG_FUNCTION_ARGS)
/* okay, all heap tuples are indexed */
heap_endscan(hscan);
#ifndef OMIT_PARTIAL_INDEX
if (pred != NULL || oldPred != NULL)
{
#ifndef OMIT_PARTIAL_INDEX
ExecDropTupleTable(tupleTable, true);
pfree(econtext);
#endif /* OMIT_PARTIAL_INDEX */
FreeExprContext(econtext);
}
#endif /* OMIT_PARTIAL_INDEX */
/*
* if we are doing bottom-up btree build, finish the build by (1)
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.50 2000/06/17 23:41:22 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.51 2000/07/12 02:36:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -136,14 +136,14 @@ rtbuild(PG_FUNCTION_ARGS)
{
tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable);
econtext = makeNode(ExprContext);
FillDummyExprContext(econtext, slot, hd, InvalidBuffer);
ExecSetSlotDescriptor(slot, hd);
econtext = MakeExprContext(slot, TransactionCommandContext);
}
else
{
econtext = NULL;
tupleTable = NULL;
slot = NULL;
econtext = NULL;
}
#endif /* OMIT_PARTIAL_INDEX */
......@@ -156,13 +156,13 @@ rtbuild(PG_FUNCTION_ARGS)
{
nh++;
#ifndef OMIT_PARTIAL_INDEX
/*
* If oldPred != NULL, this is an EXTEND INDEX command, so skip
* this tuple if it was already in the existing partial index
*/
if (oldPred != NULL)
{
#ifndef OMIT_PARTIAL_INDEX
/* SetSlotContents(slot, htup); */
slot->val = htup;
if (ExecQual((List *) oldPred, econtext, false))
......@@ -170,7 +170,6 @@ rtbuild(PG_FUNCTION_ARGS)
ni++;
continue;
}
#endif /* OMIT_PARTIAL_INDEX */
}
/*
......@@ -179,13 +178,12 @@ rtbuild(PG_FUNCTION_ARGS)
*/
if (pred != NULL)
{
#ifndef OMIT_PARTIAL_INDEX
/* SetSlotContents(slot, htup); */
slot->val = htup;
if (!ExecQual((List *) pred, econtext, false))
continue;
#endif /* OMIT_PARTIAL_INDEX */
}
#endif /* OMIT_PARTIAL_INDEX */
ni++;
......@@ -239,13 +237,13 @@ rtbuild(PG_FUNCTION_ARGS)
/* okay, all heap tuples are indexed */
heap_endscan(scan);
#ifndef OMIT_PARTIAL_INDEX
if (pred != NULL || oldPred != NULL)
{
#ifndef OMIT_PARTIAL_INDEX
ExecDropTupleTable(tupleTable, true);
pfree(econtext);
#endif /* OMIT_PARTIAL_INDEX */
FreeExprContext(econtext);
}
#endif /* OMIT_PARTIAL_INDEX */
/*
* Since we just counted the tuples in the heap, we update its stats
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.124 2000/07/05 23:11:06 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.125 2000/07/12 02:36:55 tgl Exp $
*
*
* INTERFACE ROUTINES
......@@ -1670,34 +1670,6 @@ UpdateStats(Oid relid, long reltuples, bool inplace)
}
/* -------------------------
* FillDummyExprContext
* Sets up dummy ExprContext and TupleTableSlot objects for use
* with ExecQual.
*
* NOTE: buffer is passed for historical reasons; it should
* almost certainly always be InvalidBuffer.
* -------------------------
*/
void
FillDummyExprContext(ExprContext *econtext,
TupleTableSlot *slot,
TupleDesc tupdesc,
Buffer buffer)
{
econtext->ecxt_scantuple = slot;
econtext->ecxt_innertuple = NULL;
econtext->ecxt_outertuple = NULL;
econtext->ecxt_param_list_info = NULL;
econtext->ecxt_range_table = NULL;
slot->ttc_tupleDescriptor = tupdesc;
slot->ttc_buffer = buffer;
slot->ttc_shouldFree = false;
}
/* ----------------
* DefaultBuild
*
......@@ -1777,14 +1749,14 @@ DefaultBuild(Relation heapRelation,
{
tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable);
econtext = makeNode(ExprContext);
FillDummyExprContext(econtext, slot, heapDescriptor, InvalidBuffer);
ExecSetSlotDescriptor(slot, heapDescriptor);
econtext = MakeExprContext(slot, TransactionCommandContext);
}
else
{
econtext = NULL;
tupleTable = 0;
tupleTable = NULL;
slot = NULL;
econtext = NULL;
}
#endif /* OMIT_PARTIAL_INDEX */
......@@ -1812,7 +1784,6 @@ DefaultBuild(Relation heapRelation,
reltuples++;
#ifndef OMIT_PARTIAL_INDEX
/*
* If oldPred != NULL, this is an EXTEND INDEX command, so skip
* this tuple if it was already in the existing partial index
......@@ -1877,6 +1848,7 @@ DefaultBuild(Relation heapRelation,
{
/* parameter was 'false', almost certainly wrong --- tgl 9/21/99 */
ExecDropTupleTable(tupleTable, true);
FreeExprContext(econtext);
}
#endif /* OMIT_PARTIAL_INDEX */
......
......@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.117 2000/07/05 23:11:11 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.118 2000/07/12 02:36:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -611,13 +611,11 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
char *predString;
Node **indexPred = NULL;
TupleDesc rtupdesc;
ExprContext *econtext = NULL;
EState *estate = makeNode(EState); /* for ExecConstraints() */
#ifndef OMIT_PARTIAL_INDEX
ExprContext *econtext = NULL;
TupleTable tupleTable;
TupleTableSlot *slot = NULL;
#endif
int natts;
AttrNumber *attnumP;
......@@ -651,7 +649,6 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
finfo = (FuncIndexInfo *) palloc(n_indices * sizeof(FuncIndexInfo));
finfoP = (FuncIndexInfo **) palloc(n_indices * sizeof(FuncIndexInfo *));
indexPred = (Node **) palloc(n_indices * sizeof(Node *));
econtext = NULL;
for (i = 0; i < n_indices; i++)
{
itupdescArr[i] = RelationGetDescr(index_rels[i]);
......@@ -680,36 +677,18 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
PointerGetDatum(&pgIndexP[i]->indpred)));
indexPred[i] = stringToNode(predString);
pfree(predString);
#ifndef OMIT_PARTIAL_INDEX
/* make dummy ExprContext for use by ExecQual */
if (econtext == NULL)
{
#ifndef OMIT_PARTIAL_INDEX
tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable);
econtext = makeNode(ExprContext);
econtext->ecxt_scantuple = slot;
rtupdesc = RelationGetDescr(rel);
slot->ttc_tupleDescriptor = rtupdesc;
/*
* There's no buffer associated with heap tuples
* here, so I set the slot's buffer to NULL.
* Currently, it appears that the only way a
* buffer could be needed would be if the partial
* index predicate referred to the "lock" system
* attribute. If it did, then heap_getattr would
* call HeapTupleGetRuleLock, which uses the
* buffer's descriptor to get the relation id.
* Rather than try to fix this, I'll just disallow
* partial indexes on "lock", which wouldn't be
* useful anyway. --Nels, Nov '92
*/
/* SetSlotBuffer(slot, (Buffer) NULL); */
/* SetSlotShouldFree(slot, false); */
slot->ttc_buffer = (Buffer) NULL;
slot->ttc_shouldFree = false;
#endif /* OMIT_PARTIAL_INDEX */
ExecSetSlotDescriptor(slot, rtupdesc);
econtext = MakeExprContext(slot,
TransactionCommandContext);
}
#endif /* OMIT_PARTIAL_INDEX */
}
else
indexPred[i] = NULL;
......@@ -927,10 +906,9 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
{
for (i = 0; i < n_indices; i++)
{
#ifndef OMIT_PARTIAL_INDEX
if (indexPred[i] != NULL)
{
#ifndef OMIT_PARTIAL_INDEX
/*
* if tuple doesn't satisfy predicate, don't
* update index
......@@ -939,8 +917,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
/* SetSlotContents(slot, tuple); */
if (!ExecQual((List *) indexPred[i], econtext, false))
continue;
#endif /* OMIT_PARTIAL_INDEX */
}
#endif /* OMIT_PARTIAL_INDEX */
FormIndexDatum(indexNatts[i],
(AttrNumber *) &(pgIndexP[i]->indkey[0]),
tuple,
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: execAmi.c,v 1.48 2000/06/18 22:44:03 tgl Exp $
* $Id: execAmi.c,v 1.49 2000/07/12 02:37:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -171,8 +171,8 @@ ExecBeginScan(Relation relation,
/* ----------------------------------------------------------------
* ExecCloseR
*
* closes the relation and scan descriptor for a scan or sort
* node. Also closes index relations and scans for index scans.
* closes the relation and scan descriptor for a scan node.
* Also closes index relations and scans for index scans.
* ----------------------------------------------------------------
*/
void
......@@ -197,20 +197,12 @@ ExecCloseR(Plan *node)
state = ((IndexScan *) node)->scan.scanstate;
break;
case T_Sort:
state = &(((Sort *) node)->sortstate->csstate);
break;
case T_Agg:
state = &(((Agg *) node)->aggstate->csstate);
break;
case T_TidScan:
state = ((TidScan *) node)->scan.scanstate;
break;
default:
elog(DEBUG, "ExecCloseR: not a scan or sort node!");
elog(DEBUG, "ExecCloseR: not a scan node!");
return;
}
......@@ -237,13 +229,12 @@ ExecCloseR(Plan *node)
if (IsA(node, IndexScan))
{
IndexScan *iscan = (IndexScan *) node;
IndexScanState *indexstate;
IndexScanState *indexstate = iscan->indxstate;
int numIndices;
RelationPtr indexRelationDescs;
IndexScanDescPtr indexScanDescs;
int i;
indexstate = iscan->indxstate;
numIndices = indexstate->iss_NumIndices;
indexRelationDescs = indexstate->iss_RelationDescs;
indexScanDescs = indexstate->iss_ScanDescs;
......
......@@ -27,7 +27,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.121 2000/07/05 16:17:43 wieck Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.122 2000/07/12 02:37:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -86,9 +86,12 @@ static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation,
* This routine must be called at the beginning of any execution of any
* query plan
*
* returns (AttrInfo*) which describes the attributes of the tuples to
* returns a TupleDesc which describes the attributes of the tuples to
* be returned by the query.
*
* NB: the CurrentMemoryContext when this is called must be the context
* to be used as the per-query context for the query plan. ExecutorRun()
* and ExecutorEnd() must be called in this same memory context.
* ----------------------------------------------------------------
*/
TupleDesc
......@@ -103,7 +106,8 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
{
estate->es_param_exec_vals = (ParamExecData *)
palloc(queryDesc->plantree->nParamExec * sizeof(ParamExecData));
memset(estate->es_param_exec_vals, 0, queryDesc->plantree->nParamExec * sizeof(ParamExecData));
MemSet(estate->es_param_exec_vals, 0,
queryDesc->plantree->nParamExec * sizeof(ParamExecData));
}
/*
......@@ -151,7 +155,6 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
* EXEC_RETONE: return one tuple but don't 'retrieve' it
* used in postquel function processing
*
*
* ----------------------------------------------------------------
*/
TupleTableSlot *
......@@ -687,13 +690,6 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
*/
estate->es_range_table = rangeTable;
/*
* initialize the BaseId counter so node base_id's are assigned
* correctly. Someday baseid's will have to be stored someplace other
* than estate because they should be unique per query planned.
*/
estate->es_BaseId = 1;
/*
* initialize result relation stuff
*/
......@@ -793,7 +789,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
/*
* initialize the private state information for all the nodes in the
* query tree. This opens files, allocates storage and leaves us
* ready to start processing tuples..
* ready to start processing tuples.
*/
ExecInitNode(plan, estate, NULL);
......@@ -1589,7 +1585,7 @@ ExecAttrDefault(Relation rel, HeapTuple tuple)
{
int ndef = rel->rd_att->constr->num_defval;
AttrDefault *attrdef = rel->rd_att->constr->defval;
ExprContext *econtext = makeNode(ExprContext);
ExprContext *econtext = MakeExprContext(NULL, CurrentMemoryContext);
HeapTuple newtuple;
Node *expr;
bool isnull;
......@@ -1600,23 +1596,13 @@ ExecAttrDefault(Relation rel, HeapTuple tuple)
char *repl = NULL;
int i;
econtext->ecxt_scantuple = NULL; /* scan tuple slot */
econtext->ecxt_innertuple = NULL; /* inner tuple slot */
econtext->ecxt_outertuple = NULL; /* outer tuple slot */
econtext->ecxt_relation = NULL; /* relation */
econtext->ecxt_relid = 0; /* relid */
econtext->ecxt_param_list_info = NULL; /* param list info */
econtext->ecxt_param_exec_vals = NULL; /* exec param values */
econtext->ecxt_range_table = NULL; /* range table */
for (i = 0; i < ndef; i++)
{
if (!heap_attisnull(tuple, attrdef[i].adnum))
continue;
expr = (Node *) stringToNode(attrdef[i].adbin);
val = ExecEvalExpr(expr, econtext, &isnull, &isdone);
pfree(expr);
val = ExecEvalExprSwitchContext(expr, econtext, &isnull, &isdone);
if (isnull)
continue;
......@@ -1635,20 +1621,24 @@ ExecAttrDefault(Relation rel, HeapTuple tuple)
}
pfree(econtext);
if (repl == NULL)
return tuple;
{
/* no changes needed */
newtuple = tuple;
}
else
{
newtuple = heap_modifytuple(tuple, rel, replValue, replNull, repl);
newtuple = heap_modifytuple(tuple, rel, replValue, replNull, repl);
pfree(repl);
pfree(replNull);
pfree(replValue);
heap_freetuple(tuple);
}
pfree(repl);
heap_freetuple(tuple);
pfree(replNull);
pfree(replValue);
FreeMemoryContext(econtext);
return newtuple;
}
#endif
......@@ -1658,9 +1648,10 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
{
int ncheck = rel->rd_att->constr->num_check;
ConstrCheck *check = rel->rd_att->constr->check;
ExprContext *econtext = makeNode(ExprContext);
TupleTableSlot *slot = makeNode(TupleTableSlot);
RangeTblEntry *rte = makeNode(RangeTblEntry);
ExprContext *econtext = MakeExprContext(slot,
TransactionCommandContext);
List *rtlist;
List *qual;
int i;
......@@ -1677,17 +1668,21 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
rte->relid = RelationGetRelid(rel);
/* inh, inFromCl, inJoinSet, skipAcl won't be used, leave them zero */
rtlist = lcons(rte, NIL);
econtext->ecxt_scantuple = slot; /* scan tuple slot */
econtext->ecxt_innertuple = NULL; /* inner tuple slot */
econtext->ecxt_outertuple = NULL; /* outer tuple slot */
econtext->ecxt_relation = rel; /* relation */
econtext->ecxt_relid = 0; /* relid */
econtext->ecxt_param_list_info = NULL; /* param list info */
econtext->ecxt_param_exec_vals = NULL; /* exec param values */
econtext->ecxt_range_table = rtlist; /* range table */
econtext->ecxt_range_table = rtlist; /* phony range table */
/*
* Save the de-stringized constraint expressions in command-level
* memory context. XXX should build the above stuff there too,
* instead of doing it over for each tuple.
* XXX Is it sufficient to have just one es_result_relation_constraints
* in an inherited insert/update?
*/
if (estate->es_result_relation_constraints == NULL)
{
MemoryContext oldContext;
oldContext = MemoryContextSwitchTo(TransactionCommandContext);
estate->es_result_relation_constraints =
(List **) palloc(ncheck * sizeof(List *));
......@@ -1696,6 +1691,8 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
qual = (List *) stringToNode(check[i].ccbin);
estate->es_result_relation_constraints[i] = qual;
}
MemoryContextSwitchTo(oldContext);
}
for (i = 0; i < ncheck; i++)
......@@ -1714,16 +1711,15 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
pfree(slot);
pfree(rte);
pfree(rtlist);
pfree(econtext);
return (char *) NULL;
FreeExprContext(econtext);
return (char *) NULL;
}
void
ExecConstraints(char *caller, Relation rel, HeapTuple tuple, EState *estate)
{
Assert(rel->rd_att->constr);
if (rel->rd_att->constr->has_not_null)
......@@ -1732,9 +1728,10 @@ ExecConstraints(char *caller, Relation rel, HeapTuple tuple, EState *estate)
for (attrChk = 1; attrChk <= rel->rd_att->natts; attrChk++)
{
if (rel->rd_att->attrs[attrChk - 1]->attnotnull && heap_attisnull(tuple, attrChk))
if (rel->rd_att->attrs[attrChk-1]->attnotnull &&
heap_attisnull(tuple, attrChk))
elog(ERROR, "%s: Fail to add null value in not null attribute %s",
caller, NameStr(rel->rd_att->attrs[attrChk - 1]->attname));
caller, NameStr(rel->rd_att->attrs[attrChk-1]->attname));
}
}
......@@ -1743,10 +1740,9 @@ ExecConstraints(char *caller, Relation rel, HeapTuple tuple, EState *estate)
char *failed;
if ((failed = ExecRelCheck(rel, tuple, estate)) != NULL)
elog(ERROR, "%s: rejected due to CHECK constraint %s", caller, failed);
elog(ERROR, "%s: rejected due to CHECK constraint %s",
caller, failed);
}
return;
}
TupleTableSlot *
......
This diff is collapsed.
......@@ -12,7 +12,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.11 2000/01/26 05:56:21 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.12 2000/07/12 02:37:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -30,7 +30,7 @@
* returns the next qualifying tuple in the direction specified
* in the global variable ExecDirection.
* The access method returns the next tuple and execScan() is
* responisble for checking the tuple returned against the qual-clause.
* responsible for checking the tuple returned against the qual-clause.
*
* Conditions:
* -- the "cursor" maintained by the AMI is positioned at the tuple
......@@ -39,59 +39,50 @@
* Initial States:
* -- the relation indicated is opened for scanning so that the
* "cursor" is positioned before the first qualifying tuple.
*
* May need to put startmmgr and endmmgr in here.
* ----------------------------------------------------------------
*/
TupleTableSlot *
ExecScan(Scan *node,
TupleTableSlot *(*accessMtd) ()) /* function returning a
* tuple */
ExecScanAccessMtd accessMtd) /* function returning a tuple */
{
CommonScanState *scanstate;
EState *estate;
List *qual;
bool isDone;
TupleTableSlot *slot;
TupleTableSlot *resultSlot;
HeapTuple newTuple;
ExprContext *econtext;
ProjectionInfo *projInfo;
/* ----------------
* initialize misc variables
* Fetch data from node
* ----------------
*/
newTuple = NULL;
slot = NULL;
estate = node->plan.state;
scanstate = node->scanstate;
econtext = scanstate->cstate.cs_ExprContext;
qual = node->plan.qual;
/* ----------------
* get the expression context
* Reset per-tuple memory context to free any expression evaluation
* storage allocated in the previous tuple cycle.
* ----------------
*/
econtext = scanstate->cstate.cs_ExprContext;
ResetExprContext(econtext);
/* ----------------
* initialize fields in ExprContext which don't change
* in the course of the scan..
* Check to see if we're still projecting out tuples from a previous
* scan tuple (because there is a function-returning-set in the
* projection expressions). If so, try to project another one.
* ----------------
*/
qual = node->plan.qual;
econtext->ecxt_relation = scanstate->css_currentRelation;
econtext->ecxt_relid = node->scanrelid;
if (scanstate->cstate.cs_TupFromTlist)
{
projInfo = scanstate->cstate.cs_ProjInfo;
resultSlot = ExecProject(projInfo, &isDone);
if (!isDone)
return resultSlot;
/* Done with that source tuple... */
scanstate->cstate.cs_TupFromTlist = false;
}
/*
......@@ -100,27 +91,23 @@ ExecScan(Scan *node,
*/
for (;;)
{
slot = (TupleTableSlot *) (*accessMtd) (node);
TupleTableSlot *slot;
slot = (*accessMtd) (node);
/* ----------------
* if the slot returned by the accessMtd contains
* NULL, then it means there is nothing more to scan
* so we just return the empty slot...
*
* ... with invalid TupleDesc (not the same as in
* projInfo->pi_slot) and break upper MergeJoin node.
* New code below do what ExecProject() does. - vadim 02/26/98
* so we just return an empty slot, being careful to use
* the projection result slot so it has correct tupleDesc.
* ----------------
*/
if (TupIsNull(slot))
{
scanstate->cstate.cs_TupFromTlist = false;
resultSlot = scanstate->cstate.cs_ProjInfo->pi_slot;
return (TupleTableSlot *)
ExecStoreTuple(NULL,
resultSlot,
InvalidBuffer,
true);
return ExecStoreTuple(NULL,
scanstate->cstate.cs_ProjInfo->pi_slot,
InvalidBuffer,
true);
}
/* ----------------
......@@ -131,22 +118,28 @@ ExecScan(Scan *node,
/* ----------------
* check that the current tuple satisfies the qual-clause
* if our qualification succeeds then we
* if our qualification succeeds then we may
* leave the loop.
* ----------------
*/
/*
* add a check for non-nil qual here to avoid a function call to
*
* check for non-nil qual here to avoid a function call to
* ExecQual() when the qual is nil ... saves only a few cycles,
* but they add up ...
* ----------------
*/
if (!qual || ExecQual(qual, econtext, false))
break;
/* ----------------
* Tuple fails qual, so free per-tuple memory and try again.
* ----------------
*/
ResetExprContext(econtext);
}
/* ----------------
* form a projection tuple, store it in the result tuple
* Found a satisfactory scan tuple.
*
* Form a projection tuple, store it in the result tuple
* slot and return it.
* ----------------
*/
......
......@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.37 2000/04/12 17:15:08 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.38 2000/07/12 02:37:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -76,8 +76,7 @@
* by the access methods into the scan tuple slot.
*
* - ExecSeqScan() calls ExecStoreTuple() to take the result
* tuple from ExecTargetList() and place it into the result tuple
* slot.
* tuple from ExecProject() and place it into the result tuple slot.
*
* - ExecutePlan() calls ExecRetrieve() which gets the tuple out of
* the slot passed to it by calling ExecFetchTuple(). this tuple
......@@ -182,8 +181,8 @@ ExecCreateTupleTable(int initialSize) /* initial number of slots in
/* --------------------------------
* ExecDropTupleTable
*
* This pfrees the storage assigned to the tuple table and
* optionally pfrees the contents of the table also.
* This frees the storage used by the tuple table itself
* and optionally frees the contents of the table also.
* It is expected that this routine be called by EndPlan().
* --------------------------------
*/
......@@ -239,7 +238,6 @@ ExecDropTupleTable(TupleTable table, /* tuple table */
*/
pfree(array);
pfree(table);
}
......@@ -252,13 +250,12 @@ ExecDropTupleTable(TupleTable table, /* tuple table */
*
* This routine is used to reserve slots in the table for
* use by the various plan nodes. It is expected to be
* called by the node init routines (ex: ExecInitNestLoop).
* called by the node init routines (ex: ExecInitNestLoop)
* once per slot needed by the node. Not all nodes need
* slots (some just pass tuples around).
* --------------------------------
*/
TupleTableSlot * /* return: the slot allocated in the tuple
* table */
TupleTableSlot *
ExecAllocTableSlot(TupleTable table)
{
int slotnum; /* new slot number */
......@@ -283,22 +280,12 @@ ExecAllocTableSlot(TupleTable table)
* pointers into _freed_ memory. This leads to bad ends. We
* now count the number of slots we will need and create all the
* slots we will need ahead of time. The if below should never
* happen now. Give a WARN if it does. -mer 4 Aug 1992
* happen now. Fail if it does. -mer 4 Aug 1992
* ----------------
*/
if (table->next >= table->size)
{
/*
* int newsize = NewTableSize(table->size);
*
* pfree(table->array); table->array = (Pointer) palloc(newsize *
* TableSlotSize); bzero(table->array, newsize * TableSlotSize);
* table->size = newsize;
*/
elog(NOTICE, "Plan requires more slots than are available");
elog(ERROR, "send mail to your local executor guru to fix this");
}
elog(ERROR, "Plan requires more slots than are available"
"\n\tsend mail to your local executor guru to fix this");
/* ----------------
* at this point, space in the table is guaranteed so we
......@@ -427,7 +414,7 @@ ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */
slot->val = (HeapTuple) NULL;
slot->ttc_shouldFree = true;/* probably useless code... */
slot->ttc_shouldFree = true; /* probably useless code... */
/* ----------------
* Drop the pin on the referenced buffer, if there is one.
......
/*-------------------------------------------------------------------------
*
* execUtils.c
* miscellanious executor utility routines
* miscellaneous executor utility routines
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.62 2000/07/05 23:11:14 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.63 2000/07/12 02:37:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
* ExecAssignNodeBaseInfo \
* ExecAssignDebugHooks > preforms misc work done in all the
* ExecAssignExprContext / init node routines.
* ExecAssignExprContext Common code for plan node init routines.
*
* ExecGetTypeInfo | old execCStructs interface
* ExecMakeTypeInfo | code from the version 1
......@@ -53,6 +51,7 @@
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/memutils.h"
#include "utils/relcache.h"
#include "utils/syscache.h"
......@@ -137,57 +136,104 @@ DisplayTupleCount(FILE *statfp)
#endif
/* ----------------------------------------------------------------
* miscellanious init node support functions
* miscellaneous node-init support functions
*
* ExecAssignNodeBaseInfo - assigns the baseid field of the node
* ExecAssignDebugHooks - assigns the node's debugging hooks
* ExecAssignExprContext - assigns the node's expression context
* ----------------------------------------------------------------
*/
/* ----------------
* ExecAssignNodeBaseInfo
* ExecAssignExprContext
*
* This initializes the ExprContext field. It is only necessary
* to do this for nodes which use ExecQual or ExecProject
* because those routines depend on econtext. Other nodes that
* don't have to evaluate expressions don't need to do this.
*
* as it says, this assigns the baseid field of the node and
* increments the counter in the estate. In addition, it initializes
* the base_parent field of the basenode.
* Note: we assume CurrentMemoryContext is the correct per-query context.
* This should be true during plan node initialization.
* ----------------
*/
void
ExecAssignNodeBaseInfo(EState *estate, CommonState *cstate, Plan *parent)
ExecAssignExprContext(EState *estate, CommonState *commonstate)
{
int baseId;
ExprContext *econtext = makeNode(ExprContext);
baseId = estate->es_BaseId;
cstate->cs_base_id = baseId;
estate->es_BaseId = baseId + 1;
econtext->ecxt_scantuple = NULL;
econtext->ecxt_innertuple = NULL;
econtext->ecxt_outertuple = NULL;
econtext->ecxt_per_query_memory = CurrentMemoryContext;
/*
* Create working memory for expression evaluation in this context.
*/
econtext->ecxt_per_tuple_memory =
AllocSetContextCreate(CurrentMemoryContext,
"PlanExprContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
econtext->ecxt_param_list_info = estate->es_param_list_info;
econtext->ecxt_aggvalues = NULL;
econtext->ecxt_aggnulls = NULL;
econtext->ecxt_range_table = estate->es_range_table;
commonstate->cs_ExprContext = econtext;
}
/* ----------------
* ExecAssignExprContext
* MakeExprContext
*
* This initializes the ExprContext field. It is only necessary
* to do this for nodes which use ExecQual or ExecTargetList
* because those routines depend on econtext. Other nodes which
* dont have to evaluate expressions don't need to do this.
* Build an expression context for use outside normal plan-node cases.
* A fake scan-tuple slot can be supplied (pass NULL if not needed).
* A memory context sufficiently long-lived to use as fcache context
* must be supplied as well.
* ----------------
*/
void
ExecAssignExprContext(EState *estate, CommonState *commonstate)
ExprContext *
MakeExprContext(TupleTableSlot *slot,
MemoryContext queryContext)
{
ExprContext *econtext;
ExprContext *econtext = makeNode(ExprContext);
econtext = makeNode(ExprContext);
econtext->ecxt_scantuple = NULL; /* scan tuple slot */
econtext->ecxt_innertuple = NULL; /* inner tuple slot */
econtext->ecxt_outertuple = NULL; /* outer tuple slot */
econtext->ecxt_relation = NULL; /* relation */
econtext->ecxt_relid = 0; /* relid */
econtext->ecxt_param_list_info = estate->es_param_list_info;
econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
econtext->ecxt_range_table = estate->es_range_table; /* range table */
econtext->ecxt_scantuple = slot;
econtext->ecxt_innertuple = NULL;
econtext->ecxt_outertuple = NULL;
econtext->ecxt_per_query_memory = queryContext;
/*
* We make the temporary context a child of current working context,
* not of the specified queryContext. This seems reasonable but I'm
* not totally sure about it...
*
* Expression contexts made via this routine typically don't live long
* enough to get reset, so specify a minsize of 0. That avoids alloc'ing
* any memory in the common case where expr eval doesn't use any.
*/
econtext->ecxt_per_tuple_memory =
AllocSetContextCreate(CurrentMemoryContext,
"TempExprContext",
0,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
econtext->ecxt_param_exec_vals = NULL;
econtext->ecxt_param_list_info = NULL;
econtext->ecxt_aggvalues = NULL;
econtext->ecxt_aggnulls = NULL;
econtext->ecxt_range_table = NIL;
return econtext;
}
commonstate->cs_ExprContext = econtext;
/*
* Free an ExprContext made by MakeExprContext, including the temporary
* context used for expression evaluation. Note this will cause any
* pass-by-reference expression result to go away!
*/
void
FreeExprContext(ExprContext *econtext)
{
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
pfree(econtext);
}
/* ----------------------------------------------------------------
......@@ -390,6 +436,7 @@ ExecFreeExprContext(CommonState *commonstate)
* clean up memory used.
* ----------------
*/
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
pfree(econtext);
commonstate->cs_ExprContext = NULL;
}
......@@ -398,6 +445,7 @@ ExecFreeExprContext(CommonState *commonstate)
* ExecFreeTypeInfo
* ----------------
*/
#ifdef NOT_USED
void
ExecFreeTypeInfo(CommonState *commonstate)
{
......@@ -414,6 +462,7 @@ ExecFreeTypeInfo(CommonState *commonstate)
FreeTupleDesc(tupDesc);
commonstate->cs_ResultTupleSlot->ttc_tupleDescriptor = NULL;
}
#endif
/* ----------------------------------------------------------------
* the following scan type support functions are for
......@@ -974,8 +1023,8 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
if (predicate != NULL)
{
if (econtext == NULL)
econtext = makeNode(ExprContext);
econtext->ecxt_scantuple = slot;
econtext = MakeExprContext(slot,
TransactionCommandContext);
/* Skip this index-update if the predicate isn't satisfied */
if (!ExecQual((List *) predicate, econtext, false))
......@@ -1023,7 +1072,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
pfree(result);
}
if (econtext != NULL)
pfree(econtext);
FreeExprContext(econtext);
}
void
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.35 2000/06/28 03:31:33 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.36 2000/07/12 02:37:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -57,20 +57,18 @@ ProjectAttribute(TupleDesc TD,
HeapTuple tup,
bool *isnullP)
{
Datum val,
valueP;
Datum val;
Var *attrVar = (Var *) tlist->expr;
AttrNumber attrno = attrVar->varattno;
val = heap_getattr(tup, attrno, TD, isnullP);
if (*isnullP)
return (Datum) NULL;
return (Datum) 0;
valueP = datumCopy(val,
TD->attrs[attrno - 1]->atttypid,
TD->attrs[attrno - 1]->attbyval,
(Size) TD->attrs[attrno - 1]->attlen);
return valueP;
return datumCopy(val,
TD->attrs[attrno - 1]->attbyval,
TD->attrs[attrno - 1]->attlen);
}
static execution_state *
......@@ -351,10 +349,18 @@ postquel_function(FunctionCallInfo fcinfo,
List *func_tlist,
bool *isDone)
{
MemoryContext oldcontext;
execution_state *es;
Datum result = 0;
CommandId savedId;
/*
* Switch to context in which the fcache lives. This ensures that
* parsetrees, plans, etc, will have sufficient lifetime. The
* sub-executor is responsible for deleting per-tuple information.
*/
oldcontext = MemoryContextSwitchTo(fcache->fcacheCxt);
/*
* Before we start do anything we must save CurrentScanCommandId to
* restore it before return to upper Executor. Also, we have to set
......@@ -416,6 +422,7 @@ postquel_function(FunctionCallInfo fcinfo,
* Let caller know we're finished.
*/
*isDone = true;
MemoryContextSwitchTo(oldcontext);
return (fcache->oneResult) ? result : (Datum) NULL;
}
......@@ -426,5 +433,8 @@ postquel_function(FunctionCallInfo fcinfo,
Assert(LAST_POSTQUEL_COMMAND(es));
*isDone = false;
MemoryContextSwitchTo(oldcontext);
return result;
}
This diff is collapsed.
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.34 2000/06/17 21:48:49 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.35 2000/07/12 02:37:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -219,16 +219,12 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
node->appendstate = appendstate;
/* ----------------
* Miscellanious initialization
*
* + assign node's base_id
* + assign debugging hooks
* Miscellaneous initialization
*
* Append plans don't have expression contexts because they
* never call ExecQual or ExecTargetList.
* never call ExecQual or ExecProject.
* ----------------
*/
ExecAssignNodeBaseInfo(estate, &appendstate->cstate, parent);
#define APPEND_NSLOTS 1
/* ----------------
......@@ -380,7 +376,7 @@ ExecCountSlotsAppend(Append *node)
*
* Handles the iteration over the multiple scans.
*
* NOTE: Can't call this ExecAppend, that name is used in execMain.l
* NOTE: Can't call this ExecAppend, that name is used in execMain.
* ----------------------------------------------------------------
*/
TupleTableSlot *
......
......@@ -15,7 +15,7 @@
* locate group boundaries.
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.36 2000/05/30 04:24:45 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.37 2000/07/12 02:37:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -68,13 +68,11 @@ ExecGroupEveryTuple(Group *node)
EState *estate;
ExprContext *econtext;
TupleDesc tupdesc;
HeapTuple outerTuple = NULL;
HeapTuple firsttuple;
TupleTableSlot *outerslot;
ProjectionInfo *projInfo;
TupleTableSlot *resultSlot;
bool isDone;
/* ---------------------
......@@ -84,14 +82,16 @@ ExecGroupEveryTuple(Group *node)
grpstate = node->grpstate;
if (grpstate->grp_done)
return NULL;
estate = node->plan.state;
econtext = grpstate->csstate.cstate.cs_ExprContext;
tupdesc = ExecGetScanType(&grpstate->csstate);
/* if we haven't returned first tuple of new group yet ... */
/*
* We need not call ResetExprContext here because execTuplesMatch
* will reset the per-tuple memory context once per input tuple.
*/
/* if we haven't returned first tuple of a new group yet ... */
if (grpstate->grp_useFirstTuple)
{
grpstate->grp_useFirstTuple = FALSE;
......@@ -130,7 +130,8 @@ ExecGroupEveryTuple(Group *node)
if (!execTuplesMatch(firsttuple, outerTuple,
tupdesc,
node->numCols, node->grpColIdx,
grpstate->eqfunctions))
grpstate->eqfunctions,
econtext->ecxt_per_tuple_memory))
{
/*
......@@ -179,13 +180,11 @@ ExecGroupOneTuple(Group *node)
EState *estate;
ExprContext *econtext;
TupleDesc tupdesc;
HeapTuple outerTuple = NULL;
HeapTuple firsttuple;
TupleTableSlot *outerslot;
ProjectionInfo *projInfo;
TupleTableSlot *resultSlot;
bool isDone;
/* ---------------------
......@@ -195,13 +194,15 @@ ExecGroupOneTuple(Group *node)
grpstate = node->grpstate;
if (grpstate->grp_done)
return NULL;
estate = node->plan.state;
econtext = node->grpstate->csstate.cstate.cs_ExprContext;
tupdesc = ExecGetScanType(&grpstate->csstate);
/*
* We need not call ResetExprContext here because execTuplesMatch
* will reset the per-tuple memory context once per input tuple.
*/
firsttuple = grpstate->grp_firstTuple;
if (firsttuple == NULL)
{
......@@ -237,7 +238,8 @@ ExecGroupOneTuple(Group *node)
if (!execTuplesMatch(firsttuple, outerTuple,
tupdesc,
node->numCols, node->grpColIdx,
grpstate->eqfunctions))
grpstate->eqfunctions,
econtext->ecxt_per_tuple_memory))
break;
}
......@@ -296,10 +298,8 @@ ExecInitGroup(Group *node, EState *estate, Plan *parent)
grpstate->grp_firstTuple = NULL;
/*
* assign node's base id and create expression context
* create expression context
*/
ExecAssignNodeBaseInfo(estate, &grpstate->csstate.cstate,
(Plan *) parent);
ExecAssignExprContext(estate, &grpstate->csstate.cstate);
#define GROUP_NSLOTS 2
......@@ -360,6 +360,7 @@ ExecEndGroup(Group *node)
grpstate = node->grpstate;
ExecFreeProjectionInfo(&grpstate->csstate.cstate);
ExecFreeExprContext(&grpstate->csstate.cstate);
outerPlan = outerPlan(node);
ExecEndNode(outerPlan, (Plan *) node);
......@@ -406,6 +407,9 @@ ExecReScanGroup(Group *node, ExprContext *exprCtxt, Plan *parent)
* numCols: the number of attributes to be examined
* matchColIdx: array of attribute column numbers
* eqFunctions: array of fmgr lookup info for the equality functions to use
* evalContext: short-term memory context for executing the functions
*
* NB: evalContext is reset each time!
*/
bool
execTuplesMatch(HeapTuple tuple1,
......@@ -413,16 +417,25 @@ execTuplesMatch(HeapTuple tuple1,
TupleDesc tupdesc,
int numCols,
AttrNumber *matchColIdx,
FmgrInfo *eqfunctions)
FmgrInfo *eqfunctions,
MemoryContext evalContext)
{
MemoryContext oldContext;
bool result;
int i;
/* Reset and switch into the temp context. */
MemoryContextReset(evalContext);
oldContext = MemoryContextSwitchTo(evalContext);
/*
* We cannot report a match without checking all the fields, but we
* can report a non-match as soon as we find unequal fields. So,
* start comparing at the last field (least significant sort key).
* That's the most likely to be different...
*/
result = true;
for (i = numCols; --i >= 0;)
{
AttrNumber att = matchColIdx[i];
......@@ -442,7 +455,10 @@ execTuplesMatch(HeapTuple tuple1,
&isNull2);
if (isNull1 != isNull2)
return FALSE; /* one null and one not; they aren't equal */
{
result = false; /* one null and one not; they aren't equal */
break;
}
if (isNull1)
continue; /* both are null, treat as equal */
......@@ -451,10 +467,15 @@ execTuplesMatch(HeapTuple tuple1,
if (! DatumGetBool(FunctionCall2(&eqfunctions[i],
attr1, attr2)))
return FALSE;
{
result = false; /* they aren't equal */
break;
}
}
return TRUE;
MemoryContextSwitchTo(oldContext);
return result;
}
/*
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* $Id: nodeHash.c,v 1.48 2000/06/28 03:31:34 tgl Exp $
* $Id: nodeHash.c,v 1.49 2000/07/12 02:37:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -28,7 +28,8 @@
#include "executor/nodeHash.h"
#include "executor/nodeHashjoin.h"
#include "miscadmin.h"
#include "parser/parse_expr.h"
#include "parser/parse_type.h"
static int hashFunc(Datum key, int len, bool byVal);
......@@ -45,7 +46,7 @@ ExecHash(Hash *node)
EState *estate;
HashState *hashstate;
Plan *outerNode;
Var *hashkey;
Node *hashkey;
HashJoinTable hashtable;
TupleTableSlot *slot;
ExprContext *econtext;
......@@ -139,12 +140,9 @@ ExecInitHash(Hash *node, EState *estate, Plan *parent)
/* ----------------
* Miscellaneous initialization
*
* + assign node's base_id
* + assign debugging hooks and
* + create expression context for node
* ----------------
*/
ExecAssignNodeBaseInfo(estate, &hashstate->cstate, parent);
ExecAssignExprContext(estate, &hashstate->cstate);
/* ----------------
......@@ -204,6 +202,7 @@ ExecEndHash(Hash *node)
* ----------------
*/
ExecFreeProjectionInfo(&hashstate->cstate);
ExecFreeExprContext(&hashstate->cstate);
/* ----------------
* shut down the subplan
......@@ -236,6 +235,7 @@ ExecHashTableCreate(Hash *node)
int totalbuckets;
int bucketsize;
int i;
Type typeInfo;
MemoryContext oldcxt;
/* ----------------
......@@ -346,6 +346,14 @@ ExecHashTableCreate(Hash *node)
hashtable->innerBatchSize = NULL;
hashtable->outerBatchSize = NULL;
/* ----------------
* Get info about the datatype of the hash key.
* ----------------
*/
typeInfo = typeidType(exprType(node->hashkey));
hashtable->typByVal = typeByVal(typeInfo);
hashtable->typLen = typeLen(typeInfo);
/* ----------------
* Create temporary memory contexts in which to keep the hashtable
* working storage. See notes in executor/hashjoin.h.
......@@ -448,7 +456,7 @@ ExecHashTableDestroy(HashJoinTable hashtable)
void
ExecHashTableInsert(HashJoinTable hashtable,
ExprContext *econtext,
Var *hashkey)
Node *hashkey)
{
int bucketno = ExecHashGetBucket(hashtable, econtext, hashkey);
TupleTableSlot *slot = econtext->ecxt_innertuple;
......@@ -508,43 +516,44 @@ ExecHashTableInsert(HashJoinTable hashtable,
int
ExecHashGetBucket(HashJoinTable hashtable,
ExprContext *econtext,
Var *hashkey)
Node *hashkey)
{
int bucketno;
Datum keyval;
bool isNull;
bool isDone;
/* ----------------
* Get the join attribute value of the tuple
*
* ...It's quick hack - use ExecEvalExpr instead of ExecEvalVar:
* hashkey may be T_ArrayRef, not just T_Var. - vadim 04/22/97
* We reset the eval context each time to avoid any possibility
* of memory leaks in the hash function.
* ----------------
*/
keyval = ExecEvalExpr((Node *) hashkey, econtext, &isNull, NULL);
ResetExprContext(econtext);
/*
* keyval could be null, so we better point it to something valid
* before trying to run hashFunc on it. --djm 8/17/96
*/
if (isNull)
{
execConstByVal = 0;
execConstLen = 0;
keyval = (Datum) "";
}
keyval = ExecEvalExprSwitchContext(hashkey, econtext,
&isNull, &isDone);
/* ------------------
* compute the hash function
* ------------------
*/
bucketno = hashFunc(keyval, execConstLen, execConstByVal) % hashtable->totalbuckets;
if (isNull)
{
bucketno = 0;
}
else
{
bucketno = hashFunc(keyval, hashtable->typLen, hashtable->typByVal)
% hashtable->totalbuckets;
}
#ifdef HJDEBUG
if (bucketno >= hashtable->nbuckets)
printf("hash(%d) = %d SAVED\n", keyval, bucketno);
printf("hash(%ld) = %d SAVED\n", (long) keyval, bucketno);
else
printf("hash(%d) = %d\n", keyval, bucketno);
printf("hash(%ld) = %d\n", (long) keyval, bucketno);
#endif
return bucketno;
......@@ -585,6 +594,9 @@ ExecScanHashBucket(HashJoinState *hjstate,
false); /* do not pfree this tuple */
econtext->ecxt_innertuple = inntuple;
/* reset temp memory each time to avoid leaks from qual expression */
ResetExprContext(econtext);
if (ExecQual(hjclauses, econtext, false))
{
hjstate->hj_CurTuple = hashTuple;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.30 2000/01/26 05:56:23 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.31 2000/07/12 02:37:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -51,13 +51,12 @@ ExecHashJoin(HashJoin *node)
List *qual;
ScanDirection dir;
TupleTableSlot *inntuple;
Var *outerVar;
Node *outerVar;
ExprContext *econtext;
HashJoinTable hashtable;
HeapTuple curtuple;
TupleTableSlot *outerTupleSlot;
TupleTableSlot *innerTupleSlot;
Var *innerhashkey;
int i;
bool hashPhaseDone;
......@@ -73,7 +72,6 @@ ExecHashJoin(HashJoin *node)
hashNode = (Hash *) innerPlan(node);
outerNode = outerPlan(node);
hashPhaseDone = node->hashdone;
dir = estate->es_direction;
/* -----------------
......@@ -81,13 +79,21 @@ ExecHashJoin(HashJoin *node)
* -----------------
*/
hashtable = hjstate->hj_HashTable;
econtext = hjstate->jstate.cs_ExprContext;
/* --------------------
* initialize expression context
* --------------------
/* ----------------
* Reset per-tuple memory context to free any expression evaluation
* storage allocated in the previous tuple cycle.
* ----------------
*/
econtext = hjstate->jstate.cs_ExprContext;
ResetExprContext(econtext);
/* ----------------
* Check to see if we're still projecting out tuples from a previous
* join tuple (because there is a function-returning-set in the
* projection expressions). If so, try to project another one.
* ----------------
*/
if (hjstate->jstate.cs_TupFromTlist)
{
TupleTableSlot *result;
......@@ -96,6 +102,8 @@ ExecHashJoin(HashJoin *node)
result = ExecProject(hjstate->jstate.cs_ProjInfo, &isDone);
if (!isDone)
return result;
/* Done with that source tuple... */
hjstate->jstate.cs_TupFromTlist = false;
}
/* ----------------
......@@ -112,8 +120,7 @@ ExecHashJoin(HashJoin *node)
*/
hashtable = ExecHashTableCreate(hashNode);
hjstate->hj_HashTable = hashtable;
innerhashkey = hashNode->hashkey;
hjstate->hj_InnerHashKey = innerhashkey;
hjstate->hj_InnerHashKey = hashNode->hashkey;
/* ----------------
* execute the Hash node, to build the hash table
......@@ -139,7 +146,7 @@ ExecHashJoin(HashJoin *node)
* ----------------
*/
outerTupleSlot = hjstate->jstate.cs_OuterTupleSlot;
outerVar = get_leftop(clause);
outerVar = (Node *) get_leftop(clause);
for (;;)
{
......@@ -220,6 +227,10 @@ ExecHashJoin(HashJoin *node)
InvalidBuffer,
false); /* don't pfree this tuple */
econtext->ecxt_innertuple = inntuple;
/* reset temp memory each time to avoid leaks from qpqual */
ResetExprContext(econtext);
/* ----------------
* if we pass the qual, then save state for next call and
* have ExecProject form the projection, store it
......@@ -279,12 +290,9 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
/* ----------------
* Miscellaneous initialization
*
* + assign node's base_id
* + assign debugging hooks and
* + create expression context for node
* ----------------
*/
ExecAssignNodeBaseInfo(estate, &hjstate->jstate, parent);
ExecAssignExprContext(estate, &hjstate->jstate);
#define HASHJOIN_NSLOTS 2
......@@ -343,10 +351,10 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
hjstate->hj_HashTable = (HashJoinTable) NULL;
hjstate->hj_CurBucketNo = 0;
hjstate->hj_CurTuple = (HashJoinTuple) NULL;
hjstate->hj_InnerHashKey = (Var *) NULL;
hjstate->hj_InnerHashKey = (Node *) NULL;
hjstate->jstate.cs_OuterTupleSlot = (TupleTableSlot *) NULL;
hjstate->jstate.cs_TupFromTlist = (bool) false;
hjstate->jstate.cs_TupFromTlist = false;
return TRUE;
}
......@@ -396,6 +404,7 @@ ExecEndHashJoin(HashJoin *node)
* ----------------
*/
ExecFreeProjectionInfo(&hjstate->jstate);
ExecFreeExprContext(&hjstate->jstate);
/* ----------------
* clean up subtrees
......@@ -510,7 +519,7 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
BufFile *innerFile;
TupleTableSlot *slot;
ExprContext *econtext;
Var *innerhashkey;
Node *innerhashkey;
if (newbatch > 1)
{
......@@ -651,10 +660,10 @@ ExecReScanHashJoin(HashJoin *node, ExprContext *exprCtxt, Plan *parent)
hjstate->hj_CurBucketNo = 0;
hjstate->hj_CurTuple = (HashJoinTuple) NULL;
hjstate->hj_InnerHashKey = (Var *) NULL;
hjstate->hj_InnerHashKey = (Node *) NULL;
hjstate->jstate.cs_OuterTupleSlot = (TupleTableSlot *) NULL;
hjstate->jstate.cs_TupFromTlist = (bool) false;
hjstate->jstate.cs_TupFromTlist = false;
/*
* if chgParam of subnodes is not null then plans will be re-scanned
......
This diff is collapsed.
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.31 2000/06/18 22:44:03 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.32 2000/07/12 02:37:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -158,17 +158,12 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent)
node->matstate = matstate;
/* ----------------
* Miscellanious initialization
*
* + assign node's base_id
* + assign debugging hooks and
* + assign result tuple slot
* Miscellaneous initialization
*
* Materialization nodes don't need ExprContexts because
* they never call ExecQual or ExecTargetList.
* they never call ExecQual or ExecProject.
* ----------------
*/
ExecAssignNodeBaseInfo(estate, &matstate->csstate.cstate, parent);
#define MATERIAL_NSLOTS 1
/* ----------------
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.35 2000/06/15 04:09:52 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.36 2000/07/12 02:37:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -202,45 +202,53 @@ MJFormSkipQual(List *qualList, char *replaceopname)
static bool
MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
{
bool result;
MemoryContext oldContext;
List *clause;
List *eqclause;
Datum const_value;
bool isNull;
bool isDone;
/* ----------------
* if we have no compare qualification, return nil
* ----------------
/*
* Do expression eval in short-lived context.
*/
if (compareQual == NIL)
return false;
oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
/* ----------------
* for each pair of clauses, test them until
* our compare conditions are satisfied
* our compare conditions are satisfied.
* if we reach the end of the list, none of our key greater-than
* conditions were satisfied so we return false.
* ----------------
*/
result = false; /* assume 'false' result */
eqclause = eqQual;
foreach(clause, compareQual)
{
Datum const_value;
bool isNull;
bool isDone;
/* ----------------
* first test if our compare clause is satisfied.
* if so then return true. ignore isDone, don't iterate in
* quals.
* if so then return true.
*
* A NULL result is considered false.
* ignore isDone, don't iterate in quals.
* ----------------
*/
const_value = (Datum)
ExecEvalExpr((Node *) lfirst(clause), econtext, &isNull, &isDone);
const_value = ExecEvalExpr((Node *) lfirst(clause), econtext,
&isNull, &isDone);
if (DatumGetInt32(const_value) != 0)
return true;
if (DatumGetBool(const_value) && !isNull)
{
result = true;
break;
}
/* ----------------
* ok, the compare clause failed so we test if the keys
* are equal... if key1 != key2, we return false.
* otherwise key1 = key2 so we move on to the next pair of keys.
*
* ignore isDone, don't iterate in quals.
* ----------------
*/
const_value = ExecEvalExpr((Node *) lfirst(eqclause),
......@@ -248,17 +256,15 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
&isNull,
&isDone);
if (DatumGetInt32(const_value) == 0)
return false;
if (! DatumGetBool(const_value) || isNull)
break; /* return false */
eqclause = lnext(eqclause);
}
/* ----------------
* if we get here then it means none of our key greater-than
* conditions were satisfied so we return false.
* ----------------
*/
return false;
MemoryContextSwitchTo(oldContext);
return result;
}
/* ----------------------------------------------------------------
......@@ -403,24 +409,18 @@ ExecMergeJoin(MergeJoin *node)
List *qual;
bool qualResult;
bool compareResult;
Plan *innerPlan;
TupleTableSlot *innerTupleSlot;
Plan *outerPlan;
TupleTableSlot *outerTupleSlot;
ExprContext *econtext;
#ifdef ENABLE_OUTER_JOINS
/*
* These should be set from the expression context! - thomas
* 1999-02-20
*/
static bool isLeftJoin = true;
static bool isRightJoin = false;
#endif
/* ----------------
......@@ -448,20 +448,34 @@ ExecMergeJoin(MergeJoin *node)
}
/* ----------------
* ok, everything is setup.. let's go to work
* Reset per-tuple memory context to free any expression evaluation
* storage allocated in the previous tuple cycle.
* ----------------
*/
ResetExprContext(econtext);
/* ----------------
* Check to see if we're still projecting out tuples from a previous
* join tuple (because there is a function-returning-set in the
* projection expressions). If so, try to project another one.
* ----------------
*/
if (mergestate->jstate.cs_TupFromTlist)
{
TupleTableSlot *result;
ProjectionInfo *projInfo;
bool isDone;
projInfo = mergestate->jstate.cs_ProjInfo;
result = ExecProject(projInfo, &isDone);
result = ExecProject(mergestate->jstate.cs_ProjInfo, &isDone);
if (!isDone)
return result;
/* Done with that source tuple... */
mergestate->jstate.cs_TupFromTlist = false;
}
/* ----------------
* ok, everything is setup.. let's go to work
* ----------------
*/
for (;;)
{
/* ----------------
......@@ -547,6 +561,8 @@ ExecMergeJoin(MergeJoin *node)
case EXEC_MJ_JOINTEST:
MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTEST\n");
ResetExprContext(econtext);
qualResult = ExecQual((List *) mergeclauses, econtext, false);
MJ_DEBUG_QUAL(mergeclauses, qualResult);
......@@ -565,6 +581,14 @@ ExecMergeJoin(MergeJoin *node)
MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTUPLES\n");
mergestate->mj_JoinState = EXEC_MJ_NEXTINNER;
/*
* Check the qpqual to see if we actually want to return
* this join tuple. If not, can proceed with merge.
*
* (We don't bother with a ResetExprContext here, on the
* assumption that we just did one before checking the merge
* qual. One per tuple should be sufficient.)
*/
qualResult = ExecQual((List *) qual, econtext, false);
MJ_DEBUG_QUAL(qual, qualResult);
......@@ -693,6 +717,8 @@ ExecMergeJoin(MergeJoin *node)
innerTupleSlot = econtext->ecxt_innertuple;
econtext->ecxt_innertuple = mergestate->mj_MarkedTupleSlot;
ResetExprContext(econtext);
qualResult = ExecQual((List *) mergeclauses, econtext, false);
MJ_DEBUG_QUAL(mergeclauses, qualResult);
......@@ -709,11 +735,7 @@ ExecMergeJoin(MergeJoin *node)
*/
ExecRestrPos(innerPlan);
#if 0
mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
#endif
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
}
else
{
......@@ -777,6 +799,8 @@ ExecMergeJoin(MergeJoin *node)
* we update the marked tuple and go join them.
* ----------------
*/
ResetExprContext(econtext);
qualResult = ExecQual((List *) mergeclauses, econtext, false);
MJ_DEBUG_QUAL(mergeclauses, qualResult);
......@@ -886,6 +910,8 @@ ExecMergeJoin(MergeJoin *node)
* we update the marked tuple and go join them.
* ----------------
*/
ResetExprContext(econtext);
qualResult = ExecQual((List *) mergeclauses, econtext, false);
MJ_DEBUG_QUAL(mergeclauses, qualResult);
......@@ -1142,12 +1168,9 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
/* ----------------
* Miscellaneous initialization
*
* + assign node's base_id
* + assign debugging hooks and
* + create expression context for node
* ----------------
*/
ExecAssignNodeBaseInfo(estate, &mergestate->jstate, parent);
ExecAssignExprContext(estate, &mergestate->jstate);
#define MERGEJOIN_NSLOTS 2
......@@ -1251,6 +1274,7 @@ ExecEndMergeJoin(MergeJoin *node)
* ----------------
*/
ExecFreeProjectionInfo(&mergestate->jstate);
ExecFreeExprContext(&mergestate->jstate);
/* ----------------
* shut down the subplans
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.16 2000/06/15 04:09:52 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.17 2000/07/12 02:37:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -32,18 +32,18 @@
*
* It scans the inner relation to join with current outer tuple.
*
* If none is found, next tuple form the outer relation is retrieved
* If none is found, next tuple from the outer relation is retrieved
* and the inner relation is scanned from the beginning again to join
* with the outer tuple.
*
* Nil is returned if all the remaining outer tuples are tried and
* NULL is returned if all the remaining outer tuples are tried and
* all fail to join with the inner tuples.
*
* Nil is also returned if there is no tuple from inner realtion.
* NULL is also returned if there is no tuple from inner relation.
*
* Conditions:
* -- outerTuple contains current tuple from outer relation and
* the right son(inner realtion) maintains "cursor" at the tuple
* the right son(inner relation) maintains "cursor" at the tuple
* returned previously.
* This is achieved by maintaining a scan position on the outer
* relation.
......@@ -60,10 +60,8 @@ ExecNestLoop(NestLoop *node, Plan *parent)
Plan *innerPlan;
Plan *outerPlan;
bool needNewOuterTuple;
TupleTableSlot *outerTupleSlot;
TupleTableSlot *innerTupleSlot;
List *qual;
ExprContext *econtext;
......@@ -77,11 +75,6 @@ ExecNestLoop(NestLoop *node, Plan *parent)
qual = node->join.qual;
outerPlan = outerPlan(&node->join);
innerPlan = innerPlan(&node->join);
/* ----------------
* initialize expression context
* ----------------
*/
econtext = nlstate->jstate.cs_ExprContext;
/* ----------------
......@@ -92,11 +85,18 @@ ExecNestLoop(NestLoop *node, Plan *parent)
econtext->ecxt_outertuple = outerTupleSlot;
/* ----------------
* Ok, everything is setup for the join so now loop until
* we return a qualifying join tuple..
* Reset per-tuple memory context to free any expression evaluation
* storage allocated in the previous tuple cycle.
* ----------------
*/
ResetExprContext(econtext);
/* ----------------
* Check to see if we're still projecting out tuples from a previous
* join tuple (because there is a function-returning-set in the
* projection expressions). If so, try to project another one.
* ----------------
*/
if (nlstate->jstate.cs_TupFromTlist)
{
TupleTableSlot *result;
......@@ -105,9 +105,17 @@ ExecNestLoop(NestLoop *node, Plan *parent)
result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
if (!isDone)
return result;
/* Done with that source tuple... */
nlstate->jstate.cs_TupFromTlist = false;
}
/* ----------------
* Ok, everything is setup for the join so now loop until
* we return a qualifying join tuple..
* ----------------
*/
ENL1_printf("entering main loop");
for (;;)
{
/* ----------------
......@@ -115,15 +123,7 @@ ExecNestLoop(NestLoop *node, Plan *parent)
* and join it with the current outer tuple.
* ----------------
*/
needNewOuterTuple = false;
if (!TupIsNull(outerTupleSlot))
ENL1_printf("have outer tuple, deal with it");
else
{
ENL1_printf("outer tuple is nil, need new outer tuple");
needNewOuterTuple = true;
}
needNewOuterTuple = TupIsNull(outerTupleSlot);
/* ----------------
* if we have an outerTuple, try to get the next inner tuple.
......@@ -229,9 +229,11 @@ ExecNestLoop(NestLoop *node, Plan *parent)
}
/* ----------------
* qualification failed so we have to try again..
* Tuple fails qual, so free per-tuple memory and try again.
* ----------------
*/
ResetExprContext(econtext);
ENL1_printf("qualification failed, looping");
}
}
......@@ -263,18 +265,14 @@ ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
* ----------------
*/
nlstate = makeNode(NestLoopState);
nlstate->nl_PortalFlag = false;
node->nlstate = nlstate;
/* ----------------
* Miscellanious initialization
* Miscellaneous initialization
*
* + assign node's base_id
* + assign debugging hooks and
* + create expression context for node
* ----------------
*/
ExecAssignNodeBaseInfo(estate, &nlstate->jstate, parent);
ExecAssignExprContext(estate, &nlstate->jstate);
#define NESTLOOP_NSLOTS 1
......@@ -348,6 +346,7 @@ ExecEndNestLoop(NestLoop *node)
* ----------------
*/
ExecFreeProjectionInfo(&nlstate->jstate);
ExecFreeExprContext(&nlstate->jstate);
/* ----------------
* close down subplans
......@@ -386,9 +385,7 @@ ExecReScanNestLoop(NestLoop *node, ExprContext *exprCtxt, Plan *parent)
if (outerPlan->chgParam == NULL)
ExecReScan(outerPlan, exprCtxt, (Plan *) node);
/* let outerPlan to free its result typle ... */
/* let outerPlan to free its result tuple ... */
nlstate->jstate.cs_OuterTupleSlot = NULL;
nlstate->jstate.cs_TupFromTlist = false;
return;
}
......@@ -3,21 +3,18 @@
* nodeResult.c
* support for constant nodes needing special code.
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* DESCRIPTION
*
* Example: in constant queries where no relations are scanned,
* the planner generates result nodes. Examples of such queries are:
* Result nodes are used in queries where no relations are scanned.
* Examples of such queries are:
*
* retrieve (x = 1)
* and
* append emp (name = "mike", salary = 15000)
*
* Result nodes are also used to optimise queries
* with tautological qualifications like:
* Result nodes are also used to optimise queries with constant
* qualifications (ie, quals that do not depend on the scanned data),
* such as:
*
* retrieve (emp.all) where 2 > 1
*
......@@ -27,13 +24,22 @@
* /
* SeqScan (emp.all)
*
* At runtime, the Result node evaluates the constant qual once.
* If it's false, we can return an empty result set without running
* the controlled plan at all. If it's true, we run the controlled
* plan normally and pass back the results.
*
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.13 2000/01/26 05:56:23 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.14 2000/07/12 02:37:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "postgres.h"
#include "executor/executor.h"
#include "executor/nodeResult.h"
......@@ -41,7 +47,7 @@
/* ----------------------------------------------------------------
* ExecResult(node)
*
* returns the tuples from the outer plan which satisify the
* returns the tuples from the outer plan which satisfy the
* qualification clause. Since result nodes with right
* subtrees are never planned, we ignore the right subtree
* entirely (for now).. -cim 10/7/89
......@@ -67,15 +73,17 @@ ExecResult(Result *node)
* ----------------
*/
resstate = node->resstate;
econtext = resstate->cstate.cs_ExprContext;
/* ----------------
* get the expression context
* Reset per-tuple memory context to free any expression evaluation
* storage allocated in the previous tuple cycle.
* ----------------
*/
econtext = resstate->cstate.cs_ExprContext;
ResetExprContext(econtext);
/* ----------------
* check tautological qualifications like (2 > 1)
* check constant qualifications like (2 > 1), if not already done
* ----------------
*/
if (resstate->rs_checkqual)
......@@ -92,74 +100,64 @@ ExecResult(Result *node)
}
}
/* ----------------
* Check to see if we're still projecting out tuples from a previous
* scan tuple (because there is a function-returning-set in the
* projection expressions). If so, try to project another one.
* ----------------
*/
if (resstate->cstate.cs_TupFromTlist)
{
ProjectionInfo *projInfo;
projInfo = resstate->cstate.cs_ProjInfo;
resultSlot = ExecProject(projInfo, &isDone);
resultSlot = ExecProject(resstate->cstate.cs_ProjInfo, &isDone);
if (!isDone)
return resultSlot;
/* Done with that source tuple... */
resstate->cstate.cs_TupFromTlist = false;
}
/* ----------------
* retrieve a tuple that satisfy the qual from the outer plan until
* there are no more.
*
* if rs_done is 1 then it means that we were asked to return
* a constant tuple and we alread did the last time ExecResult()
* was called, so now we are through.
* if rs_done is true then it means that we were asked to return
* a constant tuple and we already did the last time ExecResult()
* was called, OR that we failed the constant qual check.
* Either way, now we are through.
* ----------------
*/
outerPlan = outerPlan(node);
while (!resstate->rs_done)
if (!resstate->rs_done)
{
outerPlan = outerPlan(node);
/* ----------------
* get next outer tuple if necessary.
* ----------------
*/
if (outerPlan != NULL)
{
/* ----------------
* retrieve tuples from the outer plan until there are no more.
* ----------------
*/
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
if (TupIsNull(outerTupleSlot))
return NULL;
resstate->cstate.cs_OuterTupleSlot = outerTupleSlot;
/* ----------------
* XXX gross hack. use outer tuple as scan tuple for projection
* ----------------
*/
econtext->ecxt_outertuple = outerTupleSlot;
econtext->ecxt_scantuple = outerTupleSlot;
}
else
{
/* ----------------
* if we don't have an outer plan, then it's probably
* the case that we are doing a retrieve or an append
* with a constant target list, so we should only return
* the constant tuple once or never if we fail the qual.
* if we don't have an outer plan, then we are just generating
* the results from a constant target list. Do it only once.
* ----------------
*/
resstate->rs_done = 1;
resstate->rs_done = true;
}
/* ----------------
* get the information to place into the expr context
* ----------------
*/
resstate = node->resstate;
outerTupleSlot = resstate->cstate.cs_OuterTupleSlot;
/* ----------------
* fill in the information in the expression context
* XXX gross hack. use outer tuple as scan tuple
* ----------------
*/
econtext->ecxt_outertuple = outerTupleSlot;
econtext->ecxt_scantuple = outerTupleSlot;
/* ----------------
* form the result tuple and pass it back using ExecProject()
* form the result tuple using ExecProject(), and return it.
* ----------------
*/
projInfo = resstate->cstate.cs_ProjInfo;
......@@ -200,14 +198,11 @@ ExecInitResult(Result *node, EState *estate, Plan *parent)
node->resstate = resstate;
/* ----------------
* Miscellanious initialization
* Miscellaneous initialization
*
* + assign node's base_id
* + assign debugging hooks and
* + create expression context for node
* ----------------
*/
ExecAssignNodeBaseInfo(estate, &resstate->cstate, parent);
ExecAssignExprContext(estate, &resstate->cstate);
#define RESULT_NSLOTS 1
......@@ -247,7 +242,7 @@ ExecCountSlotsResult(Result *node)
/* ----------------------------------------------------------------
* ExecEndResult
*
* fees up storage allocated through C routines
* frees up storage allocated through C routines
* ----------------------------------------------------------------
*/
void
......@@ -266,9 +261,8 @@ ExecEndResult(Result *node)
* is freed at end-transaction time. -cim 6/2/91
* ----------------
*/
ExecFreeExprContext(&resstate->cstate); /* XXX - new for us - er1p */
ExecFreeTypeInfo(&resstate->cstate); /* XXX - new for us - er1p */
ExecFreeProjectionInfo(&resstate->cstate);
ExecFreeExprContext(&resstate->cstate);
/* ----------------
* shut down subplans
......@@ -301,5 +295,4 @@ ExecReScanResult(Result *node, ExprContext *exprCtxt, Plan *parent)
if (((Plan *) node)->lefttree &&
((Plan *) node)->lefttree->chgParam == NULL)
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
}
This diff is collapsed.
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.28 2000/07/09 04:17:53 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.29 2000/07/12 02:37:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -255,14 +255,10 @@ ExecInitSort(Sort *node, EState *estate, Plan *parent)
/* ----------------
* Miscellaneous initialization
*
* + assign node's base_id
* + assign debugging hooks
*
* Sort nodes don't initialize their ExprContexts because
* they never call ExecQual or ExecTargetList.
* they never call ExecQual or ExecProject.
* ----------------
*/
ExecAssignNodeBaseInfo(estate, &sortstate->csstate.cstate, parent);
#define SORT_NSLOTS 1
/* ----------------
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.25 2000/04/12 17:15:10 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.26 2000/07/12 02:37:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -37,11 +37,19 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
SubLink *sublink = node->sublink;
SubLinkType subLinkType = sublink->subLinkType;
bool useor = sublink->useor;
MemoryContext oldcontext;
TupleTableSlot *slot;
Datum result;
bool isDone;
bool found = false; /* TRUE if got at least one subplan tuple */
List *lst;
/*
* We are probably in a short-lived expression-evaluation context.
* Switch to longer-lived per-query context.
*/
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
if (node->setParam != NIL)
elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
......@@ -52,12 +60,16 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
{
foreach(lst, node->parParam)
{
ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]);
ParamExecData *prm;
prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]);
Assert(pvar != NIL);
prm->value = ExecEvalExpr((Node *) lfirst(pvar),
econtext,
&(prm->isnull), NULL);
prm->value = ExecEvalExprSwitchContext((Node *) lfirst(pvar),
econtext,
&(prm->isnull),
&isDone);
if (!isDone)
elog(ERROR, "ExecSubPlan: set values not supported for params");
pvar = lnext(pvar);
}
plan->chgParam = nconc(plan->chgParam, listCopy(node->parParam));
......@@ -84,7 +96,7 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
* return NULL. Assuming we get a tuple, we just return its first
* column (there can be only one non-junk column in this case).
*/
result = (Datum) (subLinkType == ALL_SUBLINK ? true : false);
result = BoolGetDatum(subLinkType == ALL_SUBLINK);
*isNull = false;
for (slot = ExecProcNode(plan, plan);
......@@ -93,12 +105,16 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
{
HeapTuple tup = slot->val;
TupleDesc tdesc = slot->ttc_tupleDescriptor;
Datum rowresult = (Datum) (useor ? false : true);
Datum rowresult = BoolGetDatum(! useor);
bool rownull = false;
int col = 1;
if (subLinkType == EXISTS_SUBLINK)
return (Datum) true;
{
found = true;
result = BoolGetDatum(true);
break;
}
if (subLinkType == EXPR_SUBLINK)
{
......@@ -172,8 +188,10 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
/*
* Now we can eval the combining operator for this column.
*/
expresult = ExecEvalExpr((Node *) expr, econtext, &expnull,
(bool *) NULL);
expresult = ExecEvalExprSwitchContext((Node *) expr, econtext,
&expnull, &isDone);
if (!isDone)
elog(ERROR, "ExecSubPlan: set values not supported for combining operators");
/*
* Combine the result into the row result as appropriate.
......@@ -188,9 +206,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
/* combine within row per OR semantics */
if (expnull)
rownull = true;
else if (DatumGetInt32(expresult) != 0)
else if (DatumGetBool(expresult))
{
rowresult = (Datum) true;
rowresult = BoolGetDatum(true);
rownull = false;
break; /* needn't look at any more columns */
}
......@@ -200,9 +218,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
/* combine within row per AND semantics */
if (expnull)
rownull = true;
else if (DatumGetInt32(expresult) == 0)
else if (! DatumGetBool(expresult))
{
rowresult = (Datum) false;
rowresult = BoolGetDatum(false);
rownull = false;
break; /* needn't look at any more columns */
}
......@@ -215,9 +233,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
/* combine across rows per OR semantics */
if (rownull)
*isNull = true;
else if (DatumGetInt32(rowresult) != 0)
else if (DatumGetBool(rowresult))
{
result = (Datum) true;
result = BoolGetDatum(true);
*isNull = false;
break; /* needn't look at any more rows */
}
......@@ -227,9 +245,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
/* combine across rows per AND semantics */
if (rownull)
*isNull = true;
else if (DatumGetInt32(rowresult) == 0)
else if (! DatumGetBool(rowresult))
{
result = (Datum) false;
result = BoolGetDatum(false);
*isNull = false;
break; /* needn't look at any more rows */
}
......@@ -252,11 +270,13 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
*/
if (subLinkType == EXPR_SUBLINK || subLinkType == MULTIEXPR_SUBLINK)
{
result = (Datum) false;
result = (Datum) 0;
*isNull = true;
}
}
MemoryContextSwitchTo(oldcontext);
return result;
}
......@@ -277,13 +297,13 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
ExecCreateTupleTable(ExecCountSlotsNode(node->plan) + 10);
sp_estate->es_snapshot = estate->es_snapshot;
node->shutdown = false;
node->needShutdown = false;
node->curTuple = NULL;
if (!ExecInitNode(node->plan, sp_estate, NULL))
return false;
node->shutdown = true; /* now we need to shutdown the subplan */
node->needShutdown = true; /* now we need to shutdown the subplan */
/*
* If this plan is un-correlated or undirect correlated one and want
......@@ -317,14 +337,21 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
* ----------------------------------------------------------------
*/
void
ExecSetParamPlan(SubPlan *node)
ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
{
Plan *plan = node->plan;
SubLink *sublink = node->sublink;
MemoryContext oldcontext;
TupleTableSlot *slot;
List *lst;
bool found = false;
/*
* We are probably in a short-lived expression-evaluation context.
* Switch to longer-lived per-query context.
*/
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
if (sublink->subLinkType == ANY_SUBLINK ||
sublink->subLinkType == ALL_SUBLINK)
elog(ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported");
......@@ -345,7 +372,7 @@ ExecSetParamPlan(SubPlan *node)
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
prm->execPlan = NULL;
prm->value = (Datum) true;
prm->value = BoolGetDatum(true);
prm->isnull = false;
found = true;
break;
......@@ -386,7 +413,7 @@ ExecSetParamPlan(SubPlan *node)
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
prm->execPlan = NULL;
prm->value = (Datum) false;
prm->value = BoolGetDatum(false);
prm->isnull = false;
}
else
......@@ -396,16 +423,18 @@ ExecSetParamPlan(SubPlan *node)
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
prm->execPlan = NULL;
prm->value = (Datum) NULL;
prm->value = (Datum) 0;
prm->isnull = true;
}
}
}
MemoryContextSwitchTo(oldcontext);
if (plan->extParam == NULL) /* un-correlated ... */
{
ExecEndNode(plan, plan);
node->shutdown = false;
node->needShutdown = false;
}
}
......@@ -416,10 +445,10 @@ ExecSetParamPlan(SubPlan *node)
void
ExecEndSubPlan(SubPlan *node)
{
if (node->shutdown)
if (node->needShutdown)
{
ExecEndNode(node->plan, node->plan);
node->shutdown = false;
node->needShutdown = false;
}
if (node->curTuple)
{
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.9 2000/06/15 04:09:52 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.10 2000/07/12 02:37:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -38,12 +38,16 @@ TidListCreate(List *evalList, ExprContext *econtext, ItemPointer *tidList)
List *lst;
ItemPointer itemptr;
bool isNull;
bool isDone;
int numTids = 0;
foreach(lst, evalList)
{
itemptr = (ItemPointer) ExecEvalExpr(lfirst(lst), econtext,
&isNull, (bool *) 0);
itemptr = (ItemPointer)
DatumGetPointer(ExecEvalExprSwitchContext(lfirst(lst),
econtext,
&isNull,
&isDone));
if (itemptr && ItemPointerIsValid(itemptr))
{
tidList[numTids] = itemptr;
......@@ -243,7 +247,7 @@ ExecTidScan(TidScan *node)
* use TidNext as access method
* ----------------
*/
return ExecScan(&node->scan, TidNext);
return ExecScan(&node->scan, (ExecScanAccessMtd) TidNext);
}
/* ----------------------------------------------------------------
......@@ -319,6 +323,7 @@ ExecEndTidScan(TidScan *node)
* ----------------
*/
ExecFreeProjectionInfo(&scanstate->cstate);
ExecFreeExprContext(&scanstate->cstate);
/* ----------------
* close the heap and tid relations
......@@ -332,7 +337,6 @@ ExecEndTidScan(TidScan *node)
*/
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
ExecClearTuple(scanstate->css_ScanTupleSlot);
/* ExecClearTuple(scanstate->css_RawTupleSlot); */
}
/* ----------------------------------------------------------------
......@@ -394,11 +398,8 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
RangeTblEntry *rtentry;
Oid relid;
Oid reloid;
Relation currentRelation;
int baseid;
List *execParam = NULL;
List *execParam = NIL;
/* ----------------
* assign execution state to node
......@@ -413,25 +414,12 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
* --------------------------------
*/
scanstate = makeNode(CommonScanState);
/*
scanstate->ss_ProcOuterFlag = false;
scanstate->ss_OldRelId = 0;
*/
node->scan.scanstate = scanstate;
/* ----------------
* assign node's base_id .. we don't use AssignNodeBaseid() because
* the increment is done later on after we assign the tid scan's
* scanstate. see below.
* ----------------
*/
baseid = estate->es_BaseId;
/* scanstate->csstate.cstate.bnode.base_id = baseid; */
scanstate->cstate.cs_base_id = baseid;
/* ----------------
* create expression context for node
* Miscellaneous initialization
*
* + create expression context for node
* ----------------
*/
ExecAssignExprContext(estate, &scanstate->cstate);
......@@ -443,7 +431,6 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
*/
ExecInitResultTupleSlot(estate, &scanstate->cstate);
ExecInitScanTupleSlot(estate, scanstate);
/* ExecInitRawTupleSlot(estate, scanstate); */
/* ----------------
* initialize projection info. result type comes from scan desc
......@@ -461,14 +448,6 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
tidstate = makeNode(TidScanState);
node->tidstate = tidstate;
/* ----------------
* assign base id to tid scan state also
* ----------------
*/
tidstate->cstate.cs_base_id = baseid;
baseid++;
estate->es_BaseId = baseid;
/* ----------------
* get the tid node information
* ----------------
......@@ -514,14 +493,6 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
ExecAssignScanType(scanstate, RelationGetDescr(currentRelation));
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
/* ----------------
* tid scans don't have subtrees..
* ----------------
*/
/* scanstate->ss_ProcOuterFlag = false; */
tidstate->cstate.cs_TupFromTlist = false;
/*
* if there are some PARAM_EXEC in skankeys then force tid rescan on
* first scan.
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.29 2000/05/30 00:49:45 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.30 2000/07/12 02:37:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -88,27 +88,32 @@ ExecUnique(Unique *node)
if (!execTuplesMatch(slot->val, uniquestate->priorTuple,
tupDesc,
node->numCols, node->uniqColIdx,
uniquestate->eqfunctions))
uniquestate->eqfunctions,
uniquestate->tempContext))
break;
}
/* ----------------
* We have a new tuple different from the previous saved tuple (if any).
* Save it and return it. Note that we make two copies of the tuple:
* one to keep for our own future comparisons, and one to return to the
* caller. We need to copy the tuple returned by the subplan to avoid
* holding buffer refcounts, and we need our own copy because the caller
* may alter the resultTupleSlot (eg via ExecRemoveJunk).
* Save it and return it. We must copy it because the source subplan
* won't guarantee that this source tuple is still accessible after
* fetching the next source tuple.
*
* Note that we manage the copy ourselves. We can't rely on the result
* tuple slot to maintain the tuple reference because our caller may
* replace the slot contents with a different tuple (see junk filter
* handling in execMain.c). We assume that the caller will no longer
* be interested in the current tuple after he next calls us.
* ----------------
*/
if (uniquestate->priorTuple != NULL)
heap_freetuple(uniquestate->priorTuple);
uniquestate->priorTuple = heap_copytuple(slot->val);
ExecStoreTuple(heap_copytuple(slot->val),
ExecStoreTuple(uniquestate->priorTuple,
resultTupleSlot,
InvalidBuffer,
true);
false); /* tuple does not belong to slot */
return resultTupleSlot;
}
......@@ -143,14 +148,17 @@ ExecInitUnique(Unique *node, EState *estate, Plan *parent)
/* ----------------
* Miscellaneous initialization
*
* + assign node's base_id
* + assign debugging hooks and
*
* Unique nodes have no ExprContext initialization because
* they never call ExecQual or ExecTargetList.
* they never call ExecQual or ExecProject. But they do need a
* per-tuple memory context anyway for calling execTuplesMatch.
* ----------------
*/
ExecAssignNodeBaseInfo(estate, &uniquestate->cstate, parent);
uniquestate->tempContext =
AllocSetContextCreate(CurrentMemoryContext,
"Unique",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
#define UNIQUE_NSLOTS 1
/* ------------
......@@ -207,6 +215,8 @@ ExecEndUnique(Unique *node)
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
MemoryContextDelete(uniquestate->tempContext);
/* clean up tuple table */
ExecClearTuple(uniquestate->cstate.cs_ResultTupleSlot);
if (uniquestate->priorTuple != NULL)
......
......@@ -19,7 +19,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.115 2000/06/29 07:35:56 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.116 2000/07/12 02:37:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -578,7 +578,7 @@ _copySubPlan(SubPlan *from)
Node_Copy(from, newnode, sublink);
/* do not copy execution state */
newnode->shutdown = false;
newnode->needShutdown = false;
newnode->curTuple = NULL;
return newnode;
......
......@@ -24,7 +24,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.67 2000/06/29 07:35:56 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.68 2000/07/12 02:37:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -184,8 +184,8 @@ _equalConst(Const *a, Const *b)
*/
if (a->constisnull)
return true;
return (datumIsEqual(a->constvalue, b->constvalue,
a->consttype, a->constbyval, a->constlen));
return datumIsEqual(a->constvalue, b->constvalue,
a->constbyval, a->constlen);
}
static bool
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.120 2000/06/18 22:44:05 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.121 2000/07/12 02:37:06 tgl Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
......@@ -1155,10 +1155,10 @@ _outJoinInfo(StringInfo str, JoinInfo *node)
static void
_outDatum(StringInfo str, Datum value, Oid type)
{
char *s;
Size length,
typeLength;
bool byValue;
int typeLength;
Size length;
char *s;
int i;
/*
......@@ -1167,12 +1167,12 @@ _outDatum(StringInfo str, Datum value, Oid type)
*/
byValue = get_typbyval(type);
typeLength = get_typlen(type);
length = datumGetSize(value, type, byValue, typeLength);
length = datumGetSize(value, byValue, typeLength);
if (byValue)
{
s = (char *) (&value);
appendStringInfo(str, " %d [ ", length);
appendStringInfo(str, " %u [ ", (unsigned int) length);
for (i = 0; i < (int) sizeof(Datum); i++)
appendStringInfo(str, "%d ", (int) (s[i]));
appendStringInfo(str, "] ");
......@@ -1184,14 +1184,7 @@ _outDatum(StringInfo str, Datum value, Oid type)
appendStringInfo(str, " 0 [ ] ");
else
{
/*
* length is unsigned - very bad to do < comparison to -1
* without casting it to int first!! -mer 8 Jan 1991
*/
if (((int) length) <= -1)
length = VARSIZE(s);
appendStringInfo(str, " %d [ ", length);
appendStringInfo(str, " %u [ ", (unsigned int) length);
for (i = 0; i < (int) length; i++)
appendStringInfo(str, "%d ", (int) (s[i]));
appendStringInfo(str, "] ");
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.91 2000/06/18 22:44:05 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.92 2000/07/12 02:37:06 tgl Exp $
*
* NOTES
* Most of the read functions for plan nodes are tested. (In fact, they
......@@ -608,7 +608,7 @@ _readHash()
_getPlan((Plan *) local_node);
token = lsptok(NULL, &length); /* eat :hashkey */
local_node->hashkey = (Var *) nodeRead(true);
local_node->hashkey = nodeRead(true);
return local_node;
}
......
......@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.93 2000/06/18 22:44:07 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.94 2000/07/12 02:37:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -66,7 +66,7 @@ static NestLoop *make_nestloop(List *qptlist, List *qpqual, Plan *lefttree,
Plan *righttree);
static HashJoin *make_hashjoin(List *tlist, List *qpqual,
List *hashclauses, Plan *lefttree, Plan *righttree);
static Hash *make_hash(List *tlist, Var *hashkey, Plan *lefttree);
static Hash *make_hash(List *tlist, Node *hashkey, Plan *lefttree);
static MergeJoin *make_mergejoin(List *tlist, List *qpqual,
List *mergeclauses, Plan *righttree, Plan *lefttree);
static void copy_path_costsize(Plan *dest, Path *src);
......@@ -664,7 +664,7 @@ create_hashjoin_node(HashPath *best_path,
List *hashclauses;
HashJoin *join_node;
Hash *hash_node;
Var *innerhashkey;
Node *innerhashkey;
/*
* NOTE: there will always be exactly one hashclause in the list
......@@ -694,7 +694,7 @@ create_hashjoin_node(HashPath *best_path,
(Index) 0));
/* Now the righthand op of the sole hashclause is the inner hash key. */
innerhashkey = get_rightop(lfirst(hashclauses));
innerhashkey = (Node *) get_rightop(lfirst(hashclauses));
/*
* Build the hash node and hash join node.
......@@ -1103,7 +1103,7 @@ make_hashjoin(List *tlist,
}
static Hash *
make_hash(List *tlist, Var *hashkey, Plan *lefttree)
make_hash(List *tlist, Node *hashkey, Plan *lefttree)
{
Hash *node = makeNode(Hash);
Plan *plan = &node->plan;
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.38 2000/06/18 22:44:09 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.39 2000/07/12 02:37:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -649,7 +649,7 @@ SS_finalize_plan(Plan *plan)
break;
case T_Hash:
finalize_primnode((Node *) ((Hash *) plan)->hashkey,
finalize_primnode(((Hash *) plan)->hashkey,
&results);
break;
......
This diff is collapsed.
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.35 2000/06/28 03:32:22 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.36 2000/07/12 02:37:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -72,7 +72,6 @@ CreateExecutorState(void)
state->es_param_list_info = NULL;
state->es_param_exec_vals = NULL;
state->es_BaseId = 0;
state->es_tupleTable = NULL;
state->es_junkFilter = NULL;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: index.h,v 1.27 2000/07/04 06:11:54 tgl Exp $
* $Id: index.h,v 1.28 2000/07/12 02:37:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -53,9 +53,6 @@ extern void setRelhasindexInplace(Oid relid, bool hasindex, bool immediate);
extern bool SetReindexProcessing(bool processing);
extern bool IsReindexProcessing(void);
extern void FillDummyExprContext(ExprContext *econtext, TupleTableSlot *slot,
TupleDesc tupdesc, Buffer buffer);
extern void index_build(Relation heapRelation, Relation indexRelation,
int numberOfAttributes, AttrNumber *attributeNumber,
FuncIndexInfo *funcInfo, PredInfo *predInfo,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -13,7 +13,7 @@ extern Datum ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext,
bool *isNull);
extern bool ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent);
extern void ExecReScanSetParamPlan(SubPlan *node, Plan *parent);
extern void ExecSetParamPlan(SubPlan *node);
extern void ExecSetParamPlan(SubPlan *node, ExprContext *econtext);
extern void ExecEndSubPlan(SubPlan *node);
#endif /* NODESUBPLAN_H */
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