mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-09-28 10:11:51 +02:00
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.
This commit is contained in:
parent
d1022ce3a1
commit
a9b05bdc83
@ -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 @@
|
|||||||
#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,
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* 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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
/*
|
/*
|
||||||
* 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)
|
|||||||
/*
|
/*
|
||||||
* 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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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,
|
|||||||
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,
|
|||||||
(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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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,
|
|||||||
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,
|
|||||||
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.
|
* This assert checks that the attnum is valid.
|
||||||
*/
|
*/
|
||||||
Assert(attnum <= tuple_type->natts &&
|
Assert(attnum <= tuple_type->natts);
|
||||||
tuple_type->attrs[attnum - 1] != NULL);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 (tuple_type->attrs[attnum - 1]->attisdropped)
|
|
||||||
{
|
|
||||||
*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,
|
|||||||
* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* SLOT ACCESSORS
|
||||||
* ExecStoreTuple - store a tuple in the table
|
* ExecStoreTuple - store a tuple in the table
|
||||||
* ExecFetchTuple - fetch a tuple from the table
|
|
||||||
* ExecClearTuple - clear contents of a table slot
|
* ExecClearTuple - clear contents of a table slot
|
||||||
* ExecSetSlotDescriptor - set a slot's tuple descriptor
|
* ExecSetSlotDescriptor - set a slot's tuple descriptor
|
||||||
* ExecSetSlotDescriptorIsNew - diddle the slot-desc-is-new flag
|
|
||||||
*
|
*
|
||||||
* SLOT STATUS PREDICATES
|
* SLOT STATUS PREDICATES
|
||||||
* TupIsNull - true when slot contains no tuple(Macro)
|
* TupIsNull - true when slot contains no tuple (macro)
|
||||||
*
|
*
|
||||||
* CONVENIENCE INITIALIZATION ROUTINES
|
* CONVENIENCE INITIALIZATION ROUTINES
|
||||||
* ExecInitResultTupleSlot \ convenience routines to initialize
|
* ExecInitResultTupleSlot \ convenience routines to initialize
|
||||||
@ -60,7 +58,7 @@
|
|||||||
* - ExecInitSeqScan() calls ExecInitScanTupleSlot() and
|
* - ExecInitSeqScan() calls ExecInitScanTupleSlot() and
|
||||||
* ExecInitResultTupleSlot() to reserve places in the tuple
|
* ExecInitResultTupleSlot() to reserve places in the tuple
|
||||||
* table for the tuples returned by the access methods and the
|
* 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()
|
* During ExecRun()
|
||||||
* ----------------
|
* ----------------
|
||||||
@ -71,8 +69,8 @@
|
|||||||
* tuple from ExecProject() and place it into the result tuple slot.
|
* tuple from ExecProject() and place it into the result tuple slot.
|
||||||
*
|
*
|
||||||
* - ExecutePlan() calls ExecRetrieve() which gets the tuple out of
|
* - ExecutePlan() calls ExecRetrieve() which gets the tuple out of
|
||||||
* the slot passed to it by calling ExecFetchTuple(). this tuple
|
* the slot passed to it (by direct access to slot->val, which is
|
||||||
* is then returned.
|
* ugly but not worth changing). this tuple is then returned.
|
||||||
*
|
*
|
||||||
* At ExecEnd()
|
* At ExecEnd()
|
||||||
* ----------------
|
* ----------------
|
||||||
@ -87,23 +85,6 @@
|
|||||||
* this information is also kept in the ExprContext of each node.
|
* this information is also kept in the ExprContext of each node.
|
||||||
* Soon the executor will be redesigned and ExprContext's will contain
|
* Soon the executor will be redesigned and ExprContext's will contain
|
||||||
* only slot pointers. -cim 3/14/91
|
* 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"
|
#include "postgres.h"
|
||||||
|
|
||||||
@ -124,43 +105,52 @@ static TupleDesc ExecTypeFromTLInternal(List *targetList,
|
|||||||
* tuple table create/delete functions
|
* tuple table create/delete functions
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
* ExecCreateTupleTable
|
* ExecCreateTupleTable
|
||||||
*
|
*
|
||||||
* This creates a new tuple table of the specified initial
|
* This creates a new tuple table of the specified size.
|
||||||
* size. If the size is insufficient, ExecAllocTableSlot()
|
|
||||||
* will grow the table as necessary.
|
|
||||||
*
|
*
|
||||||
* This should be used by InitPlan() to allocate the table.
|
* This should be used by InitPlan() to allocate the table.
|
||||||
* The table's address will be stored in the EState structure.
|
* The table's address will be stored in the EState structure.
|
||||||
* --------------------------------
|
* --------------------------------
|
||||||
*/
|
*/
|
||||||
TupleTable /* return: address of table */
|
TupleTable
|
||||||
ExecCreateTupleTable(int initialSize) /* initial number of slots in
|
ExecCreateTupleTable(int tableSize)
|
||||||
* table */
|
|
||||||
{
|
{
|
||||||
TupleTable newtable; /* newly allocated table */
|
TupleTable newtable;
|
||||||
TupleTableSlot *array; /* newly allocated slot array */
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
*/
|
*/
|
||||||
Assert(initialSize >= 1);
|
Assert(tableSize >= 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now allocate our new table along with space for the pointers to the
|
* allocate the table itself
|
||||||
* tuples. Zero out the slots.
|
|
||||||
*/
|
*/
|
||||||
|
newtable = (TupleTable) palloc(sizeof(TupleTableData) +
|
||||||
newtable = (TupleTable) palloc(sizeof(TupleTableData));
|
(tableSize - 1) * sizeof(TupleTableSlot));
|
||||||
array = (TupleTableSlot *) palloc0(initialSize * sizeof(TupleTableSlot));
|
newtable->size = tableSize;
|
||||||
|
|
||||||
/*
|
|
||||||
* initialize the new table and return it to the caller.
|
|
||||||
*/
|
|
||||||
newtable->size = initialSize;
|
|
||||||
newtable->next = 0;
|
newtable->next = 0;
|
||||||
newtable->array = array;
|
|
||||||
|
/*
|
||||||
|
* initialize all the slots to empty states
|
||||||
|
*/
|
||||||
|
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;
|
return newtable;
|
||||||
}
|
}
|
||||||
@ -178,21 +168,11 @@ ExecDropTupleTable(TupleTable table, /* tuple table */
|
|||||||
bool shouldFree) /* true if we should free slot
|
bool shouldFree) /* true if we should free slot
|
||||||
* contents */
|
* contents */
|
||||||
{
|
{
|
||||||
int next; /* next available slot */
|
|
||||||
TupleTableSlot *array; /* start of table array */
|
|
||||||
int i; /* counter */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
*/
|
*/
|
||||||
Assert(table != NULL);
|
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
|
* first free all the valid pointers in the tuple array and drop
|
||||||
* refcounts of any referenced buffers, if that's what the caller
|
* refcounts of any referenced buffers, if that's what the caller
|
||||||
@ -201,86 +181,27 @@ ExecDropTupleTable(TupleTable table, /* tuple table */
|
|||||||
*/
|
*/
|
||||||
if (shouldFree)
|
if (shouldFree)
|
||||||
{
|
{
|
||||||
|
int next = table->next;
|
||||||
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < next; i++)
|
for (i = 0; i < next; i++)
|
||||||
{
|
{
|
||||||
ExecClearTuple(&array[i]);
|
TupleTableSlot *slot = &(table->array[i]);
|
||||||
if (array[i].ttc_shouldFreeDesc &&
|
|
||||||
array[i].ttc_tupleDescriptor != NULL)
|
ExecClearTuple(slot);
|
||||||
FreeTupleDesc(array[i].ttc_tupleDescriptor);
|
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);
|
pfree(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
|
||||||
* tuple table slot reservation functions
|
|
||||||
* ----------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
/* --------------------------------
|
|
||||||
* ExecAllocTableSlot
|
|
||||||
*
|
|
||||||
* This routine is used to reserve slots in the table for
|
|
||||||
* use by the various plan nodes. It is expected to be
|
|
||||||
* called by the node init routines (ex: ExecInitNestLoop)
|
|
||||||
* once per slot needed by the node. Not all nodes need
|
|
||||||
* slots (some just pass tuples around).
|
|
||||||
* --------------------------------
|
|
||||||
*/
|
|
||||||
TupleTableSlot *
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
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
|
* MakeTupleTableSlot
|
||||||
*
|
*
|
||||||
@ -295,17 +216,59 @@ MakeTupleTableSlot(void)
|
|||||||
{
|
{
|
||||||
TupleTableSlot *slot = makeNode(TupleTableSlot);
|
TupleTableSlot *slot = makeNode(TupleTableSlot);
|
||||||
|
|
||||||
/* This should match ExecAllocTableSlot() */
|
/* This should match ExecCreateTupleTable() */
|
||||||
slot->val = NULL;
|
slot->val = NULL;
|
||||||
slot->ttc_shouldFree = true;
|
|
||||||
slot->ttc_descIsNew = true;
|
|
||||||
slot->ttc_shouldFreeDesc = true;
|
|
||||||
slot->ttc_tupleDescriptor = NULL;
|
slot->ttc_tupleDescriptor = NULL;
|
||||||
|
slot->ttc_shouldFree = false;
|
||||||
|
slot->ttc_shouldFreeDesc = false;
|
||||||
slot->ttc_buffer = InvalidBuffer;
|
slot->ttc_buffer = InvalidBuffer;
|
||||||
|
slot->ttc_mcxt = CurrentMemoryContext;
|
||||||
|
slot->cache_values = NULL;
|
||||||
|
slot->cache_natts = 0; /* mark slot_getattr state invalid */
|
||||||
|
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------
|
||||||
|
* tuple table slot reservation functions
|
||||||
|
* ----------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* --------------------------------
|
||||||
|
* ExecAllocTableSlot
|
||||||
|
*
|
||||||
|
* This routine is used to reserve slots in the table for
|
||||||
|
* use by the various plan nodes. It is expected to be
|
||||||
|
* called by the node init routines (ex: ExecInitNestLoop)
|
||||||
|
* once per slot needed by the node. Not all nodes need
|
||||||
|
* slots (some just pass tuples around).
|
||||||
|
* --------------------------------
|
||||||
|
*/
|
||||||
|
TupleTableSlot *
|
||||||
|
ExecAllocTableSlot(TupleTable table)
|
||||||
|
{
|
||||||
|
int slotnum; /* new slot number */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* sanity checks
|
||||||
|
*/
|
||||||
|
Assert(table != NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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");
|
||||||
|
|
||||||
|
slotnum = table->next;
|
||||||
|
table->next++;
|
||||||
|
|
||||||
|
return &(table->array[slotnum]);
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* tuple table slot accessor functions
|
* tuple table slot accessor functions
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
@ -356,21 +319,22 @@ ExecStoreTuple(HeapTuple tuple,
|
|||||||
/* passing shouldFree=true for a tuple on a disk page is not sane */
|
/* passing shouldFree=true for a tuple on a disk page is not sane */
|
||||||
Assert(BufferIsValid(buffer) ? (!shouldFree) : true);
|
Assert(BufferIsValid(buffer) ? (!shouldFree) : true);
|
||||||
|
|
||||||
/* clear out any old contents of the slot */
|
/*
|
||||||
|
* clear out any old contents of the slot
|
||||||
|
*/
|
||||||
ExecClearTuple(slot);
|
ExecClearTuple(slot);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* store the new tuple into the specified slot and return the slot
|
* store the new tuple into the specified slot.
|
||||||
* into which we stored the tuple.
|
|
||||||
*/
|
*/
|
||||||
slot->val = tuple;
|
slot->val = tuple;
|
||||||
slot->ttc_buffer = buffer;
|
|
||||||
slot->ttc_shouldFree = shouldFree;
|
slot->ttc_shouldFree = shouldFree;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If tuple is on a disk page, keep the page pinned as long as we hold
|
* 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))
|
if (BufferIsValid(buffer))
|
||||||
IncrBufferRefCount(buffer);
|
IncrBufferRefCount(buffer);
|
||||||
|
|
||||||
@ -388,27 +352,23 @@ ExecStoreTuple(HeapTuple tuple,
|
|||||||
TupleTableSlot * /* return: slot passed */
|
TupleTableSlot * /* return: slot passed */
|
||||||
ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */
|
ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */
|
||||||
{
|
{
|
||||||
HeapTuple oldtuple; /* prior contents of slot */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
*/
|
*/
|
||||||
Assert(slot != NULL);
|
Assert(slot != NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get information from the tuple table
|
* 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.)
|
||||||
*/
|
*/
|
||||||
oldtuple = slot->val;
|
if (slot->ttc_shouldFree && slot->val != NULL)
|
||||||
|
heap_freetuple(slot->val);
|
||||||
/*
|
|
||||||
* free the old contents of the specified slot if necessary.
|
|
||||||
*/
|
|
||||||
if (slot->ttc_shouldFree && oldtuple != NULL)
|
|
||||||
heap_freetuple(oldtuple);
|
|
||||||
|
|
||||||
slot->val = NULL;
|
slot->val = NULL;
|
||||||
|
slot->ttc_shouldFree = false;
|
||||||
slot->ttc_shouldFree = true; /* probably useless code... */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Drop the pin on the referenced buffer, if there is one.
|
* 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;
|
slot->ttc_buffer = InvalidBuffer;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mark slot_getattr state invalid
|
||||||
|
*/
|
||||||
|
slot->cache_natts = 0;
|
||||||
|
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,36 +398,31 @@ ExecSetSlotDescriptor(TupleTableSlot *slot, /* slot to change */
|
|||||||
TupleDesc tupdesc, /* new tuple descriptor */
|
TupleDesc tupdesc, /* new tuple descriptor */
|
||||||
bool shouldFree) /* is desc owned by slot? */
|
bool shouldFree) /* is desc owned by slot? */
|
||||||
{
|
{
|
||||||
if (slot->ttc_shouldFreeDesc &&
|
if (slot->ttc_shouldFreeDesc)
|
||||||
slot->ttc_tupleDescriptor != NULL)
|
|
||||||
FreeTupleDesc(slot->ttc_tupleDescriptor);
|
FreeTupleDesc(slot->ttc_tupleDescriptor);
|
||||||
|
|
||||||
slot->ttc_tupleDescriptor = tupdesc;
|
slot->ttc_tupleDescriptor = tupdesc;
|
||||||
slot->ttc_shouldFreeDesc = shouldFree;
|
slot->ttc_shouldFreeDesc = shouldFree;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
|
||||||
* tuple table slot status predicates
|
|
||||||
* ----------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* convenience initialization routines
|
* convenience initialization routines
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
* ExecInit{Result,Scan,Extra}TupleSlot
|
* ExecInit{Result,Scan,Extra}TupleSlot
|
||||||
*
|
*
|
||||||
|
@ -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 @@
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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,
|
|||||||
) \
|
) \
|
||||||
)
|
)
|
||||||
|
|
||||||
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,
|
|||||||
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 @@
|
|||||||
* 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);
|
|||||||
/*
|
/*
|
||||||
* 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,
|
|||||||
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 @@
|
|||||||
* 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 @@
|
|||||||
|
|
||||||
#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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user