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-2018, 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 	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
tstoreReceiveSlot_notoast(TupleTableSlot * slot,DestReceiver * self)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
tstoreReceiveSlot_detoast(TupleTableSlot * slot,DestReceiver * self)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
tstoreShutdownReceiver(DestReceiver * self)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
tstoreDestroyReceiver(DestReceiver * self)181 tstoreDestroyReceiver(DestReceiver *self)
182 {
183 	pfree(self);
184 }
185 
186 /*
187  * Initially create a DestReceiver object.
188  */
189 DestReceiver *
CreateTuplestoreDestReceiver(void)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
SetTuplestoreDestReceiverParams(DestReceiver * self,Tuplestorestate * tStore,MemoryContext tContext,bool detoast)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 }
221