]> granicus.if.org Git - postgresql/blob - src/backend/executor/tstoreReceiver.c
Make some small planner API cleanups.
[postgresql] / src / backend / executor / tstoreReceiver.c
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-2019, 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 tstoreStartupReceiver(DestReceiver *self, int operation, TupleDesc typeinfo)
49 {
50         TStoreState *myState = (TStoreState *) self;
51         bool            needtoast = false;
52         int                     natts = typeinfo->natts;
53         int                     i;
54
55         /* Check if any columns require detoast work */
56         if (myState->detoast)
57         {
58                 for (i = 0; i < natts; i++)
59                 {
60                         Form_pg_attribute attr = TupleDescAttr(typeinfo, i);
61
62                         if (attr->attisdropped)
63                                 continue;
64                         if (attr->attlen == -1)
65                         {
66                                 needtoast = true;
67                                 break;
68                         }
69                 }
70         }
71
72         /* Set up appropriate callback */
73         if (needtoast)
74         {
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));
81         }
82         else
83         {
84                 myState->pub.receiveSlot = tstoreReceiveSlot_notoast;
85                 myState->outvalues = NULL;
86                 myState->tofree = NULL;
87         }
88 }
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 tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self)
96 {
97         TStoreState *myState = (TStoreState *) self;
98
99         tuplestore_puttupleslot(myState->tstore, slot);
100
101         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 tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self)
110 {
111         TStoreState *myState = (TStoreState *) self;
112         TupleDesc       typeinfo = slot->tts_tupleDescriptor;
113         int                     natts = typeinfo->natts;
114         int                     nfree;
115         int                     i;
116         MemoryContext oldcxt;
117
118         /* Make sure the tuple is fully deconstructed */
119         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         nfree = 0;
127         for (i = 0; i < natts; i++)
128         {
129                 Datum           val = slot->tts_values[i];
130                 Form_pg_attribute attr = TupleDescAttr(typeinfo, i);
131
132                 if (!attr->attisdropped && attr->attlen == -1 && !slot->tts_isnull[i])
133                 {
134                         if (VARATT_IS_EXTERNAL(DatumGetPointer(val)))
135                         {
136                                 val = PointerGetDatum(heap_tuple_fetch_attr((struct varlena *)
137                                                                                                                         DatumGetPointer(val)));
138                                 myState->tofree[nfree++] = val;
139                         }
140                 }
141
142                 myState->outvalues[i] = val;
143         }
144
145         /*
146          * Push the modified tuple into the tuplestore.
147          */
148         oldcxt = MemoryContextSwitchTo(myState->cxt);
149         tuplestore_putvalues(myState->tstore, typeinfo,
150                                                  myState->outvalues, slot->tts_isnull);
151         MemoryContextSwitchTo(oldcxt);
152
153         /* And release any temporary detoasted values */
154         for (i = 0; i < nfree; i++)
155                 pfree(DatumGetPointer(myState->tofree[i]));
156
157         return true;
158 }
159
160 /*
161  * Clean up at end of an executor run
162  */
163 static void
164 tstoreShutdownReceiver(DestReceiver *self)
165 {
166         TStoreState *myState = (TStoreState *) self;
167
168         /* Release workspace if any */
169         if (myState->outvalues)
170                 pfree(myState->outvalues);
171         myState->outvalues = NULL;
172         if (myState->tofree)
173                 pfree(myState->tofree);
174         myState->tofree = NULL;
175 }
176
177 /*
178  * Destroy receiver when done with it
179  */
180 static void
181 tstoreDestroyReceiver(DestReceiver *self)
182 {
183         pfree(self);
184 }
185
186 /*
187  * Initially create a DestReceiver object.
188  */
189 DestReceiver *
190 CreateTuplestoreDestReceiver(void)
191 {
192         TStoreState *self = (TStoreState *) palloc0(sizeof(TStoreState));
193
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;
199
200         /* private fields will be set by SetTuplestoreDestReceiverParams */
201
202         return (DestReceiver *) self;
203 }
204
205 /*
206  * Set parameters for a TuplestoreDestReceiver
207  */
208 void
209 SetTuplestoreDestReceiverParams(DestReceiver *self,
210                                                                 Tuplestorestate *tStore,
211                                                                 MemoryContext tContext,
212                                                                 bool detoast)
213 {
214         TStoreState *myState = (TStoreState *) self;
215
216         Assert(myState->pub.mydest == DestTuplestore);
217         myState->tstore = tStore;
218         myState->cxt = tContext;
219         myState->detoast = detoast;
220 }