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