*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.96 2005/01/27 23:23:49 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.97 2005/03/14 04:41:12 tgl Exp $
*
* NOTES
* The old interface functions have been converted to macros
#include "access/heapam.h"
#include "access/tuptoaster.h"
#include "catalog/pg_type.h"
+#include "executor/tuptable.h"
/* ----------------------------------------------------------------
char *nulls)
{
HeapTupleHeader tup = tuple->t_data;
+ bool hasnulls = HeapTupleHasNulls(tuple);
Form_pg_attribute *att = tupleDesc->attrs;
int tdesc_natts = tupleDesc->natts;
int natts; /* number of atts to extract */
for (attnum = 0; attnum < natts; attnum++)
{
- if (HeapTupleHasNulls(tuple) && att_isnull(attnum, bp))
+ Form_pg_attribute thisatt = att[attnum];
+
+ if (hasnulls && att_isnull(attnum, bp))
{
values[attnum] = (Datum) 0;
nulls[attnum] = 'n';
nulls[attnum] = ' ';
- if (!slow && att[attnum]->attcacheoff >= 0)
- off = att[attnum]->attcacheoff;
+ if (!slow && thisatt->attcacheoff >= 0)
+ off = thisatt->attcacheoff;
else
{
- off = att_align(off, att[attnum]->attalign);
+ off = att_align(off, thisatt->attalign);
if (!slow)
- att[attnum]->attcacheoff = off;
+ thisatt->attcacheoff = off;
}
- values[attnum] = fetchatt(att[attnum], tp + off);
+ values[attnum] = fetchatt(thisatt, tp + off);
- off = att_addlength(off, att[attnum]->attlen, tp + off);
+ off = att_addlength(off, thisatt->attlen, tp + off);
- if (att[attnum]->attlen <= 0)
+ if (thisatt->attlen <= 0)
slow = true; /* can't use attcacheoff anymore */
}
}
/* ----------------
+ * slot_deformtuple
+ *
+ * Given a TupleTableSlot, extract data into cache_values array
+ * from the slot's tuple.
+ *
+ * This is essentially an incremental version of heap_deformtuple:
+ * on each call we extract attributes up to the one needed, without
+ * re-computing information about previously extracted attributes.
+ * slot->cache_natts is the number of attributes already extracted.
+ *
+ * This only gets called from slot_getattr. Note that slot_getattr
+ * must check for a null attribute since we don't create an array
+ * of null indicators.
+ * ----------------
+ */
+static void
+slot_deformtuple(TupleTableSlot *slot, int natts)
+{
+ HeapTuple tuple = slot->val;
+ TupleDesc tupleDesc = slot->ttc_tupleDescriptor;
+ Datum *values = slot->cache_values;
+ HeapTupleHeader tup = tuple->t_data;
+ bool hasnulls = HeapTupleHasNulls(tuple);
+ Form_pg_attribute *att = tupleDesc->attrs;
+ int attnum;
+ char *tp; /* ptr to tuple data */
+ long off; /* offset in tuple data */
+ bits8 *bp = tup->t_bits; /* ptr to null bitmask in tuple */
+ bool slow; /* can we use/set attcacheoff? */
+
+ /*
+ * Check whether the first call for this tuple, and initialize or
+ * restore loop state.
+ */
+ attnum = slot->cache_natts;
+ if (attnum == 0)
+ {
+ /* Start from the first attribute */
+ off = 0;
+ slow = false;
+ }
+ else
+ {
+ /* Restore state from previous execution */
+ off = slot->cache_off;
+ slow = slot->cache_slow;
+ }
+
+ tp = (char *) tup + tup->t_hoff;
+
+ for (; attnum < natts; attnum++)
+ {
+ Form_pg_attribute thisatt = att[attnum];
+
+ if (hasnulls && att_isnull(attnum, bp))
+ {
+ values[attnum] = (Datum) 0;
+ slow = true; /* can't use attcacheoff anymore */
+ continue;
+ }
+
+ if (!slow && thisatt->attcacheoff >= 0)
+ off = thisatt->attcacheoff;
+ else
+ {
+ off = att_align(off, thisatt->attalign);
+
+ if (!slow)
+ thisatt->attcacheoff = off;
+ }
+
+ values[attnum] = fetchatt(thisatt, tp + off);
+
+ off = att_addlength(off, thisatt->attlen, tp + off);
+
+ if (thisatt->attlen <= 0)
+ slow = true; /* can't use attcacheoff anymore */
+ }
+
+ /*
+ * Save state for next execution
+ */
+ slot->cache_natts = attnum;
+ slot->cache_off = off;
+ slot->cache_slow = slow;
+}
+
+/* --------------------------------
+ * slot_getattr
+ *
+ * This function fetches an attribute of the slot's current tuple.
+ * It is functionally equivalent to heap_getattr, but fetches of
+ * multiple attributes of the same tuple will be optimized better,
+ * because we avoid O(N^2) behavior from multiple calls of
+ * nocachegetattr(), even when attcacheoff isn't usable.
+ * --------------------------------
+ */
+Datum
+slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
+{
+ HeapTuple tuple = slot->val;
+ TupleDesc tupleDesc = slot->ttc_tupleDescriptor;
+ HeapTupleHeader tup;
+
+ /*
+ * system attributes are handled by heap_getsysattr
+ */
+ if (attnum <= 0)
+ return heap_getsysattr(tuple, attnum, tupleDesc, isnull);
+
+ /*
+ * check if attnum is out of range according to either the tupdesc
+ * or the tuple itself; if so return NULL
+ */
+ tup = tuple->t_data;
+
+ if (attnum > tup->t_natts || attnum > tupleDesc->natts)
+ {
+ *isnull = true;
+ return (Datum) 0;
+ }
+
+ /*
+ * check if target attribute is null
+ */
+ if (HeapTupleHasNulls(tuple) && att_isnull(attnum - 1, tup->t_bits))
+ {
+ *isnull = true;
+ return (Datum) 0;
+ }
+
+ /*
+ * If the attribute's column has been dropped, we force a NULL
+ * result. This case should not happen in normal use, but it could
+ * happen if we are executing a plan cached before the column was
+ * dropped.
+ */
+ if (tupleDesc->attrs[attnum - 1]->attisdropped)
+ {
+ *isnull = true;
+ return (Datum) 0;
+ }
+
+ /*
+ * If attribute wasn't already extracted, extract it and preceding
+ * attributes.
+ */
+ if (attnum > slot->cache_natts)
+ {
+ /*
+ * If first time for this TupleTableSlot, allocate the cache
+ * workspace. It must have the same lifetime as the slot, so allocate
+ * it in the slot's own context. We size the array according to what
+ * the tupdesc says, NOT the tuple.
+ */
+ if (slot->cache_values == NULL)
+ slot->cache_values = (Datum *)
+ MemoryContextAlloc(slot->ttc_mcxt,
+ tupleDesc->natts * sizeof(Datum));
+
+ slot_deformtuple(slot, attnum);
+ }
+
+ /*
+ * The result is acquired from cache_values array.
+ */
+ *isnull = false;
+ return slot->cache_values[attnum - 1];
+}
+
+/* ----------------
* heap_freetuple
* ----------------
*/
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.47 2005/01/01 05:43:06 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.48 2005/03/14 04:41:12 tgl Exp $
*
*
* INTERFACE ROUTINES
/*
* Have a chunk, extract the sequence number and the data
*/
- residx = DatumGetInt32(heap_getattr(ttup, 2, toasttupDesc, &isnull));
+ residx = DatumGetInt32(fastgetattr(ttup, 2, toasttupDesc, &isnull));
Assert(!isnull);
- chunk = DatumGetPointer(heap_getattr(ttup, 3, toasttupDesc, &isnull));
+ chunk = DatumGetPointer(fastgetattr(ttup, 3, toasttupDesc, &isnull));
Assert(!isnull);
chunksize = VARATT_SIZE(chunk) - VARHDRSZ;
/*
* Have a chunk, extract the sequence number and the data
*/
- residx = DatumGetInt32(heap_getattr(ttup, 2, toasttupDesc, &isnull));
+ residx = DatumGetInt32(fastgetattr(ttup, 2, toasttupDesc, &isnull));
Assert(!isnull);
- chunk = DatumGetPointer(heap_getattr(ttup, 3, toasttupDesc, &isnull));
+ chunk = DatumGetPointer(fastgetattr(ttup, 3, toasttupDesc, &isnull));
Assert(!isnull);
chunksize = VARATT_SIZE(chunk) - VARHDRSZ;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execJunk.c,v 1.46 2004/12/31 21:59:45 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execJunk.c,v 1.47 2005/03/14 04:41:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
Datum *value,
bool *isNull)
{
- List *targetList;
ListCell *t;
- AttrNumber resno;
- TupleDesc tupType;
- HeapTuple tuple;
/*
- * first look in the junkfilter's target list for an attribute with
+ * Look in the junkfilter's target list for an attribute with
* the given name
*/
- resno = InvalidAttrNumber;
- targetList = junkfilter->jf_targetList;
-
- foreach(t, targetList)
+ foreach(t, junkfilter->jf_targetList)
{
TargetEntry *tle = lfirst(t);
Resdom *resdom = tle->resdom;
(strcmp(resdom->resname, attrName) == 0))
{
/* We found it ! */
- resno = resdom->resno;
- break;
+ *value = slot_getattr(slot, resdom->resno, isNull);
+ return true;
}
}
- if (resno == InvalidAttrNumber)
- {
- /* Ooops! We couldn't find this attribute... */
- return false;
- }
-
- /*
- * Now extract the attribute value from the tuple.
- */
- tuple = slot->val;
- tupType = slot->ttc_tupleDescriptor;
-
- *value = heap_getattr(tuple, resno, tupType, isNull);
-
- return true;
+ /* Ooops! We couldn't find this attribute... */
+ return false;
}
/*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.171 2004/12/31 21:59:45 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.172 2005/03/14 04:41:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
bool *isNull, ExprDoneCond *isDone)
{
Var *variable = (Var *) exprstate->expr;
- Datum result;
TupleTableSlot *slot;
AttrNumber attnum;
- HeapTuple heapTuple;
- TupleDesc tuple_type;
if (isDone)
*isDone = ExprSingleResult;
break;
}
- /*
- * extract tuple information from the slot
- */
- heapTuple = slot->val;
- tuple_type = slot->ttc_tupleDescriptor;
-
+#ifdef USE_ASSERT_CHECKING
/*
* Some checks that are only applied for user attribute numbers (bogus
- * system attnums will be caught inside heap_getattr).
+ * system attnums will be caught inside slot_getattr).
*/
if (attnum > 0)
{
- /*
- * This assert checks that the attnum is valid.
- */
- Assert(attnum <= tuple_type->natts &&
- tuple_type->attrs[attnum - 1] != NULL);
+ TupleDesc tuple_type = slot->ttc_tupleDescriptor;
/*
- * If the attribute's column has been dropped, we force a NULL
- * result. This case should not happen in normal use, but it could
- * happen if we are executing a plan cached before the column was
- * dropped.
+ * This assert checks that the attnum is valid.
*/
- if (tuple_type->attrs[attnum - 1]->attisdropped)
- {
- *isNull = true;
- return (Datum) 0;
- }
+ Assert(attnum <= tuple_type->natts);
/*
* This assert checks that the datatype the plan expects to get
* Note that we can't check dropped columns, since their atttypid has
* been zeroed.
*/
- Assert(variable->vartype == tuple_type->attrs[attnum - 1]->atttypid);
+ Assert(variable->vartype == tuple_type->attrs[attnum - 1]->atttypid ||
+ tuple_type->attrs[attnum - 1]->attisdropped);
}
+#endif /* USE_ASSERT_CHECKING */
- result = heap_getattr(heapTuple, /* tuple containing attribute */
- attnum, /* attribute number of desired
- * attribute */
- tuple_type, /* tuple descriptor of tuple */
- isNull); /* return: is attribute null? */
-
- return result;
+ return slot_getattr(slot, attnum, isNull);
}
/* ----------------------------------------------------------------
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
*
* 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
* - 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()
* ----------------
* 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()
* ----------------
* 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"
* 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;
}
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
*/
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
*
ExecAllocTableSlot(TupleTable table)
{
int slotnum; /* new slot number */
- TupleTableSlot *slot;
/*
* sanity checks
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]);
}
/* ----------------------------------------------------------------
/* 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);
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.
slot->ttc_buffer = InvalidBuffer;
+ /*
+ * mark slot_getattr state invalid
+ */
+ slot->cache_natts = 0;
+
return slot;
}
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
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.94 2005/01/27 23:24:11 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.95 2005/03/14 04:41:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* ----------------
*/
-extern Datum nocachegetattr(HeapTuple tup, int attnum,
- TupleDesc att, bool *isnull);
-
#if !defined(DISABLE_COMPLEX_MACRO)
#define fastgetattr(tup, attnum, tupleDesc, isnull) \
) \
)
-extern Datum heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
- bool *isnull);
-
/* ----------------
* function prototypes for heap access method
extern int heap_attisnull(HeapTuple tup, int attnum);
extern Datum nocachegetattr(HeapTuple tup, int attnum,
TupleDesc att, bool *isnull);
+extern Datum heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
+ bool *isnull);
extern HeapTuple heap_copytuple(HeapTuple tuple);
extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
extern HeapTuple heap_formtuple(TupleDesc tupleDescriptor,
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.115 2004/12/31 22:03:29 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.116 2005/03/14 04:41:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* prototypes from functions in execTuples.c
*/
-extern TupleTable ExecCreateTupleTable(int initialSize);
+extern TupleTable ExecCreateTupleTable(int tableSize);
extern void ExecDropTupleTable(TupleTable table, bool shouldFree);
-extern TupleTableSlot *ExecAllocTableSlot(TupleTable table);
extern TupleTableSlot *MakeTupleTableSlot(void);
+extern TupleTableSlot *ExecAllocTableSlot(TupleTable table);
extern TupleTableSlot *ExecStoreTuple(HeapTuple tuple,
TupleTableSlot *slot,
Buffer buffer,
extern TupleTableSlot *ExecClearTuple(TupleTableSlot *slot);
extern void ExecSetSlotDescriptor(TupleTableSlot *slot,
TupleDesc tupdesc, bool shouldFree);
-extern void ExecSetSlotDescriptorIsNew(TupleTableSlot *slot, bool isNew);
extern void ExecInitResultTupleSlot(EState *estate, PlanState *planstate);
extern void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate);
extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate);
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/executor/tuptable.h,v 1.26 2004/12/31 22:03:29 pgsql Exp $
- *
- * NOTES
- * The tuple table interface is getting pretty ugly.
- * It should be redesigned soon.
+ * $PostgreSQL: pgsql/src/include/executor/tuptable.h,v 1.27 2005/03/14 04:41:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/htup.h"
-/* ----------------
- * The executor tuple table is managed and manipulated by special
- * code in executor/execTuples.c.
- *
- * TupleTableSlot information
- *
- * val current tuple, or NULL if no tuple
- * shouldFree boolean - should we pfree() tuple
- * descIsNew boolean - true when tupleDescriptor changes
- * tupleDescriptor type information for the tuple data
- * shouldFreeDesc boolean - should we free tupleDescriptor
- * buffer the buffer for tuples pointing to disk pages
- *
- * The executor stores pointers to tuples in a ``tuple table''
- * which is composed of TupleTableSlots. Sometimes the tuples
- * are pointers to buffer pages, while others are pointers to
- * palloc'ed memory; the shouldFree variable tells us when
- * we may call pfree() on a tuple. -cim 9/23/90
- *
- * If buffer is not InvalidBuffer, then the slot is holding a pin
- * on the indicated buffer page; drop the pin when we release the
- * slot's reference to that buffer.
- *
- * 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. -cim 1/18/90
+
+/*
+ * The executor stores pointers to tuples in a "tuple table"
+ * which is composed of TupleTableSlots. Sometimes the tuples
+ * are pointers to buffer pages, while others are pointers to
+ * palloc'ed memory; the shouldFree variable tells us whether
+ * we may call pfree() on a tuple. When shouldFree is true,
+ * the tuple is "owned" by the TupleTableSlot and should be
+ * freed when the slot's reference to the tuple is dropped.
*
- * shouldFreeDesc is similar to shouldFree: if it's true, then the
- * tupleDescriptor is "owned" by the TupleTableSlot and should be
- * freed when the slot's reference to the descriptor is dropped.
+ * shouldFreeDesc is similar to shouldFree: if it's true, then the
+ * tupleDescriptor is "owned" by the TupleTableSlot and should be
+ * freed when the slot's reference to the descriptor is dropped.
*
- * See executor.h for decls of functions defined in execTuples.c
- * -jolly
+ * If buffer is not InvalidBuffer, then the slot is holding a pin
+ * on the indicated buffer page; drop the pin when we release the
+ * slot's reference to that buffer. (shouldFree should always be
+ * false in such a case, since presumably val is pointing at the
+ * buffer page.)
*
- * ----------------
+ * The slot_getattr() routine allows extraction of attribute values from
+ * a TupleTableSlot's current tuple. It is equivalent to heap_getattr()
+ * except that it can optimize fetching of multiple values more efficiently.
+ * The cache_xxx fields of TupleTableSlot are support for slot_getattr().
*/
typedef struct TupleTableSlot
{
- NodeTag type;
- HeapTuple val;
- bool ttc_shouldFree;
- bool ttc_descIsNew;
- bool ttc_shouldFreeDesc;
- TupleDesc ttc_tupleDescriptor;
- Buffer ttc_buffer;
+ NodeTag type; /* vestigial ... allows IsA tests */
+ HeapTuple val; /* current tuple, or NULL if none */
+ TupleDesc ttc_tupleDescriptor; /* tuple's descriptor */
+ bool ttc_shouldFree; /* should pfree tuple? */
+ bool ttc_shouldFreeDesc; /* should pfree descriptor? */
+ Buffer ttc_buffer; /* tuple's buffer, or InvalidBuffer */
+ MemoryContext ttc_mcxt; /* slot itself is in this context */
+ Datum *cache_values; /* currently extracted values */
+ int cache_natts; /* # of valid values in cache_values */
+ bool cache_slow; /* saved state for slot_getattr */
+ long cache_off; /* saved state for slot_getattr */
} TupleTableSlot;
-/* ----------------
- * tuple table data structure
- * ----------------
+/*
+ * Tuple table data structure: an array of TupleTableSlots.
*/
typedef struct TupleTableData
{
- int size; /* size of the table */
+ int size; /* size of the table (number of slots) */
int next; /* next available slot number */
- TupleTableSlot *array; /* array of TupleTableSlot's */
-} TupleTableData;
+ TupleTableSlot array[1]; /* VARIABLE LENGTH ARRAY - must be last */
+} TupleTableData; /* VARIABLE LENGTH STRUCT */
typedef TupleTableData *TupleTable;
+
+/* in access/common/heaptuple.c */
+extern Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull);
+
#endif /* TUPTABLE_H */