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, bool support_cstring);
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 884261 : tts_virtual_init(TupleTableSlot *slot)
99 : {
100 884261 : }
101 :
102 : static void
103 863884 : tts_virtual_release(TupleTableSlot *slot)
104 : {
105 863884 : }
106 :
107 : static void
108 61439405 : tts_virtual_clear(TupleTableSlot *slot)
109 : {
110 61439405 : if (unlikely(TTS_SHOULDFREE(slot)))
111 : {
112 1208710 : VirtualTupleTableSlot *vslot = (VirtualTupleTableSlot *) slot;
113 :
114 1208710 : pfree(vslot->data);
115 1208710 : vslot->data = NULL;
116 :
117 1208710 : slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
118 : }
119 :
120 61439405 : slot->tts_nvalid = 0;
121 61439405 : slot->tts_flags |= TTS_FLAG_EMPTY;
122 61439405 : ItemPointerSetInvalid(&slot->tts_tid);
123 61439405 : }
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 8 : tts_virtual_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
142 : {
143 : Assert(!TTS_EMPTY(slot));
144 :
145 8 : 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 3906196 : tts_virtual_materialize(TupleTableSlot *slot)
177 : {
178 3906196 : VirtualTupleTableSlot *vslot = (VirtualTupleTableSlot *) slot;
179 3906196 : TupleDesc desc = slot->tts_tupleDescriptor;
180 3906196 : Size sz = 0;
181 : char *data;
182 :
183 : /* already materialized */
184 3906196 : if (TTS_SHOULDFREE(slot))
185 234311 : return;
186 :
187 : /* compute size of memory required */
188 10415801 : for (int natt = 0; natt < desc->natts; natt++)
189 : {
190 6743916 : CompactAttribute *att = TupleDescCompactAttr(desc, natt);
191 : Datum val;
192 :
193 6743916 : if (att->attbyval || slot->tts_isnull[natt])
194 5271388 : continue;
195 :
196 1472528 : val = slot->tts_values[natt];
197 :
198 2594543 : if (att->attlen == -1 &&
199 1122015 : 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 1472528 : sz = att_nominal_alignby(sz, att->attalignby);
211 1472528 : sz = att_addlength_datum(sz, att->attlen, val);
212 : }
213 : }
214 :
215 : /* all data is byval */
216 3671885 : if (sz == 0)
217 2463064 : return;
218 :
219 : /* allocate memory */
220 1208821 : vslot->data = data = MemoryContextAlloc(slot->tts_mcxt, sz);
221 1208821 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
222 :
223 : /* and copy all attributes into the pre-allocated space */
224 4695366 : for (int natt = 0; natt < desc->natts; natt++)
225 : {
226 3486545 : CompactAttribute *att = TupleDescCompactAttr(desc, natt);
227 : Datum val;
228 :
229 3486545 : if (att->attbyval || slot->tts_isnull[natt])
230 2014017 : continue;
231 :
232 1472528 : val = slot->tts_values[natt];
233 :
234 2594543 : if (att->attlen == -1 &&
235 1122015 : 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 1472528 : Size data_length = 0;
256 :
257 1472528 : data = (char *) att_nominal_alignby(data, att->attalignby);
258 1472528 : data_length = att_addlength_datum(data_length, att->attlen, val);
259 :
260 1472528 : memcpy(data, DatumGetPointer(val), data_length);
261 :
262 1472528 : slot->tts_values[natt] = PointerGetDatum(data);
263 1472528 : data += data_length;
264 : }
265 : }
266 : }
267 :
268 : static void
269 91344 : tts_virtual_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
270 : {
271 91344 : TupleDesc srcdesc = srcslot->tts_tupleDescriptor;
272 :
273 91344 : tts_virtual_clear(dstslot);
274 :
275 91344 : slot_getallattrs(srcslot);
276 :
277 188947 : for (int natt = 0; natt < srcdesc->natts; natt++)
278 : {
279 97603 : dstslot->tts_values[natt] = srcslot->tts_values[natt];
280 97603 : dstslot->tts_isnull[natt] = srcslot->tts_isnull[natt];
281 : }
282 :
283 91344 : dstslot->tts_nvalid = srcdesc->natts;
284 91344 : dstslot->tts_flags &= ~TTS_FLAG_EMPTY;
285 :
286 : /* make sure storage doesn't depend on external memory */
287 91344 : tts_virtual_materialize(dstslot);
288 91344 : }
289 :
290 : static HeapTuple
291 10281021 : tts_virtual_copy_heap_tuple(TupleTableSlot *slot)
292 : {
293 : Assert(!TTS_EMPTY(slot));
294 :
295 20562042 : return heap_form_tuple(slot->tts_tupleDescriptor,
296 10281021 : slot->tts_values,
297 10281021 : slot->tts_isnull);
298 : }
299 :
300 : static MinimalTuple
301 18992179 : tts_virtual_copy_minimal_tuple(TupleTableSlot *slot, Size extra)
302 : {
303 : Assert(!TTS_EMPTY(slot));
304 :
305 37984358 : return heap_form_minimal_tuple(slot->tts_tupleDescriptor,
306 18992179 : slot->tts_values,
307 18992179 : slot->tts_isnull,
308 : extra);
309 : }
310 :
311 :
312 : /*
313 : * TupleTableSlotOps implementation for HeapTupleTableSlot.
314 : */
315 :
316 : static void
317 2617997 : tts_heap_init(TupleTableSlot *slot)
318 : {
319 2617997 : }
320 :
321 : static void
322 2616998 : tts_heap_release(TupleTableSlot *slot)
323 : {
324 2616998 : }
325 :
326 : static void
327 7181610 : tts_heap_clear(TupleTableSlot *slot)
328 : {
329 7181610 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
330 :
331 : /* Free the memory for the heap tuple if it's allowed. */
332 7181610 : if (TTS_SHOULDFREE(slot))
333 : {
334 1123532 : heap_freetuple(hslot->tuple);
335 1123532 : slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
336 : }
337 :
338 7181610 : slot->tts_nvalid = 0;
339 7181610 : slot->tts_flags |= TTS_FLAG_EMPTY;
340 7181610 : ItemPointerSetInvalid(&slot->tts_tid);
341 7181610 : hslot->off = 0;
342 7181610 : hslot->tuple = NULL;
343 7181610 : }
344 :
345 : static void
346 7245281 : tts_heap_getsomeattrs(TupleTableSlot *slot, int natts)
347 : {
348 7245281 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
349 :
350 : Assert(!TTS_EMPTY(slot));
351 :
352 7245281 : slot_deform_heap_tuple(slot, hslot->tuple, &hslot->off, natts, false);
353 7245281 : }
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 2245809 : tts_heap_materialize(TupleTableSlot *slot)
400 : {
401 2245809 : 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 2245809 : if (TTS_SHOULDFREE(slot))
408 1123266 : return;
409 :
410 1122543 : 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 1122543 : slot->tts_nvalid = 0;
417 1122543 : hslot->off = 0;
418 :
419 1122543 : if (!hslot->tuple)
420 1122536 : hslot->tuple = heap_form_tuple(slot->tts_tupleDescriptor,
421 1122536 : slot->tts_values,
422 1122536 : 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 1122543 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
434 :
435 1122543 : 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 2244803 : tts_heap_get_heap_tuple(TupleTableSlot *slot)
453 : {
454 2244803 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
455 :
456 : Assert(!TTS_EMPTY(slot));
457 2244803 : if (!hslot->tuple)
458 0 : tts_heap_materialize(slot);
459 :
460 2244803 : 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 2722 : tts_heap_copy_minimal_tuple(TupleTableSlot *slot, Size extra)
477 : {
478 2722 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
479 :
480 2722 : if (!hslot->tuple)
481 21 : tts_heap_materialize(slot);
482 :
483 2722 : return minimal_tuple_from_heap_tuple(hslot->tuple, extra);
484 : }
485 :
486 : static void
487 3440481 : tts_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, bool shouldFree)
488 : {
489 3440481 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
490 :
491 3440481 : tts_heap_clear(slot);
492 :
493 3440481 : slot->tts_nvalid = 0;
494 3440481 : hslot->tuple = tuple;
495 3440481 : hslot->off = 0;
496 3440481 : slot->tts_flags &= ~(TTS_FLAG_EMPTY | TTS_FLAG_SHOULDFREE);
497 3440481 : slot->tts_tid = tuple->t_self;
498 :
499 3440481 : if (shouldFree)
500 1000 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
501 3440481 : }
502 :
503 :
504 : /*
505 : * TupleTableSlotOps implementation for MinimalTupleTableSlot.
506 : */
507 :
508 : static void
509 263770 : tts_minimal_init(TupleTableSlot *slot)
510 : {
511 263770 : 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 it's a heap tuple.
516 : */
517 263770 : mslot->tuple = &mslot->minhdr;
518 263770 : }
519 :
520 : static void
521 230749 : tts_minimal_release(TupleTableSlot *slot)
522 : {
523 230749 : }
524 :
525 : static void
526 51621287 : tts_minimal_clear(TupleTableSlot *slot)
527 : {
528 51621287 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
529 :
530 51621287 : if (TTS_SHOULDFREE(slot))
531 : {
532 8252718 : heap_free_minimal_tuple(mslot->mintuple);
533 8252718 : slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
534 : }
535 :
536 51621287 : slot->tts_nvalid = 0;
537 51621287 : slot->tts_flags |= TTS_FLAG_EMPTY;
538 51621287 : ItemPointerSetInvalid(&slot->tts_tid);
539 51621287 : mslot->off = 0;
540 51621287 : mslot->mintuple = NULL;
541 51621287 : }
542 :
543 : static void
544 38903498 : tts_minimal_getsomeattrs(TupleTableSlot *slot, int natts)
545 : {
546 38903498 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
547 :
548 : Assert(!TTS_EMPTY(slot));
549 :
550 38903498 : slot_deform_heap_tuple(slot, mslot->tuple, &mslot->off, natts, true);
551 38903498 : }
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 1023184 : tts_minimal_materialize(TupleTableSlot *slot)
588 : {
589 1023184 : 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 1023184 : if (TTS_SHOULDFREE(slot))
596 96017 : return;
597 :
598 927167 : 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 927167 : slot->tts_nvalid = 0;
605 927167 : mslot->off = 0;
606 :
607 927167 : if (!mslot->mintuple)
608 : {
609 871506 : mslot->mintuple = heap_form_minimal_tuple(slot->tts_tupleDescriptor,
610 871506 : slot->tts_values,
611 871506 : 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 55661 : mslot->mintuple = heap_copy_minimal_tuple(mslot->mintuple, 0);
623 : }
624 :
625 927167 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
626 :
627 : Assert(mslot->tuple == &mslot->minhdr);
628 :
629 927167 : mslot->minhdr.t_len = mslot->mintuple->t_len + MINIMAL_TUPLE_OFFSET;
630 927167 : mslot->minhdr.t_data = (HeapTupleHeader) ((char *) mslot->mintuple - MINIMAL_TUPLE_OFFSET);
631 :
632 927167 : MemoryContextSwitchTo(oldContext);
633 : }
634 :
635 : static void
636 773801 : tts_minimal_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
637 : {
638 : MemoryContext oldcontext;
639 : MinimalTuple mintuple;
640 :
641 773801 : oldcontext = MemoryContextSwitchTo(dstslot->tts_mcxt);
642 773801 : mintuple = ExecCopySlotMinimalTuple(srcslot);
643 773801 : MemoryContextSwitchTo(oldcontext);
644 :
645 773801 : ExecStoreMinimalTuple(mintuple, dstslot, true);
646 773801 : }
647 :
648 : static MinimalTuple
649 3363461 : tts_minimal_get_minimal_tuple(TupleTableSlot *slot)
650 : {
651 3363461 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
652 :
653 3363461 : if (!mslot->mintuple)
654 9142 : tts_minimal_materialize(slot);
655 :
656 3363461 : return mslot->mintuple;
657 : }
658 :
659 : static HeapTuple
660 491088 : tts_minimal_copy_heap_tuple(TupleTableSlot *slot)
661 : {
662 491088 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
663 :
664 491088 : if (!mslot->mintuple)
665 1079 : tts_minimal_materialize(slot);
666 :
667 491088 : return heap_tuple_from_minimal_tuple(mslot->mintuple);
668 : }
669 :
670 : static MinimalTuple
671 1858188 : tts_minimal_copy_minimal_tuple(TupleTableSlot *slot, Size extra)
672 : {
673 1858188 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
674 :
675 1858188 : if (!mslot->mintuple)
676 737258 : tts_minimal_materialize(slot);
677 :
678 1858188 : return heap_copy_minimal_tuple(mslot->mintuple, extra);
679 : }
680 :
681 : static void
682 43186595 : tts_minimal_store_tuple(TupleTableSlot *slot, MinimalTuple mtup, bool shouldFree)
683 : {
684 43186595 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
685 :
686 43186595 : tts_minimal_clear(slot);
687 :
688 : Assert(!TTS_SHOULDFREE(slot));
689 : Assert(TTS_EMPTY(slot));
690 :
691 43186595 : slot->tts_flags &= ~TTS_FLAG_EMPTY;
692 43186595 : slot->tts_nvalid = 0;
693 43186595 : mslot->off = 0;
694 :
695 43186595 : mslot->mintuple = mtup;
696 : Assert(mslot->tuple == &mslot->minhdr);
697 43186595 : mslot->minhdr.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
698 43186595 : 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 43186595 : if (shouldFree)
702 7326635 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
703 43186595 : }
704 :
705 :
706 : /*
707 : * TupleTableSlotOps implementation for BufferHeapTupleTableSlot.
708 : */
709 :
710 : static void
711 18504946 : tts_buffer_heap_init(TupleTableSlot *slot)
712 : {
713 18504946 : }
714 :
715 : static void
716 18494568 : tts_buffer_heap_release(TupleTableSlot *slot)
717 : {
718 18494568 : }
719 :
720 : static void
721 34942904 : tts_buffer_heap_clear(TupleTableSlot *slot)
722 : {
723 34942904 : 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 34942904 : if (TTS_SHOULDFREE(slot))
731 : {
732 : /* We should have unpinned the buffer while materializing the tuple. */
733 : Assert(!BufferIsValid(bslot->buffer));
734 :
735 10753133 : heap_freetuple(bslot->base.tuple);
736 10753133 : slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
737 : }
738 :
739 34942904 : if (BufferIsValid(bslot->buffer))
740 9945977 : ReleaseBuffer(bslot->buffer);
741 :
742 34942904 : slot->tts_nvalid = 0;
743 34942904 : slot->tts_flags |= TTS_FLAG_EMPTY;
744 34942904 : ItemPointerSetInvalid(&slot->tts_tid);
745 34942904 : bslot->base.tuple = NULL;
746 34942904 : bslot->base.off = 0;
747 34942904 : bslot->buffer = InvalidBuffer;
748 34942904 : }
749 :
750 : static void
751 90987233 : tts_buffer_heap_getsomeattrs(TupleTableSlot *slot, int natts)
752 : {
753 90987233 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
754 :
755 : Assert(!TTS_EMPTY(slot));
756 :
757 90987233 : slot_deform_heap_tuple(slot, bslot->base.tuple, &bslot->base.off, natts, false);
758 90987233 : }
759 :
760 : static Datum
761 72784 : tts_buffer_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
762 : {
763 72784 : 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 72784 : 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 72784 : return heap_getsysattr(bslot->base.tuple, attnum,
777 : slot->tts_tupleDescriptor, isnull);
778 : }
779 :
780 : static bool
781 564 : tts_buffer_is_current_xact_tuple(TupleTableSlot *slot)
782 : {
783 564 : 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 564 : 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 564 : xmin = HeapTupleHeaderGetRawXmin(bslot->base.tuple->t_data);
799 :
800 564 : return TransactionIdIsCurrentTransactionId(xmin);
801 : }
802 :
803 : static void
804 23394290 : tts_buffer_heap_materialize(TupleTableSlot *slot)
805 : {
806 23394290 : 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 23394290 : if (TTS_SHOULDFREE(slot))
813 19769438 : return;
814 :
815 3624852 : 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 3624852 : bslot->base.off = 0;
822 3624852 : slot->tts_nvalid = 0;
823 :
824 3624852 : 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 3386546 : bslot->base.tuple = heap_form_tuple(slot->tts_tupleDescriptor,
834 3386546 : slot->tts_values,
835 3386546 : slot->tts_isnull);
836 : }
837 : else
838 : {
839 238306 : 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 238306 : if (likely(BufferIsValid(bslot->buffer)))
846 238306 : ReleaseBuffer(bslot->buffer);
847 238306 : 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 3624852 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
858 :
859 3624852 : MemoryContextSwitchTo(oldContext);
860 : }
861 :
862 : static void
863 7326390 : tts_buffer_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
864 : {
865 7326390 : BufferHeapTupleTableSlot *bsrcslot = (BufferHeapTupleTableSlot *) srcslot;
866 7326390 : 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 7326390 : if (dstslot->tts_ops != srcslot->tts_ops ||
874 4378 : TTS_SHOULDFREE(srcslot) ||
875 4376 : !bsrcslot->base.tuple)
876 7322014 : {
877 : MemoryContext oldContext;
878 :
879 7322014 : ExecClearTuple(dstslot);
880 7322014 : dstslot->tts_flags &= ~TTS_FLAG_EMPTY;
881 7322014 : oldContext = MemoryContextSwitchTo(dstslot->tts_mcxt);
882 7322014 : bdstslot->base.tuple = ExecCopySlotHeapTuple(srcslot);
883 7322014 : dstslot->tts_flags |= TTS_FLAG_SHOULDFREE;
884 7322014 : MemoryContextSwitchTo(oldContext);
885 : }
886 : else
887 : {
888 : Assert(BufferIsValid(bsrcslot->buffer));
889 :
890 4376 : 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 4376 : memcpy(&bdstslot->base.tupdata, bdstslot->base.tuple, sizeof(HeapTupleData));
900 4376 : bdstslot->base.tuple = &bdstslot->base.tupdata;
901 : }
902 7326390 : }
903 :
904 : static HeapTuple
905 28114026 : tts_buffer_heap_get_heap_tuple(TupleTableSlot *slot)
906 : {
907 28114026 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
908 :
909 : Assert(!TTS_EMPTY(slot));
910 :
911 28114026 : if (!bslot->base.tuple)
912 0 : tts_buffer_heap_materialize(slot);
913 :
914 28114026 : return bslot->base.tuple;
915 : }
916 :
917 : static HeapTuple
918 7610691 : tts_buffer_heap_copy_heap_tuple(TupleTableSlot *slot)
919 : {
920 7610691 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
921 :
922 : Assert(!TTS_EMPTY(slot));
923 :
924 7610691 : if (!bslot->base.tuple)
925 0 : tts_buffer_heap_materialize(slot);
926 :
927 7610691 : return heap_copytuple(bslot->base.tuple);
928 : }
929 :
930 : static MinimalTuple
931 1872961 : tts_buffer_heap_copy_minimal_tuple(TupleTableSlot *slot, Size extra)
932 : {
933 1872961 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
934 :
935 : Assert(!TTS_EMPTY(slot));
936 :
937 1872961 : if (!bslot->base.tuple)
938 0 : tts_buffer_heap_materialize(slot);
939 :
940 1872961 : return minimal_tuple_from_heap_tuple(bslot->base.tuple, extra);
941 : }
942 :
943 : static inline void
944 108533653 : tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple,
945 : Buffer buffer, bool transfer_pin)
946 : {
947 108533653 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
948 :
949 108533653 : if (TTS_SHOULDFREE(slot))
950 : {
951 : /* materialized slot shouldn't have a buffer to release */
952 : Assert(!BufferIsValid(bslot->buffer));
953 :
954 239444 : heap_freetuple(bslot->base.tuple);
955 239444 : slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
956 : }
957 :
958 108533653 : slot->tts_flags &= ~TTS_FLAG_EMPTY;
959 108533653 : slot->tts_nvalid = 0;
960 108533653 : bslot->base.tuple = tuple;
961 108533653 : bslot->base.off = 0;
962 108533653 : 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 108533653 : if (bslot->buffer != buffer)
976 : {
977 13731888 : if (BufferIsValid(bslot->buffer))
978 3542242 : ReleaseBuffer(bslot->buffer);
979 :
980 13731888 : bslot->buffer = buffer;
981 :
982 13731888 : if (!transfer_pin && BufferIsValid(buffer))
983 12936355 : IncrBufferRefCount(buffer);
984 : }
985 94801765 : 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 2614042 : ReleaseBuffer(buffer);
992 : }
993 108533653 : }
994 :
995 : /*
996 : * slot_deform_heap_tuple
997 : * Given a TupleTableSlot, extract data from the slot's physical tuple
998 : * into its Datum/isnull arrays. Data is extracted up through the
999 : * reqnatts'th column. If there are insufficient attributes in the given
1000 : * tuple, then slot_getmissingattrs() is called to populate the
1001 : * remainder. If reqnatts is above the number of attributes in the
1002 : * slot's TupleDesc, an error is raised.
1003 : *
1004 : * This is essentially an incremental version of heap_deform_tuple:
1005 : * on each call we extract attributes up to the one needed, without
1006 : * re-computing information about previously extracted attributes.
1007 : * slot->tts_nvalid is the number of attributes already extracted.
1008 : *
1009 : * This is marked as always inline, so the different offp for different types
1010 : * of slots gets optimized away.
1011 : *
1012 : * support_cstring should be passed as a const to allow the compiler only
1013 : * emit code during inlining for cstring deforming when it's required.
1014 : * cstrings can exist in MinimalTuples, but not in HeapTuples.
1015 : */
1016 : static pg_attribute_always_inline void
1017 137136012 : slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
1018 : int reqnatts, bool support_cstring)
1019 : {
1020 : CompactAttribute *cattrs;
1021 : CompactAttribute *cattr;
1022 137136012 : TupleDesc tupleDesc = slot->tts_tupleDescriptor;
1023 137136012 : HeapTupleHeader tup = tuple->t_data;
1024 : size_t attnum;
1025 : int firstNonCacheOffsetAttr;
1026 : int firstNonGuaranteedAttr;
1027 : int firstNullAttr;
1028 : int natts;
1029 : Datum *values;
1030 : bool *isnull;
1031 : char *tp; /* ptr to tuple data */
1032 : uint32 off; /* offset in tuple data */
1033 :
1034 : /* Did someone forget to call TupleDescFinalize()? */
1035 : Assert(tupleDesc->firstNonCachedOffsetAttr >= 0);
1036 :
1037 137136012 : isnull = slot->tts_isnull;
1038 :
1039 : /*
1040 : * Some callers may form and deform tuples prior to NOT NULL constraints
1041 : * being checked. Here we'd like to optimize the case where we only need
1042 : * to fetch attributes before or up to the point where the attribute is
1043 : * guaranteed to exist in the tuple. We rely on the slot flag being set
1044 : * correctly to only enable this optimization when it's valid to do so.
1045 : * This optimization allows us to save fetching the number of attributes
1046 : * from the tuple and saves the additional cost of handling non-byval
1047 : * attrs.
1048 : */
1049 137136012 : firstNonGuaranteedAttr = Min(reqnatts, slot->tts_first_nonguaranteed);
1050 :
1051 137136012 : firstNonCacheOffsetAttr = tupleDesc->firstNonCachedOffsetAttr;
1052 :
1053 137136012 : if (HeapTupleHasNulls(tuple))
1054 : {
1055 35114756 : natts = HeapTupleHeaderGetNatts(tup);
1056 35114756 : tp = (char *) tup + MAXALIGN(offsetof(HeapTupleHeaderData, t_bits) +
1057 : BITMAPLEN(natts));
1058 :
1059 35114756 : natts = Min(natts, reqnatts);
1060 35114756 : if (natts > firstNonGuaranteedAttr)
1061 : {
1062 33071272 : uint8 *bp = tup->t_bits;
1063 :
1064 : /* Find the first NULL attr */
1065 33071272 : firstNullAttr = first_null_attr(bp, natts);
1066 :
1067 : /*
1068 : * And populate the isnull array for all attributes being fetched
1069 : * from the tuple.
1070 : */
1071 33071272 : populate_isnull_array(bp, natts, isnull);
1072 : }
1073 : else
1074 : {
1075 : /* Otherwise all required columns are guaranteed to exist */
1076 2043484 : firstNullAttr = natts;
1077 :
1078 : /*
1079 : * Check TupleDescFinalize() didn't get confused when setting
1080 : * firstNonGuaranteedAttr. There should never be a NULL in a
1081 : * guaranteed column.
1082 : */
1083 : Assert(first_null_attr(tup->t_bits, natts) >= firstNullAttr);
1084 : }
1085 : }
1086 : else
1087 : {
1088 102021256 : tp = (char *) tup + MAXALIGN(offsetof(HeapTupleHeaderData, t_bits));
1089 :
1090 : /*
1091 : * We only need to look at the tuple's natts if we need more than the
1092 : * guaranteed number of columns
1093 : */
1094 102021256 : if (reqnatts > firstNonGuaranteedAttr)
1095 97655613 : natts = Min(HeapTupleHeaderGetNatts(tup), reqnatts);
1096 : else
1097 : {
1098 : /* No need to access the number of attributes in the tuple */
1099 4365643 : natts = reqnatts;
1100 : }
1101 :
1102 : /* All attrs can be fetched without checking for NULLs */
1103 102021256 : firstNullAttr = natts;
1104 : }
1105 :
1106 137136012 : attnum = slot->tts_nvalid;
1107 137136012 : values = slot->tts_values;
1108 137136012 : slot->tts_nvalid = reqnatts;
1109 :
1110 : /*
1111 : * We store the tupleDesc's CompactAttribute array in 'cattrs' as gcc
1112 : * seems to be unwilling to optimize accessing the CompactAttribute
1113 : * element efficiently when accessing it via TupleDescCompactAttr().
1114 : */
1115 137136012 : cattrs = tupleDesc->compact_attrs;
1116 :
1117 : /* Ensure we calculated tp correctly */
1118 : Assert(tp == (char *) tup + tup->t_hoff);
1119 :
1120 137136012 : if (attnum < firstNonGuaranteedAttr)
1121 : {
1122 : int attlen;
1123 :
1124 : do
1125 : {
1126 47916230 : isnull[attnum] = false;
1127 47916230 : cattr = &cattrs[attnum];
1128 47916230 : attlen = cattr->attlen;
1129 :
1130 : /* We don't expect any non-byval types */
1131 47916230 : pg_assume(attlen > 0);
1132 : Assert(cattr->attbyval == true);
1133 :
1134 47916230 : off = cattr->attcacheoff;
1135 47916230 : values[attnum] = fetch_att_noerr(tp + off, true, attlen);
1136 47916230 : attnum++;
1137 47916230 : } while (attnum < firstNonGuaranteedAttr);
1138 :
1139 28486899 : off += attlen;
1140 :
1141 28486899 : if (attnum == reqnatts)
1142 6409127 : goto done;
1143 : }
1144 : else
1145 : {
1146 : /*
1147 : * We may be incrementally deforming the tuple, so set 'off' to the
1148 : * previously cached value. This may be 0, if the slot has just
1149 : * received a new tuple.
1150 : */
1151 108649113 : off = *offp;
1152 :
1153 : /* We expect *offp to be set to 0 when attnum == 0 */
1154 : Assert(off == 0 || attnum > 0);
1155 : }
1156 :
1157 : /* We can use attcacheoff up until the first NULL */
1158 130726885 : firstNonCacheOffsetAttr = Min(firstNonCacheOffsetAttr, firstNullAttr);
1159 :
1160 : /*
1161 : * Handle the portion of the tuple that we have cached the offset for up
1162 : * to the first NULL attribute. The offset is effectively fixed for
1163 : * these, so we can use the CompactAttribute's attcacheoff.
1164 : */
1165 130726885 : if (attnum < firstNonCacheOffsetAttr)
1166 : {
1167 : int attlen;
1168 :
1169 : do
1170 : {
1171 376828655 : isnull[attnum] = false;
1172 376828655 : cattr = &cattrs[attnum];
1173 376828655 : attlen = cattr->attlen;
1174 376828655 : off = cattr->attcacheoff;
1175 753657310 : values[attnum] = fetch_att_noerr(tp + off,
1176 376828655 : cattr->attbyval,
1177 : attlen);
1178 376828655 : attnum++;
1179 376828655 : } while (attnum < firstNonCacheOffsetAttr);
1180 :
1181 : /*
1182 : * Point the offset after the end of the last attribute with a cached
1183 : * offset. We expect the final cached offset attribute to have a
1184 : * fixed width, so just add the attlen to the attcacheoff
1185 : */
1186 : Assert(attlen > 0);
1187 113998936 : off += attlen;
1188 : }
1189 :
1190 : /*
1191 : * Handle any portion of the tuple that doesn't have a fixed offset up
1192 : * until the first NULL attribute. This loop only differs from the one
1193 : * after it by the NULL checks.
1194 : */
1195 166880386 : for (; attnum < firstNullAttr; attnum++)
1196 : {
1197 : int attlen;
1198 :
1199 36153501 : isnull[attnum] = false;
1200 36153501 : cattr = &cattrs[attnum];
1201 36153501 : attlen = cattr->attlen;
1202 :
1203 : /*
1204 : * Only emit the cstring-related code in align_fetch_then_add() when
1205 : * cstring support is needed. We assume support_cstring will be
1206 : * passed as a const to allow the compiler to eliminate this branch.
1207 : */
1208 36153501 : if (!support_cstring)
1209 21019453 : pg_assume(attlen > 0 || attlen == -1);
1210 :
1211 : /* align 'off', fetch the datum, and increment off beyond the datum */
1212 36153501 : values[attnum] = align_fetch_then_add(tp,
1213 : &off,
1214 36153501 : cattr->attbyval,
1215 : attlen,
1216 36153501 : cattr->attalignby);
1217 : }
1218 :
1219 : /*
1220 : * Now handle any remaining attributes in the tuple up to the requested
1221 : * attnum. This time, include NULL checks as we're now at the first NULL
1222 : * attribute.
1223 : */
1224 180116773 : for (; attnum < natts; attnum++)
1225 : {
1226 : int attlen;
1227 :
1228 49389888 : if (isnull[attnum])
1229 : {
1230 34593805 : values[attnum] = (Datum) 0;
1231 34593805 : continue;
1232 : }
1233 :
1234 14796083 : cattr = &cattrs[attnum];
1235 14796083 : attlen = cattr->attlen;
1236 :
1237 : /* As above, only emit cstring code when needed. */
1238 14796083 : if (!support_cstring)
1239 10725974 : pg_assume(attlen > 0 || attlen == -1);
1240 :
1241 : /* align 'off', fetch the datum, and increment off beyond the datum */
1242 14796083 : values[attnum] = align_fetch_then_add(tp,
1243 : &off,
1244 14796083 : cattr->attbyval,
1245 : attlen,
1246 14796083 : cattr->attalignby);
1247 : }
1248 :
1249 : /* Fetch any missing attrs and raise an error if reqnatts is invalid */
1250 130726885 : if (unlikely(attnum < reqnatts))
1251 : {
1252 : /*
1253 : * Cache the offset before calling the function to allow the compiler
1254 : * to implement a tail-call optimization
1255 : */
1256 4846 : *offp = off;
1257 4846 : slot_getmissingattrs(slot, attnum, reqnatts);
1258 4846 : return;
1259 : }
1260 130722039 : done:
1261 :
1262 : /* Save current offset for next execution */
1263 137131166 : *offp = off;
1264 : }
1265 :
1266 : const TupleTableSlotOps TTSOpsVirtual = {
1267 : .base_slot_size = sizeof(VirtualTupleTableSlot),
1268 : .init = tts_virtual_init,
1269 : .release = tts_virtual_release,
1270 : .clear = tts_virtual_clear,
1271 : .getsomeattrs = tts_virtual_getsomeattrs,
1272 : .getsysattr = tts_virtual_getsysattr,
1273 : .materialize = tts_virtual_materialize,
1274 : .is_current_xact_tuple = tts_virtual_is_current_xact_tuple,
1275 : .copyslot = tts_virtual_copyslot,
1276 :
1277 : /*
1278 : * A virtual tuple table slot can not "own" a heap tuple or a minimal
1279 : * tuple.
1280 : */
1281 : .get_heap_tuple = NULL,
1282 : .get_minimal_tuple = NULL,
1283 : .copy_heap_tuple = tts_virtual_copy_heap_tuple,
1284 : .copy_minimal_tuple = tts_virtual_copy_minimal_tuple
1285 : };
1286 :
1287 : const TupleTableSlotOps TTSOpsHeapTuple = {
1288 : .base_slot_size = sizeof(HeapTupleTableSlot),
1289 : .init = tts_heap_init,
1290 : .release = tts_heap_release,
1291 : .clear = tts_heap_clear,
1292 : .getsomeattrs = tts_heap_getsomeattrs,
1293 : .getsysattr = tts_heap_getsysattr,
1294 : .is_current_xact_tuple = tts_heap_is_current_xact_tuple,
1295 : .materialize = tts_heap_materialize,
1296 : .copyslot = tts_heap_copyslot,
1297 : .get_heap_tuple = tts_heap_get_heap_tuple,
1298 :
1299 : /* A heap tuple table slot can not "own" a minimal tuple. */
1300 : .get_minimal_tuple = NULL,
1301 : .copy_heap_tuple = tts_heap_copy_heap_tuple,
1302 : .copy_minimal_tuple = tts_heap_copy_minimal_tuple
1303 : };
1304 :
1305 : const TupleTableSlotOps TTSOpsMinimalTuple = {
1306 : .base_slot_size = sizeof(MinimalTupleTableSlot),
1307 : .init = tts_minimal_init,
1308 : .release = tts_minimal_release,
1309 : .clear = tts_minimal_clear,
1310 : .getsomeattrs = tts_minimal_getsomeattrs,
1311 : .getsysattr = tts_minimal_getsysattr,
1312 : .is_current_xact_tuple = tts_minimal_is_current_xact_tuple,
1313 : .materialize = tts_minimal_materialize,
1314 : .copyslot = tts_minimal_copyslot,
1315 :
1316 : /* A minimal tuple table slot can not "own" a heap tuple. */
1317 : .get_heap_tuple = NULL,
1318 : .get_minimal_tuple = tts_minimal_get_minimal_tuple,
1319 : .copy_heap_tuple = tts_minimal_copy_heap_tuple,
1320 : .copy_minimal_tuple = tts_minimal_copy_minimal_tuple
1321 : };
1322 :
1323 : const TupleTableSlotOps TTSOpsBufferHeapTuple = {
1324 : .base_slot_size = sizeof(BufferHeapTupleTableSlot),
1325 : .init = tts_buffer_heap_init,
1326 : .release = tts_buffer_heap_release,
1327 : .clear = tts_buffer_heap_clear,
1328 : .getsomeattrs = tts_buffer_heap_getsomeattrs,
1329 : .getsysattr = tts_buffer_heap_getsysattr,
1330 : .is_current_xact_tuple = tts_buffer_is_current_xact_tuple,
1331 : .materialize = tts_buffer_heap_materialize,
1332 : .copyslot = tts_buffer_heap_copyslot,
1333 : .get_heap_tuple = tts_buffer_heap_get_heap_tuple,
1334 :
1335 : /* A buffer heap tuple table slot can not "own" a minimal tuple. */
1336 : .get_minimal_tuple = NULL,
1337 : .copy_heap_tuple = tts_buffer_heap_copy_heap_tuple,
1338 : .copy_minimal_tuple = tts_buffer_heap_copy_minimal_tuple
1339 : };
1340 :
1341 :
1342 : /* ----------------------------------------------------------------
1343 : * tuple table create/delete functions
1344 : * ----------------------------------------------------------------
1345 : */
1346 :
1347 : /* --------------------------------
1348 : * MakeTupleTableSlot
1349 : *
1350 : * Basic routine to make an empty TupleTableSlot of given
1351 : * TupleTableSlotType. If tupleDesc is specified the slot's descriptor is
1352 : * fixed for its lifetime, gaining some efficiency. If that's
1353 : * undesirable, pass NULL. 'flags' allows any of non-TTS_FLAGS_TRANSIENT
1354 : * flags to be set in tts_flags.
1355 : * --------------------------------
1356 : */
1357 : TupleTableSlot *
1358 22270974 : MakeTupleTableSlot(TupleDesc tupleDesc,
1359 : const TupleTableSlotOps *tts_ops, uint16 flags)
1360 : {
1361 : Size basesz,
1362 : allocsz;
1363 : TupleTableSlot *slot;
1364 :
1365 22270974 : basesz = tts_ops->base_slot_size;
1366 :
1367 : /* Ensure callers don't have any way to set transient flags permanently */
1368 22270974 : flags &= ~TTS_FLAGS_TRANSIENT;
1369 :
1370 : /*
1371 : * When a fixed descriptor is specified, we can reduce overhead by
1372 : * allocating the entire slot in one go.
1373 : *
1374 : * We round the size of tts_isnull up to the next highest multiple of 8.
1375 : * This is needed as populate_isnull_array() operates on 8 elements at a
1376 : * time when converting a tuple's NULL bitmap into a boolean array.
1377 : */
1378 22270974 : if (tupleDesc)
1379 22233820 : allocsz = MAXALIGN(basesz) +
1380 22233820 : MAXALIGN(tupleDesc->natts * sizeof(Datum)) +
1381 22233820 : TYPEALIGN(8, tupleDesc->natts * sizeof(bool));
1382 : else
1383 37154 : allocsz = basesz;
1384 :
1385 22270974 : slot = palloc0(allocsz);
1386 : /* const for optimization purposes, OK to modify at allocation time */
1387 22270974 : *((const TupleTableSlotOps **) &slot->tts_ops) = tts_ops;
1388 22270974 : slot->type = T_TupleTableSlot;
1389 22270974 : slot->tts_flags = TTS_FLAG_EMPTY | flags;
1390 22270974 : if (tupleDesc != NULL)
1391 22233820 : slot->tts_flags |= TTS_FLAG_FIXED;
1392 22270974 : slot->tts_tupleDescriptor = tupleDesc;
1393 22270974 : slot->tts_mcxt = CurrentMemoryContext;
1394 22270974 : slot->tts_nvalid = 0;
1395 :
1396 22270974 : if (tupleDesc != NULL)
1397 : {
1398 22233820 : slot->tts_values = (Datum *)
1399 : (((char *) slot)
1400 22233820 : + MAXALIGN(basesz));
1401 :
1402 22233820 : slot->tts_isnull = (bool *)
1403 : (((char *) slot)
1404 22233820 : + MAXALIGN(basesz)
1405 22233820 : + MAXALIGN(tupleDesc->natts * sizeof(Datum)));
1406 :
1407 22233820 : PinTupleDesc(tupleDesc);
1408 :
1409 : /*
1410 : * Precalculate the maximum guaranteed attribute that has to exist in
1411 : * every tuple which gets deformed into this slot. When the
1412 : * TTS_FLAG_OBEYS_NOT_NULL_CONSTRAINTS flag is enabled, we simply take
1413 : * the pre-calculated value from the tupleDesc, otherwise the
1414 : * optimization is disabled, and we set the value to 0.
1415 : */
1416 22233820 : if ((flags & TTS_FLAG_OBEYS_NOT_NULL_CONSTRAINTS) != 0)
1417 291424 : slot->tts_first_nonguaranteed = tupleDesc->firstNonGuaranteedAttr;
1418 : else
1419 21942396 : slot->tts_first_nonguaranteed = 0;
1420 : }
1421 :
1422 : /*
1423 : * And allow slot type specific initialization.
1424 : */
1425 22270974 : slot->tts_ops->init(slot);
1426 :
1427 22270974 : return slot;
1428 : }
1429 :
1430 : /* --------------------------------
1431 : * ExecAllocTableSlot
1432 : *
1433 : * Create a tuple table slot within a tuple table (which is just a List).
1434 : * --------------------------------
1435 : */
1436 : TupleTableSlot *
1437 1379629 : ExecAllocTableSlot(List **tupleTable, TupleDesc desc,
1438 : const TupleTableSlotOps *tts_ops, uint16 flags)
1439 : {
1440 1379629 : TupleTableSlot *slot = MakeTupleTableSlot(desc, tts_ops, flags);
1441 :
1442 1379629 : *tupleTable = lappend(*tupleTable, slot);
1443 :
1444 1379629 : return slot;
1445 : }
1446 :
1447 : /* --------------------------------
1448 : * ExecResetTupleTable
1449 : *
1450 : * This releases any resources (buffer pins, tupdesc refcounts)
1451 : * held by the tuple table, and optionally releases the memory
1452 : * occupied by the tuple table data structure.
1453 : * It is expected that this routine be called by ExecEndPlan().
1454 : * --------------------------------
1455 : */
1456 : void
1457 519213 : ExecResetTupleTable(List *tupleTable, /* tuple table */
1458 : bool shouldFree) /* true if we should free memory */
1459 : {
1460 : ListCell *lc;
1461 :
1462 2024386 : foreach(lc, tupleTable)
1463 : {
1464 1505173 : TupleTableSlot *slot = lfirst_node(TupleTableSlot, lc);
1465 :
1466 : /* Always release resources and reset the slot to empty */
1467 1505173 : ExecClearTuple(slot);
1468 1505173 : slot->tts_ops->release(slot);
1469 1505173 : if (slot->tts_tupleDescriptor)
1470 : {
1471 1505137 : ReleaseTupleDesc(slot->tts_tupleDescriptor);
1472 1505137 : slot->tts_tupleDescriptor = NULL;
1473 : }
1474 :
1475 : /* If shouldFree, release memory occupied by the slot itself */
1476 1505173 : if (shouldFree)
1477 : {
1478 4891 : if (!TTS_FIXED(slot))
1479 : {
1480 0 : if (slot->tts_values)
1481 0 : pfree(slot->tts_values);
1482 0 : if (slot->tts_isnull)
1483 0 : pfree(slot->tts_isnull);
1484 : }
1485 4891 : pfree(slot);
1486 : }
1487 : }
1488 :
1489 : /* If shouldFree, release the list structure */
1490 519213 : if (shouldFree)
1491 4805 : list_free(tupleTable);
1492 519213 : }
1493 :
1494 : /* --------------------------------
1495 : * MakeSingleTupleTableSlot
1496 : *
1497 : * This is a convenience routine for operations that need a standalone
1498 : * TupleTableSlot not gotten from the main executor tuple table. It makes
1499 : * a single slot of given TupleTableSlotType and initializes it to use the
1500 : * given tuple descriptor.
1501 : * --------------------------------
1502 : */
1503 : TupleTableSlot *
1504 20891229 : MakeSingleTupleTableSlot(TupleDesc tupdesc,
1505 : const TupleTableSlotOps *tts_ops)
1506 : {
1507 20891229 : TupleTableSlot *slot = MakeTupleTableSlot(tupdesc, tts_ops, 0);
1508 :
1509 20891229 : return slot;
1510 : }
1511 :
1512 : /* --------------------------------
1513 : * ExecDropSingleTupleTableSlot
1514 : *
1515 : * Release a TupleTableSlot made with MakeSingleTupleTableSlot.
1516 : * DON'T use this on a slot that's part of a tuple table list!
1517 : * --------------------------------
1518 : */
1519 : void
1520 20701026 : ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
1521 : {
1522 : /* This should match ExecResetTupleTable's processing of one slot */
1523 : Assert(IsA(slot, TupleTableSlot));
1524 20701026 : ExecClearTuple(slot);
1525 20701026 : slot->tts_ops->release(slot);
1526 20701026 : if (slot->tts_tupleDescriptor)
1527 20701026 : ReleaseTupleDesc(slot->tts_tupleDescriptor);
1528 20701026 : if (!TTS_FIXED(slot))
1529 : {
1530 0 : if (slot->tts_values)
1531 0 : pfree(slot->tts_values);
1532 0 : if (slot->tts_isnull)
1533 0 : pfree(slot->tts_isnull);
1534 : }
1535 20701026 : pfree(slot);
1536 20701026 : }
1537 :
1538 :
1539 : /* ----------------------------------------------------------------
1540 : * tuple table slot accessor functions
1541 : * ----------------------------------------------------------------
1542 : */
1543 :
1544 : /* --------------------------------
1545 : * ExecSetSlotDescriptor
1546 : *
1547 : * This function is used to set the tuple descriptor associated
1548 : * with the slot's tuple. The passed descriptor must have lifespan
1549 : * at least equal to the slot's. If it is a reference-counted descriptor
1550 : * then the reference count is incremented for as long as the slot holds
1551 : * a reference.
1552 : * --------------------------------
1553 : */
1554 : void
1555 37118 : ExecSetSlotDescriptor(TupleTableSlot *slot, /* slot to change */
1556 : TupleDesc tupdesc) /* new tuple descriptor */
1557 : {
1558 : Assert(!TTS_FIXED(slot));
1559 :
1560 : /* For safety, make sure slot is empty before changing it */
1561 37118 : ExecClearTuple(slot);
1562 :
1563 : /*
1564 : * Release any old descriptor. Also release old Datum/isnull arrays if
1565 : * present (we don't bother to check if they could be re-used).
1566 : */
1567 37118 : if (slot->tts_tupleDescriptor)
1568 0 : ReleaseTupleDesc(slot->tts_tupleDescriptor);
1569 :
1570 37118 : if (slot->tts_values)
1571 0 : pfree(slot->tts_values);
1572 37118 : if (slot->tts_isnull)
1573 0 : pfree(slot->tts_isnull);
1574 :
1575 : /*
1576 : * Install the new descriptor; if it's refcounted, bump its refcount.
1577 : */
1578 37118 : slot->tts_tupleDescriptor = tupdesc;
1579 37118 : PinTupleDesc(tupdesc);
1580 :
1581 : /*
1582 : * Allocate Datum/isnull arrays of the appropriate size. These must have
1583 : * the same lifetime as the slot, so allocate in the slot's own context.
1584 : */
1585 37118 : slot->tts_values = (Datum *)
1586 37118 : MemoryContextAlloc(slot->tts_mcxt, tupdesc->natts * sizeof(Datum));
1587 :
1588 : /*
1589 : * We round the size of tts_isnull up to the next highest multiple of 8.
1590 : * This is needed as populate_isnull_array() operates on 8 elements at a
1591 : * time when converting a tuple's NULL bitmap into a boolean array.
1592 : */
1593 37118 : slot->tts_isnull = (bool *)
1594 37118 : MemoryContextAlloc(slot->tts_mcxt, TYPEALIGN(8, tupdesc->natts * sizeof(bool)));
1595 37118 : }
1596 :
1597 : /* --------------------------------
1598 : * ExecStoreHeapTuple
1599 : *
1600 : * This function is used to store an on-the-fly physical tuple into a specified
1601 : * slot in the tuple table.
1602 : *
1603 : * tuple: tuple to store
1604 : * slot: TTSOpsHeapTuple type slot to store it in
1605 : * shouldFree: true if ExecClearTuple should pfree() the tuple
1606 : * when done with it
1607 : *
1608 : * shouldFree is normally set 'true' for tuples constructed on-the-fly. But it
1609 : * can be 'false' when the referenced tuple is held in a tuple table slot
1610 : * belonging to a lower-level executor Proc node. In this case the lower-level
1611 : * slot retains ownership and responsibility for eventually releasing the
1612 : * tuple. When this method is used, we must be certain that the upper-level
1613 : * Proc node will lose interest in the tuple sooner than the lower-level one
1614 : * does! If you're not certain, copy the lower-level tuple with heap_copytuple
1615 : * and let the upper-level table slot assume ownership of the copy!
1616 : *
1617 : * Return value is just the passed-in slot pointer.
1618 : *
1619 : * If the target slot is not guaranteed to be TTSOpsHeapTuple type slot, use
1620 : * the, more expensive, ExecForceStoreHeapTuple().
1621 : * --------------------------------
1622 : */
1623 : TupleTableSlot *
1624 3440481 : ExecStoreHeapTuple(HeapTuple tuple,
1625 : TupleTableSlot *slot,
1626 : bool shouldFree)
1627 : {
1628 : /*
1629 : * sanity checks
1630 : */
1631 : Assert(tuple != NULL);
1632 : Assert(slot != NULL);
1633 : Assert(slot->tts_tupleDescriptor != NULL);
1634 :
1635 3440481 : if (unlikely(!TTS_IS_HEAPTUPLE(slot)))
1636 0 : elog(ERROR, "trying to store a heap tuple into wrong type of slot");
1637 3440481 : tts_heap_store_tuple(slot, tuple, shouldFree);
1638 :
1639 3440481 : slot->tts_tableOid = tuple->t_tableOid;
1640 :
1641 3440481 : return slot;
1642 : }
1643 :
1644 : /* --------------------------------
1645 : * ExecStoreBufferHeapTuple
1646 : *
1647 : * This function is used to store an on-disk physical tuple from a buffer
1648 : * into a specified slot in the tuple table.
1649 : *
1650 : * tuple: tuple to store
1651 : * slot: TTSOpsBufferHeapTuple type slot to store it in
1652 : * buffer: disk buffer if tuple is in a disk page, else InvalidBuffer
1653 : *
1654 : * The tuple table code acquires a pin on the buffer which is held until the
1655 : * slot is cleared, so that the tuple won't go away on us.
1656 : *
1657 : * Return value is just the passed-in slot pointer.
1658 : *
1659 : * If the target slot is not guaranteed to be TTSOpsBufferHeapTuple type slot,
1660 : * use the, more expensive, ExecForceStoreHeapTuple().
1661 : * --------------------------------
1662 : */
1663 : TupleTableSlot *
1664 105119702 : ExecStoreBufferHeapTuple(HeapTuple tuple,
1665 : TupleTableSlot *slot,
1666 : Buffer buffer)
1667 : {
1668 : /*
1669 : * sanity checks
1670 : */
1671 : Assert(tuple != NULL);
1672 : Assert(slot != NULL);
1673 : Assert(slot->tts_tupleDescriptor != NULL);
1674 : Assert(BufferIsValid(buffer));
1675 :
1676 105119702 : if (unlikely(!TTS_IS_BUFFERTUPLE(slot)))
1677 0 : elog(ERROR, "trying to store an on-disk heap tuple into wrong type of slot");
1678 105119702 : tts_buffer_heap_store_tuple(slot, tuple, buffer, false);
1679 :
1680 105119702 : slot->tts_tableOid = tuple->t_tableOid;
1681 :
1682 105119702 : return slot;
1683 : }
1684 :
1685 : /*
1686 : * Like ExecStoreBufferHeapTuple, but transfer an existing pin from the caller
1687 : * to the slot, i.e. the caller doesn't need to, and may not, release the pin.
1688 : */
1689 : TupleTableSlot *
1690 3409575 : ExecStorePinnedBufferHeapTuple(HeapTuple tuple,
1691 : TupleTableSlot *slot,
1692 : Buffer buffer)
1693 : {
1694 : /*
1695 : * sanity checks
1696 : */
1697 : Assert(tuple != NULL);
1698 : Assert(slot != NULL);
1699 : Assert(slot->tts_tupleDescriptor != NULL);
1700 : Assert(BufferIsValid(buffer));
1701 :
1702 3409575 : if (unlikely(!TTS_IS_BUFFERTUPLE(slot)))
1703 0 : elog(ERROR, "trying to store an on-disk heap tuple into wrong type of slot");
1704 3409575 : tts_buffer_heap_store_tuple(slot, tuple, buffer, true);
1705 :
1706 3409575 : slot->tts_tableOid = tuple->t_tableOid;
1707 :
1708 3409575 : return slot;
1709 : }
1710 :
1711 : /*
1712 : * Store a minimal tuple into TTSOpsMinimalTuple type slot.
1713 : *
1714 : * If the target slot is not guaranteed to be TTSOpsMinimalTuple type slot,
1715 : * use the, more expensive, ExecForceStoreMinimalTuple().
1716 : */
1717 : TupleTableSlot *
1718 40177516 : ExecStoreMinimalTuple(MinimalTuple mtup,
1719 : TupleTableSlot *slot,
1720 : bool shouldFree)
1721 : {
1722 : /*
1723 : * sanity checks
1724 : */
1725 : Assert(mtup != NULL);
1726 : Assert(slot != NULL);
1727 : Assert(slot->tts_tupleDescriptor != NULL);
1728 :
1729 40177516 : if (unlikely(!TTS_IS_MINIMALTUPLE(slot)))
1730 0 : elog(ERROR, "trying to store a minimal tuple into wrong type of slot");
1731 40177516 : tts_minimal_store_tuple(slot, mtup, shouldFree);
1732 :
1733 40177516 : return slot;
1734 : }
1735 :
1736 : /*
1737 : * Store a HeapTuple into any kind of slot, performing conversion if
1738 : * necessary.
1739 : */
1740 : void
1741 1157104 : ExecForceStoreHeapTuple(HeapTuple tuple,
1742 : TupleTableSlot *slot,
1743 : bool shouldFree)
1744 : {
1745 1157104 : if (TTS_IS_HEAPTUPLE(slot))
1746 : {
1747 263 : ExecStoreHeapTuple(tuple, slot, shouldFree);
1748 : }
1749 1156841 : else if (TTS_IS_BUFFERTUPLE(slot))
1750 : {
1751 : MemoryContext oldContext;
1752 48122 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
1753 :
1754 48122 : ExecClearTuple(slot);
1755 48122 : slot->tts_flags &= ~TTS_FLAG_EMPTY;
1756 48122 : oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
1757 48122 : bslot->base.tuple = heap_copytuple(tuple);
1758 48122 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
1759 48122 : MemoryContextSwitchTo(oldContext);
1760 :
1761 48122 : if (shouldFree)
1762 46915 : pfree(tuple);
1763 : }
1764 : else
1765 : {
1766 1108719 : ExecClearTuple(slot);
1767 1108719 : heap_deform_tuple(tuple, slot->tts_tupleDescriptor,
1768 : slot->tts_values, slot->tts_isnull);
1769 1108719 : ExecStoreVirtualTuple(slot);
1770 :
1771 1108719 : if (shouldFree)
1772 : {
1773 138058 : ExecMaterializeSlot(slot);
1774 138058 : pfree(tuple);
1775 : }
1776 : }
1777 1157104 : }
1778 :
1779 : /*
1780 : * Store a MinimalTuple into any kind of slot, performing conversion if
1781 : * necessary.
1782 : */
1783 : void
1784 4768092 : ExecForceStoreMinimalTuple(MinimalTuple mtup,
1785 : TupleTableSlot *slot,
1786 : bool shouldFree)
1787 : {
1788 4768092 : if (TTS_IS_MINIMALTUPLE(slot))
1789 : {
1790 3009079 : tts_minimal_store_tuple(slot, mtup, shouldFree);
1791 : }
1792 : else
1793 : {
1794 : HeapTupleData htup;
1795 :
1796 1759013 : ExecClearTuple(slot);
1797 :
1798 1759013 : htup.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
1799 1759013 : htup.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);
1800 1759013 : heap_deform_tuple(&htup, slot->tts_tupleDescriptor,
1801 : slot->tts_values, slot->tts_isnull);
1802 1759013 : ExecStoreVirtualTuple(slot);
1803 :
1804 1759013 : if (shouldFree)
1805 : {
1806 958860 : ExecMaterializeSlot(slot);
1807 958860 : pfree(mtup);
1808 : }
1809 : }
1810 4768092 : }
1811 :
1812 : /* --------------------------------
1813 : * ExecStoreVirtualTuple
1814 : * Mark a slot as containing a virtual tuple.
1815 : *
1816 : * The protocol for loading a slot with virtual tuple data is:
1817 : * * Call ExecClearTuple to mark the slot empty.
1818 : * * Store data into the Datum/isnull arrays.
1819 : * * Call ExecStoreVirtualTuple to mark the slot valid.
1820 : * This is a bit unclean but it avoids one round of data copying.
1821 : * --------------------------------
1822 : */
1823 : TupleTableSlot *
1824 19006583 : ExecStoreVirtualTuple(TupleTableSlot *slot)
1825 : {
1826 : /*
1827 : * sanity checks
1828 : */
1829 : Assert(slot != NULL);
1830 : Assert(slot->tts_tupleDescriptor != NULL);
1831 : Assert(TTS_EMPTY(slot));
1832 :
1833 19006583 : slot->tts_flags &= ~TTS_FLAG_EMPTY;
1834 19006583 : slot->tts_nvalid = slot->tts_tupleDescriptor->natts;
1835 :
1836 19006583 : return slot;
1837 : }
1838 :
1839 : /* --------------------------------
1840 : * ExecStoreAllNullTuple
1841 : * Set up the slot to contain a null in every column.
1842 : *
1843 : * At first glance this might sound just like ExecClearTuple, but it's
1844 : * entirely different: the slot ends up full, not empty.
1845 : * --------------------------------
1846 : */
1847 : TupleTableSlot *
1848 29819 : ExecStoreAllNullTuple(TupleTableSlot *slot)
1849 : {
1850 : /*
1851 : * sanity checks
1852 : */
1853 : Assert(slot != NULL);
1854 : Assert(slot->tts_tupleDescriptor != NULL);
1855 :
1856 : /* Clear any old contents */
1857 29819 : ExecClearTuple(slot);
1858 :
1859 : /*
1860 : * Fill all the columns of the virtual tuple with nulls
1861 : */
1862 212854 : MemSet(slot->tts_values, 0,
1863 : slot->tts_tupleDescriptor->natts * sizeof(Datum));
1864 29819 : memset(slot->tts_isnull, true,
1865 29819 : slot->tts_tupleDescriptor->natts * sizeof(bool));
1866 :
1867 29819 : return ExecStoreVirtualTuple(slot);
1868 : }
1869 :
1870 : /*
1871 : * Store a HeapTuple in datum form, into a slot. That always requires
1872 : * deforming it and storing it in virtual form.
1873 : *
1874 : * Until the slot is materialized, the contents of the slot depend on the
1875 : * datum.
1876 : */
1877 : void
1878 9 : ExecStoreHeapTupleDatum(Datum data, TupleTableSlot *slot)
1879 : {
1880 9 : HeapTupleData tuple = {0};
1881 : HeapTupleHeader td;
1882 :
1883 9 : td = DatumGetHeapTupleHeader(data);
1884 :
1885 9 : tuple.t_len = HeapTupleHeaderGetDatumLength(td);
1886 9 : tuple.t_self = td->t_ctid;
1887 9 : tuple.t_data = td;
1888 :
1889 9 : ExecClearTuple(slot);
1890 :
1891 9 : heap_deform_tuple(&tuple, slot->tts_tupleDescriptor,
1892 : slot->tts_values, slot->tts_isnull);
1893 9 : ExecStoreVirtualTuple(slot);
1894 9 : }
1895 :
1896 : /*
1897 : * ExecFetchSlotHeapTuple - fetch HeapTuple representing the slot's content
1898 : *
1899 : * The returned HeapTuple represents the slot's content as closely as
1900 : * possible.
1901 : *
1902 : * If materialize is true, the contents of the slots will be made independent
1903 : * from the underlying storage (i.e. all buffer pins are released, memory is
1904 : * allocated in the slot's context).
1905 : *
1906 : * If shouldFree is not-NULL it'll be set to true if the returned tuple has
1907 : * been allocated in the calling memory context, and must be freed by the
1908 : * caller (via explicit pfree() or a memory context reset).
1909 : *
1910 : * NB: If materialize is true, modifications of the returned tuple are
1911 : * allowed. But it depends on the type of the slot whether such modifications
1912 : * will also affect the slot's contents. While that is not the nicest
1913 : * behaviour, all such modifications are in the process of being removed.
1914 : */
1915 : HeapTuple
1916 33358451 : ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
1917 : {
1918 : /*
1919 : * sanity checks
1920 : */
1921 : Assert(slot != NULL);
1922 : Assert(!TTS_EMPTY(slot));
1923 :
1924 : /* Materialize the tuple so that the slot "owns" it, if requested. */
1925 33358451 : if (materialize)
1926 15637013 : slot->tts_ops->materialize(slot);
1927 :
1928 33358451 : if (slot->tts_ops->get_heap_tuple == NULL)
1929 : {
1930 2999622 : if (shouldFree)
1931 2999622 : *shouldFree = true;
1932 2999622 : return slot->tts_ops->copy_heap_tuple(slot);
1933 : }
1934 : else
1935 : {
1936 30358829 : if (shouldFree)
1937 27933170 : *shouldFree = false;
1938 30358829 : return slot->tts_ops->get_heap_tuple(slot);
1939 : }
1940 : }
1941 :
1942 : /* --------------------------------
1943 : * ExecFetchSlotMinimalTuple
1944 : * Fetch the slot's minimal physical tuple.
1945 : *
1946 : * If the given tuple table slot can hold a minimal tuple, indicated by a
1947 : * non-NULL get_minimal_tuple callback, the function returns the minimal
1948 : * tuple returned by that callback. It assumes that the minimal tuple
1949 : * returned by the callback is "owned" by the slot i.e. the slot is
1950 : * responsible for freeing the memory consumed by the tuple. Hence it sets
1951 : * *shouldFree to false, indicating that the caller should not free the
1952 : * memory consumed by the minimal tuple. In this case the returned minimal
1953 : * tuple should be considered as read-only.
1954 : *
1955 : * If that callback is not supported, it calls copy_minimal_tuple callback
1956 : * which is expected to return a copy of minimal tuple representing the
1957 : * contents of the slot. In this case *shouldFree is set to true,
1958 : * indicating the caller that it should free the memory consumed by the
1959 : * minimal tuple. In this case the returned minimal tuple may be written
1960 : * up.
1961 : * --------------------------------
1962 : */
1963 : MinimalTuple
1964 14576623 : ExecFetchSlotMinimalTuple(TupleTableSlot *slot,
1965 : bool *shouldFree)
1966 : {
1967 : /*
1968 : * sanity checks
1969 : */
1970 : Assert(slot != NULL);
1971 : Assert(!TTS_EMPTY(slot));
1972 :
1973 14576623 : if (slot->tts_ops->get_minimal_tuple)
1974 : {
1975 3363461 : if (shouldFree)
1976 3363461 : *shouldFree = false;
1977 3363461 : return slot->tts_ops->get_minimal_tuple(slot);
1978 : }
1979 : else
1980 : {
1981 11213162 : if (shouldFree)
1982 11213162 : *shouldFree = true;
1983 11213162 : return slot->tts_ops->copy_minimal_tuple(slot, 0);
1984 : }
1985 : }
1986 :
1987 : /* --------------------------------
1988 : * ExecFetchSlotHeapTupleDatum
1989 : * Fetch the slot's tuple as a composite-type Datum.
1990 : *
1991 : * The result is always freshly palloc'd in the caller's memory context.
1992 : * --------------------------------
1993 : */
1994 : Datum
1995 40660 : ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot)
1996 : {
1997 : HeapTuple tup;
1998 : TupleDesc tupdesc;
1999 : bool shouldFree;
2000 : Datum ret;
2001 :
2002 : /* Fetch slot's contents in regular-physical-tuple form */
2003 40660 : tup = ExecFetchSlotHeapTuple(slot, false, &shouldFree);
2004 40660 : tupdesc = slot->tts_tupleDescriptor;
2005 :
2006 : /* Convert to Datum form */
2007 40660 : ret = heap_copy_tuple_as_datum(tup, tupdesc);
2008 :
2009 40660 : if (shouldFree)
2010 40500 : pfree(tup);
2011 :
2012 40660 : return ret;
2013 : }
2014 :
2015 : /* ----------------------------------------------------------------
2016 : * convenience initialization routines
2017 : * ----------------------------------------------------------------
2018 : */
2019 :
2020 : /* ----------------
2021 : * ExecInitResultTypeTL
2022 : *
2023 : * Initialize result type, using the plan node's targetlist.
2024 : * ----------------
2025 : */
2026 : void
2027 886246 : ExecInitResultTypeTL(PlanState *planstate)
2028 : {
2029 886246 : TupleDesc tupDesc = ExecTypeFromTL(planstate->plan->targetlist);
2030 :
2031 886246 : planstate->ps_ResultTupleDesc = tupDesc;
2032 886246 : }
2033 :
2034 : /* --------------------------------
2035 : * ExecInit{Result,Scan,Extra}TupleSlot[TL]
2036 : *
2037 : * These are convenience routines to initialize the specified slot
2038 : * in nodes inheriting the appropriate state. ExecInitExtraTupleSlot
2039 : * is used for initializing special-purpose slots.
2040 : * --------------------------------
2041 : */
2042 :
2043 : /* ----------------
2044 : * ExecInitResultTupleSlotTL
2045 : *
2046 : * Initialize result tuple slot, using the tuple descriptor previously
2047 : * computed with ExecInitResultTypeTL().
2048 : * ----------------
2049 : */
2050 : void
2051 610732 : ExecInitResultSlot(PlanState *planstate, const TupleTableSlotOps *tts_ops)
2052 : {
2053 : TupleTableSlot *slot;
2054 :
2055 610732 : slot = ExecAllocTableSlot(&planstate->state->es_tupleTable,
2056 : planstate->ps_ResultTupleDesc, tts_ops, 0);
2057 610732 : planstate->ps_ResultTupleSlot = slot;
2058 :
2059 610732 : planstate->resultopsfixed = planstate->ps_ResultTupleDesc != NULL;
2060 610732 : planstate->resultops = tts_ops;
2061 610732 : planstate->resultopsset = true;
2062 610732 : }
2063 :
2064 : /* ----------------
2065 : * ExecInitResultTupleSlotTL
2066 : *
2067 : * Initialize result tuple slot, using the plan node's targetlist.
2068 : * ----------------
2069 : */
2070 : void
2071 430300 : ExecInitResultTupleSlotTL(PlanState *planstate,
2072 : const TupleTableSlotOps *tts_ops)
2073 : {
2074 430300 : ExecInitResultTypeTL(planstate);
2075 430300 : ExecInitResultSlot(planstate, tts_ops);
2076 430300 : }
2077 :
2078 : /* ----------------
2079 : * ExecInitScanTupleSlot
2080 : * ----------------
2081 : */
2082 : void
2083 471256 : ExecInitScanTupleSlot(EState *estate, ScanState *scanstate,
2084 : TupleDesc tupledesc, const TupleTableSlotOps *tts_ops,
2085 : uint16 flags)
2086 : {
2087 471256 : scanstate->ss_ScanTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable,
2088 : tupledesc, tts_ops, flags);
2089 471256 : scanstate->ps.scandesc = tupledesc;
2090 471256 : scanstate->ps.scanopsfixed = tupledesc != NULL;
2091 471256 : scanstate->ps.scanops = tts_ops;
2092 471256 : scanstate->ps.scanopsset = true;
2093 471256 : }
2094 :
2095 : /* ----------------
2096 : * ExecInitExtraTupleSlot
2097 : *
2098 : * Return a newly created slot. If tupledesc is non-NULL the slot will have
2099 : * that as its fixed tupledesc. Otherwise the caller needs to use
2100 : * ExecSetSlotDescriptor() to set the descriptor before use.
2101 : * ----------------
2102 : */
2103 : TupleTableSlot *
2104 279940 : ExecInitExtraTupleSlot(EState *estate,
2105 : TupleDesc tupledesc,
2106 : const TupleTableSlotOps *tts_ops)
2107 : {
2108 279940 : return ExecAllocTableSlot(&estate->es_tupleTable, tupledesc, tts_ops, 0);
2109 : }
2110 :
2111 : /* ----------------
2112 : * ExecInitNullTupleSlot
2113 : *
2114 : * Build a slot containing an all-nulls tuple of the given type.
2115 : * This is used as a substitute for an input tuple when performing an
2116 : * outer join.
2117 : * ----------------
2118 : */
2119 : TupleTableSlot *
2120 28800 : ExecInitNullTupleSlot(EState *estate, TupleDesc tupType,
2121 : const TupleTableSlotOps *tts_ops)
2122 : {
2123 28800 : TupleTableSlot *slot = ExecInitExtraTupleSlot(estate, tupType, tts_ops);
2124 :
2125 28800 : return ExecStoreAllNullTuple(slot);
2126 : }
2127 :
2128 : /* ---------------------------------------------------------------
2129 : * Routines for setting/accessing attributes in a slot.
2130 : * ---------------------------------------------------------------
2131 : */
2132 :
2133 : /*
2134 : * Fill in missing values for a TupleTableSlot.
2135 : *
2136 : * This is only exposed because it's needed for JIT compiled tuple
2137 : * deforming. That exception aside, there should be no callers outside of this
2138 : * file.
2139 : */
2140 : void
2141 4846 : slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, int lastAttNum)
2142 : {
2143 4846 : AttrMissing *attrmiss = NULL;
2144 :
2145 : /* Check for invalid attnums */
2146 4846 : if (unlikely(lastAttNum > slot->tts_tupleDescriptor->natts))
2147 0 : elog(ERROR, "invalid attribute number %d", lastAttNum);
2148 :
2149 4846 : if (slot->tts_tupleDescriptor->constr)
2150 3145 : attrmiss = slot->tts_tupleDescriptor->constr->missing;
2151 :
2152 4846 : if (!attrmiss)
2153 : {
2154 : /* no missing values array at all, so just fill everything in as NULL */
2155 3831 : for (int attnum = startAttNum; attnum < lastAttNum; attnum++)
2156 : {
2157 2020 : slot->tts_values[attnum] = (Datum) 0;
2158 2020 : slot->tts_isnull[attnum] = true;
2159 : }
2160 : }
2161 : else
2162 : {
2163 : /* use attrmiss to set the missing values */
2164 7045 : for (int attnum = startAttNum; attnum < lastAttNum; attnum++)
2165 : {
2166 4010 : slot->tts_values[attnum] = attrmiss[attnum].am_value;
2167 4010 : slot->tts_isnull[attnum] = !attrmiss[attnum].am_present;
2168 : }
2169 : }
2170 4846 : }
2171 :
2172 : /*
2173 : * slot_getsomeattrs_int
2174 : * external function to call getsomeattrs() for use in JIT
2175 : */
2176 : void
2177 0 : slot_getsomeattrs_int(TupleTableSlot *slot, int attnum)
2178 : {
2179 : /* Check for caller errors */
2180 : Assert(slot->tts_nvalid < attnum); /* checked in slot_getsomeattrs */
2181 : Assert(attnum > 0);
2182 :
2183 : /* Fetch as many attributes as possible from the underlying tuple. */
2184 0 : slot->tts_ops->getsomeattrs(slot, attnum);
2185 :
2186 : /*
2187 : * Avoid putting new code here as that would prevent the compiler from
2188 : * using the sibling call optimization for the above function.
2189 : */
2190 0 : }
2191 :
2192 : /* ----------------------------------------------------------------
2193 : * ExecTypeFromTL
2194 : *
2195 : * Generate a tuple descriptor for the result tuple of a targetlist.
2196 : * (A parse/plan tlist must be passed, not an ExprState tlist.)
2197 : * Note that resjunk columns, if any, are included in the result.
2198 : *
2199 : * Currently there are about 4 different places where we create
2200 : * TupleDescriptors. They should all be merged, or perhaps
2201 : * be rewritten to call BuildDesc().
2202 : * ----------------------------------------------------------------
2203 : */
2204 : TupleDesc
2205 906780 : ExecTypeFromTL(List *targetList)
2206 : {
2207 906780 : return ExecTypeFromTLInternal(targetList, false);
2208 : }
2209 :
2210 : /* ----------------------------------------------------------------
2211 : * ExecCleanTypeFromTL
2212 : *
2213 : * Same as above, but resjunk columns are omitted from the result.
2214 : * ----------------------------------------------------------------
2215 : */
2216 : TupleDesc
2217 73060 : ExecCleanTypeFromTL(List *targetList)
2218 : {
2219 73060 : return ExecTypeFromTLInternal(targetList, true);
2220 : }
2221 :
2222 : static TupleDesc
2223 979840 : ExecTypeFromTLInternal(List *targetList, bool skipjunk)
2224 : {
2225 : TupleDesc typeInfo;
2226 : ListCell *l;
2227 : int len;
2228 979840 : int cur_resno = 1;
2229 :
2230 979840 : if (skipjunk)
2231 73060 : len = ExecCleanTargetListLength(targetList);
2232 : else
2233 906780 : len = ExecTargetListLength(targetList);
2234 979840 : typeInfo = CreateTemplateTupleDesc(len);
2235 :
2236 5025952 : foreach(l, targetList)
2237 : {
2238 4046112 : TargetEntry *tle = lfirst(l);
2239 :
2240 4046112 : if (skipjunk && tle->resjunk)
2241 20139 : continue;
2242 12077919 : TupleDescInitEntry(typeInfo,
2243 : cur_resno,
2244 4025973 : tle->resname,
2245 4025973 : exprType((Node *) tle->expr),
2246 4025973 : exprTypmod((Node *) tle->expr),
2247 : 0);
2248 4025973 : TupleDescInitEntryCollation(typeInfo,
2249 : cur_resno,
2250 4025973 : exprCollation((Node *) tle->expr));
2251 4025973 : cur_resno++;
2252 : }
2253 :
2254 979840 : TupleDescFinalize(typeInfo);
2255 :
2256 979840 : return typeInfo;
2257 : }
2258 :
2259 : /*
2260 : * ExecTypeFromExprList - build a tuple descriptor from a list of Exprs
2261 : *
2262 : * This is roughly like ExecTypeFromTL, but we work from bare expressions
2263 : * not TargetEntrys. No names are attached to the tupledesc's columns.
2264 : */
2265 : TupleDesc
2266 9767 : ExecTypeFromExprList(List *exprList)
2267 : {
2268 : TupleDesc typeInfo;
2269 : ListCell *lc;
2270 9767 : int cur_resno = 1;
2271 :
2272 9767 : typeInfo = CreateTemplateTupleDesc(list_length(exprList));
2273 :
2274 27191 : foreach(lc, exprList)
2275 : {
2276 17424 : Node *e = lfirst(lc);
2277 :
2278 17424 : TupleDescInitEntry(typeInfo,
2279 : cur_resno,
2280 : NULL,
2281 : exprType(e),
2282 : exprTypmod(e),
2283 : 0);
2284 17424 : TupleDescInitEntryCollation(typeInfo,
2285 : cur_resno,
2286 : exprCollation(e));
2287 17424 : cur_resno++;
2288 : }
2289 :
2290 9767 : TupleDescFinalize(typeInfo);
2291 :
2292 9767 : return typeInfo;
2293 : }
2294 :
2295 : /*
2296 : * ExecTypeSetColNames - set column names in a RECORD TupleDesc
2297 : *
2298 : * Column names must be provided as an alias list (list of String nodes).
2299 : */
2300 : void
2301 2888 : ExecTypeSetColNames(TupleDesc typeInfo, List *namesList)
2302 : {
2303 2888 : int colno = 0;
2304 : ListCell *lc;
2305 :
2306 : /* It's only OK to change col names in a not-yet-blessed RECORD type */
2307 : Assert(typeInfo->tdtypeid == RECORDOID);
2308 : Assert(typeInfo->tdtypmod < 0);
2309 :
2310 10046 : foreach(lc, namesList)
2311 : {
2312 7158 : char *cname = strVal(lfirst(lc));
2313 : Form_pg_attribute attr;
2314 :
2315 : /* Guard against too-long names list (probably can't happen) */
2316 7158 : if (colno >= typeInfo->natts)
2317 0 : break;
2318 7158 : attr = TupleDescAttr(typeInfo, colno);
2319 7158 : colno++;
2320 :
2321 : /*
2322 : * Do nothing for empty aliases or dropped columns (these cases
2323 : * probably can't arise in RECORD types, either)
2324 : */
2325 7158 : if (cname[0] == '\0' || attr->attisdropped)
2326 16 : continue;
2327 :
2328 : /* OK, assign the column name */
2329 7142 : namestrcpy(&(attr->attname), cname);
2330 : }
2331 2888 : }
2332 :
2333 : /*
2334 : * BlessTupleDesc - make a completed tuple descriptor useful for SRFs
2335 : *
2336 : * Rowtype Datums returned by a function must contain valid type information.
2337 : * This happens "for free" if the tupdesc came from a relcache entry, but
2338 : * not if we have manufactured a tupdesc for a transient RECORD datatype.
2339 : * In that case we have to notify typcache.c of the existence of the type.
2340 : *
2341 : * TupleDescFinalize() must be called on the TupleDesc before calling this
2342 : * function.
2343 : */
2344 : TupleDesc
2345 89106 : BlessTupleDesc(TupleDesc tupdesc)
2346 : {
2347 : /* Did someone forget to call TupleDescFinalize()? */
2348 : Assert(tupdesc->firstNonCachedOffsetAttr >= 0);
2349 :
2350 89106 : if (tupdesc->tdtypeid == RECORDOID &&
2351 86383 : tupdesc->tdtypmod < 0)
2352 56347 : assign_record_type_typmod(tupdesc);
2353 :
2354 89106 : return tupdesc; /* just for notational convenience */
2355 : }
2356 :
2357 : /*
2358 : * TupleDescGetAttInMetadata - Build an AttInMetadata structure based on the
2359 : * supplied TupleDesc. AttInMetadata can be used in conjunction with C strings
2360 : * to produce a properly formed tuple.
2361 : */
2362 : AttInMetadata *
2363 14469 : TupleDescGetAttInMetadata(TupleDesc tupdesc)
2364 : {
2365 14469 : int natts = tupdesc->natts;
2366 : int i;
2367 : Oid atttypeid;
2368 : Oid attinfuncid;
2369 : FmgrInfo *attinfuncinfo;
2370 : Oid *attioparams;
2371 : int32 *atttypmods;
2372 : AttInMetadata *attinmeta;
2373 :
2374 14469 : attinmeta = palloc_object(AttInMetadata);
2375 :
2376 : /* "Bless" the tupledesc so that we can make rowtype datums with it */
2377 14469 : attinmeta->tupdesc = BlessTupleDesc(tupdesc);
2378 :
2379 : /*
2380 : * Gather info needed later to call the "in" function for each attribute
2381 : */
2382 14469 : attinfuncinfo = (FmgrInfo *) palloc0(natts * sizeof(FmgrInfo));
2383 14469 : attioparams = (Oid *) palloc0(natts * sizeof(Oid));
2384 14469 : atttypmods = (int32 *) palloc0(natts * sizeof(int32));
2385 :
2386 76023 : for (i = 0; i < natts; i++)
2387 : {
2388 61554 : Form_pg_attribute att = TupleDescAttr(tupdesc, i);
2389 :
2390 : /* Ignore dropped attributes */
2391 61554 : if (!att->attisdropped)
2392 : {
2393 61437 : atttypeid = att->atttypid;
2394 61437 : getTypeInputInfo(atttypeid, &attinfuncid, &attioparams[i]);
2395 61437 : fmgr_info(attinfuncid, &attinfuncinfo[i]);
2396 61437 : atttypmods[i] = att->atttypmod;
2397 : }
2398 : }
2399 14469 : attinmeta->attinfuncs = attinfuncinfo;
2400 14469 : attinmeta->attioparams = attioparams;
2401 14469 : attinmeta->atttypmods = atttypmods;
2402 :
2403 14469 : return attinmeta;
2404 : }
2405 :
2406 : /*
2407 : * BuildTupleFromCStrings - build a HeapTuple given user data in C string form.
2408 : * values is an array of C strings, one for each attribute of the return tuple.
2409 : * A NULL string pointer indicates we want to create a NULL field.
2410 : */
2411 : HeapTuple
2412 1039241 : BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
2413 : {
2414 1039241 : TupleDesc tupdesc = attinmeta->tupdesc;
2415 1039241 : int natts = tupdesc->natts;
2416 : Datum *dvalues;
2417 : bool *nulls;
2418 : int i;
2419 : HeapTuple tuple;
2420 :
2421 1039241 : dvalues = (Datum *) palloc(natts * sizeof(Datum));
2422 1039241 : nulls = (bool *) palloc(natts * sizeof(bool));
2423 :
2424 : /*
2425 : * Call the "in" function for each non-dropped attribute, even for nulls,
2426 : * to support domains.
2427 : */
2428 15684115 : for (i = 0; i < natts; i++)
2429 : {
2430 14644875 : if (!TupleDescCompactAttr(tupdesc, i)->attisdropped)
2431 : {
2432 : /* Non-dropped attributes */
2433 29289749 : dvalues[i] = InputFunctionCall(&attinmeta->attinfuncs[i],
2434 14644875 : values[i],
2435 14644875 : attinmeta->attioparams[i],
2436 14644875 : attinmeta->atttypmods[i]);
2437 14644874 : if (values[i] != NULL)
2438 10116151 : nulls[i] = false;
2439 : else
2440 4528723 : nulls[i] = true;
2441 : }
2442 : else
2443 : {
2444 : /* Handle dropped attributes by setting to NULL */
2445 0 : dvalues[i] = (Datum) 0;
2446 0 : nulls[i] = true;
2447 : }
2448 : }
2449 :
2450 : /*
2451 : * Form a tuple
2452 : */
2453 1039240 : tuple = heap_form_tuple(tupdesc, dvalues, nulls);
2454 :
2455 : /*
2456 : * Release locally palloc'd space. XXX would probably be good to pfree
2457 : * values of pass-by-reference datums, as well.
2458 : */
2459 1039240 : pfree(dvalues);
2460 1039240 : pfree(nulls);
2461 :
2462 1039240 : return tuple;
2463 : }
2464 :
2465 : /*
2466 : * HeapTupleHeaderGetDatum - convert a HeapTupleHeader pointer to a Datum.
2467 : *
2468 : * This must *not* get applied to an on-disk tuple; the tuple should be
2469 : * freshly made by heap_form_tuple or some wrapper routine for it (such as
2470 : * BuildTupleFromCStrings). Be sure also that the tupledesc used to build
2471 : * the tuple has a properly "blessed" rowtype.
2472 : *
2473 : * Formerly this was a macro equivalent to PointerGetDatum, relying on the
2474 : * fact that heap_form_tuple fills in the appropriate tuple header fields
2475 : * for a composite Datum. However, we now require that composite Datums not
2476 : * contain any external TOAST pointers. We do not want heap_form_tuple itself
2477 : * to enforce that; more specifically, the rule applies only to actual Datums
2478 : * and not to HeapTuple structures. Therefore, HeapTupleHeaderGetDatum is
2479 : * now a function that detects whether there are externally-toasted fields
2480 : * and constructs a new tuple with inlined fields if so. We still need
2481 : * heap_form_tuple to insert the Datum header fields, because otherwise this
2482 : * code would have no way to obtain a tupledesc for the tuple.
2483 : *
2484 : * Note that if we do build a new tuple, it's palloc'd in the current
2485 : * memory context. Beware of code that changes context between the initial
2486 : * heap_form_tuple/etc call and calling HeapTuple(Header)GetDatum.
2487 : *
2488 : * For performance-critical callers, it could be worthwhile to take extra
2489 : * steps to ensure that there aren't TOAST pointers in the output of
2490 : * heap_form_tuple to begin with. It's likely however that the costs of the
2491 : * typcache lookup and tuple disassembly/reassembly are swamped by TOAST
2492 : * dereference costs, so that the benefits of such extra effort would be
2493 : * minimal.
2494 : *
2495 : * XXX it would likely be better to create wrapper functions that produce
2496 : * a composite Datum from the field values in one step. However, there's
2497 : * enough code using the existing APIs that we couldn't get rid of this
2498 : * hack anytime soon.
2499 : */
2500 : Datum
2501 1520070 : HeapTupleHeaderGetDatum(HeapTupleHeader tuple)
2502 : {
2503 : Datum result;
2504 : TupleDesc tupDesc;
2505 :
2506 : /* No work if there are no external TOAST pointers in the tuple */
2507 1520070 : if (!HeapTupleHeaderHasExternal(tuple))
2508 1520062 : return PointerGetDatum(tuple);
2509 :
2510 : /* Use the type data saved by heap_form_tuple to look up the rowtype */
2511 8 : tupDesc = lookup_rowtype_tupdesc(HeapTupleHeaderGetTypeId(tuple),
2512 : HeapTupleHeaderGetTypMod(tuple));
2513 :
2514 : /* And do the flattening */
2515 8 : result = toast_flatten_tuple_to_datum(tuple,
2516 : HeapTupleHeaderGetDatumLength(tuple),
2517 : tupDesc);
2518 :
2519 8 : ReleaseTupleDesc(tupDesc);
2520 :
2521 8 : return result;
2522 : }
2523 :
2524 :
2525 : /*
2526 : * Functions for sending tuples to the frontend (or other specified destination)
2527 : * as though it is a SELECT result. These are used by utility commands that
2528 : * need to project directly to the destination and don't need or want full
2529 : * table function capability. Currently used by EXPLAIN and SHOW ALL.
2530 : */
2531 : TupOutputState *
2532 19830 : begin_tup_output_tupdesc(DestReceiver *dest,
2533 : TupleDesc tupdesc,
2534 : const TupleTableSlotOps *tts_ops)
2535 : {
2536 : TupOutputState *tstate;
2537 :
2538 19830 : tstate = palloc_object(TupOutputState);
2539 :
2540 19830 : tstate->slot = MakeSingleTupleTableSlot(tupdesc, tts_ops);
2541 19830 : tstate->dest = dest;
2542 :
2543 19830 : tstate->dest->rStartup(tstate->dest, (int) CMD_SELECT, tupdesc);
2544 :
2545 19830 : return tstate;
2546 : }
2547 :
2548 : /*
2549 : * write a single tuple
2550 : */
2551 : void
2552 116435 : do_tup_output(TupOutputState *tstate, const Datum *values, const bool *isnull)
2553 : {
2554 116435 : TupleTableSlot *slot = tstate->slot;
2555 116435 : int natts = slot->tts_tupleDescriptor->natts;
2556 :
2557 : /* make sure the slot is clear */
2558 116435 : ExecClearTuple(slot);
2559 :
2560 : /* insert data */
2561 116435 : memcpy(slot->tts_values, values, natts * sizeof(Datum));
2562 116435 : memcpy(slot->tts_isnull, isnull, natts * sizeof(bool));
2563 :
2564 : /* mark slot as containing a virtual tuple */
2565 116435 : ExecStoreVirtualTuple(slot);
2566 :
2567 : /* send the tuple to the receiver */
2568 116435 : (void) tstate->dest->receiveSlot(slot, tstate->dest);
2569 :
2570 : /* clean up */
2571 116435 : ExecClearTuple(slot);
2572 116435 : }
2573 :
2574 : /*
2575 : * write a chunk of text, breaking at newline characters
2576 : *
2577 : * Should only be used with a single-TEXT-attribute tupdesc.
2578 : */
2579 : void
2580 16224 : do_text_output_multiline(TupOutputState *tstate, const char *txt)
2581 : {
2582 : Datum values[1];
2583 16224 : bool isnull[1] = {false};
2584 :
2585 128290 : while (*txt)
2586 : {
2587 : const char *eol;
2588 : int len;
2589 :
2590 112066 : eol = strchr(txt, '\n');
2591 112066 : if (eol)
2592 : {
2593 112066 : len = eol - txt;
2594 112066 : eol++;
2595 : }
2596 : else
2597 : {
2598 0 : len = strlen(txt);
2599 0 : eol = txt + len;
2600 : }
2601 :
2602 112066 : values[0] = PointerGetDatum(cstring_to_text_with_len(txt, len));
2603 112066 : do_tup_output(tstate, values, isnull);
2604 112066 : pfree(DatumGetPointer(values[0]));
2605 112066 : txt = eol;
2606 : }
2607 16224 : }
2608 :
2609 : void
2610 19830 : end_tup_output(TupOutputState *tstate)
2611 : {
2612 19830 : tstate->dest->rShutdown(tstate->dest);
2613 : /* note that destroying the dest is not ours to do */
2614 19830 : ExecDropSingleTupleTableSlot(tstate->slot);
2615 19830 : pfree(tstate);
2616 19830 : }
|