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);
}
#endif
if (res != 0 || VARSIZE(a) == VARSIZE(b))
PG_RETURN_INT32(res);
if (res == 0 && VARSIZE(a) != VARSIZE(b))
{
/*
* The two strings are the same in the first len bytes, and they are
* of different lengths.
* 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);
res = -1;
else
PG_RETURN_INT32(1);
res = 1;
}
#endif
/* Avoid leaking memory when handed toasted input. */
PG_FREE_IF_COPY(a, 0);
PG_FREE_IF_COPY(b, 1);
PG_RETURN_INT32(res);
}
......@@ -12,7 +12,7 @@
* 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);
pfree(repl);
heap_freetuple(tuple);
pfree(replNull);
pfree(replValue);
heap_freetuple(tuple);
}
return newtuple;
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,25 +91,21 @@ 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,
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);
econtext->ecxt_scantuple = NULL;
econtext->ecxt_innertuple = NULL;
econtext->ecxt_outertuple = NULL;
econtext->ecxt_per_query_memory = CurrentMemoryContext;
/*
* Create working memory for expression evaluation in this context.
*/
econtext->ecxt_per_tuple_memory =
AllocSetContextCreate(CurrentMemoryContext,
"PlanExprContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
econtext->ecxt_param_list_info = estate->es_param_list_info;
econtext->ecxt_aggvalues = NULL;
econtext->ecxt_aggnulls = NULL;
econtext->ecxt_range_table = estate->es_range_table;
baseId = estate->es_BaseId;
cstate->cs_base_id = baseId;
estate->es_BaseId = baseId + 1;
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,
return datumCopy(val,
TD->attrs[attrno - 1]->attbyval,
(Size) TD->attrs[attrno - 1]->attlen);
return valueP;
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.
* ----------------
*/
if (!resstate->rs_done)
{
outerPlan = outerPlan(node);
while (!resstate->rs_done)
if (outerPlan != NULL)
{
/* ----------------
* get next outer tuple if necessary.
* retrieve tuples from the outer plan until there are no more.
* ----------------
*/
if (outerPlan != NULL)
{
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
if (TupIsNull(outerTupleSlot))
return NULL;
resstate->cstate.cs_OuterTupleSlot = 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.
* XXX gross hack. use outer tuple as scan tuple for projection
* ----------------
*/
resstate->rs_done = 1;
econtext->ecxt_outertuple = outerTupleSlot;
econtext->ecxt_scantuple = outerTupleSlot;
}
/* ----------------
* get the information to place into the expr context
* ----------------
*/
resstate = node->resstate;
outerTupleSlot = resstate->cstate.cs_OuterTupleSlot;
else
{
/* ----------------
* fill in the information in the expression context
* XXX gross hack. use outer tuple as scan tuple
* if we don't have an outer plan, then we are just generating
* the results from a constant target list. Do it only once.
* ----------------
*/
econtext->ecxt_outertuple = outerTupleSlot;
econtext->ecxt_scantuple = outerTupleSlot;
resstate->rs_done = true;
}
/* ----------------
* 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);
}
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.23 2000/06/15 04:09:52 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.24 2000/07/12 02:37:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -31,8 +31,7 @@
#include "parser/parsetree.h"
static Oid InitScanRelation(SeqScan *node, EState *estate,
CommonScanState *scanstate, Plan *outerPlan);
CommonScanState *scanstate);
static TupleTableSlot *SeqNext(SeqScan *node);
/* ----------------------------------------------------------------
......@@ -132,25 +131,11 @@ SeqNext(SeqScan *node)
TupleTableSlot *
ExecSeqScan(SeqScan *node)
{
TupleTableSlot *slot;
Plan *outerPlan;
S_printf("ExecSeqScan: scanning node: ");
S_nodeDisplay(node);
/* ----------------
* if there is an outer subplan, get a tuple from it
* else, scan the relation
* use SeqNext as access method
* ----------------
*/
if ((outerPlan = outerPlan((Plan *) node)) != NULL)
slot = ExecProcNode(outerPlan, (Plan *) node);
else
slot = ExecScan(node, SeqNext);
S1_printf("ExecSeqScan: returned tuple slot: %d\n", slot);
return slot;
return ExecScan(node, (ExecScanAccessMtd) SeqNext);
}
/* ----------------------------------------------------------------
......@@ -162,7 +147,7 @@ ExecSeqScan(SeqScan *node)
*/
static Oid
InitScanRelation(SeqScan *node, EState *estate,
CommonScanState *scanstate, Plan *outerPlan)
CommonScanState *scanstate)
{
Index relid;
List *rangeTable;
......@@ -173,12 +158,7 @@ InitScanRelation(SeqScan *node, EState *estate,
HeapScanDesc currentScanDesc;
RelationInfo *resultRelationInfo;
if (outerPlan == NULL)
{
/* ----------------
* if the outer node is nil then we are doing a simple
* sequential scan of a relation...
*
* get the relation object id from the relid'th entry
* in the range table, open that relation and initialize
* the scan state...
......@@ -195,7 +175,7 @@ InitScanRelation(SeqScan *node, EState *estate,
0, /* nkeys */
NULL, /* scan key */
0, /* is index */
direction,/* scan direction */
direction, /* scan direction */
estate->es_snapshot,
&currentRelation, /* return: rel desc */
(Pointer *) &currentScanDesc); /* return: scan desc */
......@@ -203,54 +183,31 @@ InitScanRelation(SeqScan *node, EState *estate,
scanstate->css_currentRelation = currentRelation;
scanstate->css_currentScanDesc = currentScanDesc;
ExecAssignScanType(scanstate,
RelationGetDescr(currentRelation));
}
else
{
/* ----------------
* otherwise we are scanning tuples from the
* outer subplan so we initialize the outer plan
* and nullify
* ----------------
*/
ExecInitNode(outerPlan, estate, (Plan *) node);
node->scanrelid = 0;
scanstate->css_currentRelation = NULL;
scanstate->css_currentScanDesc = NULL;
ExecAssignScanType(scanstate, NULL);
reloid = InvalidOid;
}
ExecAssignScanType(scanstate, RelationGetDescr(currentRelation));
/* ----------------
* return the relation
* ----------------
*/
return reloid;
}
/* ----------------------------------------------------------------
* ExecInitSeqScan
*
* old comments
* Creates the run-time state information for the seqscan node
* and sets the relation id to contain relevant descriptors.
*
* If there is a outer subtree (sort), the outer subtree
* is initialized and the relation id is set to the descriptors
* returned by the subtree.
* ----------------------------------------------------------------
*/
bool
ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
{
CommonScanState *scanstate;
Plan *outerPlan;
Oid reloid;
HeapScanDesc scandesc;
/* ----------------
* Once upon a time it was possible to have an outerPlan of a SeqScan,
* but not any more.
* ----------------
*/
Assert(outerPlan((Plan *) node) == NULL);
Assert(innerPlan((Plan *) node) == NULL);
/* ----------------
* assign the node's execution state
* ----------------
......@@ -265,13 +222,11 @@ ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
node->scanstate = scanstate;
/* ----------------
* Miscellanious initialization
* Miscellaneous initialization
*
* + assign node's base_id
* + create expression context for node
* ----------------
*/
ExecAssignNodeBaseInfo(estate, &scanstate->cstate, parent);
ExecAssignExprContext(estate, &scanstate->cstate);
#define SEQSCAN_NSLOTS 3
......@@ -283,12 +238,10 @@ ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
ExecInitScanTupleSlot(estate, scanstate);
/* ----------------
* initialize scan relation or outer subplan
* initialize scan relation
* ----------------
*/
outerPlan = outerPlan((Plan *) node);
reloid = InitScanRelation(node, estate, scanstate, outerPlan);
reloid = InitScanRelation(node, estate, scanstate);
scandesc = scanstate->css_currentScanDesc;
scanstate->cstate.cs_TupFromTlist = false;
......@@ -315,15 +268,12 @@ ExecCountSlotsSeqScan(SeqScan *node)
* ExecEndSeqScan
*
* frees any storage allocated through C routines.
*| ...and also closes relations and/or shuts down outer subplan
*| -cim 8/14/89
* ----------------------------------------------------------------
*/
void
ExecEndSeqScan(SeqScan *node)
{
CommonScanState *scanstate;
Plan *outerPlan;
/* ----------------
* get information from node
......@@ -341,6 +291,7 @@ ExecEndSeqScan(SeqScan *node)
* ----------------
*/
ExecFreeProjectionInfo(&scanstate->cstate);
ExecFreeExprContext(&scanstate->cstate);
/* ----------------
* close scan relation
......@@ -348,13 +299,6 @@ ExecEndSeqScan(SeqScan *node)
*/
ExecCloseR((Plan *) node);
/* ----------------
* clean up outer subtree (does nothing if there is no outerPlan)
* ----------------
*/
outerPlan = outerPlan((Plan *) node);
ExecEndNode(outerPlan, (Plan *) node);
/* ----------------
* clean out the tuple table
* ----------------
......@@ -367,6 +311,7 @@ ExecEndSeqScan(SeqScan *node)
* Join Support
* ----------------------------------------------------------------
*/
/* ----------------------------------------------------------------
* ExecSeqReScan
*
......@@ -378,7 +323,6 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
{
CommonScanState *scanstate;
EState *estate;
Plan *outerPlan;
Relation rel;
HeapScanDesc scan;
ScanDirection direction;
......@@ -386,15 +330,6 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
scanstate = node->scanstate;
estate = node->plan.state;
if ((outerPlan = outerPlan((Plan *) node)) != NULL)
{
/* we are scanning a subplan */
outerPlan = outerPlan((Plan *) node);
ExecReScan(outerPlan, exprCtxt, parent);
}
else
/* otherwise, we are scanning a relation */
{
/* If this is re-scanning of PlanQual ... */
if (estate->es_evTuple != NULL &&
estate->es_evTuple[node->scanrelid - 1] != NULL)
......@@ -407,7 +342,6 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
direction = estate->es_direction;
scan = ExecReScanR(rel, scan, direction, 0, NULL);
scanstate->css_currentScanDesc = scan;
}
}
/* ----------------------------------------------------------------
......@@ -420,33 +354,11 @@ void
ExecSeqMarkPos(SeqScan *node)
{
CommonScanState *scanstate;
Plan *outerPlan;
HeapScanDesc scan;
scanstate = node->scanstate;
/* ----------------
* if we are scanning a subplan then propagate
* the ExecMarkPos() request to the subplan
* ----------------
*/
outerPlan = outerPlan((Plan *) node);
if (outerPlan)
{
ExecMarkPos(outerPlan);
return;
}
/* ----------------
* otherwise we are scanning a relation so mark the
* position using the access methods..
*
* ----------------
*/
scan = scanstate->css_currentScanDesc;
heap_markpos(scan);
return;
}
/* ----------------------------------------------------------------
......@@ -459,28 +371,9 @@ void
ExecSeqRestrPos(SeqScan *node)
{
CommonScanState *scanstate;
Plan *outerPlan;
HeapScanDesc scan;
scanstate = node->scanstate;
/* ----------------
* if we are scanning a subplan then propagate
* the ExecRestrPos() request to the subplan
* ----------------
*/
outerPlan = outerPlan((Plan *) node);
if (outerPlan)
{
ExecRestrPos(outerPlan);
return;
}
/* ----------------
* otherwise we are scanning a relation so restore the
* position using the access methods..
* ----------------
*/
scan = scanstate->css_currentScanDesc;
heap_restrpos(scan);
}
......@@ -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),
prm->value = ExecEvalExprSwitchContext((Node *) lfirst(pvar),
econtext,
&(prm->isnull), NULL);
&(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;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.68 2000/05/30 00:49:49 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.69 2000/07/12 02:37:11 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
......@@ -30,6 +30,7 @@
#include "optimizer/var.h"
#include "parser/parse_type.h"
#include "parser/parsetree.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
......@@ -1317,7 +1318,10 @@ simplify_op_or_func(Expr *expr, List *args)
HeapTuple func_tuple;
Form_pg_proc funcform;
Type resultType;
bool resultTypByVal;
int resultTypLen;
Expr *newexpr;
ExprContext *econtext;
Datum const_val;
bool has_nonconst_input = false;
bool has_null_input = false;
......@@ -1424,25 +1428,35 @@ simplify_op_or_func(Expr *expr, List *args)
newexpr->oper = expr->oper;
newexpr->args = args;
/* Get info needed about result datatype */
resultType = typeidType(result_typeid);
resultTypByVal = typeByVal(resultType);
resultTypLen = typeLen(resultType);
/*
* It is OK to pass econtext = NULL because none of the ExecEvalExpr()
* It is OK to pass a dummy econtext because none of the ExecEvalExpr()
* code used in this situation will use econtext. That might seem
* fortuitous, but it's not so unreasonable --- a constant expression
* does not depend on context, by definition, n'est ce pas?
*/
const_val = ExecEvalExpr((Node *) newexpr, NULL,
econtext = MakeExprContext(NULL, CurrentMemoryContext);
const_val = ExecEvalExprSwitchContext((Node *) newexpr, econtext,
&const_is_null, &isDone);
Assert(isDone); /* if this isn't set, we blew it... */
/* Must copy result out of sub-context used by expression eval */
const_val = datumCopy(const_val, resultTypByVal, resultTypLen);
FreeExprContext(econtext);
pfree(newexpr);
/*
* Make the constant result node.
*/
resultType = typeidType(result_typeid);
return (Expr *) makeConst(result_typeid, typeLen(resultType),
return (Expr *) makeConst(result_typeid, resultTypLen,
const_val, const_is_null,
typeByVal(resultType),
false, false);
resultTypByVal, false, false);
}
......
......@@ -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.
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.33 2000/07/05 23:11:39 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.34 2000/07/12 02:37:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -75,6 +75,7 @@ init_fcache(Oid foid,
retval = (FunctionCachePtr) palloc(sizeof(FunctionCache));
MemSet(retval, 0, sizeof(FunctionCache));
retval->fcacheCxt = CurrentMemoryContext;
/* ----------------
* get the procedure tuple corresponding to the given functionOid
......@@ -256,22 +257,26 @@ init_fcache(Oid foid,
void
setFcache(Node *node, Oid foid, List *argList, ExprContext *econtext)
{
Func *fnode;
Oper *onode;
MemoryContext oldcontext;
FunctionCachePtr fcache;
/* Switch to a context long-lived enough for the fcache entry */
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
fcache = init_fcache(foid, argList, econtext);
if (IsA(node, Oper))
{
onode = (Oper *) node;
Oper *onode = (Oper *) node;
onode->op_fcache = fcache;
}
else if (IsA(node, Func))
{
fnode = (Func *) node;
Func *fnode = (Func *) node;
fnode->func_fcache = fcache;
}
else
elog(ERROR, "init_fcache: node must be Oper or Func!");
MemoryContextSwitchTo(oldcontext);
}
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.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment