Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * tstoreReceiver.c
4 : * An implementation of DestReceiver that stores the result tuples in
5 : * a Tuplestore.
6 : *
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.
10 : *
11 : *
12 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
13 : * Portions Copyright (c) 1994, Regents of the University of California
14 : *
15 : * IDENTIFICATION
16 : * src/backend/executor/tstoreReceiver.c
17 : *
18 : *-------------------------------------------------------------------------
19 : */
20 :
21 : #include "postgres.h"
22 :
23 : #include "access/tuptoaster.h"
24 : #include "executor/tstoreReceiver.h"
25 :
26 :
27 : typedef struct
28 : {
29 : DestReceiver pub;
30 : /* parameters: */
31 : Tuplestorestate *tstore; /* where to put the data */
32 : MemoryContext cxt; /* context containing tstore */
33 : bool detoast; /* were we told to detoast? */
34 : /* workspace: */
35 : Datum *outvalues; /* values array for result tuple */
36 : Datum *tofree; /* temp values to be pfree'd */
37 : } TStoreState;
38 :
39 :
40 : static bool tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self);
41 : static bool tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self);
42 :
43 :
44 : /*
45 : * Prepare to receive tuples from executor.
46 : */
47 : static void
48 1645 : tstoreStartupReceiver(DestReceiver *self, int operation, TupleDesc typeinfo)
49 : {
50 1645 : TStoreState *myState = (TStoreState *) self;
51 1645 : bool needtoast = false;
52 1645 : int natts = typeinfo->natts;
53 : int i;
54 :
55 : /* Check if any columns require detoast work */
56 1645 : if (myState->detoast)
57 : {
58 26 : for (i = 0; i < natts; i++)
59 : {
60 23 : Form_pg_attribute attr = TupleDescAttr(typeinfo, i);
61 :
62 23 : if (attr->attisdropped)
63 0 : continue;
64 23 : if (attr->attlen == -1)
65 : {
66 2 : needtoast = true;
67 2 : break;
68 : }
69 : }
70 : }
71 :
72 : /* Set up appropriate callback */
73 1645 : if (needtoast)
74 : {
75 2 : myState->pub.receiveSlot = tstoreReceiveSlot_detoast;
76 : /* Create workspace */
77 2 : myState->outvalues = (Datum *)
78 2 : MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
79 2 : myState->tofree = (Datum *)
80 2 : MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
81 : }
82 : else
83 : {
84 1643 : myState->pub.receiveSlot = tstoreReceiveSlot_notoast;
85 1643 : myState->outvalues = NULL;
86 1643 : myState->tofree = NULL;
87 : }
88 1645 : }
89 :
90 : /*
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.
93 : */
94 : static bool
95 17557 : tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self)
96 : {
97 17557 : TStoreState *myState = (TStoreState *) self;
98 :
99 17557 : tuplestore_puttupleslot(myState->tstore, slot);
100 :
101 17557 : return true;
102 : }
103 :
104 : /*
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.
107 : */
108 : static bool
109 6 : tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self)
110 : {
111 6 : TStoreState *myState = (TStoreState *) self;
112 6 : TupleDesc typeinfo = slot->tts_tupleDescriptor;
113 6 : int natts = typeinfo->natts;
114 : int nfree;
115 : int i;
116 : MemoryContext oldcxt;
117 :
118 : /* Make sure the tuple is fully deconstructed */
119 6 : slot_getallattrs(slot);
120 :
121 : /*
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.
125 : */
126 6 : nfree = 0;
127 18 : for (i = 0; i < natts; i++)
128 : {
129 12 : Datum val = slot->tts_values[i];
130 12 : Form_pg_attribute attr = TupleDescAttr(typeinfo, i);
131 :
132 12 : if (!attr->attisdropped && attr->attlen == -1 && !slot->tts_isnull[i])
133 : {
134 5 : if (VARATT_IS_EXTERNAL(DatumGetPointer(val)))
135 : {
136 0 : val = PointerGetDatum(heap_tuple_fetch_attr((struct varlena *)
137 : DatumGetPointer(val)));
138 0 : myState->tofree[nfree++] = val;
139 : }
140 : }
141 :
142 12 : myState->outvalues[i] = val;
143 : }
144 :
145 : /*
146 : * Push the modified tuple into the tuplestore.
147 : */
148 6 : oldcxt = MemoryContextSwitchTo(myState->cxt);
149 6 : tuplestore_putvalues(myState->tstore, typeinfo,
150 : myState->outvalues, slot->tts_isnull);
151 6 : MemoryContextSwitchTo(oldcxt);
152 :
153 : /* And release any temporary detoasted values */
154 6 : for (i = 0; i < nfree; i++)
155 0 : pfree(DatumGetPointer(myState->tofree[i]));
156 :
157 6 : return true;
158 : }
159 :
160 : /*
161 : * Clean up at end of an executor run
162 : */
163 : static void
164 1634 : tstoreShutdownReceiver(DestReceiver *self)
165 : {
166 1634 : TStoreState *myState = (TStoreState *) self;
167 :
168 : /* Release workspace if any */
169 1634 : if (myState->outvalues)
170 2 : pfree(myState->outvalues);
171 1634 : myState->outvalues = NULL;
172 1634 : if (myState->tofree)
173 2 : pfree(myState->tofree);
174 1634 : myState->tofree = NULL;
175 1634 : }
176 :
177 : /*
178 : * Destroy receiver when done with it
179 : */
180 : static void
181 1634 : tstoreDestroyReceiver(DestReceiver *self)
182 : {
183 1634 : pfree(self);
184 1634 : }
185 :
186 : /*
187 : * Initially create a DestReceiver object.
188 : */
189 : DestReceiver *
190 1668 : CreateTuplestoreDestReceiver(void)
191 : {
192 1668 : TStoreState *self = (TStoreState *) palloc0(sizeof(TStoreState));
193 :
194 1668 : self->pub.receiveSlot = tstoreReceiveSlot_notoast; /* might change */
195 1668 : self->pub.rStartup = tstoreStartupReceiver;
196 1668 : self->pub.rShutdown = tstoreShutdownReceiver;
197 1668 : self->pub.rDestroy = tstoreDestroyReceiver;
198 1668 : self->pub.mydest = DestTuplestore;
199 :
200 : /* private fields will be set by SetTuplestoreDestReceiverParams */
201 :
202 1668 : return (DestReceiver *) self;
203 : }
204 :
205 : /*
206 : * Set parameters for a TuplestoreDestReceiver
207 : */
208 : void
209 1668 : SetTuplestoreDestReceiverParams(DestReceiver *self,
210 : Tuplestorestate *tStore,
211 : MemoryContext tContext,
212 : bool detoast)
213 : {
214 1668 : TStoreState *myState = (TStoreState *) self;
215 :
216 1668 : Assert(myState->pub.mydest == DestTuplestore);
217 1668 : myState->tstore = tStore;
218 1668 : myState->cxt = tContext;
219 1668 : myState->detoast = detoast;
220 1668 : }
|