aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execTuples.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execTuples.c')
-rw-r--r--src/backend/executor/execTuples.c254
1 files changed, 107 insertions, 147 deletions
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 2864589ebb3..8574efc95d8 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.83 2004/12/31 21:59:45 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.84 2005/03/14 04:41:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -31,13 +31,11 @@
*
* SLOT ACCESSORS
* ExecStoreTuple - store a tuple in the table
- * ExecFetchTuple - fetch a tuple from the table
* ExecClearTuple - clear contents of a table slot
* ExecSetSlotDescriptor - set a slot's tuple descriptor
- * ExecSetSlotDescriptorIsNew - diddle the slot-desc-is-new flag
*
* SLOT STATUS PREDICATES
- * TupIsNull - true when slot contains no tuple(Macro)
+ * TupIsNull - true when slot contains no tuple (macro)
*
* CONVENIENCE INITIALIZATION ROUTINES
* ExecInitResultTupleSlot \ convenience routines to initialize
@@ -60,7 +58,7 @@
* - ExecInitSeqScan() calls ExecInitScanTupleSlot() and
* ExecInitResultTupleSlot() to reserve places in the tuple
* table for the tuples returned by the access methods and the
- * tuples resulting from preforming target list projections.
+ * tuples resulting from performing target list projections.
*
* During ExecRun()
* ----------------
@@ -71,8 +69,8 @@
* 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
- * is then returned.
+ * the slot passed to it (by direct access to slot->val, which is
+ * ugly but not worth changing). this tuple is then returned.
*
* At ExecEnd()
* ----------------
@@ -87,23 +85,6 @@
* this information is also kept in the ExprContext of each node.
* Soon the executor will be redesigned and ExprContext's will contain
* only slot pointers. -cim 3/14/91
- *
- * NOTES
- * The tuple table stuff is relatively new, put here to alleviate
- * the process growth problems in the executor. The other routines
- * are old (from the original lisp system) and may someday become
- * obsolete. -cim 6/23/90
- *
- * In the implementation of nested-dot queries such as
- * "retrieve (EMP.hobbies.all)", a single scan may return tuples
- * of many types, so now we return pointers to tuple descriptors
- * along with tuples returned via the tuple table. This means
- * we now have a bunch of routines to diddle the slot descriptors
- * too. -cim 1/18/90
- *
- * The tuple table stuff depends on the executor/tuptable.h macros,
- * and the TupleTableSlot node in execnodes.h.
- *
*/
#include "postgres.h"
@@ -124,43 +105,52 @@ static TupleDesc ExecTypeFromTLInternal(List *targetList,
* tuple table create/delete functions
* ----------------------------------------------------------------
*/
+
/* --------------------------------
* ExecCreateTupleTable
*
- * This creates a new tuple table of the specified initial
- * size. If the size is insufficient, ExecAllocTableSlot()
- * will grow the table as necessary.
+ * This creates a new tuple table of the specified size.
*
* This should be used by InitPlan() to allocate the table.
* The table's address will be stored in the EState structure.
* --------------------------------
*/
-TupleTable /* return: address of table */
-ExecCreateTupleTable(int initialSize) /* initial number of slots in
- * table */
+TupleTable
+ExecCreateTupleTable(int tableSize)
{
- TupleTable newtable; /* newly allocated table */
- TupleTableSlot *array; /* newly allocated slot array */
+ TupleTable newtable;
+ int i;
/*
* sanity checks
*/
- Assert(initialSize >= 1);
+ Assert(tableSize >= 1);
/*
- * Now allocate our new table along with space for the pointers to the
- * tuples. Zero out the slots.
+ * allocate the table itself
*/
-
- newtable = (TupleTable) palloc(sizeof(TupleTableData));
- array = (TupleTableSlot *) palloc0(initialSize * sizeof(TupleTableSlot));
+ newtable = (TupleTable) palloc(sizeof(TupleTableData) +
+ (tableSize - 1) * sizeof(TupleTableSlot));
+ newtable->size = tableSize;
+ newtable->next = 0;
/*
- * initialize the new table and return it to the caller.
+ * initialize all the slots to empty states
*/
- newtable->size = initialSize;
- newtable->next = 0;
- newtable->array = array;
+ for (i = 0; i < tableSize; i++)
+ {
+ TupleTableSlot *slot = &(newtable->array[i]);
+
+ slot->type = T_TupleTableSlot;
+ slot->val = NULL;
+ slot->ttc_tupleDescriptor = NULL;
+ slot->ttc_shouldFree = false;
+ slot->ttc_shouldFreeDesc = false;
+ slot->ttc_buffer = InvalidBuffer;
+ slot->ttc_mcxt = CurrentMemoryContext;
+ slot->cache_values = NULL;
+ slot->cache_natts = 0; /* mark slot_getattr state invalid */
+ }
return newtable;
}
@@ -178,22 +168,12 @@ ExecDropTupleTable(TupleTable table, /* tuple table */
bool shouldFree) /* true if we should free slot
* contents */
{
- int next; /* next available slot */
- TupleTableSlot *array; /* start of table array */
- int i; /* counter */
-
/*
* sanity checks
*/
Assert(table != NULL);
/*
- * get information from the table
- */
- array = table->array;
- next = table->next;
-
- /*
* first free all the valid pointers in the tuple array 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
@@ -201,27 +181,60 @@ ExecDropTupleTable(TupleTable table, /* tuple table */
*/
if (shouldFree)
{
+ int next = table->next;
+ int i;
+
for (i = 0; i < next; i++)
{
- ExecClearTuple(&array[i]);
- if (array[i].ttc_shouldFreeDesc &&
- array[i].ttc_tupleDescriptor != NULL)
- FreeTupleDesc(array[i].ttc_tupleDescriptor);
+ TupleTableSlot *slot = &(table->array[i]);
+
+ ExecClearTuple(slot);
+ if (slot->ttc_shouldFreeDesc)
+ FreeTupleDesc(slot->ttc_tupleDescriptor);
+ if (slot->cache_values)
+ pfree(slot->cache_values);
}
}
/*
- * finally free the tuple array and the table itself.
+ * finally free the tuple table itself.
*/
- pfree(array);
pfree(table);
}
+/* --------------------------------
+ * MakeTupleTableSlot
+ *
+ * This routine makes an empty standalone TupleTableSlot.
+ * It really shouldn't exist, but there are a few places
+ * that do this, so we may as well centralize the knowledge
+ * of what's in one ...
+ * --------------------------------
+ */
+TupleTableSlot *
+MakeTupleTableSlot(void)
+{
+ TupleTableSlot *slot = makeNode(TupleTableSlot);
+
+ /* This should match ExecCreateTupleTable() */
+ slot->val = NULL;
+ slot->ttc_tupleDescriptor = NULL;
+ slot->ttc_shouldFree = false;
+ slot->ttc_shouldFreeDesc = false;
+ slot->ttc_buffer = InvalidBuffer;
+ slot->ttc_mcxt = CurrentMemoryContext;
+ slot->cache_values = NULL;
+ slot->cache_natts = 0; /* mark slot_getattr state invalid */
+
+ return slot;
+}
+
/* ----------------------------------------------------------------
* tuple table slot reservation functions
* ----------------------------------------------------------------
*/
+
/* --------------------------------
* ExecAllocTableSlot
*
@@ -236,7 +249,6 @@ TupleTableSlot *
ExecAllocTableSlot(TupleTable table)
{
int slotnum; /* new slot number */
- TupleTableSlot *slot;
/*
* sanity checks
@@ -244,66 +256,17 @@ ExecAllocTableSlot(TupleTable table)
Assert(table != NULL);
/*
- * if our table is full we have to allocate a larger size table. Since
- * ExecAllocTableSlot() is only called before the table is ever used
- * to store tuples, we don't have to worry about the contents of the
- * old table. If this changes, then we will have to preserve the
- * contents. -cim 6/23/90
- *
- * Unfortunately, we *cannot* do this. All of the nodes in the plan that
- * have already initialized their slots will have 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. Fail if it does.
- * -mer 4 Aug 1992
+ * We expect that the table was made big enough to begin with.
+ * We cannot reallocate it on the fly since previous plan nodes
+ * have already got pointers to individual entries.
*/
if (table->next >= table->size)
elog(ERROR, "plan requires more slots than are available");
- /*
- * at this point, space in the table is guaranteed so we reserve the
- * next slot, initialize and return it.
- */
slotnum = table->next;
table->next++;
- slot = &(table->array[slotnum]);
-
- /* Make sure the allocated slot is valid (and empty) */
- slot->type = T_TupleTableSlot;
- slot->val = NULL;
- slot->ttc_shouldFree = true;
- slot->ttc_descIsNew = true;
- slot->ttc_shouldFreeDesc = true;
- slot->ttc_tupleDescriptor = NULL;
- slot->ttc_buffer = InvalidBuffer;
-
- return slot;
-}
-
-/* --------------------------------
- * MakeTupleTableSlot
- *
- * This routine makes an empty standalone TupleTableSlot.
- * It really shouldn't exist, but there are a few places
- * that do this, so we may as well centralize the knowledge
- * of what's in one ...
- * --------------------------------
- */
-TupleTableSlot *
-MakeTupleTableSlot(void)
-{
- TupleTableSlot *slot = makeNode(TupleTableSlot);
-
- /* This should match ExecAllocTableSlot() */
- slot->val = NULL;
- slot->ttc_shouldFree = true;
- slot->ttc_descIsNew = true;
- slot->ttc_shouldFreeDesc = true;
- slot->ttc_tupleDescriptor = NULL;
- slot->ttc_buffer = InvalidBuffer;
-
- return slot;
+ return &(table->array[slotnum]);
}
/* ----------------------------------------------------------------
@@ -356,21 +319,22 @@ ExecStoreTuple(HeapTuple tuple,
/* passing shouldFree=true for a tuple on a disk page is not sane */
Assert(BufferIsValid(buffer) ? (!shouldFree) : true);
- /* clear out any old contents of the slot */
+ /*
+ * clear out any old contents of the slot
+ */
ExecClearTuple(slot);
/*
- * store the new tuple into the specified slot and return the slot
- * into which we stored the tuple.
+ * store the new tuple into the specified slot.
*/
slot->val = tuple;
- 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.
+ * a pointer into it. We assume the caller already has such a pin.
*/
+ slot->ttc_buffer = buffer;
if (BufferIsValid(buffer))
IncrBufferRefCount(buffer);
@@ -388,27 +352,23 @@ ExecStoreTuple(HeapTuple tuple,
TupleTableSlot * /* return: slot passed */
ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */
{
- HeapTuple oldtuple; /* prior contents of slot */
-
/*
* sanity checks
*/
Assert(slot != NULL);
/*
- * get information from the tuple table
- */
- oldtuple = slot->val;
-
- /*
- * free the old contents of the specified slot if necessary.
+ * Free the old contents of the specified slot if necessary. (Note:
+ * we allow slot->val to be null even when shouldFree is true, because
+ * there are a few callers of ExecStoreTuple that are too lazy to
+ * distinguish whether they are passing a NULL tuple, and always pass
+ * shouldFree = true.)
*/
- if (slot->ttc_shouldFree && oldtuple != NULL)
- heap_freetuple(oldtuple);
+ if (slot->ttc_shouldFree && slot->val != NULL)
+ heap_freetuple(slot->val);
slot->val = NULL;
-
- slot->ttc_shouldFree = true; /* probably useless code... */
+ slot->ttc_shouldFree = false;
/*
* Drop the pin on the referenced buffer, if there is one.
@@ -418,6 +378,11 @@ ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */
slot->ttc_buffer = InvalidBuffer;
+ /*
+ * mark slot_getattr state invalid
+ */
+ slot->cache_natts = 0;
+
return slot;
}
@@ -433,36 +398,31 @@ ExecSetSlotDescriptor(TupleTableSlot *slot, /* slot to change */
TupleDesc tupdesc, /* new tuple descriptor */
bool shouldFree) /* is desc owned by slot? */
{
- if (slot->ttc_shouldFreeDesc &&
- slot->ttc_tupleDescriptor != NULL)
+ if (slot->ttc_shouldFreeDesc)
FreeTupleDesc(slot->ttc_tupleDescriptor);
slot->ttc_tupleDescriptor = tupdesc;
slot->ttc_shouldFreeDesc = shouldFree;
-}
-/* --------------------------------
- * ExecSetSlotDescriptorIsNew
- *
- * This function is used to change the setting of the "isNew" flag
- * --------------------------------
- */
-void
-ExecSetSlotDescriptorIsNew(TupleTableSlot *slot, /* slot to change */
- bool isNew) /* "isNew" setting */
-{
- slot->ttc_descIsNew = isNew;
+ /*
+ * mark slot_getattr state invalid
+ */
+ slot->cache_natts = 0;
+
+ /*
+ * release any old cache array since tupledesc's natts may have changed
+ */
+ if (slot->cache_values)
+ pfree(slot->cache_values);
+ slot->cache_values = NULL;
}
-/* ----------------------------------------------------------------
- * tuple table slot status predicates
- * ----------------------------------------------------------------
- */
/* ----------------------------------------------------------------
* convenience initialization routines
* ----------------------------------------------------------------
*/
+
/* --------------------------------
* ExecInit{Result,Scan,Extra}TupleSlot
*