1
1
/*-------------------------------------------------------------------------
2
2
*
3
3
* tstoreReceiver.c
4
- * an implementation of DestReceiver that stores the result tuples in
5
- * a Tuplestore
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.
6
10
*
7
11
*
8
12
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
9
13
* Portions Copyright (c) 1994, Regents of the University of California
10
14
*
11
15
* IDENTIFICATION
12
- * $PostgreSQL: pgsql/src/backend/executor/tstoreReceiver.c,v 1.20 2008/11/30 20:51:25 tgl Exp $
16
+ * $PostgreSQL: pgsql/src/backend/executor/tstoreReceiver.c,v 1.21 2008/12/01 17:06:21 tgl Exp $
13
17
*
14
18
*-------------------------------------------------------------------------
15
19
*/
16
20
17
21
#include "postgres.h"
18
22
23
+ #include "access/tuptoaster.h"
19
24
#include "executor/tstoreReceiver.h"
20
25
21
26
22
27
typedef struct
23
28
{
24
29
DestReceiver pub ;
25
- Tuplestorestate * tstore ;
26
- MemoryContext cxt ;
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 */
27
37
} TStoreState ;
28
38
29
39
40
+ static void tstoreReceiveSlot_notoast (TupleTableSlot * slot , DestReceiver * self );
41
+ static void tstoreReceiveSlot_detoast (TupleTableSlot * slot , DestReceiver * self );
42
+
43
+
30
44
/*
31
45
* Prepare to receive tuples from executor.
32
46
*/
33
47
static void
34
48
tstoreStartupReceiver (DestReceiver * self , int operation , TupleDesc typeinfo )
35
49
{
36
- /* do nothing */
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
+ }
37
87
}
38
88
39
89
/*
40
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.
41
92
*/
42
93
static void
43
- tstoreReceiveSlot (TupleTableSlot * slot , DestReceiver * self )
94
+ tstoreReceiveSlot_notoast (TupleTableSlot * slot , DestReceiver * self )
44
95
{
45
96
TStoreState * myState = (TStoreState * ) self ;
46
97
MemoryContext oldcxt = MemoryContextSwitchTo (myState -> cxt );
@@ -50,13 +101,77 @@ tstoreReceiveSlot(TupleTableSlot *slot, DestReceiver *self)
50
101
MemoryContextSwitchTo (oldcxt );
51
102
}
52
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 void
109
+ tstoreReceiveSlot_detoast (TupleTableSlot * slot , DestReceiver * self )
110
+ {
111
+ TStoreState * myState = (TStoreState * ) self ;
112
+ TupleDesc typeinfo = slot -> tts_tupleDescriptor ;
113
+ Form_pg_attribute * attrs = typeinfo -> attrs ;
114
+ int natts = typeinfo -> natts ;
115
+ int nfree ;
116
+ int i ;
117
+ MemoryContext oldcxt ;
118
+
119
+ /* Make sure the tuple is fully deconstructed */
120
+ slot_getallattrs (slot );
121
+
122
+ /*
123
+ * Fetch back any out-of-line datums. We build the new datums array in
124
+ * myState->outvalues[] (but we can re-use the slot's isnull array).
125
+ * Also, remember the fetched values to free afterwards.
126
+ */
127
+ nfree = 0 ;
128
+ for (i = 0 ; i < natts ; i ++ )
129
+ {
130
+ Datum val = slot -> tts_values [i ];
131
+
132
+ if (!attrs [i ]-> attisdropped &&
133
+ attrs [i ]-> attlen == -1 &&
134
+ !slot -> tts_isnull [i ])
135
+ {
136
+ if (VARATT_IS_EXTERNAL (DatumGetPointer (val )))
137
+ {
138
+ val = PointerGetDatum (heap_tuple_fetch_attr ((struct varlena * )
139
+ DatumGetPointer (val )));
140
+ myState -> tofree [nfree ++ ] = val ;
141
+ }
142
+ }
143
+
144
+ myState -> outvalues [i ] = val ;
145
+ }
146
+
147
+ /*
148
+ * Push the modified tuple into the tuplestore.
149
+ */
150
+ oldcxt = MemoryContextSwitchTo (myState -> cxt );
151
+ tuplestore_putvalues (myState -> tstore , typeinfo ,
152
+ myState -> outvalues , slot -> tts_isnull );
153
+ MemoryContextSwitchTo (oldcxt );
154
+
155
+ /* And release any temporary detoasted values */
156
+ for (i = 0 ; i < nfree ; i ++ )
157
+ pfree (DatumGetPointer (myState -> tofree [i ]));
158
+ }
159
+
53
160
/*
54
161
* Clean up at end of an executor run
55
162
*/
56
163
static void
57
164
tstoreShutdownReceiver (DestReceiver * self )
58
165
{
59
- /* do nothing */
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 ;
60
175
}
61
176
62
177
/*
@@ -76,7 +191,7 @@ CreateTuplestoreDestReceiver(void)
76
191
{
77
192
TStoreState * self = (TStoreState * ) palloc0 (sizeof (TStoreState ));
78
193
79
- self -> pub .receiveSlot = tstoreReceiveSlot ;
194
+ self -> pub .receiveSlot = tstoreReceiveSlot_notoast ; /* might change */
80
195
self -> pub .rStartup = tstoreStartupReceiver ;
81
196
self -> pub .rShutdown = tstoreShutdownReceiver ;
82
197
self -> pub .rDestroy = tstoreDestroyReceiver ;
@@ -93,11 +208,13 @@ CreateTuplestoreDestReceiver(void)
93
208
void
94
209
SetTuplestoreDestReceiverParams (DestReceiver * self ,
95
210
Tuplestorestate * tStore ,
96
- MemoryContext tContext )
211
+ MemoryContext tContext ,
212
+ bool detoast )
97
213
{
98
214
TStoreState * myState = (TStoreState * ) self ;
99
215
100
216
Assert (myState -> pub .mydest == DestTuplestore );
101
217
myState -> tstore = tStore ;
102
218
myState -> cxt = tContext ;
219
+ myState -> detoast = detoast ;
103
220
}
0 commit comments