Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * execTuples.c
4 : * Routines dealing with TupleTableSlots. These are used for resource
5 : * management associated with tuples (eg, releasing buffer pins for
6 : * tuples in disk buffers, or freeing the memory occupied by transient
7 : * tuples). Slots also provide access abstraction that lets us implement
8 : * "virtual" tuples to reduce data-copying overhead.
9 : *
10 : * Routines dealing with the type information for tuples. Currently,
11 : * the type information for a tuple is an array of FormData_pg_attribute.
12 : * This information is needed by routines manipulating tuples
13 : * (getattribute, formtuple, etc.).
14 : *
15 : *
16 : * EXAMPLE OF HOW TABLE ROUTINES WORK
17 : * Suppose we have a query such as SELECT emp.name FROM emp and we have
18 : * a single SeqScan node in the query plan.
19 : *
20 : * At ExecutorStart()
21 : * ----------------
22 : *
23 : * - ExecInitSeqScan() calls ExecInitScanTupleSlot() to construct a
24 : * TupleTableSlots for the tuples returned by the access method, and
25 : * ExecInitResultTypeTL() to define the node's return
26 : * type. ExecAssignScanProjectionInfo() will, if necessary, create
27 : * another TupleTableSlot for the tuples resulting from performing
28 : * target list projections.
29 : *
30 : * During ExecutorRun()
31 : * ----------------
32 : * - SeqNext() calls ExecStoreBufferHeapTuple() to place the tuple
33 : * returned by the access method into the scan tuple slot.
34 : *
35 : * - ExecSeqScan() (via ExecScan), if necessary, calls ExecProject(),
36 : * putting the result of the projection in the result tuple slot. If
37 : * not necessary, it directly returns the slot returned by SeqNext().
38 : *
39 : * - ExecutePlan() calls the output function.
40 : *
41 : * The important thing to watch in the executor code is how pointers
42 : * to the slots containing tuples are passed instead of the tuples
43 : * themselves. This facilitates the communication of related information
44 : * (such as whether or not a tuple should be pfreed, what buffer contains
45 : * this tuple, the tuple's tuple descriptor, etc). It also allows us
46 : * to avoid physically constructing projection tuples in many cases.
47 : *
48 : *
49 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
50 : * Portions Copyright (c) 1994, Regents of the University of California
51 : *
52 : *
53 : * IDENTIFICATION
54 : * src/backend/executor/execTuples.c
55 : *
56 : *-------------------------------------------------------------------------
57 : */
58 : #include "postgres.h"
59 :
60 : #include "access/heaptoast.h"
61 : #include "access/htup_details.h"
62 : #include "access/tupdesc_details.h"
63 : #include "catalog/pg_type.h"
64 : #include "funcapi.h"
65 : #include "nodes/nodeFuncs.h"
66 : #include "storage/bufmgr.h"
67 : #include "utils/builtins.h"
68 : #include "utils/expandeddatum.h"
69 : #include "utils/lsyscache.h"
70 : #include "utils/typcache.h"
71 :
72 : static TupleDesc ExecTypeFromTLInternal(List *targetList,
73 : bool skipjunk);
74 : static pg_attribute_always_inline void slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
75 : int natts);
76 : static inline void tts_buffer_heap_store_tuple(TupleTableSlot *slot,
77 : HeapTuple tuple,
78 : Buffer buffer,
79 : bool transfer_pin);
80 : static void tts_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, bool shouldFree);
81 :
82 :
83 : const TupleTableSlotOps TTSOpsVirtual;
84 : const TupleTableSlotOps TTSOpsHeapTuple;
85 : const TupleTableSlotOps TTSOpsMinimalTuple;
86 : const TupleTableSlotOps TTSOpsBufferHeapTuple;
87 :
88 :
89 : /*
90 : * TupleTableSlotOps implementations.
91 : */
92 :
93 : /*
94 : * TupleTableSlotOps implementation for VirtualTupleTableSlot.
95 : */
96 : static void
1605 andres 97 CBC 588860 : tts_virtual_init(TupleTableSlot *slot)
98 : {
99 588860 : }
100 :
101 : static void
102 577451 : tts_virtual_release(TupleTableSlot *slot)
103 : {
104 577451 : }
105 :
106 : static void
107 40183402 : tts_virtual_clear(TupleTableSlot *slot)
108 : {
109 40183402 : if (unlikely(TTS_SHOULDFREE(slot)))
110 : {
111 872835 : VirtualTupleTableSlot *vslot = (VirtualTupleTableSlot *) slot;
112 :
113 872835 : pfree(vslot->data);
114 872835 : vslot->data = NULL;
115 :
1495 116 872835 : slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
117 : }
118 :
1605 119 40183402 : slot->tts_nvalid = 0;
120 40183402 : slot->tts_flags |= TTS_FLAG_EMPTY;
1503 121 40183402 : ItemPointerSetInvalid(&slot->tts_tid);
1605 122 40183402 : }
123 :
124 : /*
125 : * VirtualTupleTableSlots always have fully populated tts_values and
126 : * tts_isnull arrays. So this function should never be called.
127 : */
128 : static void
1605 andres 129 UBC 0 : tts_virtual_getsomeattrs(TupleTableSlot *slot, int natts)
130 : {
131 0 : elog(ERROR, "getsomeattrs is not required to be called on a virtual tuple table slot");
132 : }
133 :
134 : /*
135 : * VirtualTupleTableSlots never provide system attributes (except those
136 : * handled generically, such as tableoid). We generally shouldn't get
137 : * here, but provide a user-friendly message if we do.
138 : */
139 : static Datum
1605 andres 140 CBC 6 : tts_virtual_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
141 : {
717 tgl 142 6 : Assert(!TTS_EMPTY(slot));
143 :
144 6 : ereport(ERROR,
145 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
146 : errmsg("cannot retrieve a system column in this context")));
147 :
148 : return 0; /* silence compiler warnings */
149 : }
150 :
151 : /*
152 : * To materialize a virtual slot all the datums that aren't passed by value
153 : * have to be copied into the slot's memory context. To do so, compute the
154 : * required size, and allocate enough memory to store all attributes. That's
155 : * good for cache hit ratio, but more importantly requires only memory
156 : * allocation/deallocation.
157 : */
158 : static void
1605 andres 159 2138818 : tts_virtual_materialize(TupleTableSlot *slot)
160 : {
161 2138818 : VirtualTupleTableSlot *vslot = (VirtualTupleTableSlot *) slot;
162 2138818 : TupleDesc desc = slot->tts_tupleDescriptor;
163 2138818 : Size sz = 0;
164 : char *data;
165 :
166 : /* already materialized */
167 2138818 : if (TTS_SHOULDFREE(slot))
168 191837 : return;
169 :
170 : /* compute size of memory required */
171 6044915 : for (int natt = 0; natt < desc->natts; natt++)
172 : {
173 4097934 : Form_pg_attribute att = TupleDescAttr(desc, natt);
174 : Datum val;
175 :
176 4097934 : if (att->attbyval || slot->tts_isnull[natt])
177 3184533 : continue;
178 :
179 913401 : val = slot->tts_values[natt];
180 :
181 913401 : if (att->attlen == -1 &&
182 617926 : VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(val)))
183 : {
184 : /*
185 : * We want to flatten the expanded value so that the materialized
186 : * slot doesn't depend on it.
187 : */
1605 andres 188 UBC 0 : sz = att_align_nominal(sz, att->attalign);
189 0 : sz += EOH_get_flat_size(DatumGetEOHP(val));
190 : }
191 : else
192 : {
1605 andres 193 CBC 913401 : sz = att_align_nominal(sz, att->attalign);
194 913401 : sz = att_addlength_datum(sz, att->attlen, val);
195 : }
196 : }
197 :
198 : /* all data is byval */
199 1946981 : if (sz == 0)
200 1074063 : return;
201 :
202 : /* allocate memory */
203 872918 : vslot->data = data = MemoryContextAlloc(slot->tts_mcxt, sz);
204 872918 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
205 :
206 : /* and copy all attributes into the pre-allocated space */
207 3348112 : for (int natt = 0; natt < desc->natts; natt++)
208 : {
209 2475194 : Form_pg_attribute att = TupleDescAttr(desc, natt);
210 : Datum val;
211 :
212 2475194 : if (att->attbyval || slot->tts_isnull[natt])
213 1561793 : continue;
214 :
215 913401 : val = slot->tts_values[natt];
216 :
217 913401 : if (att->attlen == -1 &&
218 617926 : VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(val)))
1605 andres 219 UBC 0 : {
220 : Size data_length;
221 :
222 : /*
223 : * We want to flatten the expanded value so that the materialized
224 : * slot doesn't depend on it.
225 : */
226 0 : ExpandedObjectHeader *eoh = DatumGetEOHP(val);
227 :
228 0 : data = (char *) att_align_nominal(data,
229 : att->attalign);
230 0 : data_length = EOH_get_flat_size(eoh);
231 0 : EOH_flatten_into(eoh, data, data_length);
232 :
233 0 : slot->tts_values[natt] = PointerGetDatum(data);
234 0 : data += data_length;
235 : }
236 : else
237 : {
1418 tgl 238 CBC 913401 : Size data_length = 0;
239 :
1605 andres 240 913401 : data = (char *) att_align_nominal(data, att->attalign);
241 913401 : data_length = att_addlength_datum(data_length, att->attlen, val);
242 :
243 913401 : memcpy(data, DatumGetPointer(val), data_length);
244 :
245 913401 : slot->tts_values[natt] = PointerGetDatum(data);
246 913401 : data += data_length;
247 : }
248 : }
249 : }
250 :
251 : static void
252 70477 : tts_virtual_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
253 : {
1295 tgl 254 70477 : TupleDesc srcdesc = srcslot->tts_tupleDescriptor;
255 :
1605 andres 256 70477 : Assert(srcdesc->natts <= dstslot->tts_tupleDescriptor->natts);
257 :
258 70477 : tts_virtual_clear(dstslot);
259 :
260 70477 : slot_getallattrs(srcslot);
261 :
262 145187 : for (int natt = 0; natt < srcdesc->natts; natt++)
263 : {
264 74710 : dstslot->tts_values[natt] = srcslot->tts_values[natt];
265 74710 : dstslot->tts_isnull[natt] = srcslot->tts_isnull[natt];
266 : }
267 :
268 70477 : dstslot->tts_nvalid = srcdesc->natts;
269 70477 : dstslot->tts_flags &= ~TTS_FLAG_EMPTY;
270 :
271 : /* make sure storage doesn't depend on external memory */
272 70477 : tts_virtual_materialize(dstslot);
273 70477 : }
274 :
275 : static HeapTuple
276 7068537 : tts_virtual_copy_heap_tuple(TupleTableSlot *slot)
277 : {
278 7068537 : Assert(!TTS_EMPTY(slot));
279 :
280 7068537 : return heap_form_tuple(slot->tts_tupleDescriptor,
281 : slot->tts_values,
282 : slot->tts_isnull);
283 : }
284 :
285 : static MinimalTuple
286 13270380 : tts_virtual_copy_minimal_tuple(TupleTableSlot *slot)
287 : {
288 13270380 : Assert(!TTS_EMPTY(slot));
289 :
290 13270380 : return heap_form_minimal_tuple(slot->tts_tupleDescriptor,
291 : slot->tts_values,
292 : slot->tts_isnull);
293 : }
294 :
295 :
296 : /*
297 : * TupleTableSlotOps implementation for HeapTupleTableSlot.
298 : */
299 :
300 : static void
301 5239628 : tts_heap_init(TupleTableSlot *slot)
302 : {
303 5239628 : }
304 :
305 : static void
306 5239231 : tts_heap_release(TupleTableSlot *slot)
307 : {
308 5239231 : }
309 :
310 : static void
311 11572437 : tts_heap_clear(TupleTableSlot *slot)
312 : {
313 11572437 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
314 :
315 : /* Free the memory for the heap tuple if it's allowed. */
316 11572437 : if (TTS_SHOULDFREE(slot))
317 : {
318 2309132 : heap_freetuple(hslot->tuple);
319 2309132 : slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
320 : }
321 :
322 11572437 : slot->tts_nvalid = 0;
323 11572437 : slot->tts_flags |= TTS_FLAG_EMPTY;
1503 324 11572437 : ItemPointerSetInvalid(&slot->tts_tid);
1605 325 11572437 : hslot->off = 0;
326 11572437 : hslot->tuple = NULL;
327 11572437 : }
328 :
329 : static void
330 11676807 : tts_heap_getsomeattrs(TupleTableSlot *slot, int natts)
331 : {
332 11676807 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
333 :
334 11676807 : Assert(!TTS_EMPTY(slot));
335 :
336 11676807 : slot_deform_heap_tuple(slot, hslot->tuple, &hslot->off, natts);
337 11676807 : }
338 :
339 : static Datum
1605 andres 340 UBC 0 : tts_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
341 : {
342 0 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
343 :
1250 tgl 344 0 : Assert(!TTS_EMPTY(slot));
345 :
346 : /*
347 : * In some code paths it's possible to get here with a non-materialized
348 : * slot, in which case we can't retrieve system columns.
349 : */
717 350 0 : if (!hslot->tuple)
351 0 : ereport(ERROR,
352 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
353 : errmsg("cannot retrieve a system column in this context")));
354 :
1605 andres 355 0 : return heap_getsysattr(hslot->tuple, attnum,
356 : slot->tts_tupleDescriptor, isnull);
357 : }
358 :
359 : static void
1605 andres 360 CBC 4286930 : tts_heap_materialize(TupleTableSlot *slot)
361 : {
362 4286930 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
363 : MemoryContext oldContext;
364 :
365 4286930 : Assert(!TTS_EMPTY(slot));
366 :
367 : /* If slot has its tuple already materialized, nothing to do. */
368 4286930 : if (TTS_SHOULDFREE(slot))
369 2178839 : return;
370 :
371 2108091 : oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
372 :
373 : /*
374 : * Have to deform from scratch, otherwise tts_values[] entries could point
375 : * into the non-materialized tuple (which might be gone when accessed).
376 : */
1250 tgl 377 2108091 : slot->tts_nvalid = 0;
378 2108091 : hslot->off = 0;
379 :
1605 andres 380 2108091 : if (!hslot->tuple)
381 2108084 : hslot->tuple = heap_form_tuple(slot->tts_tupleDescriptor,
382 : slot->tts_values,
383 : slot->tts_isnull);
384 : else
385 : {
386 : /*
387 : * The tuple contained in this slot is not allocated in the memory
388 : * context of the given slot (else it would have TTS_FLAG_SHOULDFREE
389 : * set). Copy the tuple into the given slot's memory context.
390 : */
391 7 : hslot->tuple = heap_copytuple(hslot->tuple);
392 : }
393 :
1250 tgl 394 2108091 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
395 :
1605 andres 396 2108091 : MemoryContextSwitchTo(oldContext);
397 : }
398 :
399 : static void
400 140898 : tts_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
401 : {
402 : HeapTuple tuple;
403 : MemoryContext oldcontext;
404 :
405 140898 : oldcontext = MemoryContextSwitchTo(dstslot->tts_mcxt);
406 140898 : tuple = ExecCopySlotHeapTuple(srcslot);
407 140898 : MemoryContextSwitchTo(oldcontext);
408 :
409 140898 : ExecStoreHeapTuple(tuple, dstslot, true);
410 140898 : }
411 :
412 : static HeapTuple
413 4215951 : tts_heap_get_heap_tuple(TupleTableSlot *slot)
414 : {
415 4215951 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
416 :
417 4215951 : Assert(!TTS_EMPTY(slot));
418 4215951 : if (!hslot->tuple)
1605 andres 419 UBC 0 : tts_heap_materialize(slot);
420 :
1605 andres 421 CBC 4215951 : return hslot->tuple;
422 : }
423 :
424 : static HeapTuple
425 70343 : tts_heap_copy_heap_tuple(TupleTableSlot *slot)
426 : {
427 70343 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
428 :
429 70343 : Assert(!TTS_EMPTY(slot));
430 70343 : if (!hslot->tuple)
1605 andres 431 UBC 0 : tts_heap_materialize(slot);
432 :
1605 andres 433 CBC 70343 : return heap_copytuple(hslot->tuple);
434 : }
435 :
436 : static MinimalTuple
437 2711 : tts_heap_copy_minimal_tuple(TupleTableSlot *slot)
438 : {
439 2711 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
440 :
441 2711 : if (!hslot->tuple)
442 19 : tts_heap_materialize(slot);
443 :
444 2711 : return minimal_tuple_from_heap_tuple(hslot->tuple);
445 : }
446 :
447 : static void
448 4222627 : tts_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, bool shouldFree)
449 : {
450 4222627 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
451 :
452 4222627 : tts_heap_clear(slot);
453 :
454 4222627 : slot->tts_nvalid = 0;
455 4222627 : hslot->tuple = tuple;
456 4222627 : hslot->off = 0;
1250 tgl 457 4222627 : slot->tts_flags &= ~(TTS_FLAG_EMPTY | TTS_FLAG_SHOULDFREE);
1503 andres 458 4222627 : slot->tts_tid = tuple->t_self;
459 :
1605 460 4222627 : if (shouldFree)
461 201050 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
462 4222627 : }
463 :
464 :
465 : /*
466 : * TupleTableSlotOps implementation for MinimalTupleTableSlot.
467 : */
468 :
469 : static void
470 211882 : tts_minimal_init(TupleTableSlot *slot)
471 : {
472 211882 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
473 :
474 : /*
475 : * Initialize the heap tuple pointer to access attributes of the minimal
476 : * tuple contained in the slot as if its a heap tuple.
477 : */
478 211882 : mslot->tuple = &mslot->minhdr;
479 211882 : }
480 :
481 : static void
482 194488 : tts_minimal_release(TupleTableSlot *slot)
483 : {
484 194488 : }
485 :
486 : static void
487 33384260 : tts_minimal_clear(TupleTableSlot *slot)
488 : {
489 33384260 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
490 :
491 33384260 : if (TTS_SHOULDFREE(slot))
492 : {
493 7778642 : heap_free_minimal_tuple(mslot->mintuple);
494 7778642 : slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
495 : }
496 :
497 33384260 : slot->tts_nvalid = 0;
498 33384260 : slot->tts_flags |= TTS_FLAG_EMPTY;
1503 499 33384260 : ItemPointerSetInvalid(&slot->tts_tid);
1605 500 33384260 : mslot->off = 0;
501 33384260 : mslot->mintuple = NULL;
502 33384260 : }
503 :
504 : static void
505 22396059 : tts_minimal_getsomeattrs(TupleTableSlot *slot, int natts)
506 : {
507 22396059 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
508 :
509 22396059 : Assert(!TTS_EMPTY(slot));
510 :
511 22396059 : slot_deform_heap_tuple(slot, mslot->tuple, &mslot->off, natts);
512 22396059 : }
513 :
514 : static Datum
1605 andres 515 UBC 0 : tts_minimal_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
516 : {
717 tgl 517 0 : Assert(!TTS_EMPTY(slot));
518 :
519 0 : ereport(ERROR,
520 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
521 : errmsg("cannot retrieve a system column in this context")));
522 :
523 : return 0; /* silence compiler warnings */
524 : }
525 :
526 : static void
1605 andres 527 CBC 785209 : tts_minimal_materialize(TupleTableSlot *slot)
528 : {
529 785209 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
530 : MemoryContext oldContext;
531 :
532 785209 : Assert(!TTS_EMPTY(slot));
533 :
534 : /* If slot has its tuple already materialized, nothing to do. */
535 785209 : if (TTS_SHOULDFREE(slot))
536 72006 : return;
537 :
538 713203 : oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
539 :
540 : /*
541 : * Have to deform from scratch, otherwise tts_values[] entries could point
542 : * into the non-materialized tuple (which might be gone when accessed).
543 : */
1250 tgl 544 713203 : slot->tts_nvalid = 0;
545 713203 : mslot->off = 0;
546 :
1605 andres 547 713203 : if (!mslot->mintuple)
548 : {
549 657675 : mslot->mintuple = heap_form_minimal_tuple(slot->tts_tupleDescriptor,
550 : slot->tts_values,
551 : slot->tts_isnull);
552 : }
553 : else
554 : {
555 : /*
556 : * The minimal tuple contained in this slot is not allocated in the
557 : * memory context of the given slot (else it would have
558 : * TTS_FLAG_SHOULDFREE set). Copy the minimal tuple into the given
559 : * slot's memory context.
560 : */
1605 andres 561 GIC 55528 : mslot->mintuple = heap_copy_minimal_tuple(mslot->mintuple);
1605 andres 562 ECB : }
563 :
1250 tgl 564 GIC 713203 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
1250 tgl 565 ECB :
1605 andres 566 GIC 713203 : Assert(mslot->tuple == &mslot->minhdr);
1605 andres 567 ECB :
1605 andres 568 GIC 713203 : mslot->minhdr.t_len = mslot->mintuple->t_len + MINIMAL_TUPLE_OFFSET;
1605 andres 569 CBC 713203 : mslot->minhdr.t_data = (HeapTupleHeader) ((char *) mslot->mintuple - MINIMAL_TUPLE_OFFSET);
1605 andres 570 ECB :
1605 andres 571 GIC 713203 : MemoryContextSwitchTo(oldContext);
1605 andres 572 ECB : }
573 :
574 : static void
1605 andres 575 GIC 531821 : tts_minimal_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
1605 andres 576 ECB : {
577 : MemoryContext oldcontext;
578 : MinimalTuple mintuple;
579 :
1605 andres 580 GIC 531821 : oldcontext = MemoryContextSwitchTo(dstslot->tts_mcxt);
1605 andres 581 CBC 531821 : mintuple = ExecCopySlotMinimalTuple(srcslot);
582 531821 : MemoryContextSwitchTo(oldcontext);
1605 andres 583 ECB :
1605 andres 584 GIC 531821 : ExecStoreMinimalTuple(mintuple, dstslot, true);
1605 andres 585 CBC 531821 : }
1605 andres 586 ECB :
587 : static MinimalTuple
1605 andres 588 GIC 2447307 : tts_minimal_get_minimal_tuple(TupleTableSlot *slot)
1605 andres 589 ECB : {
1605 andres 590 GIC 2447307 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
1605 andres 591 ECB :
1605 andres 592 GIC 2447307 : if (!mslot->mintuple)
1605 andres 593 LBC 0 : tts_minimal_materialize(slot);
1605 andres 594 EUB :
1605 andres 595 GIC 2447307 : return mslot->mintuple;
1605 andres 596 ECB : }
597 :
598 : static HeapTuple
1605 andres 599 GIC 495682 : tts_minimal_copy_heap_tuple(TupleTableSlot *slot)
1605 andres 600 ECB : {
1605 andres 601 GIC 495682 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
1605 andres 602 ECB :
1605 andres 603 GIC 495682 : if (!mslot->mintuple)
1605 andres 604 CBC 734 : tts_minimal_materialize(slot);
1605 andres 605 ECB :
1605 andres 606 GIC 495682 : return heap_tuple_from_minimal_tuple(mslot->mintuple);
1605 andres 607 ECB : }
608 :
609 : static MinimalTuple
1605 andres 610 GIC 1322209 : tts_minimal_copy_minimal_tuple(TupleTableSlot *slot)
1605 andres 611 ECB : {
1605 andres 612 GIC 1322209 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
1605 andres 613 ECB :
1605 andres 614 GIC 1322209 : if (!mslot->mintuple)
1605 andres 615 CBC 598596 : tts_minimal_materialize(slot);
1605 andres 616 ECB :
1605 andres 617 GIC 1322209 : return heap_copy_minimal_tuple(mslot->mintuple);
1605 andres 618 ECB : }
619 :
620 : static void
1605 andres 621 GIC 27639388 : tts_minimal_store_tuple(TupleTableSlot *slot, MinimalTuple mtup, bool shouldFree)
1605 andres 622 ECB : {
1605 andres 623 GIC 27639388 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
1605 andres 624 ECB :
1605 andres 625 GIC 27639388 : tts_minimal_clear(slot);
1605 andres 626 ECB :
1605 andres 627 GIC 27639388 : Assert(!TTS_SHOULDFREE(slot));
1605 andres 628 CBC 27639388 : Assert(TTS_EMPTY(slot));
1605 andres 629 ECB :
1605 andres 630 GIC 27639388 : slot->tts_flags &= ~TTS_FLAG_EMPTY;
1605 andres 631 CBC 27639388 : slot->tts_nvalid = 0;
632 27639388 : mslot->off = 0;
1605 andres 633 ECB :
1605 andres 634 GIC 27639388 : mslot->mintuple = mtup;
1605 andres 635 CBC 27639388 : Assert(mslot->tuple == &mslot->minhdr);
636 27639388 : mslot->minhdr.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
637 27639388 : mslot->minhdr.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);
1605 andres 638 ECB : /* no need to set t_self or t_tableOid since we won't allow access */
639 :
1605 andres 640 GIC 27639388 : if (shouldFree)
1605 andres 641 CBC 7065907 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
642 27639388 : }
1605 andres 643 ECB :
644 :
645 : /*
646 : * TupleTableSlotOps implementation for BufferHeapTupleTableSlot.
647 : */
648 :
649 : static void
1605 andres 650 GIC 15861968 : tts_buffer_heap_init(TupleTableSlot *slot)
1605 andres 651 ECB : {
1605 andres 652 GIC 15861968 : }
1605 andres 653 ECB :
654 : static void
1605 andres 655 GIC 15857121 : tts_buffer_heap_release(TupleTableSlot *slot)
1605 andres 656 ECB : {
1605 andres 657 GIC 15857121 : }
1605 andres 658 ECB :
659 : static void
1605 andres 660 GIC 27431568 : tts_buffer_heap_clear(TupleTableSlot *slot)
1605 andres 661 ECB : {
1605 andres 662 GIC 27431568 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
1605 andres 663 ECB :
664 : /*
665 : * Free the memory for heap tuple if allowed. A tuple coming from buffer
666 : * can never be freed. But we may have materialized a tuple from buffer.
667 : * Such a tuple can be freed.
668 : */
1605 andres 669 GIC 27431568 : if (TTS_SHOULDFREE(slot))
1605 andres 670 ECB : {
671 : /* We should have unpinned the buffer while materializing the tuple. */
1605 andres 672 GIC 7105962 : Assert(!BufferIsValid(bslot->buffer));
1605 andres 673 ECB :
1605 andres 674 GIC 7105962 : heap_freetuple(bslot->base.tuple);
1605 andres 675 CBC 7105962 : slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
1605 andres 676 ECB : }
677 :
1605 andres 678 GIC 27431568 : if (BufferIsValid(bslot->buffer))
1605 andres 679 CBC 6951583 : ReleaseBuffer(bslot->buffer);
1605 andres 680 ECB :
1605 andres 681 GIC 27431568 : slot->tts_nvalid = 0;
1605 andres 682 CBC 27431568 : slot->tts_flags |= TTS_FLAG_EMPTY;
1503 683 27431568 : ItemPointerSetInvalid(&slot->tts_tid);
1605 684 27431568 : bslot->base.tuple = NULL;
685 27431568 : bslot->base.off = 0;
686 27431568 : bslot->buffer = InvalidBuffer;
687 27431568 : }
1605 andres 688 ECB :
689 : static void
1605 andres 690 GIC 71856093 : tts_buffer_heap_getsomeattrs(TupleTableSlot *slot, int natts)
1605 andres 691 ECB : {
1605 andres 692 GIC 71856093 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
1605 andres 693 ECB :
1605 andres 694 GIC 71856093 : Assert(!TTS_EMPTY(slot));
1605 andres 695 ECB :
1605 andres 696 GIC 71856093 : slot_deform_heap_tuple(slot, bslot->base.tuple, &bslot->base.off, natts);
1605 andres 697 CBC 71856093 : }
1605 andres 698 ECB :
699 : static Datum
1605 andres 700 GIC 630 : tts_buffer_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
1605 andres 701 ECB : {
1605 andres 702 GIC 630 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
1605 andres 703 ECB :
1250 tgl 704 GIC 630 : Assert(!TTS_EMPTY(slot));
1250 tgl 705 ECB :
706 : /*
707 : * In some code paths it's possible to get here with a non-materialized
708 : * slot, in which case we can't retrieve system columns.
709 : */
717 tgl 710 GIC 630 : if (!bslot->base.tuple)
717 tgl 711 LBC 0 : ereport(ERROR,
717 tgl 712 EUB : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
713 : errmsg("cannot retrieve a system column in this context")));
714 :
1605 andres 715 GIC 630 : return heap_getsysattr(bslot->base.tuple, attnum,
1605 andres 716 ECB : slot->tts_tupleDescriptor, isnull);
717 : }
718 :
719 : static void
1605 andres 720 GIC 14171478 : tts_buffer_heap_materialize(TupleTableSlot *slot)
1605 andres 721 ECB : {
1605 andres 722 GIC 14171478 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
1605 andres 723 ECB : MemoryContext oldContext;
724 :
1605 andres 725 GIC 14171478 : Assert(!TTS_EMPTY(slot));
1605 andres 726 ECB :
727 : /* If slot has its tuple already materialized, nothing to do. */
1605 andres 728 GIC 14171478 : if (TTS_SHOULDFREE(slot))
1605 andres 729 CBC 12581619 : return;
1605 andres 730 ECB :
1605 andres 731 GIC 1589859 : oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
1605 andres 732 ECB :
733 : /*
734 : * Have to deform from scratch, otherwise tts_values[] entries could point
735 : * into the non-materialized tuple (which might be gone when accessed).
736 : */
1250 tgl 737 GIC 1589859 : bslot->base.off = 0;
1250 tgl 738 CBC 1589859 : slot->tts_nvalid = 0;
1250 tgl 739 ECB :
1501 andres 740 GIC 1589859 : if (!bslot->base.tuple)
1501 andres 741 ECB : {
742 : /*
743 : * Normally BufferHeapTupleTableSlot should have a tuple + buffer
744 : * associated with it, unless it's materialized (which would've
745 : * returned above). But when it's useful to allow storing virtual
746 : * tuples in a buffer slot, which then also needs to be
747 : * materializable.
748 : */
1501 andres 749 GIC 1393945 : bslot->base.tuple = heap_form_tuple(slot->tts_tupleDescriptor,
1501 andres 750 ECB : slot->tts_values,
751 : slot->tts_isnull);
752 : }
753 : else
754 : {
1501 andres 755 GIC 195914 : bslot->base.tuple = heap_copytuple(bslot->base.tuple);
1501 andres 756 ECB :
757 : /*
758 : * A heap tuple stored in a BufferHeapTupleTableSlot should have a
759 : * buffer associated with it, unless it's materialized or virtual.
760 : */
1501 andres 761 GIC 195914 : if (likely(BufferIsValid(bslot->buffer)))
1501 andres 762 CBC 195914 : ReleaseBuffer(bslot->buffer);
763 195914 : bslot->buffer = InvalidBuffer;
1501 andres 764 ECB : }
765 :
766 : /*
767 : * We don't set TTS_FLAG_SHOULDFREE until after releasing the buffer, if
768 : * any. This avoids having a transient state that would fall foul of our
769 : * assertions that a slot with TTS_FLAG_SHOULDFREE doesn't own a buffer.
770 : * In the unlikely event that ReleaseBuffer() above errors out, we'd
771 : * effectively leak the copied tuple, but that seems fairly harmless.
772 : */
1250 tgl 773 GIC 1589859 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
1250 tgl 774 ECB :
1250 tgl 775 GIC 1589859 : MemoryContextSwitchTo(oldContext);
1605 andres 776 ECB : }
777 :
778 : static void
1605 andres 779 GIC 5682685 : tts_buffer_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
1605 andres 780 ECB : {
1605 andres 781 GIC 5682685 : BufferHeapTupleTableSlot *bsrcslot = (BufferHeapTupleTableSlot *) srcslot;
1605 andres 782 CBC 5682685 : BufferHeapTupleTableSlot *bdstslot = (BufferHeapTupleTableSlot *) dstslot;
1605 andres 783 ECB :
784 : /*
785 : * If the source slot is of a different kind, or is a buffer slot that has
786 : * been materialized / is virtual, make a new copy of the tuple. Otherwise
787 : * make a new reference to the in-buffer tuple.
788 : */
1605 andres 789 GIC 5682685 : if (dstslot->tts_ops != srcslot->tts_ops ||
1501 andres 790 CBC 4377 : TTS_SHOULDFREE(srcslot) ||
791 4375 : !bsrcslot->base.tuple)
1605 792 5678310 : {
1605 andres 793 ECB : MemoryContext oldContext;
794 :
1605 andres 795 GIC 5678310 : ExecClearTuple(dstslot);
1605 andres 796 CBC 5678310 : dstslot->tts_flags &= ~TTS_FLAG_EMPTY;
797 5678310 : oldContext = MemoryContextSwitchTo(dstslot->tts_mcxt);
1574 akapila 798 5678310 : bdstslot->base.tuple = ExecCopySlotHeapTuple(srcslot);
1250 tgl 799 5678310 : dstslot->tts_flags |= TTS_FLAG_SHOULDFREE;
1605 andres 800 5678310 : MemoryContextSwitchTo(oldContext);
1605 andres 801 ECB : }
802 : else
803 : {
1501 andres 804 GIC 4375 : Assert(BufferIsValid(bsrcslot->buffer));
1501 andres 805 ECB :
1503 andres 806 GIC 4375 : tts_buffer_heap_store_tuple(dstslot, bsrcslot->base.tuple,
1503 andres 807 ECB : bsrcslot->buffer, false);
808 :
809 : /*
810 : * The HeapTupleData portion of the source tuple might be shorter
811 : * lived than the destination slot. Therefore copy the HeapTuple into
812 : * our slot's tupdata, which is guaranteed to live long enough (but
813 : * will still point into the buffer).
814 : */
1501 andres 815 GIC 4375 : memcpy(&bdstslot->base.tupdata, bdstslot->base.tuple, sizeof(HeapTupleData));
1501 andres 816 CBC 4375 : bdstslot->base.tuple = &bdstslot->base.tupdata;
1605 andres 817 ECB : }
1605 andres 818 GIC 5682685 : }
1605 andres 819 ECB :
820 : static HeapTuple
1605 andres 821 GIC 21901000 : tts_buffer_heap_get_heap_tuple(TupleTableSlot *slot)
1605 andres 822 ECB : {
1605 andres 823 GIC 21901000 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
1605 andres 824 ECB :
1605 andres 825 GIC 21901000 : Assert(!TTS_EMPTY(slot));
1605 andres 826 ECB :
1605 andres 827 GIC 21901000 : if (!bslot->base.tuple)
1605 andres 828 LBC 0 : tts_buffer_heap_materialize(slot);
1605 andres 829 EUB :
1605 andres 830 GIC 21901000 : return bslot->base.tuple;
1605 andres 831 ECB : }
832 :
833 : static HeapTuple
1605 andres 834 GIC 10126320 : tts_buffer_heap_copy_heap_tuple(TupleTableSlot *slot)
1605 andres 835 ECB : {
1605 andres 836 GIC 10126320 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
1605 andres 837 ECB :
1605 andres 838 GIC 10126320 : Assert(!TTS_EMPTY(slot));
1605 andres 839 ECB :
1605 andres 840 GIC 10126320 : if (!bslot->base.tuple)
1605 andres 841 LBC 0 : tts_buffer_heap_materialize(slot);
1605 andres 842 EUB :
1605 andres 843 GIC 10126320 : return heap_copytuple(bslot->base.tuple);
1605 andres 844 ECB : }
845 :
846 : static MinimalTuple
1605 andres 847 GIC 1264956 : tts_buffer_heap_copy_minimal_tuple(TupleTableSlot *slot)
1605 andres 848 ECB : {
1605 andres 849 GIC 1264956 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
1605 andres 850 ECB :
1605 andres 851 GIC 1264956 : Assert(!TTS_EMPTY(slot));
1605 andres 852 ECB :
1605 andres 853 GIC 1264956 : if (!bslot->base.tuple)
1605 andres 854 LBC 0 : tts_buffer_heap_materialize(slot);
1605 andres 855 EUB :
1605 andres 856 GIC 1264956 : return minimal_tuple_from_heap_tuple(bslot->base.tuple);
1605 andres 857 ECB : }
858 :
859 : static inline void
1503 andres 860 GIC 84347418 : tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple,
1503 andres 861 ECB : Buffer buffer, bool transfer_pin)
862 : {
1605 andres 863 GIC 84347418 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
1605 andres 864 ECB :
1605 andres 865 GIC 84347418 : if (TTS_SHOULDFREE(slot))
1605 andres 866 ECB : {
867 : /* materialized slot shouldn't have a buffer to release */
1605 andres 868 GIC 196748 : Assert(!BufferIsValid(bslot->buffer));
1605 andres 869 ECB :
1605 andres 870 GIC 196748 : heap_freetuple(bslot->base.tuple);
1605 andres 871 CBC 196748 : slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
1605 andres 872 ECB : }
873 :
1605 andres 874 GIC 84347418 : slot->tts_flags &= ~TTS_FLAG_EMPTY;
1605 andres 875 CBC 84347418 : slot->tts_nvalid = 0;
876 84347418 : bslot->base.tuple = tuple;
877 84347418 : bslot->base.off = 0;
1503 878 84347418 : slot->tts_tid = tuple->t_self;
1605 andres 879 ECB :
880 : /*
881 : * If tuple is on a disk page, keep the page pinned as long as we hold a
882 : * pointer into it. We assume the caller already has such a pin. If
883 : * transfer_pin is true, we'll transfer that pin to this slot, if not
884 : * we'll pin it again ourselves.
885 : *
886 : * This is coded to optimize the case where the slot previously held a
887 : * tuple on the same disk page: in that case releasing and re-acquiring
888 : * the pin is a waste of cycles. This is a common situation during
889 : * seqscans, so it's worth troubling over.
890 : */
1605 andres 891 GIC 84347418 : if (bslot->buffer != buffer)
1605 andres 892 ECB : {
1605 andres 893 GIC 10138239 : if (BufferIsValid(bslot->buffer))
1605 andres 894 CBC 2988509 : ReleaseBuffer(bslot->buffer);
1503 andres 895 ECB :
1605 andres 896 GIC 10138239 : bslot->buffer = buffer;
1503 andres 897 ECB :
1503 andres 898 GIC 10138239 : if (!transfer_pin && BufferIsValid(buffer))
1503 andres 899 CBC 10036077 : IncrBufferRefCount(buffer);
1503 andres 900 ECB : }
1503 andres 901 GIC 74209179 : else if (transfer_pin && BufferIsValid(buffer))
1503 andres 902 ECB : {
903 : /*
904 : * In transfer_pin mode the caller won't know about the same-page
905 : * optimization, so we gotta release its pin.
906 : */
1503 andres 907 GIC 176142 : ReleaseBuffer(buffer);
1605 andres 908 ECB : }
1605 andres 909 GIC 84347418 : }
1605 andres 910 ECB :
911 : /*
912 : * slot_deform_heap_tuple
913 : * Given a TupleTableSlot, extract data from the slot's physical tuple
914 : * into its Datum/isnull arrays. Data is extracted up through the
915 : * natts'th column (caller must ensure this is a legal column number).
916 : *
917 : * This is essentially an incremental version of heap_deform_tuple:
918 : * on each call we extract attributes up to the one needed, without
919 : * re-computing information about previously extracted attributes.
920 : * slot->tts_nvalid is the number of attributes already extracted.
921 : *
922 : * This is marked as always inline, so the different offp for different types
923 : * of slots gets optimized away.
924 : */
925 : static pg_attribute_always_inline void
1605 andres 926 GIC 105928959 : slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
1605 andres 927 ECB : int natts)
928 : {
1605 andres 929 GIC 105928959 : TupleDesc tupleDesc = slot->tts_tupleDescriptor;
1605 andres 930 CBC 105928959 : Datum *values = slot->tts_values;
931 105928959 : bool *isnull = slot->tts_isnull;
932 105928959 : HeapTupleHeader tup = tuple->t_data;
933 105928959 : bool hasnulls = HeapTupleHasNulls(tuple);
1605 andres 934 ECB : int attnum;
935 : char *tp; /* ptr to tuple data */
936 : uint32 off; /* offset in tuple data */
1605 andres 937 GIC 105928959 : bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
1605 andres 938 ECB : bool slow; /* can we use/set attcacheoff? */
939 :
940 : /* We can only fetch as many attributes as the tuple has. */
1605 andres 941 GIC 105928959 : natts = Min(HeapTupleHeaderGetNatts(tuple->t_data), natts);
1605 andres 942 ECB :
943 : /*
944 : * Check whether the first call for this tuple, and initialize or restore
945 : * loop state.
946 : */
1605 andres 947 GIC 105928959 : attnum = slot->tts_nvalid;
1605 andres 948 CBC 105928959 : if (attnum == 0)
1605 andres 949 ECB : {
950 : /* Start from the first attribute */
1605 andres 951 GIC 81521166 : off = 0;
1605 andres 952 CBC 81521166 : slow = false;
1605 andres 953 ECB : }
954 : else
955 : {
956 : /* Restore state from previous execution */
1605 andres 957 GIC 24407793 : off = *offp;
1605 andres 958 CBC 24407793 : slow = TTS_SLOW(slot);
1605 andres 959 ECB : }
960 :
1605 andres 961 GIC 105928959 : tp = (char *) tup + tup->t_hoff;
1605 andres 962 ECB :
1605 andres 963 GIC 463264645 : for (; attnum < natts; attnum++)
1605 andres 964 ECB : {
1605 andres 965 GIC 357335686 : Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum);
1605 andres 966 ECB :
1605 andres 967 GIC 357335686 : if (hasnulls && att_isnull(attnum, bp))
1605 andres 968 ECB : {
1605 andres 969 GIC 23036629 : values[attnum] = (Datum) 0;
1605 andres 970 CBC 23036629 : isnull[attnum] = true;
971 23036629 : slow = true; /* can't use attcacheoff anymore */
972 23036629 : continue;
1605 andres 973 ECB : }
974 :
1605 andres 975 GIC 334299057 : isnull[attnum] = false;
1605 andres 976 ECB :
1605 andres 977 GIC 334299057 : if (!slow && thisatt->attcacheoff >= 0)
1605 andres 978 CBC 316344358 : off = thisatt->attcacheoff;
979 17954699 : else if (thisatt->attlen == -1)
1605 andres 980 ECB : {
981 : /*
982 : * We can only cache the offset for a varlena attribute if the
983 : * offset is already suitably aligned, so that there would be no
984 : * pad bytes in any case: then the offset will be valid for either
985 : * an aligned or unaligned value.
986 : */
1605 andres 987 GIC 7463437 : if (!slow &&
1605 andres 988 CBC 413955 : off == att_align_nominal(off, thisatt->attalign))
989 33122 : thisatt->attcacheoff = off;
1605 andres 990 ECB : else
991 : {
1605 andres 992 GIC 7016360 : off = att_align_pointer(off, thisatt->attalign, -1,
1605 andres 993 ECB : tp + off);
1605 andres 994 GIC 7016360 : slow = true;
1605 andres 995 ECB : }
996 : }
997 : else
998 : {
999 : /* not varlena, so safe to use att_align_nominal */
1605 andres 1000 GIC 10905217 : off = att_align_nominal(off, thisatt->attalign);
1605 andres 1001 ECB :
1605 andres 1002 GIC 10905217 : if (!slow)
1605 andres 1003 CBC 263483 : thisatt->attcacheoff = off;
1605 andres 1004 ECB : }
1005 :
1605 andres 1006 GIC 334299057 : values[attnum] = fetchatt(thisatt, tp + off);
1605 andres 1007 ECB :
1605 andres 1008 GIC 334299057 : off = att_addlength_pointer(off, thisatt->attlen, tp + off);
1605 andres 1009 ECB :
1605 andres 1010 GIC 334299057 : if (thisatt->attlen <= 0)
1605 andres 1011 CBC 24873783 : slow = true; /* can't use attcacheoff anymore */
1605 andres 1012 ECB : }
1013 :
1014 : /*
1015 : * Save state for next execution
1016 : */
1605 andres 1017 GIC 105928959 : slot->tts_nvalid = attnum;
1605 andres 1018 CBC 105928959 : *offp = off;
1019 105928959 : if (slow)
1020 21414853 : slot->tts_flags |= TTS_FLAG_SLOW;
1605 andres 1021 ECB : else
1605 andres 1022 GIC 84514106 : slot->tts_flags &= ~TTS_FLAG_SLOW;
1605 andres 1023 CBC 105928959 : }
1605 andres 1024 ECB :
1025 :
1026 : const TupleTableSlotOps TTSOpsVirtual = {
1027 : .base_slot_size = sizeof(VirtualTupleTableSlot),
1028 : .init = tts_virtual_init,
1029 : .release = tts_virtual_release,
1030 : .clear = tts_virtual_clear,
1031 : .getsomeattrs = tts_virtual_getsomeattrs,
1032 : .getsysattr = tts_virtual_getsysattr,
1033 : .materialize = tts_virtual_materialize,
1034 : .copyslot = tts_virtual_copyslot,
1035 :
1036 : /*
1037 : * A virtual tuple table slot can not "own" a heap tuple or a minimal
1038 : * tuple.
1039 : */
1040 : .get_heap_tuple = NULL,
1041 : .get_minimal_tuple = NULL,
1042 : .copy_heap_tuple = tts_virtual_copy_heap_tuple,
1043 : .copy_minimal_tuple = tts_virtual_copy_minimal_tuple
1044 : };
1045 :
1046 : const TupleTableSlotOps TTSOpsHeapTuple = {
1047 : .base_slot_size = sizeof(HeapTupleTableSlot),
1048 : .init = tts_heap_init,
1049 : .release = tts_heap_release,
1050 : .clear = tts_heap_clear,
1051 : .getsomeattrs = tts_heap_getsomeattrs,
1052 : .getsysattr = tts_heap_getsysattr,
1053 : .materialize = tts_heap_materialize,
1054 : .copyslot = tts_heap_copyslot,
1055 : .get_heap_tuple = tts_heap_get_heap_tuple,
1056 :
1057 : /* A heap tuple table slot can not "own" a minimal tuple. */
1058 : .get_minimal_tuple = NULL,
1059 : .copy_heap_tuple = tts_heap_copy_heap_tuple,
1060 : .copy_minimal_tuple = tts_heap_copy_minimal_tuple
1061 : };
1062 :
1063 : const TupleTableSlotOps TTSOpsMinimalTuple = {
1064 : .base_slot_size = sizeof(MinimalTupleTableSlot),
1065 : .init = tts_minimal_init,
1066 : .release = tts_minimal_release,
1067 : .clear = tts_minimal_clear,
1068 : .getsomeattrs = tts_minimal_getsomeattrs,
1069 : .getsysattr = tts_minimal_getsysattr,
1070 : .materialize = tts_minimal_materialize,
1071 : .copyslot = tts_minimal_copyslot,
1072 :
1073 : /* A minimal tuple table slot can not "own" a heap tuple. */
1074 : .get_heap_tuple = NULL,
1075 : .get_minimal_tuple = tts_minimal_get_minimal_tuple,
1076 : .copy_heap_tuple = tts_minimal_copy_heap_tuple,
1077 : .copy_minimal_tuple = tts_minimal_copy_minimal_tuple
1078 : };
1079 :
1080 : const TupleTableSlotOps TTSOpsBufferHeapTuple = {
1081 : .base_slot_size = sizeof(BufferHeapTupleTableSlot),
1082 : .init = tts_buffer_heap_init,
1083 : .release = tts_buffer_heap_release,
1084 : .clear = tts_buffer_heap_clear,
1085 : .getsomeattrs = tts_buffer_heap_getsomeattrs,
1086 : .getsysattr = tts_buffer_heap_getsysattr,
1087 : .materialize = tts_buffer_heap_materialize,
1088 : .copyslot = tts_buffer_heap_copyslot,
1089 : .get_heap_tuple = tts_buffer_heap_get_heap_tuple,
1090 :
1091 : /* A buffer heap tuple table slot can not "own" a minimal tuple. */
1092 : .get_minimal_tuple = NULL,
1093 : .copy_heap_tuple = tts_buffer_heap_copy_heap_tuple,
1094 : .copy_minimal_tuple = tts_buffer_heap_copy_minimal_tuple
1095 : };
1096 :
1097 :
1098 : /* ----------------------------------------------------------------
1099 : * tuple table create/delete functions
1100 : * ----------------------------------------------------------------
1101 : */
1102 :
1103 : /* --------------------------------
1104 : * MakeTupleTableSlot
1105 : *
1106 : * Basic routine to make an empty TupleTableSlot of given
1107 : * TupleTableSlotType. If tupleDesc is specified the slot's descriptor is
1108 : * fixed for its lifetime, gaining some efficiency. If that's
1109 : * undesirable, pass NULL.
1110 : * --------------------------------
1111 : */
1112 : TupleTableSlot *
1606 andres 1113 GIC 21902338 : MakeTupleTableSlot(TupleDesc tupleDesc,
1606 andres 1114 ECB : const TupleTableSlotOps *tts_ops)
1115 : {
1116 : Size basesz,
1117 : allocsz;
1118 : TupleTableSlot *slot;
1119 :
1605 andres 1120 GIC 21902338 : basesz = tts_ops->base_slot_size;
9345 bruce 1121 ECB :
1122 : /*
1123 : * When a fixed descriptor is specified, we can reduce overhead by
1124 : * allocating the entire slot in one go.
1125 : */
1878 andres 1126 GIC 21902338 : if (tupleDesc)
1605 andres 1127 CBC 21883201 : allocsz = MAXALIGN(basesz) +
1878 1128 21883201 : MAXALIGN(tupleDesc->natts * sizeof(Datum)) +
1129 21883201 : MAXALIGN(tupleDesc->natts * sizeof(bool));
1878 andres 1130 ECB : else
1605 andres 1131 GIC 19137 : allocsz = basesz;
1878 andres 1132 ECB :
1605 andres 1133 GIC 21902338 : slot = palloc0(allocsz);
1606 andres 1134 ECB : /* const for optimization purposes, OK to modify at allocation time */
1606 andres 1135 GIC 21902338 : *((const TupleTableSlotOps **) &slot->tts_ops) = tts_ops;
1878 andres 1136 CBC 21902338 : slot->type = T_TupleTableSlot;
1637 1137 21902338 : slot->tts_flags |= TTS_FLAG_EMPTY;
1138 21902338 : if (tupleDesc != NULL)
1139 21883201 : slot->tts_flags |= TTS_FLAG_FIXED;
1878 1140 21902338 : slot->tts_tupleDescriptor = tupleDesc;
4942 tgl 1141 21902338 : slot->tts_mcxt = CurrentMemoryContext;
1142 21902338 : slot->tts_nvalid = 0;
9345 bruce 1143 ECB :
1878 andres 1144 GIC 21902338 : if (tupleDesc != NULL)
1878 andres 1145 ECB : {
1878 andres 1146 GIC 21883201 : slot->tts_values = (Datum *)
1878 andres 1147 ECB : (((char *) slot)
1605 andres 1148 GIC 21883201 : + MAXALIGN(basesz));
1878 andres 1149 CBC 21883201 : slot->tts_isnull = (bool *)
1878 andres 1150 ECB : (((char *) slot)
1605 andres 1151 GIC 21883201 : + MAXALIGN(basesz)
1878 andres 1152 CBC 21883201 : + MAXALIGN(tupleDesc->natts * sizeof(Datum)));
1878 andres 1153 ECB :
1878 andres 1154 GIC 21883201 : PinTupleDesc(tupleDesc);
1878 andres 1155 ECB : }
1156 :
1157 : /*
1158 : * And allow slot type specific initialization.
1159 : */
1605 andres 1160 GIC 21902338 : slot->tts_ops->init(slot);
1605 andres 1161 ECB :
4942 tgl 1162 GIC 21902338 : return slot;
4942 tgl 1163 ECB : }
1164 :
1165 : /* --------------------------------
1166 : * ExecAllocTableSlot
1167 : *
1168 : * Create a tuple table slot within a tuple table (which is just a List).
1169 : * --------------------------------
1170 : */
1171 : TupleTableSlot *
1606 andres 1172 GIC 862306 : ExecAllocTableSlot(List **tupleTable, TupleDesc desc,
1606 andres 1173 ECB : const TupleTableSlotOps *tts_ops)
1174 : {
1606 andres 1175 GIC 862306 : TupleTableSlot *slot = MakeTupleTableSlot(desc, tts_ops);
4942 tgl 1176 ECB :
4942 tgl 1177 GIC 862306 : *tupleTable = lappend(*tupleTable, slot);
9345 bruce 1178 ECB :
4942 tgl 1179 GIC 862306 : return slot;
9770 scrappy 1180 ECB : }
1181 :
1182 : /* --------------------------------
1183 : * ExecResetTupleTable
1184 : *
1185 : * This releases any resources (buffer pins, tupdesc refcounts)
1186 : * held by the tuple table, and optionally releases the memory
1187 : * occupied by the tuple table data structure.
1188 : * It is expected that this routine be called by ExecEndPlan().
1189 : * --------------------------------
1190 : */
1191 : void
4942 tgl 1192 GIC 405257 : ExecResetTupleTable(List *tupleTable, /* tuple table */
4942 tgl 1193 ECB : bool shouldFree) /* true if we should free memory */
1194 : {
1195 : ListCell *lc;
1196 :
4942 tgl 1197 GIC 1391558 : foreach(lc, tupleTable)
8598 tgl 1198 ECB : {
2190 tgl 1199 GIC 986301 : TupleTableSlot *slot = lfirst_node(TupleTableSlot, lc);
4942 tgl 1200 ECB :
1201 : /* Always release resources and reset the slot to empty */
4942 tgl 1202 GIC 986301 : ExecClearTuple(slot);
1605 andres 1203 CBC 986301 : slot->tts_ops->release(slot);
4942 tgl 1204 986301 : if (slot->tts_tupleDescriptor)
8105 tgl 1205 ECB : {
4942 tgl 1206 GIC 986274 : ReleaseTupleDesc(slot->tts_tupleDescriptor);
4942 tgl 1207 CBC 986274 : slot->tts_tupleDescriptor = NULL;
4942 tgl 1208 ECB : }
1209 :
1210 : /* If shouldFree, release memory occupied by the slot itself */
4942 tgl 1211 GIC 986301 : if (shouldFree)
4942 tgl 1212 ECB : {
1637 andres 1213 GIC 2581 : if (!TTS_FIXED(slot))
1878 andres 1214 ECB : {
1878 andres 1215 UIC 0 : if (slot->tts_values)
1878 andres 1216 UBC 0 : pfree(slot->tts_values);
1217 0 : if (slot->tts_isnull)
1218 0 : pfree(slot->tts_isnull);
1878 andres 1219 EUB : }
4942 tgl 1220 GIC 2581 : pfree(slot);
8105 tgl 1221 ECB : }
1222 : }
1223 :
1224 : /* If shouldFree, release the list structure */
4942 tgl 1225 GIC 405257 : if (shouldFree)
4942 tgl 1226 CBC 2550 : list_free(tupleTable);
9770 scrappy 1227 405257 : }
9770 scrappy 1228 ECB :
1229 : /* --------------------------------
1230 : * MakeSingleTupleTableSlot
1231 : *
1232 : * This is a convenience routine for operations that need a standalone
1233 : * TupleTableSlot not gotten from the main executor tuple table. It makes
1234 : * a single slot of given TupleTableSlotType and initializes it to use the
1235 : * given tuple descriptor.
1236 : * --------------------------------
1237 : */
1238 : TupleTableSlot *
1606 andres 1239 GIC 21039960 : MakeSingleTupleTableSlot(TupleDesc tupdesc,
1606 andres 1240 ECB : const TupleTableSlotOps *tts_ops)
1241 : {
1606 andres 1242 GIC 21039960 : TupleTableSlot *slot = MakeTupleTableSlot(tupdesc, tts_ops);
6600 tgl 1243 ECB :
6600 tgl 1244 GIC 21039960 : return slot;
6600 tgl 1245 ECB : }
1246 :
1247 : /* --------------------------------
1248 : * ExecDropSingleTupleTableSlot
1249 : *
1250 : * Release a TupleTableSlot made with MakeSingleTupleTableSlot.
1251 : * DON'T use this on a slot that's part of a tuple table list!
1252 : * --------------------------------
1253 : */
1254 : void
6598 tgl 1255 GIC 20881990 : ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
6598 tgl 1256 ECB : {
1257 : /* This should match ExecResetTupleTable's processing of one slot */
4942 tgl 1258 GIC 20881990 : Assert(IsA(slot, TupleTableSlot));
6598 tgl 1259 CBC 20881990 : ExecClearTuple(slot);
1605 andres 1260 20881990 : slot->tts_ops->release(slot);
6141 tgl 1261 20881990 : if (slot->tts_tupleDescriptor)
1262 20881990 : ReleaseTupleDesc(slot->tts_tupleDescriptor);
1637 andres 1263 20881990 : if (!TTS_FIXED(slot))
1878 andres 1264 ECB : {
1878 andres 1265 UIC 0 : if (slot->tts_values)
1878 andres 1266 UBC 0 : pfree(slot->tts_values);
1267 0 : if (slot->tts_isnull)
1268 0 : pfree(slot->tts_isnull);
1878 andres 1269 EUB : }
6598 tgl 1270 GIC 20881990 : pfree(slot);
6598 tgl 1271 CBC 20881990 : }
6598 tgl 1272 ECB :
1273 :
1274 : /* ----------------------------------------------------------------
1275 : * tuple table slot accessor functions
1276 : * ----------------------------------------------------------------
1277 : */
1278 :
1279 : /* --------------------------------
1280 : * ExecSetSlotDescriptor
1281 : *
1282 : * This function is used to set the tuple descriptor associated
1283 : * with the slot's tuple. The passed descriptor must have lifespan
1284 : * at least equal to the slot's. If it is a reference-counted descriptor
1285 : * then the reference count is incremented for as long as the slot holds
1286 : * a reference.
1287 : * --------------------------------
1288 : */
1289 : void
2118 tgl 1290 GIC 19110 : ExecSetSlotDescriptor(TupleTableSlot *slot, /* slot to change */
2118 tgl 1291 ECB : TupleDesc tupdesc) /* new tuple descriptor */
1292 : {
1637 andres 1293 GIC 19110 : Assert(!TTS_FIXED(slot));
1878 andres 1294 ECB :
1295 : /* For safety, make sure slot is empty before changing it */
6598 tgl 1296 GIC 19110 : ExecClearTuple(slot);
6598 tgl 1297 ECB :
1298 : /*
1299 : * Release any old descriptor. Also release old Datum/isnull arrays if
1300 : * present (we don't bother to check if they could be re-used).
1301 : */
6141 tgl 1302 GIC 19110 : if (slot->tts_tupleDescriptor)
6141 tgl 1303 LBC 0 : ReleaseTupleDesc(slot->tts_tupleDescriptor);
6598 tgl 1304 EUB :
6598 tgl 1305 GIC 19110 : if (slot->tts_values)
6598 tgl 1306 LBC 0 : pfree(slot->tts_values);
6598 tgl 1307 GBC 19110 : if (slot->tts_isnull)
6598 tgl 1308 LBC 0 : pfree(slot->tts_isnull);
6598 tgl 1309 EUB :
1310 : /*
1311 : * Install the new descriptor; if it's refcounted, bump its refcount.
1312 : */
6598 tgl 1313 GIC 19110 : slot->tts_tupleDescriptor = tupdesc;
6141 tgl 1314 CBC 19110 : PinTupleDesc(tupdesc);
6598 tgl 1315 ECB :
1316 : /*
1317 : * Allocate Datum/isnull arrays of the appropriate size. These must have
1318 : * the same lifetime as the slot, so allocate in the slot's own context.
1319 : */
6598 tgl 1320 GIC 19110 : slot->tts_values = (Datum *)
6598 tgl 1321 CBC 19110 : MemoryContextAlloc(slot->tts_mcxt, tupdesc->natts * sizeof(Datum));
1322 19110 : slot->tts_isnull = (bool *)
1323 19110 : MemoryContextAlloc(slot->tts_mcxt, tupdesc->natts * sizeof(bool));
1324 19110 : }
6598 tgl 1325 ECB :
1326 : /* --------------------------------
1327 : * ExecStoreHeapTuple
1328 : *
1329 : * This function is used to store an on-the-fly physical tuple into a specified
1330 : * slot in the tuple table.
1331 : *
1332 : * tuple: tuple to store
1333 : * slot: TTSOpsHeapTuple type slot to store it in
1334 : * shouldFree: true if ExecClearTuple should pfree() the tuple
1335 : * when done with it
1336 : *
1337 : * shouldFree is normally set 'true' for tuples constructed on-the-fly. But it
1338 : * can be 'false' when the referenced tuple is held in a tuple table slot
1339 : * belonging to a lower-level executor Proc node. In this case the lower-level
1340 : * slot retains ownership and responsibility for eventually releasing the
1341 : * tuple. When this method is used, we must be certain that the upper-level
1342 : * Proc node will lose interest in the tuple sooner than the lower-level one
1343 : * does! If you're not certain, copy the lower-level tuple with heap_copytuple
1344 : * and let the upper-level table slot assume ownership of the copy!
1345 : *
1346 : * Return value is just the passed-in slot pointer.
1347 : *
1348 : * If the target slot is not guaranteed to be TTSOpsHeapTuple type slot, use
1349 : * the, more expensive, ExecForceStoreHeapTuple().
1350 : * --------------------------------
1351 : */
1352 : TupleTableSlot *
1657 andres 1353 GIC 4222627 : ExecStoreHeapTuple(HeapTuple tuple,
1657 andres 1354 ECB : TupleTableSlot *slot,
1355 : bool shouldFree)
1356 : {
1357 : /*
1358 : * sanity checks
1359 : */
1657 andres 1360 GIC 4222627 : Assert(tuple != NULL);
1657 andres 1361 CBC 4222627 : Assert(slot != NULL);
1362 4222627 : Assert(slot->tts_tupleDescriptor != NULL);
1657 andres 1363 ECB :
1605 andres 1364 GIC 4222627 : if (unlikely(!TTS_IS_HEAPTUPLE(slot)))
1605 andres 1365 LBC 0 : elog(ERROR, "trying to store a heap tuple into wrong type of slot");
1605 andres 1366 GBC 4222627 : tts_heap_store_tuple(slot, tuple, shouldFree);
1657 andres 1367 ECB :
1503 andres 1368 GIC 4222627 : slot->tts_tableOid = tuple->t_tableOid;
1503 andres 1369 ECB :
1657 andres 1370 GIC 4222627 : return slot;
1657 andres 1371 ECB : }
1372 :
1373 : /* --------------------------------
1374 : * ExecStoreBufferHeapTuple
1375 : *
1376 : * This function is used to store an on-disk physical tuple from a buffer
1377 : * into a specified slot in the tuple table.
1378 : *
1379 : * tuple: tuple to store
1380 : * slot: TTSOpsBufferHeapTuple type slot to store it in
1381 : * buffer: disk buffer if tuple is in a disk page, else InvalidBuffer
1382 : *
1383 : * The tuple table code acquires a pin on the buffer which is held until the
1384 : * slot is cleared, so that the tuple won't go away on us.
1385 : *
1386 : * Return value is just the passed-in slot pointer.
1387 : *
1388 : * If the target slot is not guaranteed to be TTSOpsBufferHeapTuple type slot,
1389 : * use the, more expensive, ExecForceStoreHeapTuple().
1390 : * --------------------------------
1391 : */
1392 : TupleTableSlot *
1657 andres 1393 GIC 84064739 : ExecStoreBufferHeapTuple(HeapTuple tuple,
1657 andres 1394 ECB : TupleTableSlot *slot,
1395 : Buffer buffer)
1396 : {
1397 : /*
1398 : * sanity checks
1399 : */
1605 andres 1400 GIC 84064739 : Assert(tuple != NULL);
1605 andres 1401 CBC 84064739 : Assert(slot != NULL);
1402 84064739 : Assert(slot->tts_tupleDescriptor != NULL);
1403 84064739 : Assert(BufferIsValid(buffer));
1605 andres 1404 ECB :
1605 andres 1405 GIC 84064739 : if (unlikely(!TTS_IS_BUFFERTUPLE(slot)))
1605 andres 1406 LBC 0 : elog(ERROR, "trying to store an on-disk heap tuple into wrong type of slot");
1503 andres 1407 GBC 84064739 : tts_buffer_heap_store_tuple(slot, tuple, buffer, false);
1503 andres 1408 ECB :
1503 andres 1409 GIC 84064739 : slot->tts_tableOid = tuple->t_tableOid;
1503 andres 1410 ECB :
1503 andres 1411 GIC 84064739 : return slot;
1503 andres 1412 ECB : }
1413 :
1414 : /*
1415 : * Like ExecStoreBufferHeapTuple, but transfer an existing pin from the caller
1416 : * to the slot, i.e. the caller doesn't need to, and may not, release the pin.
1417 : */
1418 : TupleTableSlot *
1503 andres 1419 GIC 278304 : ExecStorePinnedBufferHeapTuple(HeapTuple tuple,
1503 andres 1420 ECB : TupleTableSlot *slot,
1421 : Buffer buffer)
1422 : {
1423 : /*
1424 : * sanity checks
1425 : */
1503 andres 1426 GIC 278304 : Assert(tuple != NULL);
1503 andres 1427 CBC 278304 : Assert(slot != NULL);
1428 278304 : Assert(slot->tts_tupleDescriptor != NULL);
1429 278304 : Assert(BufferIsValid(buffer));
1503 andres 1430 ECB :
1503 andres 1431 GIC 278304 : if (unlikely(!TTS_IS_BUFFERTUPLE(slot)))
1503 andres 1432 LBC 0 : elog(ERROR, "trying to store an on-disk heap tuple into wrong type of slot");
1503 andres 1433 GBC 278304 : tts_buffer_heap_store_tuple(slot, tuple, buffer, true);
6598 tgl 1434 ECB :
1503 andres 1435 GIC 278304 : slot->tts_tableOid = tuple->t_tableOid;
1503 andres 1436 ECB :
9345 bruce 1437 GIC 278304 : return slot;
9770 scrappy 1438 ECB : }
1439 :
1440 : /*
1441 : * Store a minimal tuple into TTSOpsMinimalTuple type slot.
1442 : *
1443 : * If the target slot is not guaranteed to be TTSOpsMinimalTuple type slot,
1444 : * use the, more expensive, ExecForceStoreMinimalTuple().
1445 : */
1446 : TupleTableSlot *
6130 tgl 1447 GIC 25428750 : ExecStoreMinimalTuple(MinimalTuple mtup,
6130 tgl 1448 ECB : TupleTableSlot *slot,
1449 : bool shouldFree)
1450 : {
1451 : /*
1452 : * sanity checks
1453 : */
6130 tgl 1454 GIC 25428750 : Assert(mtup != NULL);
6130 tgl 1455 CBC 25428750 : Assert(slot != NULL);
1456 25428750 : Assert(slot->tts_tupleDescriptor != NULL);
6130 tgl 1457 ECB :
1605 andres 1458 GIC 25428750 : if (unlikely(!TTS_IS_MINIMALTUPLE(slot)))
1605 andres 1459 LBC 0 : elog(ERROR, "trying to store a minimal tuple into wrong type of slot");
1605 andres 1460 GBC 25428750 : tts_minimal_store_tuple(slot, mtup, shouldFree);
6130 tgl 1461 ECB :
6130 tgl 1462 GIC 25428750 : return slot;
6130 tgl 1463 ECB : }
1464 :
1465 : /*
1466 : * Store a HeapTuple into any kind of slot, performing conversion if
1467 : * necessary.
1468 : */
1469 : void
1605 andres 1470 GIC 889090 : ExecForceStoreHeapTuple(HeapTuple tuple,
1451 andres 1471 ECB : TupleTableSlot *slot,
1472 : bool shouldFree)
1473 : {
1605 andres 1474 GIC 889090 : if (TTS_IS_HEAPTUPLE(slot))
1637 andres 1475 ECB : {
1451 andres 1476 GIC 213 : ExecStoreHeapTuple(tuple, slot, shouldFree);
1637 andres 1477 ECB : }
1605 andres 1478 GIC 888877 : else if (TTS_IS_BUFFERTUPLE(slot))
1637 andres 1479 ECB : {
1480 : MemoryContext oldContext;
1605 andres 1481 GIC 36008 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
9345 bruce 1482 ECB :
1605 andres 1483 GIC 36008 : ExecClearTuple(slot);
1605 andres 1484 CBC 36008 : slot->tts_flags &= ~TTS_FLAG_EMPTY;
1485 36008 : oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
1486 36008 : bslot->base.tuple = heap_copytuple(tuple);
1250 tgl 1487 36008 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
1605 andres 1488 36008 : MemoryContextSwitchTo(oldContext);
1451 andres 1489 ECB :
1451 andres 1490 GIC 36008 : if (shouldFree)
1451 andres 1491 CBC 35044 : pfree(tuple);
1605 andres 1492 ECB : }
1493 : else
1494 : {
1605 andres 1495 GIC 852869 : ExecClearTuple(slot);
1605 andres 1496 CBC 852869 : heap_deform_tuple(tuple, slot->tts_tupleDescriptor,
1605 andres 1497 ECB : slot->tts_values, slot->tts_isnull);
1605 andres 1498 GIC 852869 : ExecStoreVirtualTuple(slot);
1451 andres 1499 ECB :
1451 andres 1500 GIC 852869 : if (shouldFree)
1451 andres 1501 ECB : {
1451 andres 1502 GIC 133799 : ExecMaterializeSlot(slot);
1451 andres 1503 CBC 133799 : pfree(tuple);
1451 andres 1504 ECB : }
1505 : }
1605 andres 1506 GIC 889090 : }
9345 bruce 1507 ECB :
1508 : /*
1509 : * Store a MinimalTuple into any kind of slot, performing conversion if
1510 : * necessary.
1511 : */
1512 : void
1605 andres 1513 GIC 3545746 : ExecForceStoreMinimalTuple(MinimalTuple mtup,
1605 andres 1514 ECB : TupleTableSlot *slot,
1515 : bool shouldFree)
1516 : {
1605 andres 1517 GIC 3545746 : if (TTS_IS_MINIMALTUPLE(slot))
1605 andres 1518 ECB : {
1605 andres 1519 GIC 2210638 : tts_minimal_store_tuple(slot, mtup, shouldFree);
1605 andres 1520 ECB : }
1521 : else
1522 : {
1523 : HeapTupleData htup;
1524 :
1605 andres 1525 GIC 1335108 : ExecClearTuple(slot);
6600 tgl 1526 ECB :
1605 andres 1527 GIC 1335108 : htup.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
1605 andres 1528 CBC 1335108 : htup.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);
1529 1335108 : heap_deform_tuple(&htup, slot->tts_tupleDescriptor,
1605 andres 1530 ECB : slot->tts_values, slot->tts_isnull);
1605 andres 1531 GIC 1335108 : ExecStoreVirtualTuple(slot);
1451 andres 1532 ECB :
1451 andres 1533 GIC 1335108 : if (shouldFree)
1451 andres 1534 ECB : {
1451 andres 1535 GIC 735096 : ExecMaterializeSlot(slot);
1451 andres 1536 CBC 735096 : pfree(mtup);
1451 andres 1537 ECB : }
1538 : }
9770 scrappy 1539 GIC 3545746 : }
9770 scrappy 1540 ECB :
1541 : /* --------------------------------
1542 : * ExecStoreVirtualTuple
1543 : * Mark a slot as containing a virtual tuple.
1544 : *
1545 : * The protocol for loading a slot with virtual tuple data is:
1546 : * * Call ExecClearTuple to mark the slot empty.
1547 : * * Store data into the Datum/isnull arrays.
1548 : * * Call ExecStoreVirtualTuple to mark the slot valid.
1549 : * This is a bit unclean but it avoids one round of data copying.
1550 : * --------------------------------
1551 : */
1552 : TupleTableSlot *
6598 tgl 1553 GIC 13213313 : ExecStoreVirtualTuple(TupleTableSlot *slot)
9770 scrappy 1554 ECB : {
1555 : /*
1556 : * sanity checks
1557 : */
6598 tgl 1558 GIC 13213313 : Assert(slot != NULL);
6598 tgl 1559 CBC 13213313 : Assert(slot->tts_tupleDescriptor != NULL);
1637 andres 1560 13213313 : Assert(TTS_EMPTY(slot));
9770 scrappy 1561 ECB :
1637 andres 1562 GIC 13213313 : slot->tts_flags &= ~TTS_FLAG_EMPTY;
6598 tgl 1563 CBC 13213313 : slot->tts_nvalid = slot->tts_tupleDescriptor->natts;
9770 scrappy 1564 ECB :
6598 tgl 1565 GIC 13213313 : return slot;
6598 tgl 1566 ECB : }
1567 :
1568 : /* --------------------------------
1569 : * ExecStoreAllNullTuple
1570 : * Set up the slot to contain a null in every column.
1571 : *
1572 : * At first glance this might sound just like ExecClearTuple, but it's
1573 : * entirely different: the slot ends up full, not empty.
1574 : * --------------------------------
1575 : */
1576 : TupleTableSlot *
6598 tgl 1577 GIC 311223 : ExecStoreAllNullTuple(TupleTableSlot *slot)
6598 tgl 1578 ECB : {
1579 : /*
1580 : * sanity checks
1581 : */
6598 tgl 1582 GIC 311223 : Assert(slot != NULL);
6598 tgl 1583 CBC 311223 : Assert(slot->tts_tupleDescriptor != NULL);
6598 tgl 1584 ECB :
1585 : /* Clear any old contents */
6598 tgl 1586 GIC 311223 : ExecClearTuple(slot);
6600 tgl 1587 ECB :
1588 : /*
1589 : * Fill all the columns of the virtual tuple with nulls
1590 : */
6598 tgl 1591 GIC 5192225 : MemSet(slot->tts_values, 0,
6598 tgl 1592 ECB : slot->tts_tupleDescriptor->natts * sizeof(Datum));
6598 tgl 1593 GIC 311223 : memset(slot->tts_isnull, true,
6598 tgl 1594 CBC 311223 : slot->tts_tupleDescriptor->natts * sizeof(bool));
6598 tgl 1595 ECB :
6598 tgl 1596 GIC 311223 : return ExecStoreVirtualTuple(slot);
6598 tgl 1597 ECB : }
1598 :
1599 : /*
1600 : * Store a HeapTuple in datum form, into a slot. That always requires
1601 : * deforming it and storing it in virtual form.
1602 : *
1603 : * Until the slot is materialized, the contents of the slot depend on the
1604 : * datum.
1605 : */
1606 : void
1500 andres 1607 GIC 3 : ExecStoreHeapTupleDatum(Datum data, TupleTableSlot *slot)
1500 andres 1608 ECB : {
1500 andres 1609 GIC 3 : HeapTupleData tuple = {0};
1500 andres 1610 ECB : HeapTupleHeader td;
1611 :
1500 andres 1612 GIC 3 : td = DatumGetHeapTupleHeader(data);
1500 andres 1613 ECB :
1500 andres 1614 GIC 3 : tuple.t_len = HeapTupleHeaderGetDatumLength(td);
1500 andres 1615 CBC 3 : tuple.t_self = td->t_ctid;
1616 3 : tuple.t_data = td;
1500 andres 1617 ECB :
1500 andres 1618 GIC 3 : ExecClearTuple(slot);
1500 andres 1619 ECB :
1500 andres 1620 GIC 3 : heap_deform_tuple(&tuple, slot->tts_tupleDescriptor,
1500 andres 1621 ECB : slot->tts_values, slot->tts_isnull);
1500 andres 1622 GIC 3 : ExecStoreVirtualTuple(slot);
1500 andres 1623 CBC 3 : }
1500 andres 1624 ECB :
1625 : /*
1626 : * ExecFetchSlotHeapTuple - fetch HeapTuple representing the slot's content
1627 : *
1628 : * The returned HeapTuple represents the slot's content as closely as
1629 : * possible.
1630 : *
1631 : * If materialize is true, the contents of the slots will be made independent
1632 : * from the underlying storage (i.e. all buffer pins are released, memory is
1633 : * allocated in the slot's context).
1634 : *
1635 : * If shouldFree is not-NULL it'll be set to true if the returned tuple has
1636 : * been allocated in the calling memory context, and must be freed by the
1637 : * caller (via explicit pfree() or a memory context reset).
1638 : *
1639 : * NB: If materialize is true, modifications of the returned tuple are
1640 : * allowed. But it depends on the type of the slot whether such modifications
1641 : * will also affect the slot's contents. While that is not the nicest
1642 : * behaviour, all such modifications are in the process of being removed.
1643 : */
1644 : HeapTuple
1606 andres 1645 GIC 27537058 : ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
6598 tgl 1646 ECB : {
1647 : /*
1648 : * sanity checks
1649 : */
6598 tgl 1650 GIC 27537058 : Assert(slot != NULL);
1637 andres 1651 CBC 27537058 : Assert(!TTS_EMPTY(slot));
6598 tgl 1652 ECB :
1653 : /* Materialize the tuple so that the slot "owns" it, if requested. */
1605 andres 1654 GIC 27537058 : if (materialize)
1605 andres 1655 CBC 12470909 : slot->tts_ops->materialize(slot);
1606 andres 1656 ECB :
1605 andres 1657 GIC 27537058 : if (slot->tts_ops->get_heap_tuple == NULL)
1838 andrew 1658 ECB : {
1605 andres 1659 GIC 1420107 : if (shouldFree)
1605 andres 1660 CBC 1420107 : *shouldFree = true;
1661 1420107 : return slot->tts_ops->copy_heap_tuple(slot);
1605 andres 1662 ECB : }
1663 : else
1664 : {
1605 andres 1665 GIC 26116951 : if (shouldFree)
1605 andres 1666 CBC 22449785 : *shouldFree = false;
1667 26116951 : return slot->tts_ops->get_heap_tuple(slot);
1838 andrew 1668 ECB : }
1669 : }
1670 :
1671 : /* --------------------------------
1672 : * ExecFetchSlotMinimalTuple
1673 : * Fetch the slot's minimal physical tuple.
1674 : *
1675 : * If the given tuple table slot can hold a minimal tuple, indicated by a
1676 : * non-NULL get_minimal_tuple callback, the function returns the minimal
1677 : * tuple returned by that callback. It assumes that the minimal tuple
1678 : * returned by the callback is "owned" by the slot i.e. the slot is
1679 : * responsible for freeing the memory consumed by the tuple. Hence it sets
1680 : * *shouldFree to false, indicating that the caller should not free the
1681 : * memory consumed by the minimal tuple. In this case the returned minimal
1682 : * tuple should be considered as read-only.
1683 : *
1684 : * If that callback is not supported, it calls copy_minimal_tuple callback
1685 : * which is expected to return a copy of minimal tuple representing the
1686 : * contents of the slot. In this case *shouldFree is set to true,
1687 : * indicating the caller that it should free the memory consumed by the
1688 : * minimal tuple. In this case the returned minimal tuple may be written
1689 : * up.
1690 : * --------------------------------
1691 : */
1692 : MinimalTuple
1605 andres 1693 GIC 11018182 : ExecFetchSlotMinimalTuple(TupleTableSlot *slot,
1605 andres 1694 ECB : bool *shouldFree)
1695 : {
1696 : /*
1697 : * sanity checks
1698 : */
6130 tgl 1699 GIC 11018182 : Assert(slot != NULL);
1637 andres 1700 CBC 11018182 : Assert(!TTS_EMPTY(slot));
1637 andres 1701 ECB :
1605 andres 1702 GIC 11018182 : if (slot->tts_ops->get_minimal_tuple)
1605 andres 1703 ECB : {
1605 andres 1704 GIC 2447307 : if (shouldFree)
1605 andres 1705 CBC 2447307 : *shouldFree = false;
1706 2447307 : return slot->tts_ops->get_minimal_tuple(slot);
1605 andres 1707 ECB : }
1708 : else
1709 : {
1605 andres 1710 GIC 8570875 : if (shouldFree)
1605 andres 1711 CBC 8570875 : *shouldFree = true;
1712 8570875 : return slot->tts_ops->copy_minimal_tuple(slot);
1605 andres 1713 ECB : }
1714 : }
1715 :
1716 : /* --------------------------------
1717 : * ExecFetchSlotHeapTupleDatum
1718 : * Fetch the slot's tuple as a composite-type Datum.
1719 : *
1720 : * The result is always freshly palloc'd in the caller's memory context.
1721 : * --------------------------------
1722 : */
1723 : Datum
1606 andres 1724 GIC 30417 : ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot)
5276 tgl 1725 ECB : {
1726 : HeapTuple tup;
1727 : TupleDesc tupdesc;
1728 : bool shouldFree;
1729 : Datum ret;
1730 :
1731 : /* Fetch slot's contents in regular-physical-tuple form */
1606 andres 1732 GIC 30417 : tup = ExecFetchSlotHeapTuple(slot, false, &shouldFree);
5276 tgl 1733 CBC 30417 : tupdesc = slot->tts_tupleDescriptor;
3265 tgl 1734 ECB :
1735 : /* Convert to Datum form */
1606 andres 1736 GIC 30417 : ret = heap_copy_tuple_as_datum(tup, tupdesc);
1606 andres 1737 ECB :
1606 andres 1738 GIC 30417 : if (shouldFree)
1606 andres 1739 CBC 30417 : pfree(tup);
1606 andres 1740 ECB :
1606 andres 1741 GIC 30417 : return ret;
5276 tgl 1742 ECB : }
1743 :
1744 : /* ----------------------------------------------------------------
1745 : * convenience initialization routines
1746 : * ----------------------------------------------------------------
1747 : */
1748 :
1749 : /* ----------------
1750 : * ExecInitResultTypeTL
1751 : *
1752 : * Initialize result type, using the plan node's targetlist.
1753 : * ----------------
1754 : */
1755 : void
1612 andres 1756 GIC 557413 : ExecInitResultTypeTL(PlanState *planstate)
9770 scrappy 1757 ECB : {
1601 andres 1758 GIC 557413 : TupleDesc tupDesc = ExecTypeFromTL(planstate->plan->targetlist);
1878 andres 1759 ECB :
1612 andres 1760 GIC 557413 : planstate->ps_ResultTupleDesc = tupDesc;
1612 andres 1761 CBC 557413 : }
1878 andres 1762 ECB :
1763 : /* --------------------------------
1764 : * ExecInit{Result,Scan,Extra}TupleSlot[TL]
1765 : *
1766 : * These are convenience routines to initialize the specified slot
1767 : * in nodes inheriting the appropriate state. ExecInitExtraTupleSlot
1768 : * is used for initializing special-purpose slots.
1769 : * --------------------------------
1770 : */
1771 :
1772 : /* ----------------
1773 : * ExecInitResultTupleSlotTL
1774 : *
1775 : * Initialize result tuple slot, using the tuple descriptor previously
1776 : * computed with ExecInitResultTypeTL().
1777 : * ----------------
1778 : */
1779 : void
1606 andres 1780 GIC 377971 : ExecInitResultSlot(PlanState *planstate, const TupleTableSlotOps *tts_ops)
1612 andres 1781 ECB : {
1782 : TupleTableSlot *slot;
1783 :
1612 andres 1784 GIC 377971 : slot = ExecAllocTableSlot(&planstate->state->es_tupleTable,
1606 andres 1785 ECB : planstate->ps_ResultTupleDesc, tts_ops);
1612 andres 1786 GIC 377971 : planstate->ps_ResultTupleSlot = slot;
1606 andres 1787 ECB :
1606 andres 1788 GIC 377971 : planstate->resultopsfixed = planstate->ps_ResultTupleDesc != NULL;
1606 andres 1789 CBC 377971 : planstate->resultops = tts_ops;
1790 377971 : planstate->resultopsset = true;
1612 1791 377971 : }
1612 andres 1792 ECB :
1793 : /* ----------------
1794 : * ExecInitResultTupleSlotTL
1795 : *
1796 : * Initialize result tuple slot, using the plan node's targetlist.
1797 : * ----------------
1798 : */
1799 : void
1606 andres 1800 GIC 277097 : ExecInitResultTupleSlotTL(PlanState *planstate,
1606 andres 1801 ECB : const TupleTableSlotOps *tts_ops)
1802 : {
1612 andres 1803 GIC 277097 : ExecInitResultTypeTL(planstate);
1606 andres 1804 CBC 277097 : ExecInitResultSlot(planstate, tts_ops);
9770 scrappy 1805 277097 : }
9770 scrappy 1806 ECB :
1807 : /* ----------------
1808 : * ExecInitScanTupleSlot
1809 : * ----------------
1810 : */
1811 : void
1606 andres 1812 GIC 260872 : ExecInitScanTupleSlot(EState *estate, ScanState *scanstate,
1606 andres 1813 ECB : TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
1814 : {
1878 andres 1815 GIC 260872 : scanstate->ss_ScanTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable,
1606 andres 1816 ECB : tupledesc, tts_ops);
1840 andres 1817 GIC 260872 : scanstate->ps.scandesc = tupledesc;
1606 andres 1818 CBC 260872 : scanstate->ps.scanopsfixed = tupledesc != NULL;
1819 260872 : scanstate->ps.scanops = tts_ops;
1820 260872 : scanstate->ps.scanopsset = true;
9770 scrappy 1821 260872 : }
9770 scrappy 1822 ECB :
1823 : /* ----------------
1824 : * ExecInitExtraTupleSlot
1825 : *
1826 : * Return a newly created slot. If tupledesc is non-NULL the slot will have
1827 : * that as its fixed tupledesc. Otherwise the caller needs to use
1828 : * ExecSetSlotDescriptor() to set the descriptor before use.
1829 : * ----------------
1830 : */
1831 : TupleTableSlot *
1606 andres 1832 GIC 212749 : ExecInitExtraTupleSlot(EState *estate,
1606 andres 1833 ECB : TupleDesc tupledesc,
1834 : const TupleTableSlotOps *tts_ops)
1835 : {
1606 andres 1836 GIC 212749 : return ExecAllocTableSlot(&estate->es_tupleTable, tupledesc, tts_ops);
9770 scrappy 1837 ECB : }
1838 :
1839 : /* ----------------
1840 : * ExecInitNullTupleSlot
1841 : *
1842 : * Build a slot containing an all-nulls tuple of the given type.
1843 : * This is used as a substitute for an input tuple when performing an
1844 : * outer join.
1845 : * ----------------
1846 : */
1847 : TupleTableSlot *
1606 andres 1848 GIC 16768 : ExecInitNullTupleSlot(EState *estate, TupleDesc tupType,
1606 andres 1849 ECB : const TupleTableSlotOps *tts_ops)
1850 : {
1606 andres 1851 GIC 16768 : TupleTableSlot *slot = ExecInitExtraTupleSlot(estate, tupType, tts_ops);
8244 tgl 1852 ECB :
6598 tgl 1853 GIC 16768 : return ExecStoreAllNullTuple(slot);
9770 scrappy 1854 ECB : }
1855 :
1856 : /* ---------------------------------------------------------------
1857 : * Routines for setting/accessing attributes in a slot.
1858 : * ---------------------------------------------------------------
1859 : */
1860 :
1861 : /*
1862 : * Fill in missing values for a TupleTableSlot.
1863 : *
1864 : * This is only exposed because it's needed for JIT compiled tuple
1865 : * deforming. That exception aside, there should be no callers outside of this
1866 : * file.
1867 : */
1868 : void
1638 andres 1869 GIC 2829 : slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, int lastAttNum)
1638 andres 1870 ECB : {
1638 andres 1871 GIC 2829 : AttrMissing *attrmiss = NULL;
1638 andres 1872 ECB :
1638 andres 1873 GIC 2829 : if (slot->tts_tupleDescriptor->constr)
1638 andres 1874 CBC 2253 : attrmiss = slot->tts_tupleDescriptor->constr->missing;
1638 andres 1875 ECB :
1638 andres 1876 GIC 2829 : if (!attrmiss)
1638 andres 1877 ECB : {
1878 : /* no missing values array at all, so just fill everything in as NULL */
1638 andres 1879 GIC 615 : memset(slot->tts_values + startAttNum, 0,
1638 andres 1880 CBC 615 : (lastAttNum - startAttNum) * sizeof(Datum));
1881 615 : memset(slot->tts_isnull + startAttNum, 1,
1882 615 : (lastAttNum - startAttNum) * sizeof(bool));
1638 andres 1883 ECB : }
1884 : else
1885 : {
1886 : int missattnum;
1887 :
1888 : /* if there is a missing values array we must process them one by one */
1638 andres 1889 GIC 2214 : for (missattnum = startAttNum;
1638 andres 1890 CBC 5124 : missattnum < lastAttNum;
1891 2910 : missattnum++)
1638 andres 1892 ECB : {
1638 andres 1893 GIC 2910 : slot->tts_values[missattnum] = attrmiss[missattnum].am_value;
1638 andres 1894 CBC 2910 : slot->tts_isnull[missattnum] = !attrmiss[missattnum].am_present;
1638 andres 1895 ECB : }
1896 : }
1638 andres 1897 GIC 2829 : }
1638 andres 1898 ECB :
1899 : /*
1900 : * slot_getsomeattrs_int - workhorse for slot_getsomeattrs()
1901 : */
1902 : void
1605 andres 1903 GIC 105171780 : slot_getsomeattrs_int(TupleTableSlot *slot, int attnum)
1638 andres 1904 ECB : {
1905 : /* Check for caller errors */
1401 akapila 1906 GIC 105171780 : Assert(slot->tts_nvalid < attnum); /* checked in slot_getsomeattrs */
1605 andres 1907 CBC 105171780 : Assert(attnum > 0);
1638 andres 1908 ECB :
1605 andres 1909 GIC 105171780 : if (unlikely(attnum > slot->tts_tupleDescriptor->natts))
1638 andres 1910 LBC 0 : elog(ERROR, "invalid attribute number %d", attnum);
1638 andres 1911 EUB :
1912 : /* Fetch as many attributes as possible from the underlying tuple. */
1605 andres 1913 GIC 105171780 : slot->tts_ops->getsomeattrs(slot, attnum);
1638 andres 1914 ECB :
1915 : /*
1916 : * If the underlying tuple doesn't have enough attributes, tuple
1917 : * descriptor must have the missing attributes.
1918 : */
1605 andres 1919 GIC 105171780 : if (unlikely(slot->tts_nvalid < attnum))
1605 andres 1920 ECB : {
1605 andres 1921 GIC 2829 : slot_getmissingattrs(slot, slot->tts_nvalid, attnum);
1605 andres 1922 CBC 2829 : slot->tts_nvalid = attnum;
1605 andres 1923 ECB : }
1638 andres 1924 GIC 105171780 : }
1638 andres 1925 ECB :
1926 : /* ----------------------------------------------------------------
1927 : * ExecTypeFromTL
1928 : *
1929 : * Generate a tuple descriptor for the result tuple of a targetlist.
1930 : * (A parse/plan tlist must be passed, not an ExprState tlist.)
1931 : * Note that resjunk columns, if any, are included in the result.
1932 : *
1933 : * Currently there are about 4 different places where we create
1934 : * TupleDescriptors. They should all be merged, or perhaps
1935 : * be rewritten to call BuildDesc().
1936 : * ----------------------------------------------------------------
1937 : */
1938 : TupleDesc
1601 andres 1939 GIC 569995 : ExecTypeFromTL(List *targetList)
9770 scrappy 1940 ECB : {
1601 andres 1941 GIC 569995 : return ExecTypeFromTLInternal(targetList, false);
9345 bruce 1942 ECB : }
1943 :
1944 : /* ----------------------------------------------------------------
1945 : * ExecCleanTypeFromTL
1946 : *
1947 : * Same as above, but resjunk columns are omitted from the result.
1948 : * ----------------------------------------------------------------
1949 : */
1950 : TupleDesc
1601 andres 1951 GIC 42793 : ExecCleanTypeFromTL(List *targetList)
7278 tgl 1952 ECB : {
1601 andres 1953 GIC 42793 : return ExecTypeFromTLInternal(targetList, true);
7069 bruce 1954 ECB : }
1955 :
1956 : static TupleDesc
1601 andres 1957 GIC 612788 : ExecTypeFromTLInternal(List *targetList, bool skipjunk)
7069 bruce 1958 ECB : {
1959 : TupleDesc typeInfo;
1960 : ListCell *l;
1961 : int len;
6797 bruce 1962 GIC 612788 : int cur_resno = 1;
7069 bruce 1963 ECB :
7069 bruce 1964 GIC 612788 : if (skipjunk)
7069 bruce 1965 CBC 42793 : len = ExecCleanTargetListLength(targetList);
7069 bruce 1966 ECB : else
7069 bruce 1967 GIC 569995 : len = ExecTargetListLength(targetList);
1601 andres 1968 CBC 612788 : typeInfo = CreateTemplateTupleDesc(len);
7278 tgl 1969 ECB :
7069 bruce 1970 GIC 2908123 : foreach(l, targetList)
7278 tgl 1971 ECB : {
6797 bruce 1972 GIC 2295335 : TargetEntry *tle = lfirst(l);
7278 tgl 1973 ECB :
6577 tgl 1974 GIC 2295335 : if (skipjunk && tle->resjunk)
7278 tgl 1975 CBC 12750 : continue;
1976 6847755 : TupleDescInitEntry(typeInfo,
4443 peter_e 1977 ECB : cur_resno,
6577 tgl 1978 GIC 2282585 : tle->resname,
6577 tgl 1979 CBC 2282585 : exprType((Node *) tle->expr),
1980 2282585 : exprTypmod((Node *) tle->expr),
6947 tgl 1981 ECB : 0);
4443 peter_e 1982 GIC 2282585 : TupleDescInitEntryCollation(typeInfo,
4443 peter_e 1983 ECB : cur_resno,
4443 peter_e 1984 GIC 2282585 : exprCollation((Node *) tle->expr));
4443 peter_e 1985 CBC 2282585 : cur_resno++;
7278 tgl 1986 ECB : }
1987 :
7278 tgl 1988 GIC 612788 : return typeInfo;
7278 tgl 1989 ECB : }
1990 :
1991 : /*
1992 : * ExecTypeFromExprList - build a tuple descriptor from a list of Exprs
1993 : *
1994 : * This is roughly like ExecTypeFromTL, but we work from bare expressions
1995 : * not TargetEntrys. No names are attached to the tupledesc's columns.
1996 : */
1997 : TupleDesc
3072 tgl 1998 GIC 5774 : ExecTypeFromExprList(List *exprList)
6908 tgl 1999 ECB : {
2000 : TupleDesc typeInfo;
2001 : ListCell *lc;
6797 bruce 2002 GIC 5774 : int cur_resno = 1;
4072 tgl 2003 ECB :
1601 andres 2004 GIC 5774 : typeInfo = CreateTemplateTupleDesc(list_length(exprList));
6908 tgl 2005 ECB :
3072 tgl 2006 GIC 15943 : foreach(lc, exprList)
6908 tgl 2007 ECB : {
3072 tgl 2008 GIC 10169 : Node *e = lfirst(lc);
6908 tgl 2009 ECB :
6908 tgl 2010 GIC 10169 : TupleDescInitEntry(typeInfo,
4443 peter_e 2011 ECB : cur_resno,
2012 : NULL,
2013 : exprType(e),
2014 : exprTypmod(e),
2015 : 0);
4443 peter_e 2016 GIC 10169 : TupleDescInitEntryCollation(typeInfo,
4443 peter_e 2017 ECB : cur_resno,
2018 : exprCollation(e));
4443 peter_e 2019 GIC 10169 : cur_resno++;
6908 tgl 2020 ECB : }
2021 :
6908 tgl 2022 GIC 5774 : return typeInfo;
6908 tgl 2023 ECB : }
2024 :
2025 : /*
2026 : * ExecTypeSetColNames - set column names in a RECORD TupleDesc
2027 : *
2028 : * Column names must be provided as an alias list (list of String nodes).
2029 : */
2030 : void
3072 tgl 2031 GIC 1746 : ExecTypeSetColNames(TupleDesc typeInfo, List *namesList)
3072 tgl 2032 ECB : {
3072 tgl 2033 GIC 1746 : int colno = 0;
3072 tgl 2034 ECB : ListCell *lc;
2035 :
2036 : /* It's only OK to change col names in a not-yet-blessed RECORD type */
388 tgl 2037 GIC 1746 : Assert(typeInfo->tdtypeid == RECORDOID);
388 tgl 2038 CBC 1746 : Assert(typeInfo->tdtypmod < 0);
388 tgl 2039 ECB :
3072 tgl 2040 GIC 6118 : foreach(lc, namesList)
3072 tgl 2041 ECB : {
3072 tgl 2042 GIC 4372 : char *cname = strVal(lfirst(lc));
3072 tgl 2043 ECB : Form_pg_attribute attr;
2044 :
2045 : /* Guard against too-long names list (probably can't happen) */
3072 tgl 2046 GIC 4372 : if (colno >= typeInfo->natts)
3072 tgl 2047 LBC 0 : break;
2058 andres 2048 GBC 4372 : attr = TupleDescAttr(typeInfo, colno);
2058 andres 2049 CBC 4372 : colno++;
3072 tgl 2050 ECB :
2051 : /*
2052 : * Do nothing for empty aliases or dropped columns (these cases
2053 : * probably can't arise in RECORD types, either)
2054 : */
388 tgl 2055 GIC 4372 : if (cname[0] == '\0' || attr->attisdropped)
3072 tgl 2056 CBC 13 : continue;
3072 tgl 2057 ECB :
2058 : /* OK, assign the column name */
388 tgl 2059 GIC 4359 : namestrcpy(&(attr->attname), cname);
3072 tgl 2060 ECB : }
3072 tgl 2061 GIC 1746 : }
3072 tgl 2062 ECB :
2063 : /*
2064 : * BlessTupleDesc - make a completed tuple descriptor useful for SRFs
2065 : *
2066 : * Rowtype Datums returned by a function must contain valid type information.
2067 : * This happens "for free" if the tupdesc came from a relcache entry, but
2068 : * not if we have manufactured a tupdesc for a transient RECORD datatype.
2069 : * In that case we have to notify typcache.c of the existence of the type.
2070 : */
2071 : TupleDesc
6947 tgl 2072 GIC 31058 : BlessTupleDesc(TupleDesc tupdesc)
6947 tgl 2073 ECB : {
6947 tgl 2074 GIC 31058 : if (tupdesc->tdtypeid == RECORDOID &&
6947 tgl 2075 CBC 29589 : tupdesc->tdtypmod < 0)
2076 12829 : assign_record_type_typmod(tupdesc);
6947 tgl 2077 ECB :
6947 tgl 2078 GIC 31058 : return tupdesc; /* just for notational convenience */
6947 tgl 2079 ECB : }
2080 :
2081 : /*
2082 : * TupleDescGetAttInMetadata - Build an AttInMetadata structure based on the
2083 : * supplied TupleDesc. AttInMetadata can be used in conjunction with C strings
2084 : * to produce a properly formed tuple.
2085 : */
2086 : AttInMetadata *
7598 bruce 2087 GIC 2847 : TupleDescGetAttInMetadata(TupleDesc tupdesc)
7598 bruce 2088 ECB : {
7522 bruce 2089 GIC 2847 : int natts = tupdesc->natts;
7522 bruce 2090 ECB : int i;
2091 : Oid atttypeid;
2092 : Oid attinfuncid;
2093 : FmgrInfo *attinfuncinfo;
2094 : Oid *attioparams;
2095 : int32 *atttypmods;
2096 : AttInMetadata *attinmeta;
2097 :
7598 bruce 2098 GIC 2847 : attinmeta = (AttInMetadata *) palloc(sizeof(AttInMetadata));
7598 bruce 2099 ECB :
2100 : /* "Bless" the tupledesc so that we can make rowtype datums with it */
6947 tgl 2101 GIC 2847 : attinmeta->tupdesc = BlessTupleDesc(tupdesc);
6947 tgl 2102 ECB :
2103 : /*
2104 : * Gather info needed later to call the "in" function for each attribute
2105 : */
7132 bruce 2106 GIC 2847 : attinfuncinfo = (FmgrInfo *) palloc0(natts * sizeof(FmgrInfo));
6881 tgl 2107 CBC 2847 : attioparams = (Oid *) palloc0(natts * sizeof(Oid));
7132 bruce 2108 2847 : atttypmods = (int32 *) palloc0(natts * sizeof(int32));
7598 bruce 2109 ECB :
7598 bruce 2110 GIC 26587 : for (i = 0; i < natts; i++)
7598 bruce 2111 ECB : {
2058 andres 2112 GIC 23740 : Form_pg_attribute att = TupleDescAttr(tupdesc, i);
2058 andres 2113 ECB :
2114 : /* Ignore dropped attributes */
2058 andres 2115 GIC 23740 : if (!att->attisdropped)
7132 bruce 2116 ECB : {
2058 andres 2117 GIC 23627 : atttypeid = att->atttypid;
6881 tgl 2118 CBC 23627 : getTypeInputInfo(atttypeid, &attinfuncid, &attioparams[i]);
7132 bruce 2119 23627 : fmgr_info(attinfuncid, &attinfuncinfo[i]);
2058 andres 2120 23627 : atttypmods[i] = att->atttypmod;
7132 bruce 2121 ECB : }
2122 : }
7598 bruce 2123 GIC 2847 : attinmeta->attinfuncs = attinfuncinfo;
6881 tgl 2124 CBC 2847 : attinmeta->attioparams = attioparams;
7598 bruce 2125 2847 : attinmeta->atttypmods = atttypmods;
7598 bruce 2126 ECB :
7598 bruce 2127 GIC 2847 : return attinmeta;
7598 bruce 2128 ECB : }
2129 :
2130 : /*
2131 : * BuildTupleFromCStrings - build a HeapTuple given user data in C string form.
2132 : * values is an array of C strings, one for each attribute of the return tuple.
2133 : * A NULL string pointer indicates we want to create a NULL field.
2134 : */
2135 : HeapTuple
7598 bruce 2136 GIC 407734 : BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
7598 bruce 2137 ECB : {
7522 bruce 2138 GIC 407734 : TupleDesc tupdesc = attinmeta->tupdesc;
7522 bruce 2139 CBC 407734 : int natts = tupdesc->natts;
7522 bruce 2140 ECB : Datum *dvalues;
2141 : bool *nulls;
2142 : int i;
2143 : HeapTuple tuple;
2144 :
7598 bruce 2145 GIC 407734 : dvalues = (Datum *) palloc(natts * sizeof(Datum));
5271 tgl 2146 CBC 407734 : nulls = (bool *) palloc(natts * sizeof(bool));
7598 bruce 2147 ECB :
2148 : /*
2149 : * Call the "in" function for each non-dropped attribute, even for nulls,
2150 : * to support domains.
2151 : */
7598 bruce 2152 GIC 7209235 : for (i = 0; i < natts; i++)
7598 bruce 2153 ECB : {
2058 andres 2154 GIC 6801502 : if (!TupleDescAttr(tupdesc, i)->attisdropped)
7598 bruce 2155 ECB : {
2156 : /* Non-dropped attributes */
6214 tgl 2157 GIC 13603003 : dvalues[i] = InputFunctionCall(&attinmeta->attinfuncs[i],
6214 tgl 2158 CBC 6801502 : values[i],
2159 6801502 : attinmeta->attioparams[i],
2160 6801502 : attinmeta->atttypmods[i]);
7132 bruce 2161 6801501 : if (values[i] != NULL)
5271 tgl 2162 4601822 : nulls[i] = false;
7132 bruce 2163 ECB : else
5271 tgl 2164 GIC 2199679 : nulls[i] = true;
7598 bruce 2165 ECB : }
2166 : else
2167 : {
2168 : /* Handle dropped attributes by setting to NULL */
7528 tgl 2169 UIC 0 : dvalues[i] = (Datum) 0;
5271 tgl 2170 UBC 0 : nulls[i] = true;
7570 bruce 2171 EUB : }
2172 : }
2173 :
2174 : /*
2175 : * Form a tuple
2176 : */
5271 tgl 2177 GIC 407733 : tuple = heap_form_tuple(tupdesc, dvalues, nulls);
7598 bruce 2178 ECB :
2179 : /*
2180 : * Release locally palloc'd space. XXX would probably be good to pfree
2181 : * values of pass-by-reference datums, as well.
2182 : */
7528 tgl 2183 GIC 407733 : pfree(dvalues);
7528 tgl 2184 CBC 407733 : pfree(nulls);
7528 tgl 2185 ECB :
7598 bruce 2186 GIC 407733 : return tuple;
7598 bruce 2187 ECB : }
2188 :
2189 : /*
2190 : * HeapTupleHeaderGetDatum - convert a HeapTupleHeader pointer to a Datum.
2191 : *
2192 : * This must *not* get applied to an on-disk tuple; the tuple should be
2193 : * freshly made by heap_form_tuple or some wrapper routine for it (such as
2194 : * BuildTupleFromCStrings). Be sure also that the tupledesc used to build
2195 : * the tuple has a properly "blessed" rowtype.
2196 : *
2197 : * Formerly this was a macro equivalent to PointerGetDatum, relying on the
2198 : * fact that heap_form_tuple fills in the appropriate tuple header fields
2199 : * for a composite Datum. However, we now require that composite Datums not
2200 : * contain any external TOAST pointers. We do not want heap_form_tuple itself
2201 : * to enforce that; more specifically, the rule applies only to actual Datums
2202 : * and not to HeapTuple structures. Therefore, HeapTupleHeaderGetDatum is
2203 : * now a function that detects whether there are externally-toasted fields
2204 : * and constructs a new tuple with inlined fields if so. We still need
2205 : * heap_form_tuple to insert the Datum header fields, because otherwise this
2206 : * code would have no way to obtain a tupledesc for the tuple.
2207 : *
2208 : * Note that if we do build a new tuple, it's palloc'd in the current
2209 : * memory context. Beware of code that changes context between the initial
2210 : * heap_form_tuple/etc call and calling HeapTuple(Header)GetDatum.
2211 : *
2212 : * For performance-critical callers, it could be worthwhile to take extra
2213 : * steps to ensure that there aren't TOAST pointers in the output of
2214 : * heap_form_tuple to begin with. It's likely however that the costs of the
2215 : * typcache lookup and tuple disassembly/reassembly are swamped by TOAST
2216 : * dereference costs, so that the benefits of such extra effort would be
2217 : * minimal.
2218 : *
2219 : * XXX it would likely be better to create wrapper functions that produce
2220 : * a composite Datum from the field values in one step. However, there's
2221 : * enough code using the existing APIs that we couldn't get rid of this
2222 : * hack anytime soon.
2223 : */
2224 : Datum
3265 tgl 2225 GIC 493533 : HeapTupleHeaderGetDatum(HeapTupleHeader tuple)
3265 tgl 2226 ECB : {
2227 : Datum result;
2228 : TupleDesc tupDesc;
2229 :
2230 : /* No work if there are no external TOAST pointers in the tuple */
3265 tgl 2231 GIC 493533 : if (!HeapTupleHeaderHasExternal(tuple))
3265 tgl 2232 CBC 493527 : return PointerGetDatum(tuple);
3265 tgl 2233 ECB :
2234 : /* Use the type data saved by heap_form_tuple to look up the rowtype */
3265 tgl 2235 GIC 6 : tupDesc = lookup_rowtype_tupdesc(HeapTupleHeaderGetTypeId(tuple),
3265 tgl 2236 ECB : HeapTupleHeaderGetTypMod(tuple));
2237 :
2238 : /* And do the flattening */
3265 tgl 2239 GIC 6 : result = toast_flatten_tuple_to_datum(tuple,
2118 tgl 2240 CBC 6 : HeapTupleHeaderGetDatumLength(tuple),
3265 tgl 2241 ECB : tupDesc);
2242 :
3265 tgl 2243 GIC 6 : ReleaseTupleDesc(tupDesc);
3265 tgl 2244 ECB :
3265 tgl 2245 GIC 6 : return result;
3265 tgl 2246 ECB : }
2247 :
2248 :
2249 : /*
2250 : * Functions for sending tuples to the frontend (or other specified destination)
2251 : * as though it is a SELECT result. These are used by utility commands that
2252 : * need to project directly to the destination and don't need or want full
2253 : * table function capability. Currently used by EXPLAIN and SHOW ALL.
2254 : */
2255 : TupOutputState *
1606 andres 2256 GIC 12020 : begin_tup_output_tupdesc(DestReceiver *dest,
1606 andres 2257 ECB : TupleDesc tupdesc,
2258 : const TupleTableSlotOps *tts_ops)
2259 : {
2260 : TupOutputState *tstate;
2261 :
7568 bruce 2262 GIC 12020 : tstate = (TupOutputState *) palloc(sizeof(TupOutputState));
7568 bruce 2263 ECB :
1606 andres 2264 GIC 12020 : tstate->slot = MakeSingleTupleTableSlot(tupdesc, tts_ops);
7278 tgl 2265 CBC 12020 : tstate->dest = dest;
7568 bruce 2266 ECB :
2040 peter_e 2267 GIC 12020 : tstate->dest->rStartup(tstate->dest, (int) CMD_SELECT, tupdesc);
7568 bruce 2268 ECB :
7568 bruce 2269 GIC 12020 : return tstate;
7568 bruce 2270 ECB : }
2271 :
2272 : /*
2273 : * write a single tuple
2274 : */
2275 : void
5009 tgl 2276 GIC 63961 : do_tup_output(TupOutputState *tstate, Datum *values, bool *isnull)
7568 bruce 2277 ECB : {
5008 tgl 2278 GIC 63961 : TupleTableSlot *slot = tstate->slot;
5008 tgl 2279 CBC 63961 : int natts = slot->tts_tupleDescriptor->natts;
5009 tgl 2280 ECB :
2281 : /* make sure the slot is clear */
5008 tgl 2282 GIC 63961 : ExecClearTuple(slot);
7568 bruce 2283 ECB :
2284 : /* insert data */
5008 tgl 2285 GIC 63961 : memcpy(slot->tts_values, values, natts * sizeof(Datum));
5008 tgl 2286 CBC 63961 : memcpy(slot->tts_isnull, isnull, natts * sizeof(bool));
5008 tgl 2287 ECB :
2288 : /* mark slot as containing a virtual tuple */
5008 tgl 2289 GIC 63961 : ExecStoreVirtualTuple(slot);
6598 tgl 2290 ECB :
2291 : /* send the tuple to the receiver */
2040 peter_e 2292 GIC 63961 : (void) tstate->dest->receiveSlot(slot, tstate->dest);
6598 tgl 2293 ECB :
2294 : /* clean up */
5008 tgl 2295 GIC 63961 : ExecClearTuple(slot);
7568 bruce 2296 CBC 63961 : }
7568 bruce 2297 ECB :
2298 : /*
2299 : * write a chunk of text, breaking at newline characters
2300 : *
2301 : * Should only be used with a single-TEXT-attribute tupdesc.
2302 : */
2303 : void
2512 tgl 2304 GIC 9736 : do_text_output_multiline(TupOutputState *tstate, const char *txt)
7568 bruce 2305 ECB : {
2306 : Datum values[1];
4790 bruce 2307 GIC 9736 : bool isnull[1] = {false};
5009 tgl 2308 ECB :
2512 tgl 2309 GIC 70752 : while (*txt)
7568 bruce 2310 ECB : {
2311 : const char *eol;
2312 : int len;
2313 :
2512 tgl 2314 GIC 61016 : eol = strchr(txt, '\n');
7568 bruce 2315 CBC 61016 : if (eol)
5009 tgl 2316 ECB : {
2512 tgl 2317 GIC 61016 : len = eol - txt;
5009 tgl 2318 CBC 61016 : eol++;
5009 tgl 2319 ECB : }
2320 : else
2321 : {
2512 tgl 2322 UIC 0 : len = strlen(txt);
2512 tgl 2323 UBC 0 : eol = txt + len;
5009 tgl 2324 EUB : }
2325 :
2512 tgl 2326 GIC 61016 : values[0] = PointerGetDatum(cstring_to_text_with_len(txt, len));
5009 tgl 2327 CBC 61016 : do_tup_output(tstate, values, isnull);
2328 61016 : pfree(DatumGetPointer(values[0]));
2512 2329 61016 : txt = eol;
7568 bruce 2330 ECB : }
7568 bruce 2331 GIC 9736 : }
7568 bruce 2332 ECB :
2333 : void
7568 bruce 2334 GIC 12020 : end_tup_output(TupOutputState *tstate)
7568 bruce 2335 ECB : {
2040 peter_e 2336 GIC 12020 : tstate->dest->rShutdown(tstate->dest);
7278 tgl 2337 ECB : /* note that destroying the dest is not ours to do */
6598 tgl 2338 GIC 12020 : ExecDropSingleTupleTableSlot(tstate->slot);
7568 bruce 2339 CBC 12020 : pfree(tstate);
2340 12020 : }
|