1 /*-------------------------------------------------------------------------
4 * An implementation of DestReceiver that stores the result tuples in
7 * Optionally, we can force detoasting (but not decompression) of out-of-line
8 * toasted values. This is to support cursors WITH HOLD, which must retain
9 * data even if the underlying table is dropped.
12 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
13 * Portions Copyright (c) 1994, Regents of the University of California
16 * src/backend/executor/tstoreReceiver.c
18 *-------------------------------------------------------------------------
23 #include "access/tuptoaster.h"
24 #include "executor/tstoreReceiver.h"
31 Tuplestorestate *tstore; /* where to put the data */
32 MemoryContext cxt; /* context containing tstore */
33 bool detoast; /* were we told to detoast? */
35 Datum *outvalues; /* values array for result tuple */
36 Datum *tofree; /* temp values to be pfree'd */
40 static bool tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self);
41 static bool tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self);
45 * Prepare to receive tuples from executor.
48 tstoreStartupReceiver(DestReceiver *self, int operation, TupleDesc typeinfo)
50 TStoreState *myState = (TStoreState *) self;
51 bool needtoast = false;
52 int natts = typeinfo->natts;
55 /* Check if any columns require detoast work */
58 for (i = 0; i < natts; i++)
60 Form_pg_attribute attr = TupleDescAttr(typeinfo, i);
62 if (attr->attisdropped)
64 if (attr->attlen == -1)
72 /* Set up appropriate callback */
75 myState->pub.receiveSlot = tstoreReceiveSlot_detoast;
76 /* Create workspace */
77 myState->outvalues = (Datum *)
78 MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
79 myState->tofree = (Datum *)
80 MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
84 myState->pub.receiveSlot = tstoreReceiveSlot_notoast;
85 myState->outvalues = NULL;
86 myState->tofree = NULL;
91 * Receive a tuple from the executor and store it in the tuplestore.
92 * This is for the easy case where we don't have to detoast.
95 tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self)
97 TStoreState *myState = (TStoreState *) self;
99 tuplestore_puttupleslot(myState->tstore, slot);
105 * Receive a tuple from the executor and store it in the tuplestore.
106 * This is for the case where we have to detoast any toasted values.
109 tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self)
111 TStoreState *myState = (TStoreState *) self;
112 TupleDesc typeinfo = slot->tts_tupleDescriptor;
113 int natts = typeinfo->natts;
116 MemoryContext oldcxt;
118 /* Make sure the tuple is fully deconstructed */
119 slot_getallattrs(slot);
122 * Fetch back any out-of-line datums. We build the new datums array in
123 * myState->outvalues[] (but we can re-use the slot's isnull array). Also,
124 * remember the fetched values to free afterwards.
127 for (i = 0; i < natts; i++)
129 Datum val = slot->tts_values[i];
130 Form_pg_attribute attr = TupleDescAttr(typeinfo, i);
132 if (!attr->attisdropped && attr->attlen == -1 && !slot->tts_isnull[i])
134 if (VARATT_IS_EXTERNAL(DatumGetPointer(val)))
136 val = PointerGetDatum(heap_tuple_fetch_attr((struct varlena *)
137 DatumGetPointer(val)));
138 myState->tofree[nfree++] = val;
142 myState->outvalues[i] = val;
146 * Push the modified tuple into the tuplestore.
148 oldcxt = MemoryContextSwitchTo(myState->cxt);
149 tuplestore_putvalues(myState->tstore, typeinfo,
150 myState->outvalues, slot->tts_isnull);
151 MemoryContextSwitchTo(oldcxt);
153 /* And release any temporary detoasted values */
154 for (i = 0; i < nfree; i++)
155 pfree(DatumGetPointer(myState->tofree[i]));
161 * Clean up at end of an executor run
164 tstoreShutdownReceiver(DestReceiver *self)
166 TStoreState *myState = (TStoreState *) self;
168 /* Release workspace if any */
169 if (myState->outvalues)
170 pfree(myState->outvalues);
171 myState->outvalues = NULL;
173 pfree(myState->tofree);
174 myState->tofree = NULL;
178 * Destroy receiver when done with it
181 tstoreDestroyReceiver(DestReceiver *self)
187 * Initially create a DestReceiver object.
190 CreateTuplestoreDestReceiver(void)
192 TStoreState *self = (TStoreState *) palloc0(sizeof(TStoreState));
194 self->pub.receiveSlot = tstoreReceiveSlot_notoast; /* might change */
195 self->pub.rStartup = tstoreStartupReceiver;
196 self->pub.rShutdown = tstoreShutdownReceiver;
197 self->pub.rDestroy = tstoreDestroyReceiver;
198 self->pub.mydest = DestTuplestore;
200 /* private fields will be set by SetTuplestoreDestReceiverParams */
202 return (DestReceiver *) self;
206 * Set parameters for a TuplestoreDestReceiver
209 SetTuplestoreDestReceiverParams(DestReceiver *self,
210 Tuplestorestate *tStore,
211 MemoryContext tContext,
214 TStoreState *myState = (TStoreState *) self;
216 Assert(myState->pub.mydest == DestTuplestore);
217 myState->tstore = tStore;
218 myState->cxt = tContext;
219 myState->detoast = detoast;