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