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