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