@ -20,11 +20,20 @@
/*----------
* The executor stores tuples in a " tuple table " which is a List of
* independent TupleTableSlots . There are several cases we need to handle :
* 1. physical tuple in a disk buffer page
* 2. physical tuple constructed in palloc ' ed memory
* independent TupleTableSlots .
*
* There ' s various different types of tuple table slots , each being able to
* store different types of tuples . Additional types of slots can be added
* without modifying core code . The type of a slot is determined by the
* TupleTableSlotOps * passed to the slot creation routine . The builtin types
* of slots are
*
* 1. physical tuple in a disk buffer page ( TTSOpsBufferHeapTuple )
* 2. physical tuple constructed in palloc ' ed memory ( TTSOpsHeapTuple )
* 3. " minimal " physical tuple constructed in palloc ' ed memory
* 4. " virtual " tuple consisting of Datum / isnull arrays
* ( TTSOpsMinimalTuple )
* 4. " virtual " tuple consisting of Datum / isnull arrays ( TTSOpsVirtual )
*
*
* The first two cases are similar in that they both deal with " materialized "
* tuples , but resource management is different . For a tuple in a disk page
@ -37,39 +46,28 @@
* parallel to case 1. Note that a minimal tuple has no " system columns " .
* ( Actually , it could have an OID , but we have no need to access the OID . )
*
* A " virtual " tuple is an optimization used to minimize physical data
* copying in a nest of plan nodes . Any pass - by - reference Datums in the
* tuple point to storage that is not directly associated with the
* TupleTableSlot ; generally they will point to part of a tuple stored in
* a lower plan node ' s output TupleTableSlot , or to a function result
* A " virtual " tuple is an optimization used to minimize physical data copying
* in a nest of plan nodes . Until materialized pass - by - reference Datums in
* the slot point to storage that is not directly associated with the
* TupleTableSlot ; generally they will point to part of a tuple stored in a
* lower plan node ' s output TupleTableSlot , or to a function result
* constructed in a plan node ' s per - tuple econtext . It is the responsibility
* of the generating plan node to be sure these resources are not released
* for as long as the virtual tuple needs to be valid . We only use virtual
* tuples in the result slots of plan nodes - - - tuples to be copied anywhere
* else need to be " materialized " into physical tuples . Note also that a
* virtual tuple does not have any " system columns " .
*
* It is also possible for a TupleTableSlot to hold both physical and minimal
* copies of a tuple . This is done when the slot is requested to provide
* the format other than the one it currently holds . ( Originally we attempted
* to handle such requests by replacing one format with the other , but that
* had the fatal defect of invalidating any pass - by - reference Datums pointing
* into the existing slot contents . ) Both copies must contain identical data
* payloads when this is the case .
* of the generating plan node to be sure these resources are not released for
* as long as the virtual tuple needs to be valid or is materialized . Note
* also that a virtual tuple does not have any " system columns " .
*
* The Datum / isnull arrays of a TupleTableSlot serve double duty . When the
* slot contains a virtual tuple , they are the authoritative data . When the
* slot contains a physical tuple , the arrays contain data extracted from
* the tuple . ( In this state , any pass - by - reference Datums point into
* the physical tuple . ) The extracted information is built " lazily " ,
* ie , only as needed . This serves to avoid repeated extraction of data
* from the physical tuple .
* The Datum / isnull arrays of a TupleTableSlot serve double duty . For virtual
* slots they they are the authoritative data . For the other builtin slots ,
* the arrays contain data extracted from the tuple . ( In this state , any
* pass - by - reference Datums point into the physical tuple . ) The extracted
* information is built " lazily " , ie , only as needed . This serves to avoid
* repeated extraction of data from the physical tuple .
*
* A TupleTableSlot can also be " empty " , indicated by flag TTS_EMPTY set in
* tts_flags , holding no valid data . This is the only valid state for a
* freshly - created slot that has not yet had a tuple descriptor assigned to it .
* In this state , TTS_SHOULDFREE should not be set in tts_flag , tts_tuple must
* be NULL , tts_buffer InvalidBuffer , and tts_nvalid zero .
* A TupleTableSlot can also be " empty " , indicated by flag TTS_FLAG_EMPTY set
* in tts_flags , holding no valid data . This is the only valid state for a
* freshly - created slot that has not yet had a tuple descriptor assigned to
* it . In this state , TTS_SHOULDFREE should not be set in tts_flag , tts_tuple
* must be NULL , tts_buffer InvalidBuffer , and tts_nvalid zero .
*
* The tupleDescriptor is simply referenced , not copied , by the TupleTableSlot
* code . The caller of ExecSetSlotDescriptor ( ) is responsible for providing
@ -83,32 +81,12 @@
* the slot and should be freed when the slot ' s reference to the tuple is
* dropped .
*
* If tts_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 . ( tts_shouldFree should always be
* false in such a case , since presumably tts_tuple is pointing at the
* buffer page . )
*
* tts_nvalid indicates the number of valid columns in the tts_values / isnull
* arrays . When the slot is holding a " virtual " tuple this must be equal
* to the descriptor ' s natts . When the slot is holding a physical tuple
* this is equal to the number of columns we have extracted ( we always
* extract columns from left to right , so there are no holes ) .
* tts_values / tts_isnull are allocated either when the slot is created ( when
* the descriptor is provided ) , or when a descriptor is assigned to the slot ;
* they are of length equal to the descriptor ' s natts .
*
* tts_values / tts_isnull are allocated when a descriptor is assigned to the
* slot ; they are of length equal to the descriptor ' s natts .
*
* tts_mintuple must always be NULL if the slot does not hold a " minimal "
* tuple . When it does , tts_mintuple points to the actual MinimalTupleData
* object ( the thing to be pfree ' d if tts_shouldFreeMin is true ) . If the slot
* has only a minimal and not also a regular physical tuple , then tts_tuple
* points at tts_minhdr and the fields of that struct are set correctly
* for access to the minimal tuple ; in particular , tts_minhdr . t_data points
* MINIMAL_TUPLE_OFFSET bytes before tts_mintuple . This allows column
* extraction to treat the case identically to regular physical tuples .
*
* TTS_SLOW flag in tts_flags and tts_off are saved state for
* slot_deform_tuple , and should not be touched by any other code .
* The TTS_FLAG_SLOW flag and tts_off are saved state for
* slot_deform_heap_tuple , and should not be touched by any other code .
* - - - - - - - - - -
*/
@ -116,25 +94,22 @@
# define TTS_FLAG_EMPTY (1 << 1)
# define TTS_EMPTY(slot) (((slot)->tts_flags & TTS_FLAG_EMPTY) != 0)
/* should pfree tts_t uple? */
/* should pfree tuple "owned" by the slot ? */
# define TTS_FLAG_SHOULDFREE (1 << 2)
# define TTS_SHOULDFREE(slot) (((slot)->tts_flags & TTS_FLAG_SHOULDFREE) != 0)
/* should pfree tts_mintuple? */
# define TTS_FLAG_SHOULDFREEMIN (1 << 3)
# define TTS_SHOULDFREEMIN(slot) (((slot)->tts_flags & TTS_FLAG_SHOULDFREEMIN) != 0)
/* saved state for slot_deform_tuple */
# define TTS_FLAG_SLOW (1 << 4)
/* saved state for slot_deform_heap_tuple */
# define TTS_FLAG_SLOW (1 << 3)
# define TTS_SLOW(slot) (((slot)->tts_flags & TTS_FLAG_SLOW) != 0)
/* fixed tuple descriptor */
# define TTS_FLAG_FIXED (1 << 5 )
# define TTS_FLAG_FIXED (1 << 4)
# define TTS_FIXED(slot) (((slot)->tts_flags & TTS_FLAG_FIXED) != 0)
struct TupleTableSlotOps ;
typedef struct TupleTableSlotOps TupleTableSlotOps ;
/* base tuple table slot type */
typedef struct TupleTableSlot
{
NodeTag type ;
@ -142,28 +117,99 @@ typedef struct TupleTableSlot
uint16 tts_flags ; /* Boolean states */
# define FIELDNO_TUPLETABLESLOT_NVALID 2
AttrNumber tts_nvalid ; /* # of valid values in tts_values */
# define FIELDNO_TUPLETABLESLOT_TUPLE 3
HeapTuple tts_tuple ; /* physical tuple, or NULL if virtual */
const TupleTableSlotOps * const tts_ops ; /* implementation of slot */
# define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 5
# define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 4
TupleDesc tts_tupleDescriptor ; /* slot's tuple descriptor */
MemoryContext tts_mcxt ; /* slot itself is in this context */
Buffer tts_buffer ; /* tuple's buffer, or InvalidBuffer */
# define FIELDNO_TUPLETABLESLOT_OFF 8
uint32 tts_off ; /* saved state for slot_deform_tuple */
# define FIELDNO_TUPLETABLESLOT_VALUES 9
# define FIELDNO_TUPLETABLESLOT_VALUES 5
Datum * tts_values ; /* current per-attribute values */
# define FIELDNO_TUPLETABLESLOT_ISNULL 10
# define FIELDNO_TUPLETABLESLOT_ISNULL 6
bool * tts_isnull ; /* current per-attribute isnull flags */
MinimalTuple tts_mintuple ; /* minimal tuple, or NULL if none */
HeapTupleData tts_minhdr ; /* workspace for minimal-tuple-only case */
MemoryContext tts_mcxt ; /* slot itself is in this context */
} TupleTableSlot ;
/* routines for a TupleTableSlot implementation */
struct TupleTableSlotOps
{
/* body will be replaced in later commit */
int dummy ;
/* Minimum size of the slot */
size_t base_slot_size ;
/* Initialization. */
void ( * init ) ( TupleTableSlot * slot ) ;
/* Destruction. */
void ( * release ) ( TupleTableSlot * slot ) ;
/*
* Clear the contents of the slot . Only the contents are expected to be
* cleared and not the tuple descriptor . Typically an implementation of
* this callback should free the memory allocated for the tuple contained
* in the slot .
*/
void ( * clear ) ( TupleTableSlot * slot ) ;
/*
* Fill up first natts entries of tts_values and tts_isnull arrays with
* values from the tuple contained in the slot . The function may be called
* with natts more than the number of attributes available in the tuple ,
* in which case it should set tts_nvalid to the number of returned
* columns .
*/
void ( * getsomeattrs ) ( TupleTableSlot * slot , int natts ) ;
/*
* Returns value of the given system attribute as a datum and sets isnull
* to false , if it ' s not NULL . Throws an error if the slot type does not
* support system attributes .
*/
Datum ( * getsysattr ) ( TupleTableSlot * slot , int attnum , bool * isnull ) ;
/*
* Make the contents of the slot solely depend on the slot , and not on
* underlying resources ( like another memory context , buffers , etc ) .
*/
void ( * materialize ) ( TupleTableSlot * slot ) ;
/*
* Copy the contents of the source slot into the destination slot ' s own
* context . Invoked using callback of the destination slot .
*/
void ( * copyslot ) ( TupleTableSlot * dstslot , TupleTableSlot * srcslot ) ;
/*
* Return a heap tuple " owned " by the slot . It is slot ' s responsibility to
* free the memory consumed by the heap tuple . If the slot can not " own " a
* heap tuple , it should not implement this callback and should set it as
* NULL .
*/
HeapTuple ( * get_heap_tuple ) ( TupleTableSlot * slot ) ;
/*
* Return a minimal tuple " owned " by the slot . It is slot ' s responsibility
* to free the memory consumed by the minimal tuple . If the slot can not
* " own " a minimal tuple , it should not implement this callback and should
* set it as NULL .
*/
MinimalTuple ( * get_minimal_tuple ) ( TupleTableSlot * slot ) ;
/*
* Return a copy of heap tuple representing the contents of the slot . The
* copy needs to be palloc ' d in the current memory context . The slot
* itself is expected to remain unaffected . It is * not * expected to have
* meaningful " system columns " in the copy . The copy is not be " owned " by
* the slot i . e . the caller has to take responsibilty to free memory
* consumed by the slot .
*/
HeapTuple ( * copy_heap_tuple ) ( TupleTableSlot * slot ) ;
/*
* Return a copy of minimal tuple representing the contents of the slot . The
* copy needs to be palloc ' d in the current memory context . The slot
* itself is expected to remain unaffected . It is * not * expected to have
* meaningful " system columns " in the copy . The copy is not be " owned " by
* the slot i . e . the caller has to take responsibilty to free memory
* consumed by the slot .
*/
MinimalTuple ( * copy_minimal_tuple ) ( TupleTableSlot * slot ) ;
} ;
/*
@ -173,10 +219,68 @@ struct TupleTableSlotOps
extern PGDLLIMPORT const TupleTableSlotOps TTSOpsVirtual ;
extern PGDLLIMPORT const TupleTableSlotOps TTSOpsHeapTuple ;
extern PGDLLIMPORT const TupleTableSlotOps TTSOpsMinimalTuple ;
extern PGDLLIMPORT const TupleTableSlotOps TTSOpsBufferTuple ;
extern PGDLLIMPORT const TupleTableSlotOps TTSOpsBufferHeapTuple ;
# define TTS_IS_VIRTUAL(slot) ((slot)->tts_ops == &TTSOpsVirtual)
# define TTS_IS_HEAPTUPLE(slot) ((slot)->tts_ops == &TTSOpsHeapTuple)
# define TTS_IS_MINIMALTUPLE(slot) ((slot)->tts_ops == &TTSOpsMinimalTuple)
# define TTS_IS_BUFFERTUPLE(slot) ((slot)->tts_ops == &TTSOpsBufferHeapTuple)
# define TTS_HAS_PHYSICAL_TUPLE(slot) \
( ( slot ) - > tts_tuple ! = NULL & & ( slot ) - > tts_tuple ! = & ( ( slot ) - > tts_minhdr ) )
/*
* Tuple table slot implementations .
*/
typedef struct VirtualTupleTableSlot
{
TupleTableSlot base ;
char * data ; /* data for materialized slots */
} VirtualTupleTableSlot ;
typedef struct HeapTupleTableSlot
{
TupleTableSlot base ;
# define FIELDNO_HEAPTUPLETABLESLOT_TUPLE 1
HeapTuple tuple ; /* physical tuple */
# define FIELDNO_HEAPTUPLETABLESLOT_OFF 2
uint32 off ; /* saved state for slot_deform_heap_tuple */
} HeapTupleTableSlot ;
/* heap tuple residing in a buffer */
typedef struct BufferHeapTupleTableSlot
{
HeapTupleTableSlot base ;
/*
* 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 . ( TTS_FLAG_SHOULDFREE should not be set be
* false in such a case , since presumably tts_tuple is pointing at the
* buffer page . )
*/
Buffer buffer ; /* tuple's buffer, or InvalidBuffer */
} BufferHeapTupleTableSlot ;
typedef struct MinimalTupleTableSlot
{
TupleTableSlot base ;
/*
* In a minimal slot tuple points at minhdr and the fields of that struct
* are set correctly for access to the minimal tuple ; in particular ,
* minhdr . t_data points MINIMAL_TUPLE_OFFSET bytes before mintuple . This
* allows column extraction to treat the case identically to regular
* physical tuples .
*/
# define FIELDNO_MINIMALTUPLETABLESLOT_TUPLE 1
HeapTuple tuple ; /* tuple wrapper */
MinimalTuple mintuple ; /* minimal tuple, or NULL if none */
HeapTupleData minhdr ; /* workspace for minimal-tuple-only case */
# define FIELDNO_MINIMALTUPLETABLESLOT_OFF 4
uint32 off ; /* saved state for slot_deform_heap_tuple */
} MinimalTupleTableSlot ;
/*
* TupIsNull - - is a TupleTableSlot empty ?
@ -197,37 +301,26 @@ extern void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc);
extern TupleTableSlot * ExecStoreHeapTuple ( HeapTuple tuple ,
TupleTableSlot * slot ,
bool shouldFree ) ;
extern void ExecForceStoreHeapTuple ( HeapTuple tuple , TupleTableSlot * slot ) ;
extern TupleTableSlot * ExecStoreBufferHeapTuple ( HeapTuple tuple ,
TupleTableSlot * slot ,
Buffer buffer ) ;
extern TupleTableSlot * ExecStoreMinimalTuple ( MinimalTuple mtup ,
TupleTableSlot * slot ,
bool shouldFree ) ;
extern TupleTableSlot * ExecClearTuple ( TupleTableSlot * slot ) ;
extern void ExecForceStoreMinimalTuple ( MinimalTuple mtup , TupleTableSlot * slot ,
bool shouldFree ) ;
extern TupleTableSlot * ExecStoreVirtualTuple ( TupleTableSlot * slot ) ;
extern TupleTableSlot * ExecStoreAllNullTuple ( TupleTableSlot * slot ) ;
extern HeapTuple ExecCopySlotTuple ( TupleTableSlot * slot ) ;
extern MinimalTuple ExecCopySlotMinimalTuple ( TupleTableSlot * slot ) ;
extern HeapTuple ExecFetchSlotHeapTuple ( TupleTableSlot * slot , bool materialize , bool * shoulFree ) ;
extern HeapTuple ExecFetchSlotHeapTuple ( TupleTableSlot * slot , bool materialize , bool * shouldFree ) ;
extern MinimalTuple ExecFetchSlotMinimalTuple ( TupleTableSlot * slot ,
bool * shouldFree ) ;
extern Datum ExecFetchSlotHeapTupleDatum ( TupleTableSlot * slot ) ;
extern void ExecMaterializeSlot ( TupleTableSlot * slot ) ;
extern TupleTableSlot * ExecCopySlot ( TupleTableSlot * dstslot ,
TupleTableSlot * srcslot ) ;
extern void slot_getmissingattrs ( TupleTableSlot * slot , int startAttNum ,
int lastAttNum ) ;
extern Datum slot_getattr ( TupleTableSlot * slot , int attnum ,
bool * isnull ) ;
/* in access/common/heaptuple.c */
extern bool slot_attisnull ( TupleTableSlot * slot , int attnum ) ;
extern bool slot_getsysattr ( TupleTableSlot * slot , int attnum ,
Datum * value , bool * isnull ) ;
extern Datum getmissingattr ( TupleDesc tupleDesc ,
int attnum , bool * isnull ) ;
extern void slot_getsomeattrs_int ( TupleTableSlot * slot , int attnum ) ;
# ifndef FRONTEND
/*
@ -253,6 +346,120 @@ slot_getallattrs(TupleTableSlot *slot)
slot_getsomeattrs ( slot , slot - > tts_tupleDescriptor - > natts ) ;
}
# endif
/*
* slot_attisnull
*
* Detect whether an attribute of the slot is null , without actually fetching
* it .
*/
static inline bool
slot_attisnull ( TupleTableSlot * slot , int attnum )
{
AssertArg ( attnum > 0 ) ;
if ( attnum > slot - > tts_nvalid )
slot_getsomeattrs ( slot , attnum ) ;
return slot - > tts_isnull [ attnum - 1 ] ;
}
/*
* slot_getattr - fetch one attribute of the slot ' s contents .
*/
static inline Datum
slot_getattr ( TupleTableSlot * slot , int attnum ,
bool * isnull )
{
AssertArg ( attnum > 0 ) ;
if ( attnum > slot - > tts_nvalid )
slot_getsomeattrs ( slot , attnum ) ;
* isnull = slot - > tts_isnull [ attnum - 1 ] ;
return slot - > tts_values [ attnum - 1 ] ;
}
/*
* slot_getsysattr - fetch a system attribute of the slot ' s current tuple .
*
* If the slot type does not contain system attributes , this will throw an
* error . Hence before calling this function , callers should make sure that
* the slot type is the one that supports system attributes .
*/
static inline Datum
slot_getsysattr ( TupleTableSlot * slot , int attnum , bool * isnull )
{
AssertArg ( attnum < 0 ) ; /* caller error */
/* Fetch the system attribute from the underlying tuple. */
return slot - > tts_ops - > getsysattr ( slot , attnum , isnull ) ;
}
/*
* ExecClearTuple - clear the slot ' s contents
*/
static inline TupleTableSlot *
ExecClearTuple ( TupleTableSlot * slot )
{
slot - > tts_ops - > clear ( slot ) ;
return slot ;
}
/* ExecMaterializeSlot - force a slot into the "materialized" state.
*
* This causes the slot ' s tuple to be a local copy not dependent on any
* external storage ( i . e . pointing into a Buffer , or having allocations in
* another memory context ) .
*
* A typical use for this operation is to prepare a computed tuple for being
* stored on disk . The original data may or may not be virtual , but in any
* case we need a private copy for heap_insert to scribble on .
*/
static inline void
ExecMaterializeSlot ( TupleTableSlot * slot )
{
slot - > tts_ops - > materialize ( slot ) ;
}
/*
* ExecCopySlotHeapTuple - return HeapTuple allocated in caller ' s context
*/
static inline HeapTuple
ExecCopySlotHeapTuple ( TupleTableSlot * slot )
{
Assert ( ! TTS_EMPTY ( slot ) ) ;
return slot - > tts_ops - > copy_heap_tuple ( slot ) ;
}
/*
* ExecCopySlotMinimalTuple - return MinimalTuple allocated in caller ' s context
*/
static inline MinimalTuple
ExecCopySlotMinimalTuple ( TupleTableSlot * slot )
{
return slot - > tts_ops - > copy_minimal_tuple ( slot ) ;
}
/*
* ExecCopySlot - copy one slot ' s contents into another .
*
* If a source ' s system attributes are supposed to be accessed in the target
* slot , the target slot and source slot types need to match .
*/
static inline TupleTableSlot *
ExecCopySlot ( TupleTableSlot * dstslot , TupleTableSlot * srcslot )
{
Assert ( ! TTS_EMPTY ( srcslot ) ) ;
dstslot - > tts_ops - > copyslot ( dstslot , srcslot ) ;
return dstslot ;
}
# endif /* FRONTEND */
# endif /* TUPTABLE_H */