@ -1,46 +1,98 @@
/*-------------------------------------------------------------------------
*
* tstoreReceiver . c
* a n implementation of DestReceiver that stores the result tuples in
* a Tuplestore
* A n implementation of DestReceiver that stores the result tuples in
* a Tuplestore .
*
* Optionally , we can force detoasting ( but not decompression ) of out - of - line
* toasted values . This is to support cursors WITH HOLD , which must retain
* data even if the underlying table is dropped .
*
* Portions Copyright ( c ) 1996 - 2005 , PostgreSQL Global Development Group
*
* Portions Copyright ( c ) 1996 - 2008 , PostgreSQL Global Development Group
* Portions Copyright ( c ) 1994 , Regents of the University of California
*
* IDENTIFICATION
* $ PostgreSQL : pgsql / src / backend / executor / tstoreReceiver . c , v 1.15 2005 / 11 / 03 17 : 11 : 36 alvherre Exp $
* $ PostgreSQL : pgsql / src / backend / executor / tstoreReceiver . c , v 1.15 .2 .1 2008 / 12 / 01 17 : 06 : 41 tgl Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
# include "postgres.h"
# include "access/heapam.h"
# include "access/tuptoaster.h"
# include "executor/tstoreReceiver.h"
typedef struct
{
DestReceiver pub ;
Tuplestorestate * tstore ;
MemoryContext cxt ;
/* parameters: */
Tuplestorestate * tstore ; /* where to put the data */
MemoryContext cxt ; /* context containing tstore */
bool detoast ; /* were we told to detoast? */
/* workspace: */
Datum * outvalues ; /* values array for result tuple */
Datum * tofree ; /* temp values to be pfree'd */
} TStoreState ;
static void tstoreReceiveSlot_notoast ( TupleTableSlot * slot , DestReceiver * self ) ;
static void tstoreReceiveSlot_detoast ( TupleTableSlot * slot , DestReceiver * self ) ;
/*
* Prepare to receive tuples from executor .
*/
static void
tstoreStartupReceiver ( DestReceiver * self , int operation , TupleDesc typeinfo )
{
/* do nothing */
TStoreState * myState = ( TStoreState * ) self ;
bool needtoast = false ;
Form_pg_attribute * attrs = typeinfo - > attrs ;
int natts = typeinfo - > natts ;
int i ;
/* Check if any columns require detoast work */
if ( myState - > detoast )
{
for ( i = 0 ; i < natts ; i + + )
{
if ( attrs [ i ] - > attisdropped )
continue ;
if ( attrs [ i ] - > attlen = = - 1 )
{
needtoast = true ;
break ;
}
}
}
/* Set up appropriate callback */
if ( needtoast )
{
myState - > pub . receiveSlot = tstoreReceiveSlot_detoast ;
/* Create workspace */
myState - > outvalues = ( Datum * )
MemoryContextAlloc ( myState - > cxt , natts * sizeof ( Datum ) ) ;
myState - > tofree = ( Datum * )
MemoryContextAlloc ( myState - > cxt , natts * sizeof ( Datum ) ) ;
}
else
{
myState - > pub . receiveSlot = tstoreReceiveSlot_notoast ;
myState - > outvalues = NULL ;
myState - > tofree = NULL ;
}
}
/*
* Receive a tuple from the executor and store it in the tuplestore .
* This is for the easy case where we don ' t have to detoast .
*/
static void
tstoreReceiveSlot ( TupleTableSlot * slot , DestReceiver * self )
tstoreReceiveSlot_notoast ( TupleTableSlot * slot , DestReceiver * self )
{
TStoreState * myState = ( TStoreState * ) self ;
MemoryContext oldcxt = MemoryContextSwitchTo ( myState - > cxt ) ;
@ -50,13 +102,80 @@ tstoreReceiveSlot(TupleTableSlot *slot, DestReceiver *self)
MemoryContextSwitchTo ( oldcxt ) ;
}
/*
* Receive a tuple from the executor and store it in the tuplestore .
* This is for the case where we have to detoast any toasted values .
*/
static void
tstoreReceiveSlot_detoast ( TupleTableSlot * slot , DestReceiver * self )
{
TStoreState * myState = ( TStoreState * ) self ;
TupleDesc typeinfo = slot - > tts_tupleDescriptor ;
Form_pg_attribute * attrs = typeinfo - > attrs ;
int natts = typeinfo - > natts ;
int nfree ;
int i ;
HeapTuple tuple ;
MemoryContext oldcxt ;
/* Make sure the tuple is fully deconstructed */
slot_getallattrs ( slot ) ;
/*
* Fetch back any out - of - line datums . We build the new datums array in
* myState - > outvalues [ ] ( but we can re - use the slot ' s isnull array ) .
* Also , remember the fetched values to free afterwards .
*/
nfree = 0 ;
for ( i = 0 ; i < natts ; i + + )
{
Datum val = slot - > tts_values [ i ] ;
if ( ! attrs [ i ] - > attisdropped & &
attrs [ i ] - > attlen = = - 1 & &
! slot - > tts_isnull [ i ] )
{
if ( VARATT_IS_EXTERNAL ( DatumGetPointer ( val ) ) )
{
val = PointerGetDatum ( heap_tuple_fetch_attr ( ( varattrib * )
DatumGetPointer ( val ) ) ) ;
myState - > tofree [ nfree + + ] = val ;
}
}
myState - > outvalues [ i ] = val ;
}
/*
* Push the modified tuple into the tuplestore .
*/
tuple = heap_form_tuple ( typeinfo ,
myState - > outvalues , slot - > tts_isnull ) ;
oldcxt = MemoryContextSwitchTo ( myState - > cxt ) ;
tuplestore_puttuple ( myState - > tstore , tuple ) ;
MemoryContextSwitchTo ( oldcxt ) ;
heap_freetuple ( tuple ) ;
/* And release any temporary detoasted values */
for ( i = 0 ; i < nfree ; i + + )
pfree ( DatumGetPointer ( myState - > tofree [ i ] ) ) ;
}
/*
* Clean up at end of an executor run
*/
static void
tstoreShutdownReceiver ( DestReceiver * self )
{
/* do nothing */
TStoreState * myState = ( TStoreState * ) self ;
/* Release workspace if any */
if ( myState - > outvalues )
pfree ( myState - > outvalues ) ;
myState - > outvalues = NULL ;
if ( myState - > tofree )
pfree ( myState - > tofree ) ;
myState - > tofree = NULL ;
}
/*
@ -75,9 +194,9 @@ DestReceiver *
CreateTuplestoreDestReceiver ( Tuplestorestate * tStore ,
MemoryContext tContext )
{
TStoreState * self = ( TStoreState * ) palloc ( sizeof ( TStoreState ) ) ;
TStoreState * self = ( TStoreState * ) palloc0 ( sizeof ( TStoreState ) ) ;
self - > pub . receiveSlot = tstoreReceiveSlot ;
self - > pub . receiveSlot = tstoreReceiveSlot_notoast ;
self - > pub . rStartup = tstoreStartupReceiver ;
self - > pub . rShutdown = tstoreShutdownReceiver ;
self - > pub . rDestroy = tstoreDestroyReceiver ;
@ -85,6 +204,20 @@ CreateTuplestoreDestReceiver(Tuplestorestate *tStore,
self - > tstore = tStore ;
self - > cxt = tContext ;
self - > detoast = false ;
return ( DestReceiver * ) self ;
}
/*
* Set parameters for a TuplestoreDestReceiver
*/
void
SetTuplestoreDestReceiverDeToast ( DestReceiver * self ,
bool detoast )
{
TStoreState * myState = ( TStoreState * ) self ;
Assert ( myState - > pub . mydest = = DestTuplestore ) ;
myState - > detoast = detoast ;
}