aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execMain.c19
-rw-r--r--src/backend/executor/execQual.c146
-rw-r--r--src/backend/executor/execTuples.c172
-rw-r--r--src/backend/executor/nodeAppend.c11
-rw-r--r--src/backend/executor/nodeGroup.c20
-rw-r--r--src/backend/executor/nodeIndexscan.c26
-rw-r--r--src/backend/executor/nodeMaterial.c21
-rw-r--r--src/backend/executor/nodeMergejoin.c13
-rw-r--r--src/backend/executor/nodeSeqscan.c31
-rw-r--r--src/backend/executor/nodeSubplan.c2
10 files changed, 257 insertions, 204 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 97dffe548f7..f07f8777a2f 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.94 1999/09/18 19:06:47 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.95 1999/09/24 00:24:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -130,16 +130,6 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
queryDesc->plantree,
estate);
- /*
- * reset buffer refcount. the current refcounts are saved and will be
- * restored when ExecutorEnd is called
- *
- * this makes sure that when ExecutorRun's are called recursively as for
- * postquel functions, the buffers pinned by one ExecutorRun will not
- * be unpinned by another ExecutorRun.
- */
- BufferRefCountReset(estate->es_refcount);
-
return result;
}
@@ -385,10 +375,6 @@ ExecutorEnd(QueryDesc *queryDesc, EState *estate)
pfree(estate->es_param_exec_vals);
estate->es_param_exec_vals = NULL;
}
-
- /* restore saved refcounts. */
- BufferRefCountRestore(estate->es_refcount);
-
}
void
@@ -802,7 +788,7 @@ EndPlan(Plan *plan, EState *estate)
{
TupleTable tupleTable = (TupleTable) estate->es_tupleTable;
- ExecDestroyTupleTable(tupleTable, true); /* was missing last arg */
+ ExecDestroyTupleTable(tupleTable, true);
estate->es_tupleTable = NULL;
}
@@ -1678,7 +1664,6 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
sizeof(ParamExecData));
epqstate->es_tupleTable =
ExecCreateTupleTable(estate->es_tupleTable->size);
- epqstate->es_refcount = estate->es_refcount;
/* ... rest */
newepq->plan = copyObject(estate->es_origPlan);
newepq->free = NULL;
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index a44030aa406..2886cab7253 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.59 1999/09/18 23:26:37 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.60 1999/09/24 00:24:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -637,7 +637,8 @@ ExecEvalFuncArgs(FunctionCachePtr fcache,
if (!(*argIsDone))
{
- Assert(i == 0);
+ if (i != 0)
+ elog(ERROR, "functions can only take sets in their first argument");
fcache->setArg = (char *) argV[0];
fcache->hasSetArg = true;
}
@@ -758,35 +759,48 @@ ExecMakeFunctionResult(Node *node,
if (fcache->language == SQLlanguageId)
{
Datum result;
+ bool argDone;
Assert(funcNode);
- result = postquel_function(funcNode, (char **) argV, isNull, isDone);
- /*
- * finagle the situation where we are iterating through all
- * results in a nested dot function (whose argument function
+ /*--------------------
+ * This loop handles the situation where we are iterating through
+ * all results in a nested dot function (whose argument function
* returns a set of tuples) and the current function finally
- * finishes. We need to get the next argument in the set and run
- * the function all over again. This is getting unclean.
+ * finishes. We need to get the next argument in the set and start
+ * the function all over again. We might have to do it more than
+ * once, if the function produces no results for a particular argument.
+ * This is getting unclean.
+ *--------------------
*/
- if ((*isDone) && (fcache->hasSetArg))
+ for (;;)
{
- bool argDone;
+ result = postquel_function(funcNode, (char **) argV,
+ isNull, isDone);
+
+ if (! *isDone)
+ break; /* got a result from current argument */
+ if (! fcache->hasSetArg)
+ break; /* input not a set, so done */
+ /* OK, get the next argument... */
ExecEvalFuncArgs(fcache, econtext, arguments, argV, &argDone);
if (argDone)
{
+ /* End of arguments, so reset the setArg flag and say "Done" */
fcache->setArg = (char *) NULL;
+ fcache->hasSetArg = false;
*isDone = true;
result = (Datum) NULL;
+ break;
}
- else
- result = postquel_function(funcNode,
- (char **) argV,
- isNull,
- isDone);
+
+ /* If we reach here, loop around to run the function on the
+ * new argument.
+ */
}
+
if (funcisset)
{
@@ -805,6 +819,7 @@ ExecMakeFunctionResult(Node *node,
if (*isDone)
((Func *) node)->func_fcache = NULL;
}
+
return result;
}
else
@@ -1424,8 +1439,10 @@ ExecTargetList(List *targetlist,
{
char nulls_array[64];
bool fjNullArray[64];
- bool *fjIsNull;
+ bool itemIsDoneArray[64];
char *null_head;
+ bool *fjIsNull;
+ bool *itemIsDone;
List *tl;
TargetEntry *tle;
Node *expr;
@@ -1434,6 +1451,7 @@ ExecTargetList(List *targetlist,
Datum constvalue;
HeapTuple newTuple;
bool isNull;
+ bool haveDoneIters;
static struct tupleDesc NullTupleDesc; /* we assume this inits to zeroes */
/*
@@ -1457,24 +1475,30 @@ ExecTargetList(List *targetlist,
/*
* allocate an array of char's to hold the "null" information only if
* we have a really large targetlist. otherwise we use the stack.
+ *
+ * We also allocate a bool array that is used to hold fjoin result state,
+ * and another that holds the isDone status for each targetlist item.
*/
if (nodomains > 64)
{
null_head = (char *) palloc(nodomains + 1);
fjIsNull = (bool *) palloc(nodomains + 1);
+ itemIsDone = (bool *) palloc(nodomains + 1);
}
else
{
null_head = &nulls_array[0];
fjIsNull = &fjNullArray[0];
+ itemIsDone = &itemIsDoneArray[0];
}
/*
* evaluate all the expressions in the target list
*/
- EV_printf("ExecTargetList: setting target list values\n");
- *isDone = true;
+ *isDone = true; /* until proven otherwise */
+ haveDoneIters = false; /* any isDone Iter exprs in tlist? */
+
foreach(tl, targetlist)
{
@@ -1493,13 +1517,11 @@ ExecTargetList(List *targetlist,
expr = tle->expr;
resdom = tle->resdom;
resind = resdom->resno - 1;
+
constvalue = (Datum) ExecEvalExpr(expr,
econtext,
&isNull,
- isDone);
-
- if ((IsA(expr, Iter)) && (*isDone))
- return (HeapTuple) NULL;
+ &itemIsDone[resind]);
values[resind] = constvalue;
@@ -1507,6 +1529,14 @@ ExecTargetList(List *targetlist,
null_head[resind] = ' ';
else
null_head[resind] = 'n';
+
+ if (IsA(expr, Iter))
+ {
+ if (itemIsDone[resind])
+ haveDoneIters = true;
+ else
+ *isDone = false; /* we have undone Iters in the list */
+ }
}
else
{
@@ -1518,6 +1548,8 @@ ExecTargetList(List *targetlist,
DatumPtr results = fjNode->fj_results;
ExecEvalFjoin(tle, econtext, fjIsNull, isDone);
+
+ /* this is probably wrong: */
if (*isDone)
return (HeapTuple) NULL;
@@ -1558,18 +1590,86 @@ ExecTargetList(List *targetlist,
}
}
+ if (haveDoneIters)
+ {
+ if (*isDone)
+ {
+ /* all Iters are done, so return a null indicating tlist set
+ * expansion is complete.
+ */
+ newTuple = NULL;
+ goto exit;
+ }
+ else
+ {
+ /* We have some done and some undone Iters. Restart the done ones
+ * so that we can deliver a tuple (if possible).
+ *
+ * XXX this code is a crock, because it only works for Iters at
+ * the top level of tlist expressions, and doesn't even work right
+ * for them: you should get all possible combinations of Iter
+ * results, but you won't unless the numbers of values returned by
+ * each are relatively prime. Should have a mechanism more like
+ * aggregate functions, where we make a list of all Iters
+ * contained in the tlist and cycle through their values in a
+ * methodical fashion. To do someday; can't get excited about
+ * fixing a Berkeley feature that's not in SQL92. (The only
+ * reason we're doing this much is that we have to be sure all
+ * the Iters are run to completion, or their subplan executors
+ * will have unreleased resources, e.g. pinned buffers...)
+ */
+ foreach(tl, targetlist)
+ {
+ tle = lfirst(tl);
+
+ if (tle->resdom != NULL)
+ {
+ expr = tle->expr;
+ resdom = tle->resdom;
+ resind = resdom->resno - 1;
+
+ if (IsA(expr, Iter) && itemIsDone[resind])
+ {
+ constvalue = (Datum) ExecEvalExpr(expr,
+ econtext,
+ &isNull,
+ &itemIsDone[resind]);
+ if (itemIsDone[resind])
+ {
+ /* Oh dear, this Iter is returning an empty set.
+ * Guess we can't make a tuple after all.
+ */
+ *isDone = true;
+ newTuple = NULL;
+ goto exit;
+ }
+
+ values[resind] = constvalue;
+
+ if (!isNull)
+ null_head[resind] = ' ';
+ else
+ null_head[resind] = 'n';
+ }
+ }
+ }
+ }
+ }
+
/*
* form the new result tuple (in the "normal" context)
*/
newTuple = (HeapTuple) heap_formtuple(targettype, values, null_head);
+exit:
/*
- * free the nulls array if we allocated one..
+ * free the status arrays if we palloc'd them
*/
if (nodomains > 64)
{
pfree(null_head);
pfree(fjIsNull);
+ pfree(itemIsDone);
}
return newTuple;
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 6e2e249c9a8..835dba7c5cd 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.29 1999/07/17 20:16:57 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.30 1999/09/24 00:24:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -38,9 +38,6 @@
* ExecSetSlotDescriptor - set a slot's tuple descriptor
* ExecSetSlotDescriptorIsNew - diddle the slot-desc-is-new flag
* ExecSetNewSlotDescriptor - set a desc and the is-new-flag all at once
- * ExecSlotBuffer - return buffer of tuple in slot
- * ExecSetSlotBuffer - set the buffer for tuple in slot
- * ExecIncrSlotBufferRefcnt - bump the refcnt of the slot buffer(Macro)
*
* SLOT STATUS PREDICATES
* TupIsNull - true when slot contains no tuple(Macro)
@@ -193,7 +190,7 @@ ExecDestroyTupleTable(TupleTable table, /* tuple table */
bool shouldFree) /* true if we should free slot
* contents */
{
- int next; /* next avaliable slot */
+ int next; /* next available slot */
TupleTableSlot *array; /* start of table array */
int i; /* counter */
@@ -212,38 +209,27 @@ ExecDestroyTupleTable(TupleTable table, /* tuple table */
/* ----------------
* first free all the valid pointers in the tuple array
- * if that's what the caller wants..
+ * and drop refcounts of any referenced buffers,
+ * if that's what the caller wants. (There is probably
+ * no good reason for the caller ever not to want it!)
*
- * Note: we do nothing about the Buffer and Tuple Descriptor's
+ * Note: we do nothing about the Tuple Descriptor's
* we store in the slots. This may have to change (ex: we should
* probably worry about pfreeing tuple descs too) -cim 3/14/91
+ *
+ * Right now, the handling of tuple pointers and buffer refcounts
+ * is clean, but the handling of tuple descriptors is NOT; they
+ * are copied around with wild abandon. It would take some work
+ * to make tuple descs pfree'able. Fortunately, since they're
+ * normally only made once per scan, it's probably not worth
+ * worrying about... tgl 9/21/99
* ----------------
*/
if (shouldFree)
+ {
for (i = 0; i < next; i++)
- {
- TupleTableSlot slot;
- HeapTuple tuple;
-
- slot = array[i];
- tuple = slot.val;
-
- if (tuple != NULL)
- {
- slot.val = (HeapTuple) NULL;
- if (slot.ttc_shouldFree)
- {
- /* ----------------
- * since a tuple may contain a pointer to
- * lock information allocated along with the
- * tuple, we have to be careful to free any
- * rule locks also -cim 1/17/90
- * ----------------
- */
- pfree(tuple);
- }
- }
- }
+ ExecClearTuple(&array[i]);
+ }
/* ----------------
* finally free the tuple array and the table itself.
@@ -274,6 +260,7 @@ TupleTableSlot * /* return: the slot allocated in the tuple
ExecAllocTableSlot(TupleTable table)
{
int slotnum; /* new slot number */
+ TupleTableSlot* slot;
/* ----------------
* sanity checks
@@ -319,9 +306,18 @@ ExecAllocTableSlot(TupleTable table)
slotnum = table->next;
table->next++;
- table->array[slotnum].type = T_TupleTableSlot;
+ slot = &(table->array[slotnum]);
+
+ /* Make sure the allocated slot is valid (and empty) */
+ slot->type = T_TupleTableSlot;
+ slot->val = (HeapTuple) NULL;
+ slot->ttc_shouldFree = true;
+ slot->ttc_descIsNew = true;
+ slot->ttc_tupleDescriptor = (TupleDesc) NULL;
+ slot->ttc_buffer = InvalidBuffer;
+ slot->ttc_whichplan = -1;
- return &(table->array[slotnum]);
+ return slot;
}
/* ----------------------------------------------------------------
@@ -333,26 +329,49 @@ ExecAllocTableSlot(TupleTable table)
* ExecStoreTuple
*
* This function is used to store a tuple into a specified
- * slot in the tuple table. Note: the only slots which should
- * be called with shouldFree == false are those slots used to
- * store tuples not allocated with pfree(). Currently the
- * seqscan and indexscan nodes use this for the tuples returned
- * by amgetattr, which are actually pointers onto disk pages.
+ * slot in the tuple table.
+ *
+ * tuple: tuple to store
+ * slot: slot to store it in
+ * buffer: disk buffer if tuple is in a disk page, else InvalidBuffer
+ * shouldFree: true if ExecClearTuple should pfree() the tuple
+ * when done with it
+ *
+ * If 'buffer' is not InvalidBuffer, the tuple table code acquires a pin
+ * on the buffer which is held until the slot is cleared, so that the tuple
+ * won't go away on us.
+ *
+ * shouldFree is normally set 'true' for tuples constructed on-the-fly.
+ * It must always be 'false' for tuples that are stored in disk pages,
+ * since we don't want to try to pfree those.
+ *
+ * Another case where it is 'false' is when the referenced tuple is held
+ * in a tuple table slot belonging to a lower-level executor Proc node.
+ * In this case the lower-level slot retains ownership and responsibility
+ * for eventually releasing the tuple. When this method is used, we must
+ * be certain that the upper-level Proc node will lose interest in the tuple
+ * sooner than the lower-level one does! If you're not certain, copy the
+ * lower-level tuple with heap_copytuple and let the upper-level table
+ * slot assume ownership of the copy!
+ *
+ * Return value is just the passed-in slot pointer.
* --------------------------------
*/
-TupleTableSlot * /* return: slot passed */
-ExecStoreTuple(HeapTuple tuple, /* tuple to store */
- TupleTableSlot *slot, /* slot in which to store tuple */
- Buffer buffer, /* buffer associated with tuple */
- bool shouldFree) /* true if we call pfree() when we gc. */
+TupleTableSlot *
+ExecStoreTuple(HeapTuple tuple,
+ TupleTableSlot *slot,
+ Buffer buffer,
+ bool shouldFree)
{
/* ----------------
* sanity checks
* ----------------
*/
Assert(slot != NULL);
+ /* passing shouldFree=true for a tuple on a disk page is not sane */
+ Assert(BufferIsValid(buffer) ? (!shouldFree) : true);
- /* clear out the slot first */
+ /* clear out any old contents of the slot */
ExecClearTuple(slot);
/* ----------------
@@ -364,6 +383,12 @@ ExecStoreTuple(HeapTuple tuple, /* tuple to store */
slot->ttc_buffer = buffer;
slot->ttc_shouldFree = shouldFree;
+ /* If tuple is on a disk page, keep the page pinned as long as we hold
+ * a pointer into it.
+ */
+ if (BufferIsValid(buffer))
+ IncrBufferRefCount(buffer);
+
return slot;
}
@@ -395,29 +420,20 @@ ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */
* ----------------
*/
if (slot->ttc_shouldFree && oldtuple != NULL)
- {
- /* ----------------
- * since a tuple may contain a pointer to
- * lock information allocated along with the
- * tuple, we have to be careful to free any
- * rule locks also -cim 1/17/90
- * ----------------
- */
pfree(oldtuple);
- }
+
+ slot->val = (HeapTuple) NULL;
+
+ slot->ttc_shouldFree = true; /* probably useless code... */
/* ----------------
- * store NULL into the specified slot and return the slot.
- * - also set buffer to InvalidBuffer -cim 3/14/91
+ * Drop the pin on the referenced buffer, if there is one.
* ----------------
*/
- slot->val = (HeapTuple) NULL;
-
if (BufferIsValid(slot->ttc_buffer))
ReleaseBuffer(slot->ttc_buffer);
slot->ttc_buffer = InvalidBuffer;
- slot->ttc_shouldFree = true;
return slot;
}
@@ -525,41 +541,6 @@ ExecSetNewSlotDescriptor(TupleTableSlot *slot, /* slot to change */
#endif
-/* --------------------------------
- * ExecSlotBuffer
- *
- * This function is used to get the tuple descriptor associated
- * with the slot's tuple. Be very careful with this as it does not
- * balance the reference counts. If the buffer returned is stored
- * someplace else, then also use ExecIncrSlotBufferRefcnt().
- *
- * Now a macro in tuptable.h
- * --------------------------------
- */
-
-/* --------------------------------
- * ExecSetSlotBuffer
- *
- * This function is used to set the tuple descriptor associated
- * with the slot's tuple. Be very careful with this as it does not
- * balance the reference counts. If we're using this then we should
- * also use ExecIncrSlotBufferRefcnt().
- * --------------------------------
- */
-#ifdef NOT_USED
-Buffer /* return: old slot buffer */
-ExecSetSlotBuffer(TupleTableSlot *slot, /* slot to change */
- Buffer b) /* tuple descriptor */
-{
- Buffer oldb = slot->ttc_buffer;
-
- slot->ttc_buffer = b;
-
- return oldb;
-}
-
-#endif
-
/* ----------------------------------------------------------------
* tuple table slot status predicates
* ----------------------------------------------------------------
@@ -601,12 +582,7 @@ ExecSlotDescriptorIsNew(TupleTableSlot *slot) /* slot to inspect */
#define INIT_SLOT_ALLOC \
tupleTable = (TupleTable) estate->es_tupleTable; \
- slot = ExecAllocTableSlot(tupleTable); \
- slot->val = (HeapTuple)NULL; \
- slot->ttc_shouldFree = true; \
- slot->ttc_tupleDescriptor = (TupleDesc)NULL; \
- slot->ttc_whichplan = -1;\
- slot->ttc_descIsNew = true;
+ slot = ExecAllocTableSlot(tupleTable);
/* ----------------
* ExecInitResultTupleSlot
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index bd515d51f97..f20d9c56bc6 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.25 1999/09/18 19:06:48 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.26 1999/09/24 00:24:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -399,12 +399,13 @@ ExecProcAppend(Append *node)
{
/* ----------------
* if the subplan gave us something then place a copy of
- * whatever we get into our result slot and return it, else..
+ * whatever we get into our result slot and return it.
+ *
+ * Note we rely on the subplan to retain ownership of the
+ * tuple for as long as we need it --- we don't copy it.
* ----------------
*/
- return ExecStoreTuple(result->val,
- result_slot, result->ttc_buffer, false);
-
+ return ExecStoreTuple(result->val, result_slot, InvalidBuffer, false);
}
else
{
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index f856d4780bc..38f7a0365db 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -13,7 +13,7 @@
* columns. (ie. tuples from the same group are consecutive)
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.29 1999/07/17 20:16:58 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.30 1999/09/24 00:24:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -91,10 +91,12 @@ ExecGroupEveryTuple(Group *node)
{
grpstate->grp_useFirstTuple = FALSE;
+ /* note we rely on subplan to hold ownership of the tuple
+ * for as long as we need it; we don't copy it.
+ */
ExecStoreTuple(grpstate->grp_firstTuple,
grpstate->csstate.css_ScanTupleSlot,
- InvalidBuffer,
- false);
+ InvalidBuffer, false);
}
else
{
@@ -129,10 +131,12 @@ ExecGroupEveryTuple(Group *node)
}
}
+ /* note we rely on subplan to hold ownership of the tuple
+ * for as long as we need it; we don't copy it.
+ */
ExecStoreTuple(outerTuple,
grpstate->csstate.css_ScanTupleSlot,
- outerslot->ttc_buffer,
- false);
+ InvalidBuffer, false);
}
/* ----------------
@@ -226,10 +230,12 @@ ExecGroupOneTuple(Group *node)
*/
projInfo = grpstate->csstate.cstate.cs_ProjInfo;
+ /* note we rely on subplan to hold ownership of the tuple
+ * for as long as we need it; we don't copy it.
+ */
ExecStoreTuple(firsttuple,
grpstate->csstate.css_ScanTupleSlot,
- InvalidBuffer,
- false);
+ InvalidBuffer, false);
econtext->ecxt_scantuple = grpstate->csstate.css_ScanTupleSlot;
resultSlot = ExecProject(projInfo, &isDone);
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 362851a425a..b9e3cf58636 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.42 1999/08/12 00:42:43 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.43 1999/09/24 00:24:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -125,14 +125,14 @@ IndexNext(IndexScan *node)
{
int iptr;
- slot->ttc_buffer = InvalidBuffer;
- slot->ttc_shouldFree = false;
+ ExecClearTuple(slot);
if (estate->es_evTupleNull[node->scan.scanrelid - 1])
- {
- slot->val = NULL; /* must not free tuple! */
- return (slot);
- }
+ return slot; /* return empty slot */
+
+ /* probably ought to use ExecStoreTuple here... */
slot->val = estate->es_evTuple[node->scan.scanrelid - 1];
+ slot->ttc_shouldFree = false;
+
for (iptr = 0; iptr < numIndices; iptr++)
{
scanstate->cstate.cs_ExprContext->ecxt_scantuple = slot;
@@ -142,6 +142,7 @@ IndexNext(IndexScan *node)
}
if (iptr == numIndices) /* would not be returned by indices */
slot->val = NULL;
+
/* Flag for the next call that no more tuples */
estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
return (slot);
@@ -192,7 +193,7 @@ IndexNext(IndexScan *node)
* the scan state. Eventually we will only do this and not
* return a tuple. Note: we pass 'false' because tuples
* returned by amgetnext are pointers onto disk pages and
- * were not created with palloc() and so should not be pfree()'d.
+ * must not be pfree()'d.
* ----------------
*/
ExecStoreTuple(tuple, /* tuple to store */
@@ -201,6 +202,13 @@ IndexNext(IndexScan *node)
false); /* don't pfree */
/*
+ * At this point we have an extra pin on the buffer,
+ * because ExecStoreTuple incremented the pin count.
+ * Drop our local pin.
+ */
+ ReleaseBuffer(buffer);
+
+ /*
* We must check to see if the current tuple would have
* been matched by an earlier index, so we don't double
* report it. We do this by passing the tuple through
@@ -223,8 +231,6 @@ IndexNext(IndexScan *node)
else
ExecClearTuple(slot);
}
- if (BufferIsValid(buffer))
- ReleaseBuffer(buffer);
}
if (indexNumber < numIndices)
{
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index 783dbc7b328..24232617cf6 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.25 1999/07/16 04:58:50 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.26 1999/09/24 00:24:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -31,7 +31,7 @@
* ExecMaterial
*
* The first time this is called, ExecMaterial retrieves tuples
- * this node's outer subplan and inserts them into a temporary
+ * from this node's outer subplan and inserts them into a temporary
* relation. After this is done, a flag is set indicating that
* the subplan has been materialized. Once the relation is
* materialized, the first tuple is then returned. Successive
@@ -41,7 +41,7 @@
* Initial State:
*
* ExecMaterial assumes the temporary relation has been
- * created and openend by ExecInitMaterial during the prior
+ * created and opened by ExecInitMaterial during the prior
* InitPlan() phase.
*
* ----------------------------------------------------------------
@@ -116,18 +116,7 @@ ExecMaterial(Material *node)
if (TupIsNull(slot))
break;
- /*
- * heap_insert changes something...
- */
- if (slot->ttc_buffer != InvalidBuffer)
- heapTuple = heap_copytuple(slot->val);
- else
- heapTuple = slot->val;
-
- heap_insert(tempRelation, heapTuple);
-
- if (slot->ttc_buffer != InvalidBuffer)
- pfree(heapTuple);
+ heap_insert(tempRelation, slot->val);
ExecClearTuple(slot);
}
@@ -164,7 +153,7 @@ ExecMaterial(Material *node)
/* ----------------
* at this point we know we have a sorted relation so
- * we preform a simple scan on it with amgetnext()..
+ * we perform a simple scan on it with amgetnext()..
* ----------------
*/
currentScanDesc = matstate->csstate.css_currentScanDesc;
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 62b53af3c65..4b3f021fe0c 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.28 1999/07/16 04:58:50 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.29 1999/09/24 00:24:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1153,15 +1153,18 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
#define MERGEJOIN_NSLOTS 2
/* ----------------
* tuple table initialization
+ *
+ * XXX why aren't we getting a tuple table slot in the normal way?
* ----------------
*/
ExecInitResultTupleSlot(estate, &mergestate->jstate);
- mjSlot = (TupleTableSlot *) palloc(sizeof(TupleTableSlot));
+ mjSlot = makeNode(TupleTableSlot);
mjSlot->val = NULL;
mjSlot->ttc_shouldFree = true;
+ mjSlot->ttc_descIsNew = true;
mjSlot->ttc_tupleDescriptor = NULL;
+ mjSlot->ttc_buffer = InvalidBuffer;
mjSlot->ttc_whichplan = -1;
- mjSlot->ttc_descIsNew = true;
mergestate->mj_MarkedTupleSlot = mjSlot;
/* ----------------
@@ -1278,11 +1281,9 @@ ExecReScanMergeJoin(MergeJoin *node, ExprContext *exprCtxt, Plan *parent)
TupleTableSlot *mjSlot = mergestate->mj_MarkedTupleSlot;
ExecClearTuple(mjSlot);
- mjSlot->val = NULL;
- mjSlot->ttc_shouldFree = true;
mjSlot->ttc_tupleDescriptor = NULL;
- mjSlot->ttc_whichplan = -1;
mjSlot->ttc_descIsNew = true;
+ mjSlot->ttc_whichplan = -1;
mergestate->mj_JoinState = EXEC_MJ_INITIALIZE;
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index c83aa725a70..eb73733b58f 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.20 1999/07/16 04:58:52 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.21 1999/09/24 00:24:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -74,20 +74,20 @@ SeqNext(SeqScan *node)
if (estate->es_evTuple != NULL &&
estate->es_evTuple[node->scanrelid - 1] != NULL)
{
- slot->ttc_buffer = InvalidBuffer;
- slot->ttc_shouldFree = false;
+ ExecClearTuple(slot);
if (estate->es_evTupleNull[node->scanrelid - 1])
- {
- slot->val = NULL; /* must not free tuple! */
- return (slot);
- }
+ return slot; /* return empty slot */
+
+ /* probably ought to use ExecStoreTuple here... */
slot->val = estate->es_evTuple[node->scanrelid - 1];
+ slot->ttc_shouldFree = false;
/*
* Note that unlike IndexScan, SeqScan never use keys in
- * heap_beginscan (and this is very bad) - so, here we have not
+ * heap_beginscan (and this is very bad) - so, here we do not
* check are keys ok or not.
*/
+
/* Flag for the next call that no more tuples */
estate->es_evTupleNull[node->scanrelid - 1] = true;
return (slot);
@@ -104,7 +104,9 @@ SeqNext(SeqScan *node)
* in our scan tuple slot and return the slot. Note: we pass 'false'
* because tuples returned by heap_getnext() are pointers onto
* disk pages and were not created with palloc() and so should not
- * be pfree()'d.
+ * be pfree()'d. Note also that ExecStoreTuple will increment the
+ * refcount of the buffer; the refcount will not be dropped until
+ * the tuple table slot is cleared.
* ----------------
*/
@@ -114,17 +116,6 @@ SeqNext(SeqScan *node)
* this tuple */
false); /* don't pfree this pointer */
- /* ----------------
- * XXX -- mao says: The sequential scan for heap relations will
- * automatically unpin the buffer this tuple is on when we cross
- * a page boundary. The clearslot code also does this. We bump
- * the pin count on the page here, since we actually have two
- * pointers to it -- one in the scan desc and one in the tuple
- * table slot. --mar 20 91
- * ----------------
- */
- ExecIncrSlotBufferRefcnt(slot);
-
return slot;
}
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index 4bd0eb2ff31..32a39ee18d9 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -165,8 +165,6 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
sp_estate->es_tupleTable =
ExecCreateTupleTable(ExecCountSlotsNode(node->plan) + 10);
- pfree(sp_estate->es_refcount);
- sp_estate->es_refcount = estate->es_refcount;
sp_estate->es_snapshot = estate->es_snapshot;
if (!ExecInitNode(node->plan, sp_estate, NULL))