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