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
tstoreStartupReceiver(DestReceiver * self,int operation,TupleDesc typeinfo)48 tstoreStartupReceiver(DestReceiver *self, int operation, TupleDesc typeinfo)
49 {
50 	TStoreState *myState = (TStoreState *) self;
51 	bool		needtoast = false;
52 	Form_pg_attribute *attrs = typeinfo->attrs;
53 	int			natts = typeinfo->natts;
54 	int			i;
55 
56 	/* Check if any columns require detoast work */
57 	if (myState->detoast)
58 	{
59 		for (i = 0; i < natts; i++)
60 		{
61 			if (attrs[i]->attisdropped)
62 				continue;
63 			if (attrs[i]->attlen == -1)
64 			{
65 				needtoast = true;
66 				break;
67 			}
68 		}
69 	}
70 
71 	/* Set up appropriate callback */
72 	if (needtoast)
73 	{
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));
80 	}
81 	else
82 	{
83 		myState->pub.receiveSlot = tstoreReceiveSlot_notoast;
84 		myState->outvalues = NULL;
85 		myState->tofree = NULL;
86 	}
87 }
88 
89 /*
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.
92  */
93 static bool
tstoreReceiveSlot_notoast(TupleTableSlot * slot,DestReceiver * self)94 tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self)
95 {
96 	TStoreState *myState = (TStoreState *) self;
97 
98 	tuplestore_puttupleslot(myState->tstore, slot);
99 
100 	return true;
101 }
102 
103 /*
104  * Receive a tuple from the executor and store it in the tuplestore.
105  * This is for the case where we have to detoast any toasted values.
106  */
107 static bool
tstoreReceiveSlot_detoast(TupleTableSlot * slot,DestReceiver * self)108 tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self)
109 {
110 	TStoreState *myState = (TStoreState *) self;
111 	TupleDesc	typeinfo = slot->tts_tupleDescriptor;
112 	Form_pg_attribute *attrs = typeinfo->attrs;
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 
131 		if (!attrs[i]->attisdropped &&
132 			attrs[i]->attlen == -1 &&
133 			!slot->tts_isnull[i])
134 		{
135 			if (VARATT_IS_EXTERNAL(DatumGetPointer(val)))
136 			{
137 				val = PointerGetDatum(heap_tuple_fetch_attr((struct varlena *)
138 															DatumGetPointer(val)));
139 				myState->tofree[nfree++] = val;
140 			}
141 		}
142 
143 		myState->outvalues[i] = val;
144 	}
145 
146 	/*
147 	 * Push the modified tuple into the tuplestore.
148 	 */
149 	oldcxt = MemoryContextSwitchTo(myState->cxt);
150 	tuplestore_putvalues(myState->tstore, typeinfo,
151 						 myState->outvalues, slot->tts_isnull);
152 	MemoryContextSwitchTo(oldcxt);
153 
154 	/* And release any temporary detoasted values */
155 	for (i = 0; i < nfree; i++)
156 		pfree(DatumGetPointer(myState->tofree[i]));
157 
158 	return true;
159 }
160 
161 /*
162  * Clean up at end of an executor run
163  */
164 static void
tstoreShutdownReceiver(DestReceiver * self)165 tstoreShutdownReceiver(DestReceiver *self)
166 {
167 	TStoreState *myState = (TStoreState *) self;
168 
169 	/* Release workspace if any */
170 	if (myState->outvalues)
171 		pfree(myState->outvalues);
172 	myState->outvalues = NULL;
173 	if (myState->tofree)
174 		pfree(myState->tofree);
175 	myState->tofree = NULL;
176 }
177 
178 /*
179  * Destroy receiver when done with it
180  */
181 static void
tstoreDestroyReceiver(DestReceiver * self)182 tstoreDestroyReceiver(DestReceiver *self)
183 {
184 	pfree(self);
185 }
186 
187 /*
188  * Initially create a DestReceiver object.
189  */
190 DestReceiver *
CreateTuplestoreDestReceiver(void)191 CreateTuplestoreDestReceiver(void)
192 {
193 	TStoreState *self = (TStoreState *) palloc0(sizeof(TStoreState));
194 
195 	self->pub.receiveSlot = tstoreReceiveSlot_notoast;	/* might change */
196 	self->pub.rStartup = tstoreStartupReceiver;
197 	self->pub.rShutdown = tstoreShutdownReceiver;
198 	self->pub.rDestroy = tstoreDestroyReceiver;
199 	self->pub.mydest = DestTuplestore;
200 
201 	/* private fields will be set by SetTuplestoreDestReceiverParams */
202 
203 	return (DestReceiver *) self;
204 }
205 
206 /*
207  * Set parameters for a TuplestoreDestReceiver
208  */
209 void
SetTuplestoreDestReceiverParams(DestReceiver * self,Tuplestorestate * tStore,MemoryContext tContext,bool detoast)210 SetTuplestoreDestReceiverParams(DestReceiver *self,
211 								Tuplestorestate *tStore,
212 								MemoryContext tContext,
213 								bool detoast)
214 {
215 	TStoreState *myState = (TStoreState *) self;
216 
217 	Assert(myState->pub.mydest == DestTuplestore);
218 	myState->tstore = tStore;
219 	myState->cxt = tContext;
220 	myState->detoast = detoast;
221 }
222