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-2011, 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 void tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self);
41
static void 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
Form_pg_attribute *attrs = typeinfo->attrs;
53
int natts = typeinfo->natts;
56
/* Check if any columns require detoast work */
59
for (i = 0; i < natts; i++)
61
if (attrs[i]->attisdropped)
63
if (attrs[i]->attlen == -1)
71
/* Set up appropriate callback */
74
myState->pub.receiveSlot = tstoreReceiveSlot_detoast;
75
/* Create workspace */
76
myState->outvalues = (Datum *)
77
MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
78
myState->tofree = (Datum *)
79
MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
83
myState->pub.receiveSlot = tstoreReceiveSlot_notoast;
84
myState->outvalues = NULL;
85
myState->tofree = NULL;
90
* Receive a tuple from the executor and store it in the tuplestore.
91
* This is for the easy case where we don't have to detoast.
94
tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self)
96
TStoreState *myState = (TStoreState *) self;
98
tuplestore_puttupleslot(myState->tstore, slot);
102
* Receive a tuple from the executor and store it in the tuplestore.
103
* This is for the case where we have to detoast any toasted values.
106
tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self)
108
TStoreState *myState = (TStoreState *) self;
109
TupleDesc typeinfo = slot->tts_tupleDescriptor;
110
Form_pg_attribute *attrs = typeinfo->attrs;
111
int natts = typeinfo->natts;
114
MemoryContext oldcxt;
116
/* Make sure the tuple is fully deconstructed */
117
slot_getallattrs(slot);
120
* Fetch back any out-of-line datums. We build the new datums array in
121
* myState->outvalues[] (but we can re-use the slot's isnull array). Also,
122
* remember the fetched values to free afterwards.
125
for (i = 0; i < natts; i++)
127
Datum val = slot->tts_values[i];
129
if (!attrs[i]->attisdropped &&
130
attrs[i]->attlen == -1 &&
131
!slot->tts_isnull[i])
133
if (VARATT_IS_EXTERNAL(DatumGetPointer(val)))
135
val = PointerGetDatum(heap_tuple_fetch_attr((struct varlena *)
136
DatumGetPointer(val)));
137
myState->tofree[nfree++] = val;
141
myState->outvalues[i] = val;
145
* Push the modified tuple into the tuplestore.
147
oldcxt = MemoryContextSwitchTo(myState->cxt);
148
tuplestore_putvalues(myState->tstore, typeinfo,
149
myState->outvalues, slot->tts_isnull);
150
MemoryContextSwitchTo(oldcxt);
152
/* And release any temporary detoasted values */
153
for (i = 0; i < nfree; i++)
154
pfree(DatumGetPointer(myState->tofree[i]));
158
* Clean up at end of an executor run
161
tstoreShutdownReceiver(DestReceiver *self)
163
TStoreState *myState = (TStoreState *) self;
165
/* Release workspace if any */
166
if (myState->outvalues)
167
pfree(myState->outvalues);
168
myState->outvalues = NULL;
170
pfree(myState->tofree);
171
myState->tofree = NULL;
175
* Destroy receiver when done with it
178
tstoreDestroyReceiver(DestReceiver *self)
184
* Initially create a DestReceiver object.
187
CreateTuplestoreDestReceiver(void)
189
TStoreState *self = (TStoreState *) palloc0(sizeof(TStoreState));
191
self->pub.receiveSlot = tstoreReceiveSlot_notoast; /* might change */
192
self->pub.rStartup = tstoreStartupReceiver;
193
self->pub.rShutdown = tstoreShutdownReceiver;
194
self->pub.rDestroy = tstoreDestroyReceiver;
195
self->pub.mydest = DestTuplestore;
197
/* private fields will be set by SetTuplestoreDestReceiverParams */
199
return (DestReceiver *) self;
203
* Set parameters for a TuplestoreDestReceiver
206
SetTuplestoreDestReceiverParams(DestReceiver *self,
207
Tuplestorestate *tStore,
208
MemoryContext tContext,
211
TStoreState *myState = (TStoreState *) self;
213
Assert(myState->pub.mydest == DestTuplestore);
214
myState->tstore = tStore;
215
myState->cxt = tContext;
216
myState->detoast = detoast;