1 /*-------------------------------------------------------------------------
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.
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.).
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.
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.
30 * During ExecutorRun()
32 * - SeqNext() calls ExecStoreBufferHeapTuple() to place the tuple
33 * returned by the access method into the scan tuple slot.
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().
39 * - ExecutePlan() calls the output function.
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.
49 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
50 * Portions Copyright (c) 1994, Regents of the University of California
54 * src/backend/executor/execTuples.c
56 *-------------------------------------------------------------------------
60 #include "access/htup_details.h"
61 #include "access/tupdesc_details.h"
62 #include "access/tuptoaster.h"
64 #include "catalog/pg_type.h"
65 #include "nodes/nodeFuncs.h"
66 #include "storage/bufmgr.h"
67 #include "utils/builtins.h"
68 #include "utils/lsyscache.h"
69 #include "utils/typcache.h"
72 static TupleDesc ExecTypeFromTLInternal(List *targetList,
74 static pg_attribute_always_inline void
75 slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
77 static void tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, Buffer buffer);
80 const TupleTableSlotOps TTSOpsVirtual;
81 const TupleTableSlotOps TTSOpsHeapTuple;
82 const TupleTableSlotOps TTSOpsMinimalTuple;
83 const TupleTableSlotOps TTSOpsBufferHeapTuple;
87 * TupleTableSlotOps implementations.
91 * TupleTableSlotOps implementation for VirtualTupleTableSlot.
94 tts_virtual_init(TupleTableSlot *slot)
99 tts_virtual_release(TupleTableSlot *slot)
104 tts_virtual_clear(TupleTableSlot *slot)
106 if (unlikely(TTS_SHOULDFREE(slot)))
108 VirtualTupleTableSlot *vslot = (VirtualTupleTableSlot *) slot;
113 slot->tts_flags = ~TTS_FLAG_SHOULDFREE;
116 slot->tts_nvalid = 0;
117 slot->tts_flags |= TTS_FLAG_EMPTY;
121 * Attribute values are readily available in tts_values and tts_isnull array
122 * in a VirtualTupleTableSlot. So there should be no need to call either of the
123 * following two functions.
126 tts_virtual_getsomeattrs(TupleTableSlot *slot, int natts)
128 elog(ERROR, "getsomeattrs is not required to be called on a virtual tuple table slot");
132 tts_virtual_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
134 elog(ERROR, "virtual tuple table slot does not have system atttributes");
136 return 0; /* silence compiler warnings */
140 * To materialize a virtual slot all the datums that aren't passed by value
141 * have to be copied into the slot's memory context. To do so, compute the
142 * required size, and allocate enough memory to store all attributes. That's
143 * good for cache hit ratio, but more importantly requires only memory
144 * allocation/deallocation.
147 tts_virtual_materialize(TupleTableSlot *slot)
149 VirtualTupleTableSlot *vslot = (VirtualTupleTableSlot *) slot;
150 TupleDesc desc = slot->tts_tupleDescriptor;
154 /* already materialized */
155 if (TTS_SHOULDFREE(slot))
158 /* compute size of memory required */
159 for (int natt = 0; natt < desc->natts; natt++)
161 Form_pg_attribute att = TupleDescAttr(desc, natt);
164 if (att->attbyval || slot->tts_isnull[natt])
167 val = slot->tts_values[natt];
169 if (att->attlen == -1 &&
170 VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(val)))
173 * We want to flatten the expanded value so that the materialized
174 * slot doesn't depend on it.
176 sz = att_align_nominal(sz, att->attalign);
177 sz += EOH_get_flat_size(DatumGetEOHP(val));
181 sz = att_align_nominal(sz, att->attalign);
182 sz = att_addlength_datum(sz, att->attlen, val);
186 /* all data is byval */
190 /* allocate memory */
191 vslot->data = data = MemoryContextAlloc(slot->tts_mcxt, sz);
192 slot->tts_flags |= TTS_FLAG_SHOULDFREE;
194 /* and copy all attributes into the pre-allocated space */
195 for (int natt = 0; natt < desc->natts; natt++)
197 Form_pg_attribute att = TupleDescAttr(desc, natt);
200 if (att->attbyval || slot->tts_isnull[natt])
203 val = slot->tts_values[natt];
205 if (att->attlen == -1 &&
206 VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(val)))
211 * We want to flatten the expanded value so that the materialized
212 * slot doesn't depend on it.
214 ExpandedObjectHeader *eoh = DatumGetEOHP(val);
216 data = (char *) att_align_nominal(data,
218 data_length = EOH_get_flat_size(eoh);
219 EOH_flatten_into(eoh, data, data_length);
221 slot->tts_values[natt] = PointerGetDatum(data);
226 Size data_length = 0;
228 data = (char *) att_align_nominal(data, att->attalign);
229 data_length = att_addlength_datum(data_length, att->attlen, val);
231 memcpy(data, DatumGetPointer(val), data_length);
233 slot->tts_values[natt] = PointerGetDatum(data);
240 tts_virtual_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
242 TupleDesc srcdesc = dstslot->tts_tupleDescriptor;
244 Assert(srcdesc->natts <= dstslot->tts_tupleDescriptor->natts);
246 tts_virtual_clear(dstslot);
248 slot_getallattrs(srcslot);
250 for (int natt = 0; natt < srcdesc->natts; natt++)
252 dstslot->tts_values[natt] = srcslot->tts_values[natt];
253 dstslot->tts_isnull[natt] = srcslot->tts_isnull[natt];
256 dstslot->tts_nvalid = srcdesc->natts;
257 dstslot->tts_flags &= ~TTS_FLAG_EMPTY;
259 /* make sure storage doesn't depend on external memory */
260 tts_virtual_materialize(dstslot);
264 tts_virtual_copy_heap_tuple(TupleTableSlot *slot)
266 Assert(!TTS_EMPTY(slot));
268 return heap_form_tuple(slot->tts_tupleDescriptor,
275 tts_virtual_copy_minimal_tuple(TupleTableSlot *slot)
277 Assert(!TTS_EMPTY(slot));
279 return heap_form_minimal_tuple(slot->tts_tupleDescriptor,
286 * TupleTableSlotOps implementation for HeapTupleTableSlot.
290 tts_heap_init(TupleTableSlot *slot)
295 tts_heap_release(TupleTableSlot *slot)
300 tts_heap_clear(TupleTableSlot *slot)
302 HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
304 /* Free the memory for the heap tuple if it's allowed. */
305 if (TTS_SHOULDFREE(slot))
307 heap_freetuple(hslot->tuple);
308 slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
311 slot->tts_nvalid = 0;
312 slot->tts_flags |= TTS_FLAG_EMPTY;
318 tts_heap_getsomeattrs(TupleTableSlot *slot, int natts)
320 HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
322 Assert(!TTS_EMPTY(slot));
324 slot_deform_heap_tuple(slot, hslot->tuple, &hslot->off, natts);
328 tts_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
330 HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
332 return heap_getsysattr(hslot->tuple, attnum,
333 slot->tts_tupleDescriptor, isnull);
337 tts_heap_materialize(TupleTableSlot *slot)
339 HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
340 MemoryContext oldContext;
342 Assert(!TTS_EMPTY(slot));
344 /* This slot has it's tuple already materialized. Nothing to do. */
345 if (TTS_SHOULDFREE(slot))
348 slot->tts_flags |= TTS_FLAG_SHOULDFREE;
350 oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
353 hslot->tuple = heap_form_tuple(slot->tts_tupleDescriptor,
359 * The tuple contained in this slot is not allocated in the memory
360 * context of the given slot (else it would have TTS_SHOULDFREE set).
361 * Copy the tuple into the given slot's memory context.
363 hslot->tuple = heap_copytuple(hslot->tuple);
367 * Have to deform from scratch, otherwise tts_values[] entries could point
368 * into the non-materialized tuple (which might be gone when accessed).
370 slot->tts_nvalid = 0;
373 MemoryContextSwitchTo(oldContext);
377 tts_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
380 MemoryContext oldcontext;
382 oldcontext = MemoryContextSwitchTo(dstslot->tts_mcxt);
383 tuple = ExecCopySlotHeapTuple(srcslot);
384 MemoryContextSwitchTo(oldcontext);
386 ExecStoreHeapTuple(tuple, dstslot, true);
390 tts_heap_get_heap_tuple(TupleTableSlot *slot)
392 HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
394 Assert(!TTS_EMPTY(slot));
396 tts_heap_materialize(slot);
402 tts_heap_copy_heap_tuple(TupleTableSlot *slot)
404 HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
406 Assert(!TTS_EMPTY(slot));
408 tts_heap_materialize(slot);
410 return heap_copytuple(hslot->tuple);
414 tts_heap_copy_minimal_tuple(TupleTableSlot *slot)
416 HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
419 tts_heap_materialize(slot);
421 return minimal_tuple_from_heap_tuple(hslot->tuple);
425 tts_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, bool shouldFree)
427 HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
429 tts_heap_clear(slot);
431 slot->tts_nvalid = 0;
432 hslot->tuple = tuple;
434 slot->tts_flags &= ~TTS_FLAG_EMPTY;
437 slot->tts_flags |= TTS_FLAG_SHOULDFREE;
442 * TupleTableSlotOps implementation for MinimalTupleTableSlot.
446 tts_minimal_init(TupleTableSlot *slot)
448 MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
451 * Initialize the heap tuple pointer to access attributes of the minimal
452 * tuple contained in the slot as if its a heap tuple.
454 mslot->tuple = &mslot->minhdr;
458 tts_minimal_release(TupleTableSlot *slot)
463 tts_minimal_clear(TupleTableSlot *slot)
465 MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
467 if (TTS_SHOULDFREE(slot))
469 heap_free_minimal_tuple(mslot->mintuple);
470 slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
473 slot->tts_nvalid = 0;
474 slot->tts_flags |= TTS_FLAG_EMPTY;
476 mslot->mintuple = NULL;
480 tts_minimal_getsomeattrs(TupleTableSlot *slot, int natts)
482 MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
484 Assert(!TTS_EMPTY(slot));
486 slot_deform_heap_tuple(slot, mslot->tuple, &mslot->off, natts);
490 tts_minimal_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
492 elog(ERROR, "minimal tuple table slot does not have system atttributes");
494 return 0; /* silence compiler warnings */
498 tts_minimal_materialize(TupleTableSlot *slot)
500 MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
501 MemoryContext oldContext;
503 Assert(!TTS_EMPTY(slot));
505 /* This slot has it's tuple already materialized. Nothing to do. */
506 if (TTS_SHOULDFREE(slot))
509 slot->tts_flags |= TTS_FLAG_SHOULDFREE;
510 oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
512 if (!mslot->mintuple)
514 mslot->mintuple = heap_form_minimal_tuple(slot->tts_tupleDescriptor,
521 * The minimal tuple contained in this slot is not allocated in the
522 * memory context of the given slot (else it would have TTS_SHOULDFREE
523 * set). Copy the minimal tuple into the given slot's memory context.
525 mslot->mintuple = heap_copy_minimal_tuple(mslot->mintuple);
528 Assert(mslot->tuple == &mslot->minhdr);
530 mslot->minhdr.t_len = mslot->mintuple->t_len + MINIMAL_TUPLE_OFFSET;
531 mslot->minhdr.t_data = (HeapTupleHeader) ((char *) mslot->mintuple - MINIMAL_TUPLE_OFFSET);
533 MemoryContextSwitchTo(oldContext);
536 * Have to deform from scratch, otherwise tts_values[] entries could point
537 * into the non-materialized tuple (which might be gone when accessed).
539 slot->tts_nvalid = 0;
544 tts_minimal_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
546 MemoryContext oldcontext;
547 MinimalTuple mintuple;
549 oldcontext = MemoryContextSwitchTo(dstslot->tts_mcxt);
550 mintuple = ExecCopySlotMinimalTuple(srcslot);
551 MemoryContextSwitchTo(oldcontext);
553 ExecStoreMinimalTuple(mintuple, dstslot, true);
557 tts_minimal_get_minimal_tuple(TupleTableSlot *slot)
559 MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
561 if (!mslot->mintuple)
562 tts_minimal_materialize(slot);
564 return mslot->mintuple;
568 tts_minimal_copy_heap_tuple(TupleTableSlot *slot)
570 MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
572 if (!mslot->mintuple)
573 tts_minimal_materialize(slot);
575 return heap_tuple_from_minimal_tuple(mslot->mintuple);
579 tts_minimal_copy_minimal_tuple(TupleTableSlot *slot)
581 MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
583 if (!mslot->mintuple)
584 tts_minimal_materialize(slot);
586 return heap_copy_minimal_tuple(mslot->mintuple);
590 tts_minimal_store_tuple(TupleTableSlot *slot, MinimalTuple mtup, bool shouldFree)
592 MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
594 tts_minimal_clear(slot);
596 Assert(!TTS_SHOULDFREE(slot));
597 Assert(TTS_EMPTY(slot));
599 slot->tts_flags &= ~TTS_FLAG_EMPTY;
600 slot->tts_nvalid = 0;
603 mslot->mintuple = mtup;
604 Assert(mslot->tuple == &mslot->minhdr);
605 mslot->minhdr.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
606 mslot->minhdr.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);
607 /* no need to set t_self or t_tableOid since we won't allow access */
610 slot->tts_flags |= TTS_FLAG_SHOULDFREE;
612 Assert(!TTS_SHOULDFREE(slot));
617 * TupleTableSlotOps implementation for BufferHeapTupleTableSlot.
621 tts_buffer_heap_init(TupleTableSlot *slot)
626 tts_buffer_heap_release(TupleTableSlot *slot)
631 tts_buffer_heap_clear(TupleTableSlot *slot)
633 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
636 * Free the memory for heap tuple if allowed. A tuple coming from buffer
637 * can never be freed. But we may have materialized a tuple from buffer.
638 * Such a tuple can be freed.
640 if (TTS_SHOULDFREE(slot))
642 /* We should have unpinned the buffer while materializing the tuple. */
643 Assert(!BufferIsValid(bslot->buffer));
645 heap_freetuple(bslot->base.tuple);
646 slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
648 Assert(!BufferIsValid(bslot->buffer));
651 if (BufferIsValid(bslot->buffer))
652 ReleaseBuffer(bslot->buffer);
654 slot->tts_nvalid = 0;
655 slot->tts_flags |= TTS_FLAG_EMPTY;
656 bslot->base.tuple = NULL;
658 bslot->buffer = InvalidBuffer;
662 tts_buffer_heap_getsomeattrs(TupleTableSlot *slot, int natts)
664 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
666 Assert(!TTS_EMPTY(slot));
668 slot_deform_heap_tuple(slot, bslot->base.tuple, &bslot->base.off, natts);
672 tts_buffer_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
674 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
676 return heap_getsysattr(bslot->base.tuple, attnum,
677 slot->tts_tupleDescriptor, isnull);
681 tts_buffer_heap_materialize(TupleTableSlot *slot)
683 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
684 MemoryContext oldContext;
686 Assert(!TTS_EMPTY(slot));
688 /* If already materialized nothing to do. */
689 if (TTS_SHOULDFREE(slot))
692 slot->tts_flags |= TTS_FLAG_SHOULDFREE;
695 * A heap tuple stored in a BufferHeapTupleTableSlot should have a buffer
696 * associated with it, unless it's materialized (which would've returned
699 Assert(bslot->base.tuple);
701 oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
702 bslot->base.tuple = heap_copytuple(bslot->base.tuple);
703 MemoryContextSwitchTo(oldContext);
706 * A heap tuple stored in a BufferHeapTupleTableSlot should have a buffer
707 * associated with it, unless it's materialized.
709 Assert(BufferIsValid(bslot->buffer));
710 if (likely(BufferIsValid(bslot->buffer)))
711 ReleaseBuffer(bslot->buffer);
712 bslot->buffer = InvalidBuffer;
715 * Have to deform from scratch, otherwise tts_values[] entries could point
716 * into the non-materialized tuple (which might be gone when accessed).
719 slot->tts_nvalid = 0;
723 tts_buffer_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
725 BufferHeapTupleTableSlot *bsrcslot = (BufferHeapTupleTableSlot *) srcslot;
726 BufferHeapTupleTableSlot *bdstslot = (BufferHeapTupleTableSlot *) dstslot;
729 * If the source slot is of a different kind, or is a buffer slot that has
730 * been materialized, make a new copy of the tuple.
732 if (dstslot->tts_ops != srcslot->tts_ops ||
733 TTS_SHOULDFREE(srcslot))
735 MemoryContext oldContext;
737 ExecClearTuple(dstslot);
738 dstslot->tts_flags |= TTS_FLAG_SHOULDFREE;
739 dstslot->tts_flags &= ~TTS_FLAG_EMPTY;
740 oldContext = MemoryContextSwitchTo(dstslot->tts_mcxt);
741 bdstslot->base.tuple = ExecCopySlotHeapTuple(srcslot);
742 MemoryContextSwitchTo(oldContext);
746 tts_buffer_heap_store_tuple(dstslot, bsrcslot->base.tuple, bsrcslot->buffer);
748 * Need to materialize because the HeapTupleData portion of the tuple
749 * might be in a foreign memory context. That's annoying, but until
750 * that's moved into the slot, unavoidable.
752 tts_buffer_heap_materialize(dstslot);
757 tts_buffer_heap_get_heap_tuple(TupleTableSlot *slot)
759 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
761 Assert(!TTS_EMPTY(slot));
763 if (!bslot->base.tuple)
764 tts_buffer_heap_materialize(slot);
766 return bslot->base.tuple;
770 tts_buffer_heap_copy_heap_tuple(TupleTableSlot *slot)
772 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
774 Assert(!TTS_EMPTY(slot));
776 if (!bslot->base.tuple)
777 tts_buffer_heap_materialize(slot);
779 return heap_copytuple(bslot->base.tuple);
783 tts_buffer_heap_copy_minimal_tuple(TupleTableSlot *slot)
785 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
787 Assert(!TTS_EMPTY(slot));
789 if (!bslot->base.tuple)
790 tts_buffer_heap_materialize(slot);
792 return minimal_tuple_from_heap_tuple(bslot->base.tuple);
796 tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, Buffer buffer)
798 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
800 if (TTS_SHOULDFREE(slot))
802 /* materialized slot shouldn't have a buffer to release */
803 Assert(!BufferIsValid(bslot->buffer));
805 heap_freetuple(bslot->base.tuple);
806 slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
809 slot->tts_flags &= ~TTS_FLAG_EMPTY;
810 slot->tts_nvalid = 0;
811 bslot->base.tuple = tuple;
815 * If tuple is on a disk page, keep the page pinned as long as we hold a
816 * pointer into it. We assume the caller already has such a pin.
818 * This is coded to optimize the case where the slot previously held a
819 * tuple on the same disk page: in that case releasing and re-acquiring
820 * the pin is a waste of cycles. This is a common situation during
821 * seqscans, so it's worth troubling over.
823 if (bslot->buffer != buffer)
825 if (BufferIsValid(bslot->buffer))
826 ReleaseBuffer(bslot->buffer);
827 bslot->buffer = buffer;
828 IncrBufferRefCount(buffer);
833 * slot_deform_heap_tuple
834 * Given a TupleTableSlot, extract data from the slot's physical tuple
835 * into its Datum/isnull arrays. Data is extracted up through the
836 * natts'th column (caller must ensure this is a legal column number).
838 * This is essentially an incremental version of heap_deform_tuple:
839 * on each call we extract attributes up to the one needed, without
840 * re-computing information about previously extracted attributes.
841 * slot->tts_nvalid is the number of attributes already extracted.
843 * This is marked as always inline, so the different offp for different types
844 * of slots gets optimized away.
846 static pg_attribute_always_inline void
847 slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
850 TupleDesc tupleDesc = slot->tts_tupleDescriptor;
851 Datum *values = slot->tts_values;
852 bool *isnull = slot->tts_isnull;
853 HeapTupleHeader tup = tuple->t_data;
854 bool hasnulls = HeapTupleHasNulls(tuple);
856 char *tp; /* ptr to tuple data */
857 uint32 off; /* offset in tuple data */
858 bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
859 bool slow; /* can we use/set attcacheoff? */
861 /* We can only fetch as many attributes as the tuple has. */
862 natts = Min(HeapTupleHeaderGetNatts(tuple->t_data), natts);
865 * Check whether the first call for this tuple, and initialize or restore
868 attnum = slot->tts_nvalid;
871 /* Start from the first attribute */
877 /* Restore state from previous execution */
879 slow = TTS_SLOW(slot);
882 tp = (char *) tup + tup->t_hoff;
884 for (; attnum < natts; attnum++)
886 Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum);
888 if (hasnulls && att_isnull(attnum, bp))
890 values[attnum] = (Datum) 0;
891 isnull[attnum] = true;
892 slow = true; /* can't use attcacheoff anymore */
896 isnull[attnum] = false;
898 if (!slow && thisatt->attcacheoff >= 0)
899 off = thisatt->attcacheoff;
900 else if (thisatt->attlen == -1)
903 * We can only cache the offset for a varlena attribute if the
904 * offset is already suitably aligned, so that there would be no
905 * pad bytes in any case: then the offset will be valid for either
906 * an aligned or unaligned value.
909 off == att_align_nominal(off, thisatt->attalign))
910 thisatt->attcacheoff = off;
913 off = att_align_pointer(off, thisatt->attalign, -1,
920 /* not varlena, so safe to use att_align_nominal */
921 off = att_align_nominal(off, thisatt->attalign);
924 thisatt->attcacheoff = off;
927 values[attnum] = fetchatt(thisatt, tp + off);
929 off = att_addlength_pointer(off, thisatt->attlen, tp + off);
931 if (thisatt->attlen <= 0)
932 slow = true; /* can't use attcacheoff anymore */
936 * Save state for next execution
938 slot->tts_nvalid = attnum;
941 slot->tts_flags |= TTS_FLAG_SLOW;
943 slot->tts_flags &= ~TTS_FLAG_SLOW;
947 const TupleTableSlotOps TTSOpsVirtual = {
948 .base_slot_size = sizeof(VirtualTupleTableSlot),
949 .init = tts_virtual_init,
950 .release = tts_virtual_release,
951 .clear = tts_virtual_clear,
952 .getsomeattrs = tts_virtual_getsomeattrs,
953 .getsysattr = tts_virtual_getsysattr,
954 .materialize = tts_virtual_materialize,
955 .copyslot = tts_virtual_copyslot,
958 * A virtual tuple table slot can not "own" a heap tuple or a minimal
961 .get_heap_tuple = NULL,
962 .get_minimal_tuple = NULL,
963 .copy_heap_tuple = tts_virtual_copy_heap_tuple,
964 .copy_minimal_tuple = tts_virtual_copy_minimal_tuple
967 const TupleTableSlotOps TTSOpsHeapTuple = {
968 .base_slot_size = sizeof(HeapTupleTableSlot),
969 .init = tts_heap_init,
970 .release = tts_heap_release,
971 .clear = tts_heap_clear,
972 .getsomeattrs = tts_heap_getsomeattrs,
973 .getsysattr = tts_heap_getsysattr,
974 .materialize = tts_heap_materialize,
975 .copyslot = tts_heap_copyslot,
976 .get_heap_tuple = tts_heap_get_heap_tuple,
978 /* A heap tuple table slot can not "own" a minimal tuple. */
979 .get_minimal_tuple = NULL,
980 .copy_heap_tuple = tts_heap_copy_heap_tuple,
981 .copy_minimal_tuple = tts_heap_copy_minimal_tuple
984 const TupleTableSlotOps TTSOpsMinimalTuple = {
985 .base_slot_size = sizeof(MinimalTupleTableSlot),
986 .init = tts_minimal_init,
987 .release = tts_minimal_release,
988 .clear = tts_minimal_clear,
989 .getsomeattrs = tts_minimal_getsomeattrs,
990 .getsysattr = tts_minimal_getsysattr,
991 .materialize = tts_minimal_materialize,
992 .copyslot = tts_minimal_copyslot,
994 /* A minimal tuple table slot can not "own" a heap tuple. */
995 .get_heap_tuple = NULL,
996 .get_minimal_tuple = tts_minimal_get_minimal_tuple,
997 .copy_heap_tuple = tts_minimal_copy_heap_tuple,
998 .copy_minimal_tuple = tts_minimal_copy_minimal_tuple
1001 const TupleTableSlotOps TTSOpsBufferHeapTuple = {
1002 .base_slot_size = sizeof(BufferHeapTupleTableSlot),
1003 .init = tts_buffer_heap_init,
1004 .release = tts_buffer_heap_release,
1005 .clear = tts_buffer_heap_clear,
1006 .getsomeattrs = tts_buffer_heap_getsomeattrs,
1007 .getsysattr = tts_buffer_heap_getsysattr,
1008 .materialize = tts_buffer_heap_materialize,
1009 .copyslot = tts_buffer_heap_copyslot,
1010 .get_heap_tuple = tts_buffer_heap_get_heap_tuple,
1012 /* A buffer heap tuple table slot can not "own" a minimal tuple. */
1013 .get_minimal_tuple = NULL,
1014 .copy_heap_tuple = tts_buffer_heap_copy_heap_tuple,
1015 .copy_minimal_tuple = tts_buffer_heap_copy_minimal_tuple
1019 /* ----------------------------------------------------------------
1020 * tuple table create/delete functions
1021 * ----------------------------------------------------------------
1024 /* --------------------------------
1025 * MakeTupleTableSlot
1027 * Basic routine to make an empty TupleTableSlot of given
1028 * TupleTableSlotType. If tupleDesc is specified the slot's descriptor is
1029 * fixed for it's lifetime, gaining some efficiency. If that's
1030 * undesirable, pass NULL.
1031 * --------------------------------
1034 MakeTupleTableSlot(TupleDesc tupleDesc,
1035 const TupleTableSlotOps *tts_ops)
1037 Size basesz, allocsz;
1038 TupleTableSlot *slot;
1039 basesz = tts_ops->base_slot_size;
1042 * When a fixed descriptor is specified, we can reduce overhead by
1043 * allocating the entire slot in one go.
1046 allocsz = MAXALIGN(basesz) +
1047 MAXALIGN(tupleDesc->natts * sizeof(Datum)) +
1048 MAXALIGN(tupleDesc->natts * sizeof(bool));
1052 slot = palloc0(allocsz);
1053 /* const for optimization purposes, OK to modify at allocation time */
1054 *((const TupleTableSlotOps **) &slot->tts_ops) = tts_ops;
1055 slot->type = T_TupleTableSlot;
1056 slot->tts_flags |= TTS_FLAG_EMPTY;
1057 if (tupleDesc != NULL)
1058 slot->tts_flags |= TTS_FLAG_FIXED;
1059 slot->tts_tupleDescriptor = tupleDesc;
1060 slot->tts_mcxt = CurrentMemoryContext;
1061 slot->tts_nvalid = 0;
1063 if (tupleDesc != NULL)
1065 slot->tts_values = (Datum *)
1067 + MAXALIGN(basesz));
1068 slot->tts_isnull = (bool *)
1071 + MAXALIGN(tupleDesc->natts * sizeof(Datum)));
1073 PinTupleDesc(tupleDesc);
1077 * And allow slot type specific initialization.
1079 slot->tts_ops->init(slot);
1084 /* --------------------------------
1085 * ExecAllocTableSlot
1087 * Create a tuple table slot within a tuple table (which is just a List).
1088 * --------------------------------
1091 ExecAllocTableSlot(List **tupleTable, TupleDesc desc,
1092 const TupleTableSlotOps *tts_ops)
1094 TupleTableSlot *slot = MakeTupleTableSlot(desc, tts_ops);
1096 *tupleTable = lappend(*tupleTable, slot);
1101 /* --------------------------------
1102 * ExecResetTupleTable
1104 * This releases any resources (buffer pins, tupdesc refcounts)
1105 * held by the tuple table, and optionally releases the memory
1106 * occupied by the tuple table data structure.
1107 * It is expected that this routine be called by EndPlan().
1108 * --------------------------------
1111 ExecResetTupleTable(List *tupleTable, /* tuple table */
1112 bool shouldFree) /* true if we should free memory */
1116 foreach(lc, tupleTable)
1118 TupleTableSlot *slot = lfirst_node(TupleTableSlot, lc);
1120 /* Always release resources and reset the slot to empty */
1121 ExecClearTuple(slot);
1122 slot->tts_ops->release(slot);
1123 if (slot->tts_tupleDescriptor)
1125 ReleaseTupleDesc(slot->tts_tupleDescriptor);
1126 slot->tts_tupleDescriptor = NULL;
1129 /* If shouldFree, release memory occupied by the slot itself */
1132 if (!TTS_FIXED(slot))
1134 if (slot->tts_values)
1135 pfree(slot->tts_values);
1136 if (slot->tts_isnull)
1137 pfree(slot->tts_isnull);
1143 /* If shouldFree, release the list structure */
1145 list_free(tupleTable);
1148 /* --------------------------------
1149 * MakeSingleTupleTableSlot
1151 * This is a convenience routine for operations that need a standalone
1152 * TupleTableSlot not gotten from the main executor tuple table. It makes
1153 * a single slot of given TupleTableSlotType and initializes it to use the
1154 * given tuple descriptor.
1155 * --------------------------------
1158 MakeSingleTupleTableSlot(TupleDesc tupdesc,
1159 const TupleTableSlotOps *tts_ops)
1161 TupleTableSlot *slot = MakeTupleTableSlot(tupdesc, tts_ops);
1166 /* --------------------------------
1167 * ExecDropSingleTupleTableSlot
1169 * Release a TupleTableSlot made with MakeSingleTupleTableSlot.
1170 * DON'T use this on a slot that's part of a tuple table list!
1171 * --------------------------------
1174 ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
1176 /* This should match ExecResetTupleTable's processing of one slot */
1177 Assert(IsA(slot, TupleTableSlot));
1178 ExecClearTuple(slot);
1179 slot->tts_ops->release(slot);
1180 if (slot->tts_tupleDescriptor)
1181 ReleaseTupleDesc(slot->tts_tupleDescriptor);
1182 if (!TTS_FIXED(slot))
1184 if (slot->tts_values)
1185 pfree(slot->tts_values);
1186 if (slot->tts_isnull)
1187 pfree(slot->tts_isnull);
1193 /* ----------------------------------------------------------------
1194 * tuple table slot accessor functions
1195 * ----------------------------------------------------------------
1198 /* --------------------------------
1199 * ExecSetSlotDescriptor
1201 * This function is used to set the tuple descriptor associated
1202 * with the slot's tuple. The passed descriptor must have lifespan
1203 * at least equal to the slot's. If it is a reference-counted descriptor
1204 * then the reference count is incremented for as long as the slot holds
1206 * --------------------------------
1209 ExecSetSlotDescriptor(TupleTableSlot *slot, /* slot to change */
1210 TupleDesc tupdesc) /* new tuple descriptor */
1212 Assert(!TTS_FIXED(slot));
1214 /* For safety, make sure slot is empty before changing it */
1215 ExecClearTuple(slot);
1218 * Release any old descriptor. Also release old Datum/isnull arrays if
1219 * present (we don't bother to check if they could be re-used).
1221 if (slot->tts_tupleDescriptor)
1222 ReleaseTupleDesc(slot->tts_tupleDescriptor);
1224 if (slot->tts_values)
1225 pfree(slot->tts_values);
1226 if (slot->tts_isnull)
1227 pfree(slot->tts_isnull);
1230 * Install the new descriptor; if it's refcounted, bump its refcount.
1232 slot->tts_tupleDescriptor = tupdesc;
1233 PinTupleDesc(tupdesc);
1236 * Allocate Datum/isnull arrays of the appropriate size. These must have
1237 * the same lifetime as the slot, so allocate in the slot's own context.
1239 slot->tts_values = (Datum *)
1240 MemoryContextAlloc(slot->tts_mcxt, tupdesc->natts * sizeof(Datum));
1241 slot->tts_isnull = (bool *)
1242 MemoryContextAlloc(slot->tts_mcxt, tupdesc->natts * sizeof(bool));
1245 /* --------------------------------
1246 * ExecStoreHeapTuple
1248 * This function is used to store an on-the-fly physical tuple into a specified
1249 * slot in the tuple table.
1251 * tuple: tuple to store
1252 * slot: TTSOpsHeapTuple type slot to store it in
1253 * shouldFree: true if ExecClearTuple should pfree() the tuple
1256 * shouldFree is normally set 'true' for tuples constructed on-the-fly. But it
1257 * can be 'false' when the referenced tuple is held in a tuple table slot
1258 * belonging to a lower-level executor Proc node. In this case the lower-level
1259 * slot retains ownership and responsibility for eventually releasing the
1260 * tuple. When this method is used, we must be certain that the upper-level
1261 * Proc node will lose interest in the tuple sooner than the lower-level one
1262 * does! If you're not certain, copy the lower-level tuple with heap_copytuple
1263 * and let the upper-level table slot assume ownership of the copy!
1265 * Return value is just the passed-in slot pointer.
1267 * If the target slot is not guaranteed to be TTSOpsHeapTuple type slot, use
1268 * the, more expensive, ExecForceStoreHeapTuple().
1269 * --------------------------------
1272 ExecStoreHeapTuple(HeapTuple tuple,
1273 TupleTableSlot *slot,
1279 Assert(tuple != NULL);
1280 Assert(slot != NULL);
1281 Assert(slot->tts_tupleDescriptor != NULL);
1283 if (unlikely(!TTS_IS_HEAPTUPLE(slot)))
1284 elog(ERROR, "trying to store a heap tuple into wrong type of slot");
1285 tts_heap_store_tuple(slot, tuple, shouldFree);
1290 /* --------------------------------
1291 * ExecStoreBufferHeapTuple
1293 * This function is used to store an on-disk physical tuple from a buffer
1294 * into a specified slot in the tuple table.
1296 * tuple: tuple to store
1297 * slot: TTSOpsBufferHeapTuple type slot to store it in
1298 * buffer: disk buffer if tuple is in a disk page, else InvalidBuffer
1300 * The tuple table code acquires a pin on the buffer which is held until the
1301 * slot is cleared, so that the tuple won't go away on us.
1303 * Return value is just the passed-in slot pointer.
1305 * If the target slot is not guaranteed to be TTSOpsBufferHeapTuple type slot,
1306 * use the, more expensive, ExecForceStoreHeapTuple().
1307 * --------------------------------
1310 ExecStoreBufferHeapTuple(HeapTuple tuple,
1311 TupleTableSlot *slot,
1317 Assert(tuple != NULL);
1318 Assert(slot != NULL);
1319 Assert(slot->tts_tupleDescriptor != NULL);
1320 Assert(BufferIsValid(buffer));
1322 if (unlikely(!TTS_IS_BUFFERTUPLE(slot)))
1323 elog(ERROR, "trying to store an on-disk heap tuple into wrong type of slot");
1324 tts_buffer_heap_store_tuple(slot, tuple, buffer);
1330 * Store a minimal tuple into TTSOpsMinimalTuple type slot.
1332 * If the target slot is not guaranteed to be TTSOpsMinimalTuple type slot,
1333 * use the, more expensive, ExecForceStoreMinimalTuple().
1336 ExecStoreMinimalTuple(MinimalTuple mtup,
1337 TupleTableSlot *slot,
1343 Assert(mtup != NULL);
1344 Assert(slot != NULL);
1345 Assert(slot->tts_tupleDescriptor != NULL);
1347 if (unlikely(!TTS_IS_MINIMALTUPLE(slot)))
1348 elog(ERROR, "trying to store a minimal tuple into wrong type of slot");
1349 tts_minimal_store_tuple(slot, mtup, shouldFree);
1355 * Store a HeapTuple into any kind of slot, performing conversion if
1359 ExecForceStoreHeapTuple(HeapTuple tuple,
1360 TupleTableSlot *slot)
1362 if (TTS_IS_HEAPTUPLE(slot))
1364 ExecStoreHeapTuple(tuple, slot, false);
1366 else if (TTS_IS_BUFFERTUPLE(slot))
1368 MemoryContext oldContext;
1369 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
1371 ExecClearTuple(slot);
1372 slot->tts_flags |= TTS_FLAG_SHOULDFREE;
1373 slot->tts_flags &= ~TTS_FLAG_EMPTY;
1374 oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
1375 bslot->base.tuple = heap_copytuple(tuple);
1376 MemoryContextSwitchTo(oldContext);
1380 ExecClearTuple(slot);
1381 heap_deform_tuple(tuple, slot->tts_tupleDescriptor,
1382 slot->tts_values, slot->tts_isnull);
1383 ExecStoreVirtualTuple(slot);
1388 * Store a MinimalTuple into any kind of slot, performing conversion if
1392 ExecForceStoreMinimalTuple(MinimalTuple mtup,
1393 TupleTableSlot *slot,
1396 if (TTS_IS_MINIMALTUPLE(slot))
1398 tts_minimal_store_tuple(slot, mtup, shouldFree);
1404 ExecClearTuple(slot);
1406 htup.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
1407 htup.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);
1408 heap_deform_tuple(&htup, slot->tts_tupleDescriptor,
1409 slot->tts_values, slot->tts_isnull);
1410 ExecStoreVirtualTuple(slot);
1414 /* --------------------------------
1415 * ExecStoreVirtualTuple
1416 * Mark a slot as containing a virtual tuple.
1418 * The protocol for loading a slot with virtual tuple data is:
1419 * * Call ExecClearTuple to mark the slot empty.
1420 * * Store data into the Datum/isnull arrays.
1421 * * Call ExecStoreVirtualTuple to mark the slot valid.
1422 * This is a bit unclean but it avoids one round of data copying.
1423 * --------------------------------
1426 ExecStoreVirtualTuple(TupleTableSlot *slot)
1431 Assert(slot != NULL);
1432 Assert(slot->tts_tupleDescriptor != NULL);
1433 Assert(TTS_EMPTY(slot));
1435 slot->tts_flags &= ~TTS_FLAG_EMPTY;
1436 slot->tts_nvalid = slot->tts_tupleDescriptor->natts;
1441 /* --------------------------------
1442 * ExecStoreAllNullTuple
1443 * Set up the slot to contain a null in every column.
1445 * At first glance this might sound just like ExecClearTuple, but it's
1446 * entirely different: the slot ends up full, not empty.
1447 * --------------------------------
1450 ExecStoreAllNullTuple(TupleTableSlot *slot)
1455 Assert(slot != NULL);
1456 Assert(slot->tts_tupleDescriptor != NULL);
1458 /* Clear any old contents */
1459 ExecClearTuple(slot);
1462 * Fill all the columns of the virtual tuple with nulls
1464 MemSet(slot->tts_values, 0,
1465 slot->tts_tupleDescriptor->natts * sizeof(Datum));
1466 memset(slot->tts_isnull, true,
1467 slot->tts_tupleDescriptor->natts * sizeof(bool));
1469 return ExecStoreVirtualTuple(slot);
1473 * ExecFetchSlotHeapTuple - fetch HeapTuple representing the slot's content
1475 * The returned HeapTuple represents the slot's content as closely as
1478 * If materialize is true, the contents of the slots will be made independent
1479 * from the underlying storage (i.e. all buffer pins are released, memory is
1480 * allocated in the slot's context).
1482 * If shouldFree is not-NULL it'll be set to true if the returned tuple has
1483 * been allocated in the calling memory context, and must be freed by the
1484 * caller (via explicit pfree() or a memory context reset).
1486 * NB: If materialize is true, modifications of the returned tuple are
1487 * allowed. But it depends on the type of the slot whether such modifications
1488 * will also affect the slot's contents. While that is not the nicest
1489 * behaviour, all such modifcations are in the process of being removed.
1492 ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
1497 Assert(slot != NULL);
1498 Assert(!TTS_EMPTY(slot));
1500 /* Materialize the tuple so that the slot "owns" it, if requested. */
1502 slot->tts_ops->materialize(slot);
1504 if (slot->tts_ops->get_heap_tuple == NULL)
1508 return slot->tts_ops->copy_heap_tuple(slot);
1513 *shouldFree = false;
1514 return slot->tts_ops->get_heap_tuple(slot);
1518 /* --------------------------------
1519 * ExecFetchSlotMinimalTuple
1520 * Fetch the slot's minimal physical tuple.
1522 * If the given tuple table slot can hold a minimal tuple, indicated by a
1523 * non-NULL get_minimal_tuple callback, the function returns the minimal
1524 * tuple returned by that callback. It assumes that the minimal tuple
1525 * returned by the callback is "owned" by the slot i.e. the slot is
1526 * responsible for freeing the memory consumed by the tuple. Hence it sets
1527 * *shouldFree to false, indicating that the caller should not free the
1528 * memory consumed by the minimal tuple. In this case the returned minimal
1529 * tuple should be considered as read-only.
1531 * If that callback is not supported, it calls copy_minimal_tuple callback
1532 * which is expected to return a copy of minimal tuple represnting the
1533 * contents of the slot. In this case *shouldFree is set to true,
1534 * indicating the caller that it should free the memory consumed by the
1535 * minimal tuple. In this case the returned minimal tuple may be written
1537 * --------------------------------
1540 ExecFetchSlotMinimalTuple(TupleTableSlot *slot,
1546 Assert(slot != NULL);
1547 Assert(!TTS_EMPTY(slot));
1549 if (slot->tts_ops->get_minimal_tuple)
1552 *shouldFree = false;
1553 return slot->tts_ops->get_minimal_tuple(slot);
1559 return slot->tts_ops->copy_minimal_tuple(slot);
1563 /* --------------------------------
1564 * ExecFetchSlotHeapTupleDatum
1565 * Fetch the slot's tuple as a composite-type Datum.
1567 * The result is always freshly palloc'd in the caller's memory context.
1568 * --------------------------------
1571 ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot)
1578 /* Fetch slot's contents in regular-physical-tuple form */
1579 tup = ExecFetchSlotHeapTuple(slot, false, &shouldFree);
1580 tupdesc = slot->tts_tupleDescriptor;
1582 /* Convert to Datum form */
1583 ret = heap_copy_tuple_as_datum(tup, tupdesc);
1591 /* ----------------------------------------------------------------
1592 * convenience initialization routines
1593 * ----------------------------------------------------------------
1597 * ExecInitResultTypeTL
1599 * Initialize result type, using the plan node's targetlist.
1603 ExecInitResultTypeTL(PlanState *planstate)
1605 TupleDesc tupDesc = ExecTypeFromTL(planstate->plan->targetlist);
1607 tupDesc = ExecTypeFromTL(planstate->plan->targetlist);
1608 planstate->ps_ResultTupleDesc = tupDesc;
1611 /* --------------------------------
1612 * ExecInit{Result,Scan,Extra}TupleSlot[TL]
1614 * These are convenience routines to initialize the specified slot
1615 * in nodes inheriting the appropriate state. ExecInitExtraTupleSlot
1616 * is used for initializing special-purpose slots.
1617 * --------------------------------
1621 * ExecInitResultTupleSlotTL
1623 * Initialize result tuple slot, using the tuple descriptor previously
1624 * computed with ExecInitResultTypeTL().
1628 ExecInitResultSlot(PlanState *planstate, const TupleTableSlotOps *tts_ops)
1630 TupleTableSlot *slot;
1632 slot = ExecAllocTableSlot(&planstate->state->es_tupleTable,
1633 planstate->ps_ResultTupleDesc, tts_ops);
1634 planstate->ps_ResultTupleSlot = slot;
1636 planstate->resultopsfixed = planstate->ps_ResultTupleDesc != NULL;
1637 planstate->resultops = tts_ops;
1638 planstate->resultopsset = true;
1642 * ExecInitResultTupleSlotTL
1644 * Initialize result tuple slot, using the plan node's targetlist.
1648 ExecInitResultTupleSlotTL(PlanState *planstate,
1649 const TupleTableSlotOps *tts_ops)
1651 ExecInitResultTypeTL(planstate);
1652 ExecInitResultSlot(planstate, tts_ops);
1656 * ExecInitScanTupleSlot
1660 ExecInitScanTupleSlot(EState *estate, ScanState *scanstate,
1661 TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
1663 scanstate->ss_ScanTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable,
1664 tupledesc, tts_ops);
1665 scanstate->ps.scandesc = tupledesc;
1666 scanstate->ps.scanopsfixed = tupledesc != NULL;
1667 scanstate->ps.scanops = tts_ops;
1668 scanstate->ps.scanopsset = true;
1672 * ExecInitExtraTupleSlot
1674 * Return a newly created slot. If tupledesc is non-NULL the slot will have
1675 * that as its fixed tupledesc. Otherwise the caller needs to use
1676 * ExecSetSlotDescriptor() to set the descriptor before use.
1680 ExecInitExtraTupleSlot(EState *estate,
1681 TupleDesc tupledesc,
1682 const TupleTableSlotOps *tts_ops)
1684 return ExecAllocTableSlot(&estate->es_tupleTable, tupledesc, tts_ops);
1688 * ExecInitNullTupleSlot
1690 * Build a slot containing an all-nulls tuple of the given type.
1691 * This is used as a substitute for an input tuple when performing an
1696 ExecInitNullTupleSlot(EState *estate, TupleDesc tupType,
1697 const TupleTableSlotOps *tts_ops)
1699 TupleTableSlot *slot = ExecInitExtraTupleSlot(estate, tupType, tts_ops);
1701 return ExecStoreAllNullTuple(slot);
1704 /* ---------------------------------------------------------------
1705 * Routines for setting/accessing attributes in a slot.
1706 * ---------------------------------------------------------------
1710 * Fill in missing values for a TupleTableSlot.
1712 * This is only exposed because it's needed for JIT compiled tuple
1713 * deforming. That exception aside, there should be no callers outside of this
1717 slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, int lastAttNum)
1719 AttrMissing *attrmiss = NULL;
1721 if (slot->tts_tupleDescriptor->constr)
1722 attrmiss = slot->tts_tupleDescriptor->constr->missing;
1726 /* no missing values array at all, so just fill everything in as NULL */
1727 memset(slot->tts_values + startAttNum, 0,
1728 (lastAttNum - startAttNum) * sizeof(Datum));
1729 memset(slot->tts_isnull + startAttNum, 1,
1730 (lastAttNum - startAttNum) * sizeof(bool));
1736 /* if there is a missing values array we must process them one by one */
1737 for (missattnum = startAttNum;
1738 missattnum < lastAttNum;
1741 slot->tts_values[missattnum] = attrmiss[missattnum].am_value;
1742 slot->tts_isnull[missattnum] = !attrmiss[missattnum].am_present;
1749 * slot_getsomeattrs_int - workhorse for slot_getsomeattrs()
1752 slot_getsomeattrs_int(TupleTableSlot *slot, int attnum)
1754 /* Check for caller errors */
1755 Assert(slot->tts_nvalid < attnum); /* slot_getsomeattr checked */
1758 if (unlikely(attnum > slot->tts_tupleDescriptor->natts))
1759 elog(ERROR, "invalid attribute number %d", attnum);
1761 /* Fetch as many attributes as possible from the underlying tuple. */
1762 slot->tts_ops->getsomeattrs(slot, attnum);
1765 * If the underlying tuple doesn't have enough attributes, tuple descriptor
1766 * must have the missing attributes.
1768 if (unlikely(slot->tts_nvalid < attnum))
1770 slot_getmissingattrs(slot, slot->tts_nvalid, attnum);
1771 slot->tts_nvalid = attnum;
1775 /* ----------------------------------------------------------------
1778 * Generate a tuple descriptor for the result tuple of a targetlist.
1779 * (A parse/plan tlist must be passed, not an ExprState tlist.)
1780 * Note that resjunk columns, if any, are included in the result.
1782 * Currently there are about 4 different places where we create
1783 * TupleDescriptors. They should all be merged, or perhaps
1784 * be rewritten to call BuildDesc().
1785 * ----------------------------------------------------------------
1788 ExecTypeFromTL(List *targetList)
1790 return ExecTypeFromTLInternal(targetList, false);
1793 /* ----------------------------------------------------------------
1794 * ExecCleanTypeFromTL
1796 * Same as above, but resjunk columns are omitted from the result.
1797 * ----------------------------------------------------------------
1800 ExecCleanTypeFromTL(List *targetList)
1802 return ExecTypeFromTLInternal(targetList, true);
1806 ExecTypeFromTLInternal(List *targetList, bool skipjunk)
1814 len = ExecCleanTargetListLength(targetList);
1816 len = ExecTargetListLength(targetList);
1817 typeInfo = CreateTemplateTupleDesc(len);
1819 foreach(l, targetList)
1821 TargetEntry *tle = lfirst(l);
1823 if (skipjunk && tle->resjunk)
1825 TupleDescInitEntry(typeInfo,
1828 exprType((Node *) tle->expr),
1829 exprTypmod((Node *) tle->expr),
1831 TupleDescInitEntryCollation(typeInfo,
1833 exprCollation((Node *) tle->expr));
1841 * ExecTypeFromExprList - build a tuple descriptor from a list of Exprs
1843 * This is roughly like ExecTypeFromTL, but we work from bare expressions
1844 * not TargetEntrys. No names are attached to the tupledesc's columns.
1847 ExecTypeFromExprList(List *exprList)
1853 typeInfo = CreateTemplateTupleDesc(list_length(exprList));
1855 foreach(lc, exprList)
1857 Node *e = lfirst(lc);
1859 TupleDescInitEntry(typeInfo,
1865 TupleDescInitEntryCollation(typeInfo,
1875 * ExecTypeSetColNames - set column names in a TupleDesc
1877 * Column names must be provided as an alias list (list of String nodes).
1879 * For some callers, the supplied tupdesc has a named rowtype (not RECORD)
1880 * and it is moderately likely that the alias list matches the column names
1881 * already present in the tupdesc. If we do change any column names then
1882 * we must reset the tupdesc's type to anonymous RECORD; but we avoid doing
1883 * so if no names change.
1886 ExecTypeSetColNames(TupleDesc typeInfo, List *namesList)
1888 bool modified = false;
1892 foreach(lc, namesList)
1894 char *cname = strVal(lfirst(lc));
1895 Form_pg_attribute attr;
1897 /* Guard against too-long names list */
1898 if (colno >= typeInfo->natts)
1900 attr = TupleDescAttr(typeInfo, colno);
1903 /* Ignore empty aliases (these must be for dropped columns) */
1904 if (cname[0] == '\0')
1907 /* Change tupdesc only if alias is actually different */
1908 if (strcmp(cname, NameStr(attr->attname)) != 0)
1910 namestrcpy(&(attr->attname), cname);
1915 /* If we modified the tupdesc, it's now a new record type */
1918 typeInfo->tdtypeid = RECORDOID;
1919 typeInfo->tdtypmod = -1;
1924 * BlessTupleDesc - make a completed tuple descriptor useful for SRFs
1926 * Rowtype Datums returned by a function must contain valid type information.
1927 * This happens "for free" if the tupdesc came from a relcache entry, but
1928 * not if we have manufactured a tupdesc for a transient RECORD datatype.
1929 * In that case we have to notify typcache.c of the existence of the type.
1932 BlessTupleDesc(TupleDesc tupdesc)
1934 if (tupdesc->tdtypeid == RECORDOID &&
1935 tupdesc->tdtypmod < 0)
1936 assign_record_type_typmod(tupdesc);
1938 return tupdesc; /* just for notational convenience */
1942 * TupleDescGetAttInMetadata - Build an AttInMetadata structure based on the
1943 * supplied TupleDesc. AttInMetadata can be used in conjunction with C strings
1944 * to produce a properly formed tuple.
1947 TupleDescGetAttInMetadata(TupleDesc tupdesc)
1949 int natts = tupdesc->natts;
1953 FmgrInfo *attinfuncinfo;
1956 AttInMetadata *attinmeta;
1958 attinmeta = (AttInMetadata *) palloc(sizeof(AttInMetadata));
1960 /* "Bless" the tupledesc so that we can make rowtype datums with it */
1961 attinmeta->tupdesc = BlessTupleDesc(tupdesc);
1964 * Gather info needed later to call the "in" function for each attribute
1966 attinfuncinfo = (FmgrInfo *) palloc0(natts * sizeof(FmgrInfo));
1967 attioparams = (Oid *) palloc0(natts * sizeof(Oid));
1968 atttypmods = (int32 *) palloc0(natts * sizeof(int32));
1970 for (i = 0; i < natts; i++)
1972 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
1974 /* Ignore dropped attributes */
1975 if (!att->attisdropped)
1977 atttypeid = att->atttypid;
1978 getTypeInputInfo(atttypeid, &attinfuncid, &attioparams[i]);
1979 fmgr_info(attinfuncid, &attinfuncinfo[i]);
1980 atttypmods[i] = att->atttypmod;
1983 attinmeta->attinfuncs = attinfuncinfo;
1984 attinmeta->attioparams = attioparams;
1985 attinmeta->atttypmods = atttypmods;
1991 * BuildTupleFromCStrings - build a HeapTuple given user data in C string form.
1992 * values is an array of C strings, one for each attribute of the return tuple.
1993 * A NULL string pointer indicates we want to create a NULL field.
1996 BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
1998 TupleDesc tupdesc = attinmeta->tupdesc;
1999 int natts = tupdesc->natts;
2005 dvalues = (Datum *) palloc(natts * sizeof(Datum));
2006 nulls = (bool *) palloc(natts * sizeof(bool));
2009 * Call the "in" function for each non-dropped attribute, even for nulls,
2010 * to support domains.
2012 for (i = 0; i < natts; i++)
2014 if (!TupleDescAttr(tupdesc, i)->attisdropped)
2016 /* Non-dropped attributes */
2017 dvalues[i] = InputFunctionCall(&attinmeta->attinfuncs[i],
2019 attinmeta->attioparams[i],
2020 attinmeta->atttypmods[i]);
2021 if (values[i] != NULL)
2028 /* Handle dropped attributes by setting to NULL */
2029 dvalues[i] = (Datum) 0;
2037 tuple = heap_form_tuple(tupdesc, dvalues, nulls);
2040 * Release locally palloc'd space. XXX would probably be good to pfree
2041 * values of pass-by-reference datums, as well.
2050 * HeapTupleHeaderGetDatum - convert a HeapTupleHeader pointer to a Datum.
2052 * This must *not* get applied to an on-disk tuple; the tuple should be
2053 * freshly made by heap_form_tuple or some wrapper routine for it (such as
2054 * BuildTupleFromCStrings). Be sure also that the tupledesc used to build
2055 * the tuple has a properly "blessed" rowtype.
2057 * Formerly this was a macro equivalent to PointerGetDatum, relying on the
2058 * fact that heap_form_tuple fills in the appropriate tuple header fields
2059 * for a composite Datum. However, we now require that composite Datums not
2060 * contain any external TOAST pointers. We do not want heap_form_tuple itself
2061 * to enforce that; more specifically, the rule applies only to actual Datums
2062 * and not to HeapTuple structures. Therefore, HeapTupleHeaderGetDatum is
2063 * now a function that detects whether there are externally-toasted fields
2064 * and constructs a new tuple with inlined fields if so. We still need
2065 * heap_form_tuple to insert the Datum header fields, because otherwise this
2066 * code would have no way to obtain a tupledesc for the tuple.
2068 * Note that if we do build a new tuple, it's palloc'd in the current
2069 * memory context. Beware of code that changes context between the initial
2070 * heap_form_tuple/etc call and calling HeapTuple(Header)GetDatum.
2072 * For performance-critical callers, it could be worthwhile to take extra
2073 * steps to ensure that there aren't TOAST pointers in the output of
2074 * heap_form_tuple to begin with. It's likely however that the costs of the
2075 * typcache lookup and tuple disassembly/reassembly are swamped by TOAST
2076 * dereference costs, so that the benefits of such extra effort would be
2079 * XXX it would likely be better to create wrapper functions that produce
2080 * a composite Datum from the field values in one step. However, there's
2081 * enough code using the existing APIs that we couldn't get rid of this
2082 * hack anytime soon.
2085 HeapTupleHeaderGetDatum(HeapTupleHeader tuple)
2090 /* No work if there are no external TOAST pointers in the tuple */
2091 if (!HeapTupleHeaderHasExternal(tuple))
2092 return PointerGetDatum(tuple);
2094 /* Use the type data saved by heap_form_tuple to look up the rowtype */
2095 tupDesc = lookup_rowtype_tupdesc(HeapTupleHeaderGetTypeId(tuple),
2096 HeapTupleHeaderGetTypMod(tuple));
2098 /* And do the flattening */
2099 result = toast_flatten_tuple_to_datum(tuple,
2100 HeapTupleHeaderGetDatumLength(tuple),
2103 ReleaseTupleDesc(tupDesc);
2110 * Functions for sending tuples to the frontend (or other specified destination)
2111 * as though it is a SELECT result. These are used by utility commands that
2112 * need to project directly to the destination and don't need or want full
2113 * table function capability. Currently used by EXPLAIN and SHOW ALL.
2116 begin_tup_output_tupdesc(DestReceiver *dest,
2118 const TupleTableSlotOps *tts_ops)
2120 TupOutputState *tstate;
2122 tstate = (TupOutputState *) palloc(sizeof(TupOutputState));
2124 tstate->slot = MakeSingleTupleTableSlot(tupdesc, tts_ops);
2125 tstate->dest = dest;
2127 tstate->dest->rStartup(tstate->dest, (int) CMD_SELECT, tupdesc);
2133 * write a single tuple
2136 do_tup_output(TupOutputState *tstate, Datum *values, bool *isnull)
2138 TupleTableSlot *slot = tstate->slot;
2139 int natts = slot->tts_tupleDescriptor->natts;
2141 /* make sure the slot is clear */
2142 ExecClearTuple(slot);
2145 memcpy(slot->tts_values, values, natts * sizeof(Datum));
2146 memcpy(slot->tts_isnull, isnull, natts * sizeof(bool));
2148 /* mark slot as containing a virtual tuple */
2149 ExecStoreVirtualTuple(slot);
2151 /* send the tuple to the receiver */
2152 (void) tstate->dest->receiveSlot(slot, tstate->dest);
2155 ExecClearTuple(slot);
2159 * write a chunk of text, breaking at newline characters
2161 * Should only be used with a single-TEXT-attribute tupdesc.
2164 do_text_output_multiline(TupOutputState *tstate, const char *txt)
2167 bool isnull[1] = {false};
2174 eol = strchr(txt, '\n');
2186 values[0] = PointerGetDatum(cstring_to_text_with_len(txt, len));
2187 do_tup_output(tstate, values, isnull);
2188 pfree(DatumGetPointer(values[0]));
2194 end_tup_output(TupOutputState *tstate)
2196 tstate->dest->rShutdown(tstate->dest);
2197 /* note that destroying the dest is not ours to do */
2198 ExecDropSingleTupleTableSlot(tstate->slot);