Commit a9b05bdc authored by Tom Lane's avatar Tom Lane

Avoid O(N^2) overhead in repeated nocachegetattr calls when columns of

a tuple are being accessed via ExecEvalVar and the attcacheoff shortcut
isn't usable (due to nulls and/or varlena columns).  To do this, cache
Datums extracted from a tuple in the associated TupleTableSlot.
Also some code cleanup in and around the TupleTable handling.
Atsushi Ogawa with some kibitzing by Tom Lane.
parent d1022ce3
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* The old interface functions have been converted to macros * The old interface functions have been converted to macros
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "access/heapam.h" #include "access/heapam.h"
#include "access/tuptoaster.h" #include "access/tuptoaster.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "executor/tuptable.h"
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -751,6 +752,7 @@ heap_deformtuple(HeapTuple tuple, ...@@ -751,6 +752,7 @@ heap_deformtuple(HeapTuple tuple,
char *nulls) char *nulls)
{ {
HeapTupleHeader tup = tuple->t_data; HeapTupleHeader tup = tuple->t_data;
bool hasnulls = HeapTupleHasNulls(tuple);
Form_pg_attribute *att = tupleDesc->attrs; Form_pg_attribute *att = tupleDesc->attrs;
int tdesc_natts = tupleDesc->natts; int tdesc_natts = tupleDesc->natts;
int natts; /* number of atts to extract */ int natts; /* number of atts to extract */
...@@ -775,7 +777,9 @@ heap_deformtuple(HeapTuple tuple, ...@@ -775,7 +777,9 @@ heap_deformtuple(HeapTuple tuple,
for (attnum = 0; attnum < natts; attnum++) 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; values[attnum] = (Datum) 0;
nulls[attnum] = 'n'; nulls[attnum] = 'n';
...@@ -785,21 +789,21 @@ heap_deformtuple(HeapTuple tuple, ...@@ -785,21 +789,21 @@ heap_deformtuple(HeapTuple tuple,
nulls[attnum] = ' '; nulls[attnum] = ' ';
if (!slow && att[attnum]->attcacheoff >= 0) if (!slow && thisatt->attcacheoff >= 0)
off = att[attnum]->attcacheoff; off = thisatt->attcacheoff;
else else
{ {
off = att_align(off, att[attnum]->attalign); off = att_align(off, thisatt->attalign);
if (!slow) 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 */ slow = true; /* can't use attcacheoff anymore */
} }
...@@ -814,6 +818,177 @@ heap_deformtuple(HeapTuple tuple, ...@@ -814,6 +818,177 @@ heap_deformtuple(HeapTuple tuple,
} }
} }
/* ----------------
* 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 * heap_freetuple
* ---------------- * ----------------
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
...@@ -1197,9 +1197,9 @@ toast_fetch_datum(varattrib *attr) ...@@ -1197,9 +1197,9 @@ toast_fetch_datum(varattrib *attr)
/* /*
* Have a chunk, extract the sequence number and the data * 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); Assert(!isnull);
chunk = DatumGetPointer(heap_getattr(ttup, 3, toasttupDesc, &isnull)); chunk = DatumGetPointer(fastgetattr(ttup, 3, toasttupDesc, &isnull));
Assert(!isnull); Assert(!isnull);
chunksize = VARATT_SIZE(chunk) - VARHDRSZ; chunksize = VARATT_SIZE(chunk) - VARHDRSZ;
...@@ -1372,9 +1372,9 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length) ...@@ -1372,9 +1372,9 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length)
/* /*
* Have a chunk, extract the sequence number and the data * 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); Assert(!isnull);
chunk = DatumGetPointer(heap_getattr(ttup, 3, toasttupDesc, &isnull)); chunk = DatumGetPointer(fastgetattr(ttup, 3, toasttupDesc, &isnull));
Assert(!isnull); Assert(!isnull);
chunksize = VARATT_SIZE(chunk) - VARHDRSZ; chunksize = VARATT_SIZE(chunk) - VARHDRSZ;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -209,20 +209,13 @@ ExecGetJunkAttribute(JunkFilter *junkfilter, ...@@ -209,20 +209,13 @@ ExecGetJunkAttribute(JunkFilter *junkfilter,
Datum *value, Datum *value,
bool *isNull) bool *isNull)
{ {
List *targetList;
ListCell *t; 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 * the given name
*/ */
resno = InvalidAttrNumber; foreach(t, junkfilter->jf_targetList)
targetList = junkfilter->jf_targetList;
foreach(t, targetList)
{ {
TargetEntry *tle = lfirst(t); TargetEntry *tle = lfirst(t);
Resdom *resdom = tle->resdom; Resdom *resdom = tle->resdom;
...@@ -231,26 +224,13 @@ ExecGetJunkAttribute(JunkFilter *junkfilter, ...@@ -231,26 +224,13 @@ ExecGetJunkAttribute(JunkFilter *junkfilter,
(strcmp(resdom->resname, attrName) == 0)) (strcmp(resdom->resname, attrName) == 0))
{ {
/* We found it ! */ /* We found it ! */
resno = resdom->resno; *value = slot_getattr(slot, resdom->resno, isNull);
break; return true;
} }
} }
if (resno == InvalidAttrNumber)
{
/* Ooops! We couldn't find this attribute... */ /* Ooops! We couldn't find this attribute... */
return false; 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;
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -438,11 +438,8 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext, ...@@ -438,11 +438,8 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull, ExprDoneCond *isDone)
{ {
Var *variable = (Var *) exprstate->expr; Var *variable = (Var *) exprstate->expr;
Datum result;
TupleTableSlot *slot; TupleTableSlot *slot;
AttrNumber attnum; AttrNumber attnum;
HeapTuple heapTuple;
TupleDesc tuple_type;
if (isDone) if (isDone)
*isDone = ExprSingleResult; *isDone = ExprSingleResult;
...@@ -475,35 +472,19 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext, ...@@ -475,35 +472,19 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
break; break;
} }
/* #ifdef USE_ASSERT_CHECKING
* extract tuple information from the slot
*/
heapTuple = slot->val;
tuple_type = slot->ttc_tupleDescriptor;
/* /*
* Some checks that are only applied for user attribute numbers (bogus * 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) if (attnum > 0)
{ {
/* TupleDesc tuple_type = slot->ttc_tupleDescriptor;
* This assert checks that the attnum is valid.
*/
Assert(attnum <= tuple_type->natts &&
tuple_type->attrs[attnum - 1] != NULL);
/* /*
* If the attribute's column has been dropped, we force a NULL * This assert checks that the attnum is valid.
* 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 (tuple_type->attrs[attnum - 1]->attisdropped) Assert(attnum <= tuple_type->natts);
{
*isNull = true;
return (Datum) 0;
}
/* /*
* This assert checks that the datatype the plan expects to get * This assert checks that the datatype the plan expects to get
...@@ -515,16 +496,12 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext, ...@@ -515,16 +496,12 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
* Note that we can't check dropped columns, since their atttypid has * Note that we can't check dropped columns, since their atttypid has
* been zeroed. * 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 */ return slot_getattr(slot, attnum, isNull);
attnum, /* attribute number of desired
* attribute */
tuple_type, /* tuple descriptor of tuple */
isNull); /* return: is attribute null? */
return result;
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -40,9 +40,6 @@ ...@@ -40,9 +40,6 @@
* ---------------- * ----------------
*/ */
extern Datum nocachegetattr(HeapTuple tup, int attnum,
TupleDesc att, bool *isnull);
#if !defined(DISABLE_COMPLEX_MACRO) #if !defined(DISABLE_COMPLEX_MACRO)
#define fastgetattr(tup, attnum, tupleDesc, isnull) \ #define fastgetattr(tup, attnum, tupleDesc, isnull) \
...@@ -115,9 +112,6 @@ extern Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, ...@@ -115,9 +112,6 @@ extern Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
) \ ) \
) )
extern Datum heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
bool *isnull);
/* ---------------- /* ----------------
* function prototypes for heap access method * function prototypes for heap access method
...@@ -191,6 +185,8 @@ extern void DataFill(char *data, TupleDesc tupleDesc, ...@@ -191,6 +185,8 @@ extern void DataFill(char *data, TupleDesc tupleDesc,
extern int heap_attisnull(HeapTuple tup, int attnum); extern int heap_attisnull(HeapTuple tup, int attnum);
extern Datum nocachegetattr(HeapTuple tup, int attnum, extern Datum nocachegetattr(HeapTuple tup, int attnum,
TupleDesc att, bool *isnull); TupleDesc att, bool *isnull);
extern Datum heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
bool *isnull);
extern HeapTuple heap_copytuple(HeapTuple tuple); extern HeapTuple heap_copytuple(HeapTuple tuple);
extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest); extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
extern HeapTuple heap_formtuple(TupleDesc tupleDescriptor, extern HeapTuple heap_formtuple(TupleDesc tupleDescriptor,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -158,10 +158,10 @@ extern void ExecAssignScanProjectionInfo(ScanState *node); ...@@ -158,10 +158,10 @@ extern void ExecAssignScanProjectionInfo(ScanState *node);
/* /*
* prototypes from functions in execTuples.c * prototypes from functions in execTuples.c
*/ */
extern TupleTable ExecCreateTupleTable(int initialSize); extern TupleTable ExecCreateTupleTable(int tableSize);
extern void ExecDropTupleTable(TupleTable table, bool shouldFree); extern void ExecDropTupleTable(TupleTable table, bool shouldFree);
extern TupleTableSlot *ExecAllocTableSlot(TupleTable table);
extern TupleTableSlot *MakeTupleTableSlot(void); extern TupleTableSlot *MakeTupleTableSlot(void);
extern TupleTableSlot *ExecAllocTableSlot(TupleTable table);
extern TupleTableSlot *ExecStoreTuple(HeapTuple tuple, extern TupleTableSlot *ExecStoreTuple(HeapTuple tuple,
TupleTableSlot *slot, TupleTableSlot *slot,
Buffer buffer, Buffer buffer,
...@@ -169,7 +169,6 @@ extern TupleTableSlot *ExecStoreTuple(HeapTuple tuple, ...@@ -169,7 +169,6 @@ extern TupleTableSlot *ExecStoreTuple(HeapTuple tuple,
extern TupleTableSlot *ExecClearTuple(TupleTableSlot *slot); extern TupleTableSlot *ExecClearTuple(TupleTableSlot *slot);
extern void ExecSetSlotDescriptor(TupleTableSlot *slot, extern void ExecSetSlotDescriptor(TupleTableSlot *slot,
TupleDesc tupdesc, bool shouldFree); TupleDesc tupdesc, bool shouldFree);
extern void ExecSetSlotDescriptorIsNew(TupleTableSlot *slot, bool isNew);
extern void ExecInitResultTupleSlot(EState *estate, PlanState *planstate); extern void ExecInitResultTupleSlot(EState *estate, PlanState *planstate);
extern void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate); extern void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate);
extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate); extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate);
......
...@@ -7,11 +7,7 @@ ...@@ -7,11 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 $ * $PostgreSQL: pgsql/src/include/executor/tuptable.h,v 1.27 2005/03/14 04:41:13 tgl Exp $
*
* NOTES
* The tuple table interface is getting pretty ugly.
* It should be redesigned soon.
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -20,65 +16,60 @@ ...@@ -20,65 +16,60 @@
#include "access/htup.h" #include "access/htup.h"
/* ----------------
* The executor tuple table is managed and manipulated by special /*
* code in executor/execTuples.c. * The executor stores pointers to tuples in a "tuple table"
*
* 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 * which is composed of TupleTableSlots. Sometimes the tuples
* are pointers to buffer pages, while others are pointers to * are pointers to buffer pages, while others are pointers to
* palloc'ed memory; the shouldFree variable tells us when * palloc'ed memory; the shouldFree variable tells us whether
* we may call pfree() on a tuple. -cim 9/23/90 * we may call pfree() on a tuple. When shouldFree is true,
* * the tuple is "owned" by the TupleTableSlot and should be
* If buffer is not InvalidBuffer, then the slot is holding a pin * freed when the slot's reference to the tuple is dropped.
* 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
* *
* shouldFreeDesc is similar to shouldFree: if it's true, then the * shouldFreeDesc is similar to shouldFree: if it's true, then the
* tupleDescriptor is "owned" by the TupleTableSlot and should be * tupleDescriptor is "owned" by the TupleTableSlot and should be
* freed when the slot's reference to the descriptor is dropped. * freed when the slot's reference to the descriptor is dropped.
* *
* See executor.h for decls of functions defined in execTuples.c * If buffer is not InvalidBuffer, then the slot is holding a pin
* -jolly * 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 typedef struct TupleTableSlot
{ {
NodeTag type; NodeTag type; /* vestigial ... allows IsA tests */
HeapTuple val; HeapTuple val; /* current tuple, or NULL if none */
bool ttc_shouldFree; TupleDesc ttc_tupleDescriptor; /* tuple's descriptor */
bool ttc_descIsNew; bool ttc_shouldFree; /* should pfree tuple? */
bool ttc_shouldFreeDesc; bool ttc_shouldFreeDesc; /* should pfree descriptor? */
TupleDesc ttc_tupleDescriptor; Buffer ttc_buffer; /* tuple's buffer, or InvalidBuffer */
Buffer ttc_buffer; 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; } TupleTableSlot;
/* ---------------- /*
* tuple table data structure * Tuple table data structure: an array of TupleTableSlots.
* ----------------
*/ */
typedef struct TupleTableData typedef struct TupleTableData
{ {
int size; /* size of the table */ int size; /* size of the table (number of slots) */
int next; /* next available slot number */ int next; /* next available slot number */
TupleTableSlot *array; /* array of TupleTableSlot's */ TupleTableSlot array[1]; /* VARIABLE LENGTH ARRAY - must be last */
} TupleTableData; } TupleTableData; /* VARIABLE LENGTH STRUCT */
typedef TupleTableData *TupleTable; typedef TupleTableData *TupleTable;
/* in access/common/heaptuple.c */
extern Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull);
#endif /* TUPTABLE_H */ #endif /* TUPTABLE_H */
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