PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
tstoreReceiver.c
Go to the documentation of this file.
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 * Also optionally, we can apply a tuple conversion map before storing.
12 *
13 *
14 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
15 * Portions Copyright (c) 1994, Regents of the University of California
16 *
17 * IDENTIFICATION
18 * src/backend/executor/tstoreReceiver.c
19 *
20 *-------------------------------------------------------------------------
21 */
22
23#include "postgres.h"
24
25#include "access/detoast.h"
26#include "access/tupconvert.h"
28
29
30typedef struct
31{
33 /* parameters: */
34 Tuplestorestate *tstore; /* where to put the data */
35 MemoryContext cxt; /* context containing tstore */
36 bool detoast; /* were we told to detoast? */
37 TupleDesc target_tupdesc; /* target tupdesc, or NULL if none */
38 const char *map_failure_msg; /* tupdesc mapping failure message */
39 /* workspace: */
40 Datum *outvalues; /* values array for result tuple */
41 Datum *tofree; /* temp values to be pfree'd */
42 TupleConversionMap *tupmap; /* conversion map, if needed */
43 TupleTableSlot *mapslot; /* slot for mapped tuples */
45
46
50
51
52/*
53 * Prepare to receive tuples from executor.
54 */
55static void
56tstoreStartupReceiver(DestReceiver *self, int operation, TupleDesc typeinfo)
57{
58 TStoreState *myState = (TStoreState *) self;
59 bool needtoast = false;
60 int natts = typeinfo->natts;
61 int i;
62
63 /* Check if any columns require detoast work */
64 if (myState->detoast)
65 {
66 for (i = 0; i < natts; i++)
67 {
68 CompactAttribute *attr = TupleDescCompactAttr(typeinfo, i);
69
70 if (attr->attisdropped)
71 continue;
72 if (attr->attlen == -1)
73 {
74 needtoast = true;
75 break;
76 }
77 }
78 }
79
80 /* Check if tuple conversion is needed */
81 if (myState->target_tupdesc)
82 myState->tupmap = convert_tuples_by_position(typeinfo,
83 myState->target_tupdesc,
84 myState->map_failure_msg);
85 else
86 myState->tupmap = NULL;
87
88 /* Set up appropriate callback */
89 if (needtoast)
90 {
91 Assert(!myState->tupmap);
93 /* Create workspace */
94 myState->outvalues = (Datum *)
95 MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
96 myState->tofree = (Datum *)
97 MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
98 myState->mapslot = NULL;
99 }
100 else if (myState->tupmap)
101 {
103 myState->outvalues = NULL;
104 myState->tofree = NULL;
107 }
108 else
109 {
111 myState->outvalues = NULL;
112 myState->tofree = NULL;
113 myState->mapslot = NULL;
114 }
115}
116
117/*
118 * Receive a tuple from the executor and store it in the tuplestore.
119 * This is for the easy case where we don't have to detoast nor map anything.
120 */
121static bool
123{
124 TStoreState *myState = (TStoreState *) self;
125
126 tuplestore_puttupleslot(myState->tstore, slot);
127
128 return true;
129}
130
131/*
132 * Receive a tuple from the executor and store it in the tuplestore.
133 * This is for the case where we have to detoast any toasted values.
134 */
135static bool
137{
138 TStoreState *myState = (TStoreState *) self;
139 TupleDesc typeinfo = slot->tts_tupleDescriptor;
140 int natts = typeinfo->natts;
141 int nfree;
142 int i;
143 MemoryContext oldcxt;
144
145 /* Make sure the tuple is fully deconstructed */
146 slot_getallattrs(slot);
147
148 /*
149 * Fetch back any out-of-line datums. We build the new datums array in
150 * myState->outvalues[] (but we can re-use the slot's isnull array). Also,
151 * remember the fetched values to free afterwards.
152 */
153 nfree = 0;
154 for (i = 0; i < natts; i++)
155 {
156 Datum val = slot->tts_values[i];
157 CompactAttribute *attr = TupleDescCompactAttr(typeinfo, i);
158
159 if (!attr->attisdropped && attr->attlen == -1 && !slot->tts_isnull[i])
160 {
162 {
165 myState->tofree[nfree++] = val;
166 }
167 }
168
169 myState->outvalues[i] = val;
170 }
171
172 /*
173 * Push the modified tuple into the tuplestore.
174 */
175 oldcxt = MemoryContextSwitchTo(myState->cxt);
176 tuplestore_putvalues(myState->tstore, typeinfo,
177 myState->outvalues, slot->tts_isnull);
178 MemoryContextSwitchTo(oldcxt);
179
180 /* And release any temporary detoasted values */
181 for (i = 0; i < nfree; i++)
182 pfree(DatumGetPointer(myState->tofree[i]));
183
184 return true;
185}
186
187/*
188 * Receive a tuple from the executor and store it in the tuplestore.
189 * This is for the case where we must apply a tuple conversion map.
190 */
191static bool
193{
194 TStoreState *myState = (TStoreState *) self;
195
196 execute_attr_map_slot(myState->tupmap->attrMap, slot, myState->mapslot);
197 tuplestore_puttupleslot(myState->tstore, myState->mapslot);
198
199 return true;
200}
201
202/*
203 * Clean up at end of an executor run
204 */
205static void
207{
208 TStoreState *myState = (TStoreState *) self;
209
210 /* Release workspace if any */
211 if (myState->outvalues)
212 pfree(myState->outvalues);
213 myState->outvalues = NULL;
214 if (myState->tofree)
215 pfree(myState->tofree);
216 myState->tofree = NULL;
217 if (myState->tupmap)
218 free_conversion_map(myState->tupmap);
219 myState->tupmap = NULL;
220 if (myState->mapslot)
222 myState->mapslot = NULL;
223}
224
225/*
226 * Destroy receiver when done with it
227 */
228static void
230{
231 pfree(self);
232}
233
234/*
235 * Initially create a DestReceiver object.
236 */
239{
240 TStoreState *self = (TStoreState *) palloc0(sizeof(TStoreState));
241
242 self->pub.receiveSlot = tstoreReceiveSlot_notoast; /* might change */
246 self->pub.mydest = DestTuplestore;
247
248 /* private fields will be set by SetTuplestoreDestReceiverParams */
249
250 return (DestReceiver *) self;
251}
252
253/*
254 * Set parameters for a TuplestoreDestReceiver
255 *
256 * tStore: where to store the tuples
257 * tContext: memory context containing tStore
258 * detoast: forcibly detoast contained data?
259 * target_tupdesc: if not NULL, forcibly convert tuples to this rowtype
260 * map_failure_msg: error message to use if mapping to target_tupdesc fails
261 *
262 * We don't currently support both detoast and target_tupdesc at the same
263 * time, just because no existing caller needs that combination.
264 */
265void
267 Tuplestorestate *tStore,
268 MemoryContext tContext,
269 bool detoast,
270 TupleDesc target_tupdesc,
271 const char *map_failure_msg)
272{
273 TStoreState *myState = (TStoreState *) self;
274
275 Assert(!(detoast && target_tupdesc));
276
277 Assert(myState->pub.mydest == DestTuplestore);
278 myState->tstore = tStore;
279 myState->cxt = tContext;
280 myState->detoast = detoast;
281 myState->target_tupdesc = target_tupdesc;
282 myState->map_failure_msg = map_failure_msg;
283}
#define Assert(condition)
Definition: c.h:812
@ DestTuplestore
Definition: dest.h:93
struct varlena * detoast_external_attr(struct varlena *attr)
Definition: detoast.c:45
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1425
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:84
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1441
long val
Definition: informix.c:689
int i
Definition: isn.c:72
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc0(Size size)
Definition: mcxt.c:1347
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
bool attisdropped
Definition: tupdesc.h:75
int16 attlen
Definition: tupdesc.h:69
Tuplestorestate * tstore
MemoryContext cxt
const char * map_failure_msg
TupleTableSlot * mapslot
Datum * tofree
TupleDesc target_tupdesc
DestReceiver pub
TupleConversionMap * tupmap
Datum * outvalues
AttrMap * attrMap
Definition: tupconvert.h:28
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:123
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
void(* rStartup)(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition: dest.h:121
void(* rShutdown)(DestReceiver *self)
Definition: dest.h:124
bool(* receiveSlot)(TupleTableSlot *slot, DestReceiver *self)
Definition: dest.h:118
void(* rDestroy)(DestReceiver *self)
Definition: dest.h:126
CommandDest mydest
Definition: dest.h:128
Definition: c.h:641
static bool tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self)
DestReceiver * CreateTuplestoreDestReceiver(void)
static bool tstoreReceiveSlot_tupmap(TupleTableSlot *slot, DestReceiver *self)
static void tstoreStartupReceiver(DestReceiver *self, int operation, TupleDesc typeinfo)
static void tstoreShutdownReceiver(DestReceiver *self)
void SetTuplestoreDestReceiverParams(DestReceiver *self, Tuplestorestate *tStore, MemoryContext tContext, bool detoast, TupleDesc target_tupdesc, const char *map_failure_msg)
static void tstoreDestroyReceiver(DestReceiver *self)
static bool tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self)
void free_conversion_map(TupleConversionMap *map)
Definition: tupconvert.c:299
TupleConversionMap * convert_tuples_by_position(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:59
TupleTableSlot * execute_attr_map_slot(AttrMap *attrMap, TupleTableSlot *in_slot, TupleTableSlot *out_slot)
Definition: tupconvert.c:192
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:169
void tuplestore_puttupleslot(Tuplestorestate *state, TupleTableSlot *slot)
Definition: tuplestore.c:742
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:784
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:368
#define VARATT_IS_EXTERNAL(PTR)
Definition: varatt.h:289