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