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