Header And Logo

PostgreSQL
| The world's most advanced open source database.

tstoreReceiver.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * tstoreReceiver.c
00004  *    An implementation of DestReceiver that stores the result tuples in
00005  *    a Tuplestore.
00006  *
00007  * Optionally, we can force detoasting (but not decompression) of out-of-line
00008  * toasted values.  This is to support cursors WITH HOLD, which must retain
00009  * data even if the underlying table is dropped.
00010  *
00011  *
00012  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00013  * Portions Copyright (c) 1994, Regents of the University of California
00014  *
00015  * IDENTIFICATION
00016  *    src/backend/executor/tstoreReceiver.c
00017  *
00018  *-------------------------------------------------------------------------
00019  */
00020 
00021 #include "postgres.h"
00022 
00023 #include "access/tuptoaster.h"
00024 #include "executor/tstoreReceiver.h"
00025 
00026 
00027 typedef struct
00028 {
00029     DestReceiver pub;
00030     /* parameters: */
00031     Tuplestorestate *tstore;    /* where to put the data */
00032     MemoryContext cxt;          /* context containing tstore */
00033     bool        detoast;        /* were we told to detoast? */
00034     /* workspace: */
00035     Datum      *outvalues;      /* values array for result tuple */
00036     Datum      *tofree;         /* temp values to be pfree'd */
00037 } TStoreState;
00038 
00039 
00040 static void tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self);
00041 static void tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self);
00042 
00043 
00044 /*
00045  * Prepare to receive tuples from executor.
00046  */
00047 static void
00048 tstoreStartupReceiver(DestReceiver *self, int operation, TupleDesc typeinfo)
00049 {
00050     TStoreState *myState = (TStoreState *) self;
00051     bool        needtoast = false;
00052     Form_pg_attribute *attrs = typeinfo->attrs;
00053     int         natts = typeinfo->natts;
00054     int         i;
00055 
00056     /* Check if any columns require detoast work */
00057     if (myState->detoast)
00058     {
00059         for (i = 0; i < natts; i++)
00060         {
00061             if (attrs[i]->attisdropped)
00062                 continue;
00063             if (attrs[i]->attlen == -1)
00064             {
00065                 needtoast = true;
00066                 break;
00067             }
00068         }
00069     }
00070 
00071     /* Set up appropriate callback */
00072     if (needtoast)
00073     {
00074         myState->pub.receiveSlot = tstoreReceiveSlot_detoast;
00075         /* Create workspace */
00076         myState->outvalues = (Datum *)
00077             MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
00078         myState->tofree = (Datum *)
00079             MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
00080     }
00081     else
00082     {
00083         myState->pub.receiveSlot = tstoreReceiveSlot_notoast;
00084         myState->outvalues = NULL;
00085         myState->tofree = NULL;
00086     }
00087 }
00088 
00089 /*
00090  * Receive a tuple from the executor and store it in the tuplestore.
00091  * This is for the easy case where we don't have to detoast.
00092  */
00093 static void
00094 tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self)
00095 {
00096     TStoreState *myState = (TStoreState *) self;
00097 
00098     tuplestore_puttupleslot(myState->tstore, slot);
00099 }
00100 
00101 /*
00102  * Receive a tuple from the executor and store it in the tuplestore.
00103  * This is for the case where we have to detoast any toasted values.
00104  */
00105 static void
00106 tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self)
00107 {
00108     TStoreState *myState = (TStoreState *) self;
00109     TupleDesc   typeinfo = slot->tts_tupleDescriptor;
00110     Form_pg_attribute *attrs = typeinfo->attrs;
00111     int         natts = typeinfo->natts;
00112     int         nfree;
00113     int         i;
00114     MemoryContext oldcxt;
00115 
00116     /* Make sure the tuple is fully deconstructed */
00117     slot_getallattrs(slot);
00118 
00119     /*
00120      * Fetch back any out-of-line datums.  We build the new datums array in
00121      * myState->outvalues[] (but we can re-use the slot's isnull array). Also,
00122      * remember the fetched values to free afterwards.
00123      */
00124     nfree = 0;
00125     for (i = 0; i < natts; i++)
00126     {
00127         Datum       val = slot->tts_values[i];
00128 
00129         if (!attrs[i]->attisdropped &&
00130             attrs[i]->attlen == -1 &&
00131             !slot->tts_isnull[i])
00132         {
00133             if (VARATT_IS_EXTERNAL(DatumGetPointer(val)))
00134             {
00135                 val = PointerGetDatum(heap_tuple_fetch_attr((struct varlena *)
00136                                                       DatumGetPointer(val)));
00137                 myState->tofree[nfree++] = val;
00138             }
00139         }
00140 
00141         myState->outvalues[i] = val;
00142     }
00143 
00144     /*
00145      * Push the modified tuple into the tuplestore.
00146      */
00147     oldcxt = MemoryContextSwitchTo(myState->cxt);
00148     tuplestore_putvalues(myState->tstore, typeinfo,
00149                          myState->outvalues, slot->tts_isnull);
00150     MemoryContextSwitchTo(oldcxt);
00151 
00152     /* And release any temporary detoasted values */
00153     for (i = 0; i < nfree; i++)
00154         pfree(DatumGetPointer(myState->tofree[i]));
00155 }
00156 
00157 /*
00158  * Clean up at end of an executor run
00159  */
00160 static void
00161 tstoreShutdownReceiver(DestReceiver *self)
00162 {
00163     TStoreState *myState = (TStoreState *) self;
00164 
00165     /* Release workspace if any */
00166     if (myState->outvalues)
00167         pfree(myState->outvalues);
00168     myState->outvalues = NULL;
00169     if (myState->tofree)
00170         pfree(myState->tofree);
00171     myState->tofree = NULL;
00172 }
00173 
00174 /*
00175  * Destroy receiver when done with it
00176  */
00177 static void
00178 tstoreDestroyReceiver(DestReceiver *self)
00179 {
00180     pfree(self);
00181 }
00182 
00183 /*
00184  * Initially create a DestReceiver object.
00185  */
00186 DestReceiver *
00187 CreateTuplestoreDestReceiver(void)
00188 {
00189     TStoreState *self = (TStoreState *) palloc0(sizeof(TStoreState));
00190 
00191     self->pub.receiveSlot = tstoreReceiveSlot_notoast;  /* might change */
00192     self->pub.rStartup = tstoreStartupReceiver;
00193     self->pub.rShutdown = tstoreShutdownReceiver;
00194     self->pub.rDestroy = tstoreDestroyReceiver;
00195     self->pub.mydest = DestTuplestore;
00196 
00197     /* private fields will be set by SetTuplestoreDestReceiverParams */
00198 
00199     return (DestReceiver *) self;
00200 }
00201 
00202 /*
00203  * Set parameters for a TuplestoreDestReceiver
00204  */
00205 void
00206 SetTuplestoreDestReceiverParams(DestReceiver *self,
00207                                 Tuplestorestate *tStore,
00208                                 MemoryContext tContext,
00209                                 bool detoast)
00210 {
00211     TStoreState *myState = (TStoreState *) self;
00212 
00213     Assert(myState->pub.mydest == DestTuplestore);
00214     myState->tstore = tStore;
00215     myState->cxt = tContext;
00216     myState->detoast = detoast;
00217 }