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 slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
76 static inline void tts_buffer_heap_store_tuple(TupleTableSlot *slot,
80 static void tts_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, bool shouldFree);
83 const TupleTableSlotOps TTSOpsVirtual;
84 const TupleTableSlotOps TTSOpsHeapTuple;
85 const TupleTableSlotOps TTSOpsMinimalTuple;
86 const TupleTableSlotOps TTSOpsBufferHeapTuple;
90 * TupleTableSlotOps implementations.
94 * TupleTableSlotOps implementation for VirtualTupleTableSlot.
97 tts_virtual_init(TupleTableSlot *slot)
102 tts_virtual_release(TupleTableSlot *slot)
107 tts_virtual_clear(TupleTableSlot *slot)
109 if (unlikely(TTS_SHOULDFREE(slot)))
111 VirtualTupleTableSlot *vslot = (VirtualTupleTableSlot *) slot;
116 slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
119 slot->tts_nvalid = 0;
120 slot->tts_flags |= TTS_FLAG_EMPTY;
121 ItemPointerSetInvalid(&slot->tts_tid);
125 * Attribute values are readily available in tts_values and tts_isnull array
126 * in a VirtualTupleTableSlot. So there should be no need to call either of the
127 * following two functions.
130 tts_virtual_getsomeattrs(TupleTableSlot *slot, int natts)
132 elog(ERROR, "getsomeattrs is not required to be called on a virtual tuple table slot");
136 tts_virtual_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
138 elog(ERROR, "virtual tuple table slot does not have system attributes");
140 return 0; /* silence compiler warnings */
144 * To materialize a virtual slot all the datums that aren't passed by value
145 * have to be copied into the slot's memory context. To do so, compute the
146 * required size, and allocate enough memory to store all attributes. That's
147 * good for cache hit ratio, but more importantly requires only memory
148 * allocation/deallocation.
151 tts_virtual_materialize(TupleTableSlot *slot)
153 VirtualTupleTableSlot *vslot = (VirtualTupleTableSlot *) slot;
154 TupleDesc desc = slot->tts_tupleDescriptor;
158 /* already materialized */
159 if (TTS_SHOULDFREE(slot))
162 /* compute size of memory required */
163 for (int natt = 0; natt < desc->natts; natt++)
165 Form_pg_attribute att = TupleDescAttr(desc, natt);
168 if (att->attbyval || slot->tts_isnull[natt])
171 val = slot->tts_values[natt];
173 if (att->attlen == -1 &&
174 VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(val)))
177 * We want to flatten the expanded value so that the materialized
178 * slot doesn't depend on it.
180 sz = att_align_nominal(sz, att->attalign);
181 sz += EOH_get_flat_size(DatumGetEOHP(val));
185 sz = att_align_nominal(sz, att->attalign);
186 sz = att_addlength_datum(sz, att->attlen, val);
190 /* all data is byval */
194 /* allocate memory */
195 vslot->data = data = MemoryContextAlloc(slot->tts_mcxt, sz);
196 slot->tts_flags |= TTS_FLAG_SHOULDFREE;
198 /* and copy all attributes into the pre-allocated space */
199 for (int natt = 0; natt < desc->natts; natt++)
201 Form_pg_attribute att = TupleDescAttr(desc, natt);
204 if (att->attbyval || slot->tts_isnull[natt])
207 val = slot->tts_values[natt];
209 if (att->attlen == -1 &&
210 VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(val)))
215 * We want to flatten the expanded value so that the materialized
216 * slot doesn't depend on it.
218 ExpandedObjectHeader *eoh = DatumGetEOHP(val);
220 data = (char *) att_align_nominal(data,
222 data_length = EOH_get_flat_size(eoh);
223 EOH_flatten_into(eoh, data, data_length);
225 slot->tts_values[natt] = PointerGetDatum(data);
230 Size data_length = 0;
232 data = (char *) att_align_nominal(data, att->attalign);
233 data_length = att_addlength_datum(data_length, att->attlen, val);
235 memcpy(data, DatumGetPointer(val), data_length);
237 slot->tts_values[natt] = PointerGetDatum(data);
244 tts_virtual_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
246 TupleDesc srcdesc = dstslot->tts_tupleDescriptor;
248 Assert(srcdesc->natts <= dstslot->tts_tupleDescriptor->natts);
250 tts_virtual_clear(dstslot);
252 slot_getallattrs(srcslot);
254 for (int natt = 0; natt < srcdesc->natts; natt++)
256 dstslot->tts_values[natt] = srcslot->tts_values[natt];
257 dstslot->tts_isnull[natt] = srcslot->tts_isnull[natt];
260 dstslot->tts_nvalid = srcdesc->natts;
261 dstslot->tts_flags &= ~TTS_FLAG_EMPTY;
263 /* make sure storage doesn't depend on external memory */
264 tts_virtual_materialize(dstslot);
268 tts_virtual_copy_heap_tuple(TupleTableSlot *slot)
270 Assert(!TTS_EMPTY(slot));
272 return heap_form_tuple(slot->tts_tupleDescriptor,
279 tts_virtual_copy_minimal_tuple(TupleTableSlot *slot)
281 Assert(!TTS_EMPTY(slot));
283 return heap_form_minimal_tuple(slot->tts_tupleDescriptor,
290 * TupleTableSlotOps implementation for HeapTupleTableSlot.
294 tts_heap_init(TupleTableSlot *slot)
299 tts_heap_release(TupleTableSlot *slot)
304 tts_heap_clear(TupleTableSlot *slot)
306 HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
308 /* Free the memory for the heap tuple if it's allowed. */
309 if (TTS_SHOULDFREE(slot))
311 heap_freetuple(hslot->tuple);
312 slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
315 slot->tts_nvalid = 0;
316 slot->tts_flags |= TTS_FLAG_EMPTY;
317 ItemPointerSetInvalid(&slot->tts_tid);
323 tts_heap_getsomeattrs(TupleTableSlot *slot, int natts)
325 HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
327 Assert(!TTS_EMPTY(slot));
329 slot_deform_heap_tuple(slot, hslot->tuple, &hslot->off, natts);
333 tts_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
335 HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
337 return heap_getsysattr(hslot->tuple, attnum,
338 slot->tts_tupleDescriptor, isnull);
342 tts_heap_materialize(TupleTableSlot *slot)
344 HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
345 MemoryContext oldContext;
347 Assert(!TTS_EMPTY(slot));
349 /* This slot has it's tuple already materialized. Nothing to do. */
350 if (TTS_SHOULDFREE(slot))
353 slot->tts_flags |= TTS_FLAG_SHOULDFREE;
355 oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
358 hslot->tuple = heap_form_tuple(slot->tts_tupleDescriptor,
364 * The tuple contained in this slot is not allocated in the memory
365 * context of the given slot (else it would have TTS_SHOULDFREE set).
366 * Copy the tuple into the given slot's memory context.
368 hslot->tuple = heap_copytuple(hslot->tuple);
372 * Have to deform from scratch, otherwise tts_values[] entries could point
373 * into the non-materialized tuple (which might be gone when accessed).
375 slot->tts_nvalid = 0;
378 MemoryContextSwitchTo(oldContext);
382 tts_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
385 MemoryContext oldcontext;
387 oldcontext = MemoryContextSwitchTo(dstslot->tts_mcxt);
388 tuple = ExecCopySlotHeapTuple(srcslot);
389 MemoryContextSwitchTo(oldcontext);
391 ExecStoreHeapTuple(tuple, dstslot, true);
395 tts_heap_get_heap_tuple(TupleTableSlot *slot)
397 HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
399 Assert(!TTS_EMPTY(slot));
401 tts_heap_materialize(slot);
407 tts_heap_copy_heap_tuple(TupleTableSlot *slot)
409 HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
411 Assert(!TTS_EMPTY(slot));
413 tts_heap_materialize(slot);
415 return heap_copytuple(hslot->tuple);
419 tts_heap_copy_minimal_tuple(TupleTableSlot *slot)
421 HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
424 tts_heap_materialize(slot);
426 return minimal_tuple_from_heap_tuple(hslot->tuple);
430 tts_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, bool shouldFree)
432 HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
434 tts_heap_clear(slot);
436 slot->tts_nvalid = 0;
437 hslot->tuple = tuple;
439 slot->tts_flags &= ~TTS_FLAG_EMPTY;
440 slot->tts_tid = tuple->t_self;
443 slot->tts_flags |= TTS_FLAG_SHOULDFREE;
448 * TupleTableSlotOps implementation for MinimalTupleTableSlot.
452 tts_minimal_init(TupleTableSlot *slot)
454 MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
457 * Initialize the heap tuple pointer to access attributes of the minimal
458 * tuple contained in the slot as if its a heap tuple.
460 mslot->tuple = &mslot->minhdr;
464 tts_minimal_release(TupleTableSlot *slot)
469 tts_minimal_clear(TupleTableSlot *slot)
471 MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
473 if (TTS_SHOULDFREE(slot))
475 heap_free_minimal_tuple(mslot->mintuple);
476 slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
479 slot->tts_nvalid = 0;
480 slot->tts_flags |= TTS_FLAG_EMPTY;
481 ItemPointerSetInvalid(&slot->tts_tid);
483 mslot->mintuple = NULL;
487 tts_minimal_getsomeattrs(TupleTableSlot *slot, int natts)
489 MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
491 Assert(!TTS_EMPTY(slot));
493 slot_deform_heap_tuple(slot, mslot->tuple, &mslot->off, natts);
497 tts_minimal_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
499 elog(ERROR, "minimal tuple table slot does not have system attributes");
501 return 0; /* silence compiler warnings */
505 tts_minimal_materialize(TupleTableSlot *slot)
507 MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
508 MemoryContext oldContext;
510 Assert(!TTS_EMPTY(slot));
512 /* This slot has it's tuple already materialized. Nothing to do. */
513 if (TTS_SHOULDFREE(slot))
516 slot->tts_flags |= TTS_FLAG_SHOULDFREE;
517 oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
519 if (!mslot->mintuple)
521 mslot->mintuple = heap_form_minimal_tuple(slot->tts_tupleDescriptor,
528 * The minimal tuple contained in this slot is not allocated in the
529 * memory context of the given slot (else it would have TTS_SHOULDFREE
530 * set). Copy the minimal tuple into the given slot's memory context.
532 mslot->mintuple = heap_copy_minimal_tuple(mslot->mintuple);
535 Assert(mslot->tuple == &mslot->minhdr);
537 mslot->minhdr.t_len = mslot->mintuple->t_len + MINIMAL_TUPLE_OFFSET;
538 mslot->minhdr.t_data = (HeapTupleHeader) ((char *) mslot->mintuple - MINIMAL_TUPLE_OFFSET);
540 MemoryContextSwitchTo(oldContext);
543 * Have to deform from scratch, otherwise tts_values[] entries could point
544 * into the non-materialized tuple (which might be gone when accessed).
546 slot->tts_nvalid = 0;
551 tts_minimal_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
553 MemoryContext oldcontext;
554 MinimalTuple mintuple;
556 oldcontext = MemoryContextSwitchTo(dstslot->tts_mcxt);
557 mintuple = ExecCopySlotMinimalTuple(srcslot);
558 MemoryContextSwitchTo(oldcontext);
560 ExecStoreMinimalTuple(mintuple, dstslot, true);
564 tts_minimal_get_minimal_tuple(TupleTableSlot *slot)
566 MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
568 if (!mslot->mintuple)
569 tts_minimal_materialize(slot);
571 return mslot->mintuple;
575 tts_minimal_copy_heap_tuple(TupleTableSlot *slot)
577 MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
579 if (!mslot->mintuple)
580 tts_minimal_materialize(slot);
582 return heap_tuple_from_minimal_tuple(mslot->mintuple);
586 tts_minimal_copy_minimal_tuple(TupleTableSlot *slot)
588 MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
590 if (!mslot->mintuple)
591 tts_minimal_materialize(slot);
593 return heap_copy_minimal_tuple(mslot->mintuple);
597 tts_minimal_store_tuple(TupleTableSlot *slot, MinimalTuple mtup, bool shouldFree)
599 MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
601 tts_minimal_clear(slot);
603 Assert(!TTS_SHOULDFREE(slot));
604 Assert(TTS_EMPTY(slot));
606 slot->tts_flags &= ~TTS_FLAG_EMPTY;
607 slot->tts_nvalid = 0;
610 mslot->mintuple = mtup;
611 Assert(mslot->tuple == &mslot->minhdr);
612 mslot->minhdr.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
613 mslot->minhdr.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);
614 /* no need to set t_self or t_tableOid since we won't allow access */
617 slot->tts_flags |= TTS_FLAG_SHOULDFREE;
619 Assert(!TTS_SHOULDFREE(slot));
624 * TupleTableSlotOps implementation for BufferHeapTupleTableSlot.
628 tts_buffer_heap_init(TupleTableSlot *slot)
633 tts_buffer_heap_release(TupleTableSlot *slot)
638 tts_buffer_heap_clear(TupleTableSlot *slot)
640 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
643 * Free the memory for heap tuple if allowed. A tuple coming from buffer
644 * can never be freed. But we may have materialized a tuple from buffer.
645 * Such a tuple can be freed.
647 if (TTS_SHOULDFREE(slot))
649 /* We should have unpinned the buffer while materializing the tuple. */
650 Assert(!BufferIsValid(bslot->buffer));
652 heap_freetuple(bslot->base.tuple);
653 slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
655 Assert(!BufferIsValid(bslot->buffer));
658 if (BufferIsValid(bslot->buffer))
659 ReleaseBuffer(bslot->buffer);
661 slot->tts_nvalid = 0;
662 slot->tts_flags |= TTS_FLAG_EMPTY;
663 ItemPointerSetInvalid(&slot->tts_tid);
664 bslot->base.tuple = NULL;
666 bslot->buffer = InvalidBuffer;
670 tts_buffer_heap_getsomeattrs(TupleTableSlot *slot, int natts)
672 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
674 Assert(!TTS_EMPTY(slot));
676 slot_deform_heap_tuple(slot, bslot->base.tuple, &bslot->base.off, natts);
680 tts_buffer_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
682 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
684 return heap_getsysattr(bslot->base.tuple, attnum,
685 slot->tts_tupleDescriptor, isnull);
689 tts_buffer_heap_materialize(TupleTableSlot *slot)
691 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
692 MemoryContext oldContext;
694 Assert(!TTS_EMPTY(slot));
696 /* If already materialized nothing to do. */
697 if (TTS_SHOULDFREE(slot))
700 slot->tts_flags |= TTS_FLAG_SHOULDFREE;
702 oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
704 if (!bslot->base.tuple)
707 * Normally BufferHeapTupleTableSlot should have a tuple + buffer
708 * associated with it, unless it's materialized (which would've
709 * returned above). But when it's useful to allow storing virtual
710 * tuples in a buffer slot, which then also needs to be
713 bslot->base.tuple = heap_form_tuple(slot->tts_tupleDescriptor,
720 bslot->base.tuple = heap_copytuple(bslot->base.tuple);
723 * A heap tuple stored in a BufferHeapTupleTableSlot should have a
724 * buffer associated with it, unless it's materialized or virtual.
726 Assert(BufferIsValid(bslot->buffer));
727 if (likely(BufferIsValid(bslot->buffer)))
728 ReleaseBuffer(bslot->buffer);
729 bslot->buffer = InvalidBuffer;
731 MemoryContextSwitchTo(oldContext);
734 * Have to deform from scratch, otherwise tts_values[] entries could point
735 * into the non-materialized tuple (which might be gone when accessed).
738 slot->tts_nvalid = 0;
742 tts_buffer_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
744 BufferHeapTupleTableSlot *bsrcslot = (BufferHeapTupleTableSlot *) srcslot;
745 BufferHeapTupleTableSlot *bdstslot = (BufferHeapTupleTableSlot *) dstslot;
748 * If the source slot is of a different kind, or is a buffer slot that has
749 * been materialized / is virtual, make a new copy of the tuple. Otherwise
750 * make a new reference to the in-buffer tuple.
752 if (dstslot->tts_ops != srcslot->tts_ops ||
753 TTS_SHOULDFREE(srcslot) ||
754 !bsrcslot->base.tuple)
756 MemoryContext oldContext;
758 ExecClearTuple(dstslot);
759 dstslot->tts_flags |= TTS_FLAG_SHOULDFREE;
760 dstslot->tts_flags &= ~TTS_FLAG_EMPTY;
761 oldContext = MemoryContextSwitchTo(dstslot->tts_mcxt);
762 bdstslot->base.tuple = ExecCopySlotHeapTuple(srcslot);
763 MemoryContextSwitchTo(oldContext);
767 Assert(BufferIsValid(bsrcslot->buffer));
769 tts_buffer_heap_store_tuple(dstslot, bsrcslot->base.tuple,
770 bsrcslot->buffer, false);
773 * The HeapTupleData portion of the source tuple might be shorter
774 * lived than the destination slot. Therefore copy the HeapTuple into
775 * our slot's tupdata, which is guaranteed to live long enough (but
776 * will still point into the buffer).
778 memcpy(&bdstslot->base.tupdata, bdstslot->base.tuple, sizeof(HeapTupleData));
779 bdstslot->base.tuple = &bdstslot->base.tupdata;
784 tts_buffer_heap_get_heap_tuple(TupleTableSlot *slot)
786 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
788 Assert(!TTS_EMPTY(slot));
790 if (!bslot->base.tuple)
791 tts_buffer_heap_materialize(slot);
793 return bslot->base.tuple;
797 tts_buffer_heap_copy_heap_tuple(TupleTableSlot *slot)
799 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
801 Assert(!TTS_EMPTY(slot));
803 if (!bslot->base.tuple)
804 tts_buffer_heap_materialize(slot);
806 return heap_copytuple(bslot->base.tuple);
810 tts_buffer_heap_copy_minimal_tuple(TupleTableSlot *slot)
812 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
814 Assert(!TTS_EMPTY(slot));
816 if (!bslot->base.tuple)
817 tts_buffer_heap_materialize(slot);
819 return minimal_tuple_from_heap_tuple(bslot->base.tuple);
823 tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple,
824 Buffer buffer, bool transfer_pin)
826 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
828 if (TTS_SHOULDFREE(slot))
830 /* materialized slot shouldn't have a buffer to release */
831 Assert(!BufferIsValid(bslot->buffer));
833 heap_freetuple(bslot->base.tuple);
834 slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
837 slot->tts_flags &= ~TTS_FLAG_EMPTY;
838 slot->tts_nvalid = 0;
839 bslot->base.tuple = tuple;
841 slot->tts_tid = tuple->t_self;
844 * If tuple is on a disk page, keep the page pinned as long as we hold a
845 * pointer into it. We assume the caller already has such a pin. If
846 * transfer_pin is true, we'll transfer that pin to this slot, if not
847 * we'll pin it again ourselves.
849 * This is coded to optimize the case where the slot previously held a
850 * tuple on the same disk page: in that case releasing and re-acquiring
851 * the pin is a waste of cycles. This is a common situation during
852 * seqscans, so it's worth troubling over.
854 if (bslot->buffer != buffer)
856 if (BufferIsValid(bslot->buffer))
857 ReleaseBuffer(bslot->buffer);
859 bslot->buffer = buffer;
861 if (!transfer_pin && BufferIsValid(buffer))
862 IncrBufferRefCount(buffer);
864 else if (transfer_pin && BufferIsValid(buffer))
867 * In transfer_pin mode the caller won't know about the same-page
868 * optimization, so we gotta release its pin.
870 ReleaseBuffer(buffer);
875 * slot_deform_heap_tuple
876 * Given a TupleTableSlot, extract data from the slot's physical tuple
877 * into its Datum/isnull arrays. Data is extracted up through the
878 * natts'th column (caller must ensure this is a legal column number).
880 * This is essentially an incremental version of heap_deform_tuple:
881 * on each call we extract attributes up to the one needed, without
882 * re-computing information about previously extracted attributes.
883 * slot->tts_nvalid is the number of attributes already extracted.
885 * This is marked as always inline, so the different offp for different types
886 * of slots gets optimized away.
888 static pg_attribute_always_inline void
889 slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
892 TupleDesc tupleDesc = slot->tts_tupleDescriptor;
893 Datum *values = slot->tts_values;
894 bool *isnull = slot->tts_isnull;
895 HeapTupleHeader tup = tuple->t_data;
896 bool hasnulls = HeapTupleHasNulls(tuple);
898 char *tp; /* ptr to tuple data */
899 uint32 off; /* offset in tuple data */
900 bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
901 bool slow; /* can we use/set attcacheoff? */
903 /* We can only fetch as many attributes as the tuple has. */
904 natts = Min(HeapTupleHeaderGetNatts(tuple->t_data), natts);
907 * Check whether the first call for this tuple, and initialize or restore
910 attnum = slot->tts_nvalid;
913 /* Start from the first attribute */
919 /* Restore state from previous execution */
921 slow = TTS_SLOW(slot);
924 tp = (char *) tup + tup->t_hoff;
926 for (; attnum < natts; attnum++)
928 Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum);
930 if (hasnulls && att_isnull(attnum, bp))
932 values[attnum] = (Datum) 0;
933 isnull[attnum] = true;
934 slow = true; /* can't use attcacheoff anymore */
938 isnull[attnum] = false;
940 if (!slow && thisatt->attcacheoff >= 0)
941 off = thisatt->attcacheoff;
942 else if (thisatt->attlen == -1)
945 * We can only cache the offset for a varlena attribute if the
946 * offset is already suitably aligned, so that there would be no
947 * pad bytes in any case: then the offset will be valid for either
948 * an aligned or unaligned value.
951 off == att_align_nominal(off, thisatt->attalign))
952 thisatt->attcacheoff = off;
955 off = att_align_pointer(off, thisatt->attalign, -1,
962 /* not varlena, so safe to use att_align_nominal */
963 off = att_align_nominal(off, thisatt->attalign);
966 thisatt->attcacheoff = off;
969 values[attnum] = fetchatt(thisatt, tp + off);
971 off = att_addlength_pointer(off, thisatt->attlen, tp + off);
973 if (thisatt->attlen <= 0)
974 slow = true; /* can't use attcacheoff anymore */
978 * Save state for next execution
980 slot->tts_nvalid = attnum;
983 slot->tts_flags |= TTS_FLAG_SLOW;
985 slot->tts_flags &= ~TTS_FLAG_SLOW;
989 const TupleTableSlotOps TTSOpsVirtual = {
990 .base_slot_size = sizeof(VirtualTupleTableSlot),
991 .init = tts_virtual_init,
992 .release = tts_virtual_release,
993 .clear = tts_virtual_clear,
994 .getsomeattrs = tts_virtual_getsomeattrs,
995 .getsysattr = tts_virtual_getsysattr,
996 .materialize = tts_virtual_materialize,
997 .copyslot = tts_virtual_copyslot,
1000 * A virtual tuple table slot can not "own" a heap tuple or a minimal
1003 .get_heap_tuple = NULL,
1004 .get_minimal_tuple = NULL,
1005 .copy_heap_tuple = tts_virtual_copy_heap_tuple,
1006 .copy_minimal_tuple = tts_virtual_copy_minimal_tuple
1009 const TupleTableSlotOps TTSOpsHeapTuple = {
1010 .base_slot_size = sizeof(HeapTupleTableSlot),
1011 .init = tts_heap_init,
1012 .release = tts_heap_release,
1013 .clear = tts_heap_clear,
1014 .getsomeattrs = tts_heap_getsomeattrs,
1015 .getsysattr = tts_heap_getsysattr,
1016 .materialize = tts_heap_materialize,
1017 .copyslot = tts_heap_copyslot,
1018 .get_heap_tuple = tts_heap_get_heap_tuple,
1020 /* A heap tuple table slot can not "own" a minimal tuple. */
1021 .get_minimal_tuple = NULL,
1022 .copy_heap_tuple = tts_heap_copy_heap_tuple,
1023 .copy_minimal_tuple = tts_heap_copy_minimal_tuple
1026 const TupleTableSlotOps TTSOpsMinimalTuple = {
1027 .base_slot_size = sizeof(MinimalTupleTableSlot),
1028 .init = tts_minimal_init,
1029 .release = tts_minimal_release,
1030 .clear = tts_minimal_clear,
1031 .getsomeattrs = tts_minimal_getsomeattrs,
1032 .getsysattr = tts_minimal_getsysattr,
1033 .materialize = tts_minimal_materialize,
1034 .copyslot = tts_minimal_copyslot,
1036 /* A minimal tuple table slot can not "own" a heap tuple. */
1037 .get_heap_tuple = NULL,
1038 .get_minimal_tuple = tts_minimal_get_minimal_tuple,
1039 .copy_heap_tuple = tts_minimal_copy_heap_tuple,
1040 .copy_minimal_tuple = tts_minimal_copy_minimal_tuple
1043 const TupleTableSlotOps TTSOpsBufferHeapTuple = {
1044 .base_slot_size = sizeof(BufferHeapTupleTableSlot),
1045 .init = tts_buffer_heap_init,
1046 .release = tts_buffer_heap_release,
1047 .clear = tts_buffer_heap_clear,
1048 .getsomeattrs = tts_buffer_heap_getsomeattrs,
1049 .getsysattr = tts_buffer_heap_getsysattr,
1050 .materialize = tts_buffer_heap_materialize,
1051 .copyslot = tts_buffer_heap_copyslot,
1052 .get_heap_tuple = tts_buffer_heap_get_heap_tuple,
1054 /* A buffer heap tuple table slot can not "own" a minimal tuple. */
1055 .get_minimal_tuple = NULL,
1056 .copy_heap_tuple = tts_buffer_heap_copy_heap_tuple,
1057 .copy_minimal_tuple = tts_buffer_heap_copy_minimal_tuple
1061 /* ----------------------------------------------------------------
1062 * tuple table create/delete functions
1063 * ----------------------------------------------------------------
1066 /* --------------------------------
1067 * MakeTupleTableSlot
1069 * Basic routine to make an empty TupleTableSlot of given
1070 * TupleTableSlotType. If tupleDesc is specified the slot's descriptor is
1071 * fixed for its lifetime, gaining some efficiency. If that's
1072 * undesirable, pass NULL.
1073 * --------------------------------
1076 MakeTupleTableSlot(TupleDesc tupleDesc,
1077 const TupleTableSlotOps *tts_ops)
1081 TupleTableSlot *slot;
1083 basesz = tts_ops->base_slot_size;
1086 * When a fixed descriptor is specified, we can reduce overhead by
1087 * allocating the entire slot in one go.
1090 allocsz = MAXALIGN(basesz) +
1091 MAXALIGN(tupleDesc->natts * sizeof(Datum)) +
1092 MAXALIGN(tupleDesc->natts * sizeof(bool));
1096 slot = palloc0(allocsz);
1097 /* const for optimization purposes, OK to modify at allocation time */
1098 *((const TupleTableSlotOps **) &slot->tts_ops) = tts_ops;
1099 slot->type = T_TupleTableSlot;
1100 slot->tts_flags |= TTS_FLAG_EMPTY;
1101 if (tupleDesc != NULL)
1102 slot->tts_flags |= TTS_FLAG_FIXED;
1103 slot->tts_tupleDescriptor = tupleDesc;
1104 slot->tts_mcxt = CurrentMemoryContext;
1105 slot->tts_nvalid = 0;
1107 if (tupleDesc != NULL)
1109 slot->tts_values = (Datum *)
1111 + MAXALIGN(basesz));
1112 slot->tts_isnull = (bool *)
1115 + MAXALIGN(tupleDesc->natts * sizeof(Datum)));
1117 PinTupleDesc(tupleDesc);
1121 * And allow slot type specific initialization.
1123 slot->tts_ops->init(slot);
1128 /* --------------------------------
1129 * ExecAllocTableSlot
1131 * Create a tuple table slot within a tuple table (which is just a List).
1132 * --------------------------------
1135 ExecAllocTableSlot(List **tupleTable, TupleDesc desc,
1136 const TupleTableSlotOps *tts_ops)
1138 TupleTableSlot *slot = MakeTupleTableSlot(desc, tts_ops);
1140 *tupleTable = lappend(*tupleTable, slot);
1145 /* --------------------------------
1146 * ExecResetTupleTable
1148 * This releases any resources (buffer pins, tupdesc refcounts)
1149 * held by the tuple table, and optionally releases the memory
1150 * occupied by the tuple table data structure.
1151 * It is expected that this routine be called by ExecEndPlan().
1152 * --------------------------------
1155 ExecResetTupleTable(List *tupleTable, /* tuple table */
1156 bool shouldFree) /* true if we should free memory */
1160 foreach(lc, tupleTable)
1162 TupleTableSlot *slot = lfirst_node(TupleTableSlot, lc);
1164 /* Always release resources and reset the slot to empty */
1165 ExecClearTuple(slot);
1166 slot->tts_ops->release(slot);
1167 if (slot->tts_tupleDescriptor)
1169 ReleaseTupleDesc(slot->tts_tupleDescriptor);
1170 slot->tts_tupleDescriptor = NULL;
1173 /* If shouldFree, release memory occupied by the slot itself */
1176 if (!TTS_FIXED(slot))
1178 if (slot->tts_values)
1179 pfree(slot->tts_values);
1180 if (slot->tts_isnull)
1181 pfree(slot->tts_isnull);
1187 /* If shouldFree, release the list structure */
1189 list_free(tupleTable);
1192 /* --------------------------------
1193 * MakeSingleTupleTableSlot
1195 * This is a convenience routine for operations that need a standalone
1196 * TupleTableSlot not gotten from the main executor tuple table. It makes
1197 * a single slot of given TupleTableSlotType and initializes it to use the
1198 * given tuple descriptor.
1199 * --------------------------------
1202 MakeSingleTupleTableSlot(TupleDesc tupdesc,
1203 const TupleTableSlotOps *tts_ops)
1205 TupleTableSlot *slot = MakeTupleTableSlot(tupdesc, tts_ops);
1210 /* --------------------------------
1211 * ExecDropSingleTupleTableSlot
1213 * Release a TupleTableSlot made with MakeSingleTupleTableSlot.
1214 * DON'T use this on a slot that's part of a tuple table list!
1215 * --------------------------------
1218 ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
1220 /* This should match ExecResetTupleTable's processing of one slot */
1221 Assert(IsA(slot, TupleTableSlot));
1222 ExecClearTuple(slot);
1223 slot->tts_ops->release(slot);
1224 if (slot->tts_tupleDescriptor)
1225 ReleaseTupleDesc(slot->tts_tupleDescriptor);
1226 if (!TTS_FIXED(slot))
1228 if (slot->tts_values)
1229 pfree(slot->tts_values);
1230 if (slot->tts_isnull)
1231 pfree(slot->tts_isnull);
1237 /* ----------------------------------------------------------------
1238 * tuple table slot accessor functions
1239 * ----------------------------------------------------------------
1242 /* --------------------------------
1243 * ExecSetSlotDescriptor
1245 * This function is used to set the tuple descriptor associated
1246 * with the slot's tuple. The passed descriptor must have lifespan
1247 * at least equal to the slot's. If it is a reference-counted descriptor
1248 * then the reference count is incremented for as long as the slot holds
1250 * --------------------------------
1253 ExecSetSlotDescriptor(TupleTableSlot *slot, /* slot to change */
1254 TupleDesc tupdesc) /* new tuple descriptor */
1256 Assert(!TTS_FIXED(slot));
1258 /* For safety, make sure slot is empty before changing it */
1259 ExecClearTuple(slot);
1262 * Release any old descriptor. Also release old Datum/isnull arrays if
1263 * present (we don't bother to check if they could be re-used).
1265 if (slot->tts_tupleDescriptor)
1266 ReleaseTupleDesc(slot->tts_tupleDescriptor);
1268 if (slot->tts_values)
1269 pfree(slot->tts_values);
1270 if (slot->tts_isnull)
1271 pfree(slot->tts_isnull);
1274 * Install the new descriptor; if it's refcounted, bump its refcount.
1276 slot->tts_tupleDescriptor = tupdesc;
1277 PinTupleDesc(tupdesc);
1280 * Allocate Datum/isnull arrays of the appropriate size. These must have
1281 * the same lifetime as the slot, so allocate in the slot's own context.
1283 slot->tts_values = (Datum *)
1284 MemoryContextAlloc(slot->tts_mcxt, tupdesc->natts * sizeof(Datum));
1285 slot->tts_isnull = (bool *)
1286 MemoryContextAlloc(slot->tts_mcxt, tupdesc->natts * sizeof(bool));
1289 /* --------------------------------
1290 * ExecStoreHeapTuple
1292 * This function is used to store an on-the-fly physical tuple into a specified
1293 * slot in the tuple table.
1295 * tuple: tuple to store
1296 * slot: TTSOpsHeapTuple type slot to store it in
1297 * shouldFree: true if ExecClearTuple should pfree() the tuple
1300 * shouldFree is normally set 'true' for tuples constructed on-the-fly. But it
1301 * can be 'false' when the referenced tuple is held in a tuple table slot
1302 * belonging to a lower-level executor Proc node. In this case the lower-level
1303 * slot retains ownership and responsibility for eventually releasing the
1304 * tuple. When this method is used, we must be certain that the upper-level
1305 * Proc node will lose interest in the tuple sooner than the lower-level one
1306 * does! If you're not certain, copy the lower-level tuple with heap_copytuple
1307 * and let the upper-level table slot assume ownership of the copy!
1309 * Return value is just the passed-in slot pointer.
1311 * If the target slot is not guaranteed to be TTSOpsHeapTuple type slot, use
1312 * the, more expensive, ExecForceStoreHeapTuple().
1313 * --------------------------------
1316 ExecStoreHeapTuple(HeapTuple tuple,
1317 TupleTableSlot *slot,
1323 Assert(tuple != NULL);
1324 Assert(slot != NULL);
1325 Assert(slot->tts_tupleDescriptor != NULL);
1327 if (unlikely(!TTS_IS_HEAPTUPLE(slot)))
1328 elog(ERROR, "trying to store a heap tuple into wrong type of slot");
1329 tts_heap_store_tuple(slot, tuple, shouldFree);
1331 slot->tts_tableOid = tuple->t_tableOid;
1336 /* --------------------------------
1337 * ExecStoreBufferHeapTuple
1339 * This function is used to store an on-disk physical tuple from a buffer
1340 * into a specified slot in the tuple table.
1342 * tuple: tuple to store
1343 * slot: TTSOpsBufferHeapTuple type slot to store it in
1344 * buffer: disk buffer if tuple is in a disk page, else InvalidBuffer
1346 * The tuple table code acquires a pin on the buffer which is held until the
1347 * slot is cleared, so that the tuple won't go away on us.
1349 * Return value is just the passed-in slot pointer.
1351 * If the target slot is not guaranteed to be TTSOpsBufferHeapTuple type slot,
1352 * use the, more expensive, ExecForceStoreHeapTuple().
1353 * --------------------------------
1356 ExecStoreBufferHeapTuple(HeapTuple tuple,
1357 TupleTableSlot *slot,
1363 Assert(tuple != NULL);
1364 Assert(slot != NULL);
1365 Assert(slot->tts_tupleDescriptor != NULL);
1366 Assert(BufferIsValid(buffer));
1368 if (unlikely(!TTS_IS_BUFFERTUPLE(slot)))
1369 elog(ERROR, "trying to store an on-disk heap tuple into wrong type of slot");
1370 tts_buffer_heap_store_tuple(slot, tuple, buffer, false);
1372 slot->tts_tableOid = tuple->t_tableOid;
1378 * Like ExecStoreBufferHeapTuple, but transfer an existing pin from the caller
1379 * to the slot, i.e. the caller doesn't need to, and may not, release the pin.
1382 ExecStorePinnedBufferHeapTuple(HeapTuple tuple,
1383 TupleTableSlot *slot,
1389 Assert(tuple != NULL);
1390 Assert(slot != NULL);
1391 Assert(slot->tts_tupleDescriptor != NULL);
1392 Assert(BufferIsValid(buffer));
1394 if (unlikely(!TTS_IS_BUFFERTUPLE(slot)))
1395 elog(ERROR, "trying to store an on-disk heap tuple into wrong type of slot");
1396 tts_buffer_heap_store_tuple(slot, tuple, buffer, true);
1398 slot->tts_tableOid = tuple->t_tableOid;
1404 * Store a minimal tuple into TTSOpsMinimalTuple type slot.
1406 * If the target slot is not guaranteed to be TTSOpsMinimalTuple type slot,
1407 * use the, more expensive, ExecForceStoreMinimalTuple().
1410 ExecStoreMinimalTuple(MinimalTuple mtup,
1411 TupleTableSlot *slot,
1417 Assert(mtup != NULL);
1418 Assert(slot != NULL);
1419 Assert(slot->tts_tupleDescriptor != NULL);
1421 if (unlikely(!TTS_IS_MINIMALTUPLE(slot)))
1422 elog(ERROR, "trying to store a minimal tuple into wrong type of slot");
1423 tts_minimal_store_tuple(slot, mtup, shouldFree);
1429 * Store a HeapTuple into any kind of slot, performing conversion if
1433 ExecForceStoreHeapTuple(HeapTuple tuple,
1434 TupleTableSlot *slot,
1437 if (TTS_IS_HEAPTUPLE(slot))
1439 ExecStoreHeapTuple(tuple, slot, shouldFree);
1441 else if (TTS_IS_BUFFERTUPLE(slot))
1443 MemoryContext oldContext;
1444 BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
1446 ExecClearTuple(slot);
1447 slot->tts_flags |= TTS_FLAG_SHOULDFREE;
1448 slot->tts_flags &= ~TTS_FLAG_EMPTY;
1449 oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
1450 bslot->base.tuple = heap_copytuple(tuple);
1451 MemoryContextSwitchTo(oldContext);
1458 ExecClearTuple(slot);
1459 heap_deform_tuple(tuple, slot->tts_tupleDescriptor,
1460 slot->tts_values, slot->tts_isnull);
1461 ExecStoreVirtualTuple(slot);
1465 ExecMaterializeSlot(slot);
1472 * Store a MinimalTuple into any kind of slot, performing conversion if
1476 ExecForceStoreMinimalTuple(MinimalTuple mtup,
1477 TupleTableSlot *slot,
1480 if (TTS_IS_MINIMALTUPLE(slot))
1482 tts_minimal_store_tuple(slot, mtup, shouldFree);
1488 ExecClearTuple(slot);
1490 htup.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
1491 htup.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);
1492 heap_deform_tuple(&htup, slot->tts_tupleDescriptor,
1493 slot->tts_values, slot->tts_isnull);
1494 ExecStoreVirtualTuple(slot);
1498 ExecMaterializeSlot(slot);
1504 /* --------------------------------
1505 * ExecStoreVirtualTuple
1506 * Mark a slot as containing a virtual tuple.
1508 * The protocol for loading a slot with virtual tuple data is:
1509 * * Call ExecClearTuple to mark the slot empty.
1510 * * Store data into the Datum/isnull arrays.
1511 * * Call ExecStoreVirtualTuple to mark the slot valid.
1512 * This is a bit unclean but it avoids one round of data copying.
1513 * --------------------------------
1516 ExecStoreVirtualTuple(TupleTableSlot *slot)
1521 Assert(slot != NULL);
1522 Assert(slot->tts_tupleDescriptor != NULL);
1523 Assert(TTS_EMPTY(slot));
1525 slot->tts_flags &= ~TTS_FLAG_EMPTY;
1526 slot->tts_nvalid = slot->tts_tupleDescriptor->natts;
1531 /* --------------------------------
1532 * ExecStoreAllNullTuple
1533 * Set up the slot to contain a null in every column.
1535 * At first glance this might sound just like ExecClearTuple, but it's
1536 * entirely different: the slot ends up full, not empty.
1537 * --------------------------------
1540 ExecStoreAllNullTuple(TupleTableSlot *slot)
1545 Assert(slot != NULL);
1546 Assert(slot->tts_tupleDescriptor != NULL);
1548 /* Clear any old contents */
1549 ExecClearTuple(slot);
1552 * Fill all the columns of the virtual tuple with nulls
1554 MemSet(slot->tts_values, 0,
1555 slot->tts_tupleDescriptor->natts * sizeof(Datum));
1556 memset(slot->tts_isnull, true,
1557 slot->tts_tupleDescriptor->natts * sizeof(bool));
1559 return ExecStoreVirtualTuple(slot);
1563 * Store a HeapTuple in datum form, into a slot. That always requires
1564 * deforming it and storing it in virtual form.
1566 * Until the slot is materialized, the contents of the slot depend on the
1570 ExecStoreHeapTupleDatum(Datum data, TupleTableSlot *slot)
1572 HeapTupleData tuple = {0};
1575 td = DatumGetHeapTupleHeader(data);
1577 tuple.t_len = HeapTupleHeaderGetDatumLength(td);
1578 tuple.t_self = td->t_ctid;
1581 ExecClearTuple(slot);
1583 heap_deform_tuple(&tuple, slot->tts_tupleDescriptor,
1584 slot->tts_values, slot->tts_isnull);
1585 ExecStoreVirtualTuple(slot);
1589 * ExecFetchSlotHeapTuple - fetch HeapTuple representing the slot's content
1591 * The returned HeapTuple represents the slot's content as closely as
1594 * If materialize is true, the contents of the slots will be made independent
1595 * from the underlying storage (i.e. all buffer pins are released, memory is
1596 * allocated in the slot's context).
1598 * If shouldFree is not-NULL it'll be set to true if the returned tuple has
1599 * been allocated in the calling memory context, and must be freed by the
1600 * caller (via explicit pfree() or a memory context reset).
1602 * NB: If materialize is true, modifications of the returned tuple are
1603 * allowed. But it depends on the type of the slot whether such modifications
1604 * will also affect the slot's contents. While that is not the nicest
1605 * behaviour, all such modifications are in the process of being removed.
1608 ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
1613 Assert(slot != NULL);
1614 Assert(!TTS_EMPTY(slot));
1616 /* Materialize the tuple so that the slot "owns" it, if requested. */
1618 slot->tts_ops->materialize(slot);
1620 if (slot->tts_ops->get_heap_tuple == NULL)
1624 return slot->tts_ops->copy_heap_tuple(slot);
1629 *shouldFree = false;
1630 return slot->tts_ops->get_heap_tuple(slot);
1634 /* --------------------------------
1635 * ExecFetchSlotMinimalTuple
1636 * Fetch the slot's minimal physical tuple.
1638 * If the given tuple table slot can hold a minimal tuple, indicated by a
1639 * non-NULL get_minimal_tuple callback, the function returns the minimal
1640 * tuple returned by that callback. It assumes that the minimal tuple
1641 * returned by the callback is "owned" by the slot i.e. the slot is
1642 * responsible for freeing the memory consumed by the tuple. Hence it sets
1643 * *shouldFree to false, indicating that the caller should not free the
1644 * memory consumed by the minimal tuple. In this case the returned minimal
1645 * tuple should be considered as read-only.
1647 * If that callback is not supported, it calls copy_minimal_tuple callback
1648 * which is expected to return a copy of minimal tuple representing the
1649 * contents of the slot. In this case *shouldFree is set to true,
1650 * indicating the caller that it should free the memory consumed by the
1651 * minimal tuple. In this case the returned minimal tuple may be written
1653 * --------------------------------
1656 ExecFetchSlotMinimalTuple(TupleTableSlot *slot,
1662 Assert(slot != NULL);
1663 Assert(!TTS_EMPTY(slot));
1665 if (slot->tts_ops->get_minimal_tuple)
1668 *shouldFree = false;
1669 return slot->tts_ops->get_minimal_tuple(slot);
1675 return slot->tts_ops->copy_minimal_tuple(slot);
1679 /* --------------------------------
1680 * ExecFetchSlotHeapTupleDatum
1681 * Fetch the slot's tuple as a composite-type Datum.
1683 * The result is always freshly palloc'd in the caller's memory context.
1684 * --------------------------------
1687 ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot)
1694 /* Fetch slot's contents in regular-physical-tuple form */
1695 tup = ExecFetchSlotHeapTuple(slot, false, &shouldFree);
1696 tupdesc = slot->tts_tupleDescriptor;
1698 /* Convert to Datum form */
1699 ret = heap_copy_tuple_as_datum(tup, tupdesc);
1707 /* ----------------------------------------------------------------
1708 * convenience initialization routines
1709 * ----------------------------------------------------------------
1713 * ExecInitResultTypeTL
1715 * Initialize result type, using the plan node's targetlist.
1719 ExecInitResultTypeTL(PlanState *planstate)
1721 TupleDesc tupDesc = ExecTypeFromTL(planstate->plan->targetlist);
1723 planstate->ps_ResultTupleDesc = tupDesc;
1726 /* --------------------------------
1727 * ExecInit{Result,Scan,Extra}TupleSlot[TL]
1729 * These are convenience routines to initialize the specified slot
1730 * in nodes inheriting the appropriate state. ExecInitExtraTupleSlot
1731 * is used for initializing special-purpose slots.
1732 * --------------------------------
1736 * ExecInitResultTupleSlotTL
1738 * Initialize result tuple slot, using the tuple descriptor previously
1739 * computed with ExecInitResultTypeTL().
1743 ExecInitResultSlot(PlanState *planstate, const TupleTableSlotOps *tts_ops)
1745 TupleTableSlot *slot;
1747 slot = ExecAllocTableSlot(&planstate->state->es_tupleTable,
1748 planstate->ps_ResultTupleDesc, tts_ops);
1749 planstate->ps_ResultTupleSlot = slot;
1751 planstate->resultopsfixed = planstate->ps_ResultTupleDesc != NULL;
1752 planstate->resultops = tts_ops;
1753 planstate->resultopsset = true;
1757 * ExecInitResultTupleSlotTL
1759 * Initialize result tuple slot, using the plan node's targetlist.
1763 ExecInitResultTupleSlotTL(PlanState *planstate,
1764 const TupleTableSlotOps *tts_ops)
1766 ExecInitResultTypeTL(planstate);
1767 ExecInitResultSlot(planstate, tts_ops);
1771 * ExecInitScanTupleSlot
1775 ExecInitScanTupleSlot(EState *estate, ScanState *scanstate,
1776 TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
1778 scanstate->ss_ScanTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable,
1779 tupledesc, tts_ops);
1780 scanstate->ps.scandesc = tupledesc;
1781 scanstate->ps.scanopsfixed = tupledesc != NULL;
1782 scanstate->ps.scanops = tts_ops;
1783 scanstate->ps.scanopsset = true;
1787 * ExecInitExtraTupleSlot
1789 * Return a newly created slot. If tupledesc is non-NULL the slot will have
1790 * that as its fixed tupledesc. Otherwise the caller needs to use
1791 * ExecSetSlotDescriptor() to set the descriptor before use.
1795 ExecInitExtraTupleSlot(EState *estate,
1796 TupleDesc tupledesc,
1797 const TupleTableSlotOps *tts_ops)
1799 return ExecAllocTableSlot(&estate->es_tupleTable, tupledesc, tts_ops);
1803 * ExecInitNullTupleSlot
1805 * Build a slot containing an all-nulls tuple of the given type.
1806 * This is used as a substitute for an input tuple when performing an
1811 ExecInitNullTupleSlot(EState *estate, TupleDesc tupType,
1812 const TupleTableSlotOps *tts_ops)
1814 TupleTableSlot *slot = ExecInitExtraTupleSlot(estate, tupType, tts_ops);
1816 return ExecStoreAllNullTuple(slot);
1819 /* ---------------------------------------------------------------
1820 * Routines for setting/accessing attributes in a slot.
1821 * ---------------------------------------------------------------
1825 * Fill in missing values for a TupleTableSlot.
1827 * This is only exposed because it's needed for JIT compiled tuple
1828 * deforming. That exception aside, there should be no callers outside of this
1832 slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, int lastAttNum)
1834 AttrMissing *attrmiss = NULL;
1836 if (slot->tts_tupleDescriptor->constr)
1837 attrmiss = slot->tts_tupleDescriptor->constr->missing;
1841 /* no missing values array at all, so just fill everything in as NULL */
1842 memset(slot->tts_values + startAttNum, 0,
1843 (lastAttNum - startAttNum) * sizeof(Datum));
1844 memset(slot->tts_isnull + startAttNum, 1,
1845 (lastAttNum - startAttNum) * sizeof(bool));
1851 /* if there is a missing values array we must process them one by one */
1852 for (missattnum = startAttNum;
1853 missattnum < lastAttNum;
1856 slot->tts_values[missattnum] = attrmiss[missattnum].am_value;
1857 slot->tts_isnull[missattnum] = !attrmiss[missattnum].am_present;
1864 * slot_getsomeattrs_int - workhorse for slot_getsomeattrs()
1867 slot_getsomeattrs_int(TupleTableSlot *slot, int attnum)
1869 /* Check for caller errors */
1870 Assert(slot->tts_nvalid < attnum); /* checked in slot_getsomeattrs */
1873 if (unlikely(attnum > slot->tts_tupleDescriptor->natts))
1874 elog(ERROR, "invalid attribute number %d", attnum);
1876 /* Fetch as many attributes as possible from the underlying tuple. */
1877 slot->tts_ops->getsomeattrs(slot, attnum);
1880 * If the underlying tuple doesn't have enough attributes, tuple
1881 * descriptor must have the missing attributes.
1883 if (unlikely(slot->tts_nvalid < attnum))
1885 slot_getmissingattrs(slot, slot->tts_nvalid, attnum);
1886 slot->tts_nvalid = attnum;
1890 /* ----------------------------------------------------------------
1893 * Generate a tuple descriptor for the result tuple of a targetlist.
1894 * (A parse/plan tlist must be passed, not an ExprState tlist.)
1895 * Note that resjunk columns, if any, are included in the result.
1897 * Currently there are about 4 different places where we create
1898 * TupleDescriptors. They should all be merged, or perhaps
1899 * be rewritten to call BuildDesc().
1900 * ----------------------------------------------------------------
1903 ExecTypeFromTL(List *targetList)
1905 return ExecTypeFromTLInternal(targetList, false);
1908 /* ----------------------------------------------------------------
1909 * ExecCleanTypeFromTL
1911 * Same as above, but resjunk columns are omitted from the result.
1912 * ----------------------------------------------------------------
1915 ExecCleanTypeFromTL(List *targetList)
1917 return ExecTypeFromTLInternal(targetList, true);
1921 ExecTypeFromTLInternal(List *targetList, bool skipjunk)
1929 len = ExecCleanTargetListLength(targetList);
1931 len = ExecTargetListLength(targetList);
1932 typeInfo = CreateTemplateTupleDesc(len);
1934 foreach(l, targetList)
1936 TargetEntry *tle = lfirst(l);
1938 if (skipjunk && tle->resjunk)
1940 TupleDescInitEntry(typeInfo,
1943 exprType((Node *) tle->expr),
1944 exprTypmod((Node *) tle->expr),
1946 TupleDescInitEntryCollation(typeInfo,
1948 exprCollation((Node *) tle->expr));
1956 * ExecTypeFromExprList - build a tuple descriptor from a list of Exprs
1958 * This is roughly like ExecTypeFromTL, but we work from bare expressions
1959 * not TargetEntrys. No names are attached to the tupledesc's columns.
1962 ExecTypeFromExprList(List *exprList)
1968 typeInfo = CreateTemplateTupleDesc(list_length(exprList));
1970 foreach(lc, exprList)
1972 Node *e = lfirst(lc);
1974 TupleDescInitEntry(typeInfo,
1980 TupleDescInitEntryCollation(typeInfo,
1990 * ExecTypeSetColNames - set column names in a TupleDesc
1992 * Column names must be provided as an alias list (list of String nodes).
1994 * For some callers, the supplied tupdesc has a named rowtype (not RECORD)
1995 * and it is moderately likely that the alias list matches the column names
1996 * already present in the tupdesc. If we do change any column names then
1997 * we must reset the tupdesc's type to anonymous RECORD; but we avoid doing
1998 * so if no names change.
2001 ExecTypeSetColNames(TupleDesc typeInfo, List *namesList)
2003 bool modified = false;
2007 foreach(lc, namesList)
2009 char *cname = strVal(lfirst(lc));
2010 Form_pg_attribute attr;
2012 /* Guard against too-long names list */
2013 if (colno >= typeInfo->natts)
2015 attr = TupleDescAttr(typeInfo, colno);
2018 /* Ignore empty aliases (these must be for dropped columns) */
2019 if (cname[0] == '\0')
2022 /* Change tupdesc only if alias is actually different */
2023 if (strcmp(cname, NameStr(attr->attname)) != 0)
2025 namestrcpy(&(attr->attname), cname);
2030 /* If we modified the tupdesc, it's now a new record type */
2033 typeInfo->tdtypeid = RECORDOID;
2034 typeInfo->tdtypmod = -1;
2039 * BlessTupleDesc - make a completed tuple descriptor useful for SRFs
2041 * Rowtype Datums returned by a function must contain valid type information.
2042 * This happens "for free" if the tupdesc came from a relcache entry, but
2043 * not if we have manufactured a tupdesc for a transient RECORD datatype.
2044 * In that case we have to notify typcache.c of the existence of the type.
2047 BlessTupleDesc(TupleDesc tupdesc)
2049 if (tupdesc->tdtypeid == RECORDOID &&
2050 tupdesc->tdtypmod < 0)
2051 assign_record_type_typmod(tupdesc);
2053 return tupdesc; /* just for notational convenience */
2057 * TupleDescGetAttInMetadata - Build an AttInMetadata structure based on the
2058 * supplied TupleDesc. AttInMetadata can be used in conjunction with C strings
2059 * to produce a properly formed tuple.
2062 TupleDescGetAttInMetadata(TupleDesc tupdesc)
2064 int natts = tupdesc->natts;
2068 FmgrInfo *attinfuncinfo;
2071 AttInMetadata *attinmeta;
2073 attinmeta = (AttInMetadata *) palloc(sizeof(AttInMetadata));
2075 /* "Bless" the tupledesc so that we can make rowtype datums with it */
2076 attinmeta->tupdesc = BlessTupleDesc(tupdesc);
2079 * Gather info needed later to call the "in" function for each attribute
2081 attinfuncinfo = (FmgrInfo *) palloc0(natts * sizeof(FmgrInfo));
2082 attioparams = (Oid *) palloc0(natts * sizeof(Oid));
2083 atttypmods = (int32 *) palloc0(natts * sizeof(int32));
2085 for (i = 0; i < natts; i++)
2087 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
2089 /* Ignore dropped attributes */
2090 if (!att->attisdropped)
2092 atttypeid = att->atttypid;
2093 getTypeInputInfo(atttypeid, &attinfuncid, &attioparams[i]);
2094 fmgr_info(attinfuncid, &attinfuncinfo[i]);
2095 atttypmods[i] = att->atttypmod;
2098 attinmeta->attinfuncs = attinfuncinfo;
2099 attinmeta->attioparams = attioparams;
2100 attinmeta->atttypmods = atttypmods;
2106 * BuildTupleFromCStrings - build a HeapTuple given user data in C string form.
2107 * values is an array of C strings, one for each attribute of the return tuple.
2108 * A NULL string pointer indicates we want to create a NULL field.
2111 BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
2113 TupleDesc tupdesc = attinmeta->tupdesc;
2114 int natts = tupdesc->natts;
2120 dvalues = (Datum *) palloc(natts * sizeof(Datum));
2121 nulls = (bool *) palloc(natts * sizeof(bool));
2124 * Call the "in" function for each non-dropped attribute, even for nulls,
2125 * to support domains.
2127 for (i = 0; i < natts; i++)
2129 if (!TupleDescAttr(tupdesc, i)->attisdropped)
2131 /* Non-dropped attributes */
2132 dvalues[i] = InputFunctionCall(&attinmeta->attinfuncs[i],
2134 attinmeta->attioparams[i],
2135 attinmeta->atttypmods[i]);
2136 if (values[i] != NULL)
2143 /* Handle dropped attributes by setting to NULL */
2144 dvalues[i] = (Datum) 0;
2152 tuple = heap_form_tuple(tupdesc, dvalues, nulls);
2155 * Release locally palloc'd space. XXX would probably be good to pfree
2156 * values of pass-by-reference datums, as well.
2165 * HeapTupleHeaderGetDatum - convert a HeapTupleHeader pointer to a Datum.
2167 * This must *not* get applied to an on-disk tuple; the tuple should be
2168 * freshly made by heap_form_tuple or some wrapper routine for it (such as
2169 * BuildTupleFromCStrings). Be sure also that the tupledesc used to build
2170 * the tuple has a properly "blessed" rowtype.
2172 * Formerly this was a macro equivalent to PointerGetDatum, relying on the
2173 * fact that heap_form_tuple fills in the appropriate tuple header fields
2174 * for a composite Datum. However, we now require that composite Datums not
2175 * contain any external TOAST pointers. We do not want heap_form_tuple itself
2176 * to enforce that; more specifically, the rule applies only to actual Datums
2177 * and not to HeapTuple structures. Therefore, HeapTupleHeaderGetDatum is
2178 * now a function that detects whether there are externally-toasted fields
2179 * and constructs a new tuple with inlined fields if so. We still need
2180 * heap_form_tuple to insert the Datum header fields, because otherwise this
2181 * code would have no way to obtain a tupledesc for the tuple.
2183 * Note that if we do build a new tuple, it's palloc'd in the current
2184 * memory context. Beware of code that changes context between the initial
2185 * heap_form_tuple/etc call and calling HeapTuple(Header)GetDatum.
2187 * For performance-critical callers, it could be worthwhile to take extra
2188 * steps to ensure that there aren't TOAST pointers in the output of
2189 * heap_form_tuple to begin with. It's likely however that the costs of the
2190 * typcache lookup and tuple disassembly/reassembly are swamped by TOAST
2191 * dereference costs, so that the benefits of such extra effort would be
2194 * XXX it would likely be better to create wrapper functions that produce
2195 * a composite Datum from the field values in one step. However, there's
2196 * enough code using the existing APIs that we couldn't get rid of this
2197 * hack anytime soon.
2200 HeapTupleHeaderGetDatum(HeapTupleHeader tuple)
2205 /* No work if there are no external TOAST pointers in the tuple */
2206 if (!HeapTupleHeaderHasExternal(tuple))
2207 return PointerGetDatum(tuple);
2209 /* Use the type data saved by heap_form_tuple to look up the rowtype */
2210 tupDesc = lookup_rowtype_tupdesc(HeapTupleHeaderGetTypeId(tuple),
2211 HeapTupleHeaderGetTypMod(tuple));
2213 /* And do the flattening */
2214 result = toast_flatten_tuple_to_datum(tuple,
2215 HeapTupleHeaderGetDatumLength(tuple),
2218 ReleaseTupleDesc(tupDesc);
2225 * Functions for sending tuples to the frontend (or other specified destination)
2226 * as though it is a SELECT result. These are used by utility commands that
2227 * need to project directly to the destination and don't need or want full
2228 * table function capability. Currently used by EXPLAIN and SHOW ALL.
2231 begin_tup_output_tupdesc(DestReceiver *dest,
2233 const TupleTableSlotOps *tts_ops)
2235 TupOutputState *tstate;
2237 tstate = (TupOutputState *) palloc(sizeof(TupOutputState));
2239 tstate->slot = MakeSingleTupleTableSlot(tupdesc, tts_ops);
2240 tstate->dest = dest;
2242 tstate->dest->rStartup(tstate->dest, (int) CMD_SELECT, tupdesc);
2248 * write a single tuple
2251 do_tup_output(TupOutputState *tstate, Datum *values, bool *isnull)
2253 TupleTableSlot *slot = tstate->slot;
2254 int natts = slot->tts_tupleDescriptor->natts;
2256 /* make sure the slot is clear */
2257 ExecClearTuple(slot);
2260 memcpy(slot->tts_values, values, natts * sizeof(Datum));
2261 memcpy(slot->tts_isnull, isnull, natts * sizeof(bool));
2263 /* mark slot as containing a virtual tuple */
2264 ExecStoreVirtualTuple(slot);
2266 /* send the tuple to the receiver */
2267 (void) tstate->dest->receiveSlot(slot, tstate->dest);
2270 ExecClearTuple(slot);
2274 * write a chunk of text, breaking at newline characters
2276 * Should only be used with a single-TEXT-attribute tupdesc.
2279 do_text_output_multiline(TupOutputState *tstate, const char *txt)
2282 bool isnull[1] = {false};
2289 eol = strchr(txt, '\n');
2301 values[0] = PointerGetDatum(cstring_to_text_with_len(txt, len));
2302 do_tup_output(tstate, values, isnull);
2303 pfree(DatumGetPointer(values[0]));
2309 end_tup_output(TupOutputState *tstate)
2311 tstate->dest->rShutdown(tstate->dest);
2312 /* note that destroying the dest is not ours to do */
2313 ExecDropSingleTupleTableSlot(tstate->slot);