Branch data 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_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 : 977084 : tts_virtual_init(TupleTableSlot *slot)
99 : : {
100 : 977084 : }
101 : :
102 : : static void
103 : 955637 : tts_virtual_release(TupleTableSlot *slot)
104 : : {
105 : 955637 : }
106 : :
107 : : static void
108 : 62132123 : tts_virtual_clear(TupleTableSlot *slot)
109 : : {
110 [ + + ]: 62132123 : if (unlikely(TTS_SHOULDFREE(slot)))
111 : : {
112 : 1230965 : VirtualTupleTableSlot *vslot = (VirtualTupleTableSlot *) slot;
113 : :
114 : 1230965 : pfree(vslot->data);
115 : 1230965 : vslot->data = NULL;
116 : :
117 : 1230965 : slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
118 : : }
119 : :
120 : 62132123 : slot->tts_nvalid = 0;
121 : 62132123 : slot->tts_flags |= TTS_FLAG_EMPTY;
122 : 62132123 : ItemPointerSetInvalid(&slot->tts_tid);
123 : 62132123 : }
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 : 3983818 : tts_virtual_materialize(TupleTableSlot *slot)
177 : : {
178 : 3983818 : VirtualTupleTableSlot *vslot = (VirtualTupleTableSlot *) slot;
179 : 3983818 : TupleDesc desc = slot->tts_tupleDescriptor;
180 : 3983818 : Size sz = 0;
181 : : char *data;
182 : :
183 : : /* already materialized */
184 [ + + ]: 3983818 : if (TTS_SHOULDFREE(slot))
185 : 235425 : return;
186 : :
187 : : /* compute size of memory required */
188 [ + + ]: 10588845 : for (int natt = 0; natt < desc->natts; natt++)
189 : : {
190 : 6840452 : CompactAttribute *att = TupleDescCompactAttr(desc, natt);
191 : : Datum val;
192 : :
193 [ + + + + ]: 6840452 : if (att->attbyval || slot->tts_isnull[natt])
194 : 5348175 : continue;
195 : :
196 : 1492277 : val = slot->tts_values[natt];
197 : :
198 [ + + - + ]: 2633831 : if (att->attlen == -1 &&
199 : 1141554 : 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 : 1492277 : sz = att_nominal_alignby(sz, att->attalignby);
211 [ + + + - ]: 1492277 : sz = att_addlength_datum(sz, att->attlen, val);
212 : : }
213 : :
214 [ - + ]: 1492277 : if (!AllocSizeIsValid(sz))
215 [ # # ]: 0 : ereport(ERROR,
216 : : errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
217 : : errmsg("tuple is too big"));
218 : : }
219 : :
220 : : /* all data is byval */
221 [ + + ]: 3748393 : if (sz == 0)
222 : 2517350 : return;
223 : :
224 : : /* allocate memory */
225 : 1231043 : vslot->data = data = MemoryContextAlloc(slot->tts_mcxt, sz);
226 : 1231043 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
227 : :
228 : : /* and copy all attributes into the pre-allocated space */
229 [ + + ]: 4762809 : for (int natt = 0; natt < desc->natts; natt++)
230 : : {
231 : 3531766 : CompactAttribute *att = TupleDescCompactAttr(desc, natt);
232 : : Datum val;
233 : :
234 [ + + + + ]: 3531766 : if (att->attbyval || slot->tts_isnull[natt])
235 : 2039489 : continue;
236 : :
237 : 1492277 : val = slot->tts_values[natt];
238 : :
239 [ + + - + ]: 2633831 : if (att->attlen == -1 &&
240 : 1141554 : VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(val)))
241 : 0 : {
242 : : Size data_length;
243 : :
244 : : /*
245 : : * We want to flatten the expanded value so that the materialized
246 : : * slot doesn't depend on it.
247 : : */
248 : 0 : ExpandedObjectHeader *eoh = DatumGetEOHP(val);
249 : :
250 : 0 : data = (char *) att_nominal_alignby(data,
251 : : att->attalignby);
252 : 0 : data_length = EOH_get_flat_size(eoh);
253 : 0 : EOH_flatten_into(eoh, data, data_length);
254 : :
255 : 0 : slot->tts_values[natt] = PointerGetDatum(data);
256 : 0 : data += data_length;
257 : : }
258 : : else
259 : : {
260 : 1492277 : Size data_length = 0;
261 : :
262 : 1492277 : data = (char *) att_nominal_alignby(data, att->attalignby);
263 [ + + + - ]: 1492277 : data_length = att_addlength_datum(data_length, att->attlen, val);
264 : :
265 : 1492277 : memcpy(data, DatumGetPointer(val), data_length);
266 : :
267 : 1492277 : slot->tts_values[natt] = PointerGetDatum(data);
268 : 1492277 : data += data_length;
269 : : }
270 : : }
271 : : }
272 : :
273 : : static void
274 : 91254 : tts_virtual_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
275 : : {
276 : 91254 : TupleDesc srcdesc = srcslot->tts_tupleDescriptor;
277 : :
278 : 91254 : tts_virtual_clear(dstslot);
279 : :
280 : 91254 : slot_getallattrs(srcslot);
281 : :
282 [ + + ]: 183778 : for (int natt = 0; natt < srcdesc->natts; natt++)
283 : : {
284 : 92524 : dstslot->tts_values[natt] = srcslot->tts_values[natt];
285 : 92524 : dstslot->tts_isnull[natt] = srcslot->tts_isnull[natt];
286 : : }
287 : :
288 : 91254 : dstslot->tts_nvalid = srcdesc->natts;
289 : 91254 : dstslot->tts_flags &= ~TTS_FLAG_EMPTY;
290 : :
291 : : /* make sure storage doesn't depend on external memory */
292 : 91254 : tts_virtual_materialize(dstslot);
293 : 91254 : }
294 : :
295 : : static HeapTuple
296 : 10564186 : tts_virtual_copy_heap_tuple(TupleTableSlot *slot)
297 : : {
298 : : Assert(!TTS_EMPTY(slot));
299 : :
300 : 21128372 : return heap_form_tuple(slot->tts_tupleDescriptor,
301 : 10564186 : slot->tts_values,
302 : 10564186 : slot->tts_isnull);
303 : : }
304 : :
305 : : static MinimalTuple
306 : 18376664 : tts_virtual_copy_minimal_tuple(TupleTableSlot *slot, Size extra)
307 : : {
308 : : Assert(!TTS_EMPTY(slot));
309 : :
310 : 36753328 : return heap_form_minimal_tuple(slot->tts_tupleDescriptor,
311 : 18376664 : slot->tts_values,
312 : 18376664 : slot->tts_isnull,
313 : : extra);
314 : : }
315 : :
316 : :
317 : : /*
318 : : * TupleTableSlotOps implementation for HeapTupleTableSlot.
319 : : */
320 : :
321 : : static void
322 : 2626800 : tts_heap_init(TupleTableSlot *slot)
323 : : {
324 : 2626800 : }
325 : :
326 : : static void
327 : 2626084 : tts_heap_release(TupleTableSlot *slot)
328 : : {
329 : 2626084 : }
330 : :
331 : : static void
332 : 6725273 : tts_heap_clear(TupleTableSlot *slot)
333 : : {
334 : 6725273 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
335 : :
336 : : /* Free the memory for the heap tuple if it's allowed. */
337 [ + + ]: 6725273 : if (TTS_SHOULDFREE(slot))
338 : : {
339 : 1124321 : heap_freetuple(hslot->tuple);
340 : 1124321 : slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
341 : : }
342 : :
343 : 6725273 : slot->tts_nvalid = 0;
344 : 6725273 : slot->tts_flags |= TTS_FLAG_EMPTY;
345 : 6725273 : ItemPointerSetInvalid(&slot->tts_tid);
346 : 6725273 : hslot->off = 0;
347 : 6725273 : hslot->tuple = NULL;
348 : 6725273 : }
349 : :
350 : : static void
351 : 6814046 : tts_heap_getsomeattrs(TupleTableSlot *slot, int natts)
352 : : {
353 : 6814046 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
354 : :
355 : : Assert(!TTS_EMPTY(slot));
356 : :
357 : 6814046 : slot_deform_heap_tuple(slot, hslot->tuple, &hslot->off, natts, false);
358 : 6814046 : }
359 : :
360 : : static Datum
361 : 0 : tts_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
362 : : {
363 : 0 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
364 : :
365 : : Assert(!TTS_EMPTY(slot));
366 : :
367 : : /*
368 : : * In some code paths it's possible to get here with a non-materialized
369 : : * slot, in which case we can't retrieve system columns.
370 : : */
371 [ # # ]: 0 : if (!hslot->tuple)
372 [ # # ]: 0 : ereport(ERROR,
373 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
374 : : errmsg("cannot retrieve a system column in this context")));
375 : :
376 : 0 : return heap_getsysattr(hslot->tuple, attnum,
377 : : slot->tts_tupleDescriptor, isnull);
378 : : }
379 : :
380 : : static bool
381 : 0 : tts_heap_is_current_xact_tuple(TupleTableSlot *slot)
382 : : {
383 : 0 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
384 : : TransactionId xmin;
385 : :
386 : : Assert(!TTS_EMPTY(slot));
387 : :
388 : : /*
389 : : * In some code paths it's possible to get here with a non-materialized
390 : : * slot, in which case we can't check if tuple is created by the current
391 : : * transaction.
392 : : */
393 [ # # ]: 0 : if (!hslot->tuple)
394 [ # # ]: 0 : ereport(ERROR,
395 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
396 : : errmsg("don't have a storage tuple in this context")));
397 : :
398 : 0 : xmin = HeapTupleHeaderGetRawXmin(hslot->tuple->t_data);
399 : :
400 : 0 : return TransactionIdIsCurrentTransactionId(xmin);
401 : : }
402 : :
403 : : static void
404 : 2247374 : tts_heap_materialize(TupleTableSlot *slot)
405 : : {
406 : 2247374 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
407 : : MemoryContext oldContext;
408 : :
409 : : Assert(!TTS_EMPTY(slot));
410 : :
411 : : /* If slot has its tuple already materialized, nothing to do. */
412 [ + + ]: 2247374 : if (TTS_SHOULDFREE(slot))
413 : 1124049 : return;
414 : :
415 : 1123325 : oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
416 : :
417 : : /*
418 : : * Have to deform from scratch, otherwise tts_values[] entries could point
419 : : * into the non-materialized tuple (which might be gone when accessed).
420 : : */
421 : 1123325 : slot->tts_nvalid = 0;
422 : 1123325 : hslot->off = 0;
423 : :
424 [ + + ]: 1123325 : if (!hslot->tuple)
425 : 1123318 : hslot->tuple = heap_form_tuple(slot->tts_tupleDescriptor,
426 : 1123318 : slot->tts_values,
427 : 1123318 : slot->tts_isnull);
428 : : else
429 : : {
430 : : /*
431 : : * The tuple contained in this slot is not allocated in the memory
432 : : * context of the given slot (else it would have TTS_FLAG_SHOULDFREE
433 : : * set). Copy the tuple into the given slot's memory context.
434 : : */
435 : 7 : hslot->tuple = heap_copytuple(hslot->tuple);
436 : : }
437 : :
438 : 1123325 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
439 : :
440 : 1123325 : MemoryContextSwitchTo(oldContext);
441 : : }
442 : :
443 : : static void
444 : 905 : tts_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
445 : : {
446 : : HeapTuple tuple;
447 : : MemoryContext oldcontext;
448 : :
449 : 905 : oldcontext = MemoryContextSwitchTo(dstslot->tts_mcxt);
450 : 905 : tuple = ExecCopySlotHeapTuple(srcslot);
451 : 905 : MemoryContextSwitchTo(oldcontext);
452 : :
453 : 905 : ExecStoreHeapTuple(tuple, dstslot, true);
454 : 905 : }
455 : :
456 : : static HeapTuple
457 : 2246364 : tts_heap_get_heap_tuple(TupleTableSlot *slot)
458 : : {
459 : 2246364 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
460 : :
461 : : Assert(!TTS_EMPTY(slot));
462 [ - + ]: 2246364 : if (!hslot->tuple)
463 : 0 : tts_heap_materialize(slot);
464 : :
465 : 2246364 : return hslot->tuple;
466 : : }
467 : :
468 : : static HeapTuple
469 : 346 : tts_heap_copy_heap_tuple(TupleTableSlot *slot)
470 : : {
471 : 346 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
472 : :
473 : : Assert(!TTS_EMPTY(slot));
474 [ - + ]: 346 : if (!hslot->tuple)
475 : 0 : tts_heap_materialize(slot);
476 : :
477 : 346 : return heap_copytuple(hslot->tuple);
478 : : }
479 : :
480 : : static MinimalTuple
481 : 2735 : tts_heap_copy_minimal_tuple(TupleTableSlot *slot, Size extra)
482 : : {
483 : 2735 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
484 : :
485 [ + + ]: 2735 : if (!hslot->tuple)
486 : 21 : tts_heap_materialize(slot);
487 : :
488 : 2735 : return minimal_tuple_from_heap_tuple(hslot->tuple, extra);
489 : : }
490 : :
491 : : static void
492 : 2974179 : tts_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, bool shouldFree)
493 : : {
494 : 2974179 : HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
495 : :
496 : : /*
497 : : * The tuple later will likely get deformed and/or copied. Validate a
498 : : * versioned datum once when it enters the slot, rather than having to
499 : : * check on every copy and each incremental deformation.
500 : : */
501 [ + + ]: 2974179 : if (HeapTupleHeaderIsVersionedDatum(tuple->t_data))
502 : 31667 : heap_datum_check(tuple->t_data, slot->tts_tupleDescriptor);
503 : :
504 : 2974179 : tts_heap_clear(slot);
505 : :
506 : 2974179 : slot->tts_nvalid = 0;
507 : 2974179 : hslot->tuple = tuple;
508 : 2974179 : hslot->off = 0;
509 : 2974179 : slot->tts_flags &= ~(TTS_FLAG_EMPTY | TTS_FLAG_SHOULDFREE);
510 : 2974179 : slot->tts_tid = tuple->t_self;
511 : :
512 [ + + ]: 2974179 : if (shouldFree)
513 : 1007 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
514 : 2974179 : }
515 : :
516 : :
517 : : /*
518 : : * TupleTableSlotOps implementation for MinimalTupleTableSlot.
519 : : */
520 : :
521 : : static void
522 : 270447 : tts_minimal_init(TupleTableSlot *slot)
523 : : {
524 : 270447 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
525 : :
526 : : /*
527 : : * Initialize the heap tuple pointer to access attributes of the minimal
528 : : * tuple contained in the slot as if it's a heap tuple.
529 : : */
530 : 270447 : mslot->tuple = &mslot->minhdr;
531 : 270447 : }
532 : :
533 : : static void
534 : 236919 : tts_minimal_release(TupleTableSlot *slot)
535 : : {
536 : 236919 : }
537 : :
538 : : static void
539 : 52412216 : tts_minimal_clear(TupleTableSlot *slot)
540 : : {
541 : 52412216 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
542 : :
543 [ + + ]: 52412216 : if (TTS_SHOULDFREE(slot))
544 : : {
545 : 8536605 : heap_free_minimal_tuple(mslot->mintuple);
546 : 8536605 : slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
547 : : }
548 : :
549 : 52412216 : slot->tts_nvalid = 0;
550 : 52412216 : slot->tts_flags |= TTS_FLAG_EMPTY;
551 : 52412216 : ItemPointerSetInvalid(&slot->tts_tid);
552 : 52412216 : mslot->off = 0;
553 : 52412216 : mslot->mintuple = NULL;
554 : 52412216 : }
555 : :
556 : : static void
557 : 38954392 : tts_minimal_getsomeattrs(TupleTableSlot *slot, int natts)
558 : : {
559 : 38954392 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
560 : :
561 : : Assert(!TTS_EMPTY(slot));
562 : :
563 : 38954392 : slot_deform_heap_tuple(slot, mslot->tuple, &mslot->off, natts, true);
564 : 38954392 : }
565 : :
566 : : /*
567 : : * MinimalTupleTableSlots never provide system attributes. We generally
568 : : * shouldn't get here, but provide a user-friendly message if we do.
569 : : */
570 : : static Datum
571 : 0 : tts_minimal_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
572 : : {
573 : : Assert(!TTS_EMPTY(slot));
574 : :
575 [ # # ]: 0 : ereport(ERROR,
576 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
577 : : errmsg("cannot retrieve a system column in this context")));
578 : :
579 : : return 0; /* silence compiler warnings */
580 : : }
581 : :
582 : : /*
583 : : * Within MinimalTuple abstraction transaction information is unavailable.
584 : : * We generally shouldn't get here, but provide a user-friendly message if
585 : : * we do.
586 : : */
587 : : static bool
588 : 0 : tts_minimal_is_current_xact_tuple(TupleTableSlot *slot)
589 : : {
590 : : Assert(!TTS_EMPTY(slot));
591 : :
592 [ # # ]: 0 : ereport(ERROR,
593 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
594 : : errmsg("don't have transaction information for this type of tuple")));
595 : :
596 : : return false; /* silence compiler warnings */
597 : : }
598 : :
599 : : static void
600 : 1051868 : tts_minimal_materialize(TupleTableSlot *slot)
601 : : {
602 : 1051868 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
603 : : MemoryContext oldContext;
604 : :
605 : : Assert(!TTS_EMPTY(slot));
606 : :
607 : : /* If slot has its tuple already materialized, nothing to do. */
608 [ + + ]: 1051868 : if (TTS_SHOULDFREE(slot))
609 : 96006 : return;
610 : :
611 : 955862 : oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
612 : :
613 : : /*
614 : : * Have to deform from scratch, otherwise tts_values[] entries could point
615 : : * into the non-materialized tuple (which might be gone when accessed).
616 : : */
617 : 955862 : slot->tts_nvalid = 0;
618 : 955862 : mslot->off = 0;
619 : :
620 [ + + ]: 955862 : if (!mslot->mintuple)
621 : : {
622 : 899380 : mslot->mintuple = heap_form_minimal_tuple(slot->tts_tupleDescriptor,
623 : 899380 : slot->tts_values,
624 : 899380 : slot->tts_isnull,
625 : : 0);
626 : : }
627 : : else
628 : : {
629 : : /*
630 : : * The minimal tuple contained in this slot is not allocated in the
631 : : * memory context of the given slot (else it would have
632 : : * TTS_FLAG_SHOULDFREE set). Copy the minimal tuple into the given
633 : : * slot's memory context.
634 : : */
635 : 56482 : mslot->mintuple = heap_copy_minimal_tuple(mslot->mintuple, 0);
636 : : }
637 : :
638 : 955862 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
639 : :
640 : : Assert(mslot->tuple == &mslot->minhdr);
641 : :
642 : 955862 : mslot->minhdr.t_len = mslot->mintuple->t_len + MINIMAL_TUPLE_OFFSET;
643 : 955862 : mslot->minhdr.t_data = (HeapTupleHeader) ((char *) mslot->mintuple - MINIMAL_TUPLE_OFFSET);
644 : :
645 : 955862 : MemoryContextSwitchTo(oldContext);
646 : : }
647 : :
648 : : static void
649 : 739710 : tts_minimal_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
650 : : {
651 : : MemoryContext oldcontext;
652 : : MinimalTuple mintuple;
653 : :
654 : 739710 : oldcontext = MemoryContextSwitchTo(dstslot->tts_mcxt);
655 : 739710 : mintuple = ExecCopySlotMinimalTuple(srcslot);
656 : 739710 : MemoryContextSwitchTo(oldcontext);
657 : :
658 : 739710 : ExecStoreMinimalTuple(mintuple, dstslot, true);
659 : 739710 : }
660 : :
661 : : static MinimalTuple
662 : 3342701 : tts_minimal_get_minimal_tuple(TupleTableSlot *slot)
663 : : {
664 : 3342701 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
665 : :
666 [ + + ]: 3342701 : if (!mslot->mintuple)
667 : 7122 : tts_minimal_materialize(slot);
668 : :
669 : 3342701 : return mslot->mintuple;
670 : : }
671 : :
672 : : static HeapTuple
673 : 652244 : tts_minimal_copy_heap_tuple(TupleTableSlot *slot)
674 : : {
675 : 652244 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
676 : :
677 [ + + ]: 652244 : if (!mslot->mintuple)
678 : 1152 : tts_minimal_materialize(slot);
679 : :
680 : 652244 : return heap_tuple_from_minimal_tuple(mslot->mintuple);
681 : : }
682 : :
683 : : static MinimalTuple
684 : 1925675 : tts_minimal_copy_minimal_tuple(TupleTableSlot *slot, Size extra)
685 : : {
686 : 1925675 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
687 : :
688 [ + + ]: 1925675 : if (!mslot->mintuple)
689 : 766696 : tts_minimal_materialize(slot);
690 : :
691 : 1925675 : return heap_copy_minimal_tuple(mslot->mintuple, extra);
692 : : }
693 : :
694 : : static void
695 : 43688939 : tts_minimal_store_tuple(TupleTableSlot *slot, MinimalTuple mtup, bool shouldFree)
696 : : {
697 : 43688939 : MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
698 : :
699 : 43688939 : tts_minimal_clear(slot);
700 : :
701 : : Assert(!TTS_SHOULDFREE(slot));
702 : : Assert(TTS_EMPTY(slot));
703 : :
704 : 43688939 : slot->tts_flags &= ~TTS_FLAG_EMPTY;
705 : 43688939 : slot->tts_nvalid = 0;
706 : 43688939 : mslot->off = 0;
707 : :
708 : 43688939 : mslot->mintuple = mtup;
709 : : Assert(mslot->tuple == &mslot->minhdr);
710 : 43688939 : mslot->minhdr.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
711 : 43688939 : mslot->minhdr.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);
712 : : /* no need to set t_self or t_tableOid since we won't allow access */
713 : :
714 [ + + ]: 43688939 : if (shouldFree)
715 : 7581873 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
716 : 43688939 : }
717 : :
718 : :
719 : : /*
720 : : * TupleTableSlotOps implementation for BufferHeapTupleTableSlot.
721 : : */
722 : :
723 : : static void
724 : 11207135 : tts_buffer_heap_init(TupleTableSlot *slot)
725 : : {
726 : 11207135 : }
727 : :
728 : : static void
729 : 11196043 : tts_buffer_heap_release(TupleTableSlot *slot)
730 : : {
731 : 11196043 : }
732 : :
733 : : static void
734 : 27368904 : tts_buffer_heap_clear(TupleTableSlot *slot)
735 : : {
736 : 27368904 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
737 : :
738 : : /*
739 : : * Free the memory for heap tuple if allowed. A tuple coming from buffer
740 : : * can never be freed. But we may have materialized a tuple from buffer.
741 : : * Such a tuple can be freed.
742 : : */
743 [ + + ]: 27368904 : if (TTS_SHOULDFREE(slot))
744 : : {
745 : : /* We should have unpinned the buffer while materializing the tuple. */
746 : : Assert(!BufferIsValid(bslot->buffer));
747 : :
748 : 11122125 : heap_freetuple(bslot->base.tuple);
749 : 11122125 : slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
750 : : }
751 : :
752 [ + + ]: 27368904 : if (BufferIsValid(bslot->buffer))
753 : 9823285 : ReleaseBuffer(bslot->buffer);
754 : :
755 : 27368904 : slot->tts_nvalid = 0;
756 : 27368904 : slot->tts_flags |= TTS_FLAG_EMPTY;
757 : 27368904 : ItemPointerSetInvalid(&slot->tts_tid);
758 : 27368904 : bslot->base.tuple = NULL;
759 : 27368904 : bslot->base.off = 0;
760 : 27368904 : bslot->buffer = InvalidBuffer;
761 : 27368904 : }
762 : :
763 : : static void
764 : 87414159 : tts_buffer_heap_getsomeattrs(TupleTableSlot *slot, int natts)
765 : : {
766 : 87414159 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
767 : :
768 : : Assert(!TTS_EMPTY(slot));
769 : :
770 : 87414159 : slot_deform_heap_tuple(slot, bslot->base.tuple, &bslot->base.off, natts, false);
771 : 87414159 : }
772 : :
773 : : static Datum
774 : 72805 : tts_buffer_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
775 : : {
776 : 72805 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
777 : :
778 : : Assert(!TTS_EMPTY(slot));
779 : :
780 : : /*
781 : : * In some code paths it's possible to get here with a non-materialized
782 : : * slot, in which case we can't retrieve system columns.
783 : : */
784 [ - + ]: 72805 : if (!bslot->base.tuple)
785 [ # # ]: 0 : ereport(ERROR,
786 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
787 : : errmsg("cannot retrieve a system column in this context")));
788 : :
789 : 72805 : return heap_getsysattr(bslot->base.tuple, attnum,
790 : : slot->tts_tupleDescriptor, isnull);
791 : : }
792 : :
793 : : static bool
794 : 570 : tts_buffer_is_current_xact_tuple(TupleTableSlot *slot)
795 : : {
796 : 570 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
797 : : TransactionId xmin;
798 : :
799 : : Assert(!TTS_EMPTY(slot));
800 : :
801 : : /*
802 : : * In some code paths it's possible to get here with a non-materialized
803 : : * slot, in which case we can't check if tuple is created by the current
804 : : * transaction.
805 : : */
806 [ - + ]: 570 : if (!bslot->base.tuple)
807 [ # # ]: 0 : ereport(ERROR,
808 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
809 : : errmsg("don't have a storage tuple in this context")));
810 : :
811 : 570 : xmin = HeapTupleHeaderGetRawXmin(bslot->base.tuple->t_data);
812 : :
813 : 570 : return TransactionIdIsCurrentTransactionId(xmin);
814 : : }
815 : :
816 : : static void
817 : 24225289 : tts_buffer_heap_materialize(TupleTableSlot *slot)
818 : : {
819 : 24225289 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
820 : : MemoryContext oldContext;
821 : :
822 : : Assert(!TTS_EMPTY(slot));
823 : :
824 : : /* If slot has its tuple already materialized, nothing to do. */
825 [ + + ]: 24225289 : if (TTS_SHOULDFREE(slot))
826 : 20586558 : return;
827 : :
828 : 3638731 : oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
829 : :
830 : : /*
831 : : * Have to deform from scratch, otherwise tts_values[] entries could point
832 : : * into the non-materialized tuple (which might be gone when accessed).
833 : : */
834 : 3638731 : bslot->base.off = 0;
835 : 3638731 : slot->tts_nvalid = 0;
836 : :
837 [ + + ]: 3638731 : if (!bslot->base.tuple)
838 : : {
839 : : /*
840 : : * Normally BufferHeapTupleTableSlot should have a tuple + buffer
841 : : * associated with it, unless it's materialized (which would've
842 : : * returned above). But when it's useful to allow storing virtual
843 : : * tuples in a buffer slot, which then also needs to be
844 : : * materializable.
845 : : */
846 : 3400262 : bslot->base.tuple = heap_form_tuple(slot->tts_tupleDescriptor,
847 : 3400262 : slot->tts_values,
848 : 3400262 : slot->tts_isnull);
849 : : }
850 : : else
851 : : {
852 : 238469 : bslot->base.tuple = heap_copytuple(bslot->base.tuple);
853 : :
854 : : /*
855 : : * A heap tuple stored in a BufferHeapTupleTableSlot should have a
856 : : * buffer associated with it, unless it's materialized or virtual.
857 : : */
858 [ + - ]: 238469 : if (likely(BufferIsValid(bslot->buffer)))
859 : 238469 : ReleaseBuffer(bslot->buffer);
860 : 238469 : bslot->buffer = InvalidBuffer;
861 : : }
862 : :
863 : : /*
864 : : * We don't set TTS_FLAG_SHOULDFREE until after releasing the buffer, if
865 : : * any. This avoids having a transient state that would fall foul of our
866 : : * assertions that a slot with TTS_FLAG_SHOULDFREE doesn't own a buffer.
867 : : * In the unlikely event that ReleaseBuffer() above errors out, we'd
868 : : * effectively leak the copied tuple, but that seems fairly harmless.
869 : : */
870 : 3638731 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
871 : :
872 : 3638731 : MemoryContextSwitchTo(oldContext);
873 : : }
874 : :
875 : : static void
876 : 7721550 : tts_buffer_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
877 : : {
878 : 7721550 : BufferHeapTupleTableSlot *bsrcslot = (BufferHeapTupleTableSlot *) srcslot;
879 : 7721550 : BufferHeapTupleTableSlot *bdstslot = (BufferHeapTupleTableSlot *) dstslot;
880 : :
881 : : /* ---
882 : : * If the source slot is of a different kind, or is a buffer slot that has
883 : : * been materialized / is virtual, make a new copy of the tuple. Otherwise
884 : : * make a new reference to the in-buffer tuple.
885 : : *
886 : : * There's no need to call heap_datum_check() here:
887 : : *
888 : : * - If the source is a buffer slot with a tuple in a buffer, the table
889 : : * locking protects (and the tuple is not marked as versioned)
890 : : *
891 : : * - If the source is a buffer slot with an allocated tuple or a heap slot,
892 : : * the tuple was checked when stored into the slot
893 : : *
894 : : * - If the source is a virtual slot, the heap tuple acquired below was
895 : : * just formed and thus will match the source slot's descriptor
896 : : *
897 : : * - Minimal slots do not carry composite tuples
898 : : *
899 : : * In all cases the planner / executor startup needs to have made sure the
900 : : * slot's descriptors are compatible. It might make sense to verify that,
901 : : * but that'd need to be done regardless of the tuple being a composite
902 : : * tuple or a row tuple.
903 : : * ---
904 : : */
905 [ + + ]: 7721550 : if (dstslot->tts_ops != srcslot->tts_ops ||
906 [ + + ]: 4363 : TTS_SHOULDFREE(srcslot) ||
907 [ - + ]: 4361 : !bsrcslot->base.tuple)
908 : 7717189 : {
909 : : MemoryContext oldContext;
910 : :
911 : 7717189 : ExecClearTuple(dstslot);
912 : 7717189 : dstslot->tts_flags &= ~TTS_FLAG_EMPTY;
913 : 7717189 : oldContext = MemoryContextSwitchTo(dstslot->tts_mcxt);
914 : 7717189 : bdstslot->base.tuple = ExecCopySlotHeapTuple(srcslot);
915 : 7717189 : dstslot->tts_flags |= TTS_FLAG_SHOULDFREE;
916 : 7717189 : MemoryContextSwitchTo(oldContext);
917 : : }
918 : : else
919 : : {
920 : : Assert(BufferIsValid(bsrcslot->buffer));
921 : :
922 : 4361 : tts_buffer_heap_store_tuple(dstslot, bsrcslot->base.tuple,
923 : : bsrcslot->buffer, false);
924 : :
925 : : /*
926 : : * The HeapTupleData portion of the source tuple might be shorter
927 : : * lived than the destination slot. Therefore copy the HeapTuple into
928 : : * our slot's tupdata, which is guaranteed to live long enough (but
929 : : * will still point into the buffer).
930 : : */
931 : 4361 : memcpy(&bdstslot->base.tupdata, bdstslot->base.tuple, sizeof(HeapTupleData));
932 : 4361 : bdstslot->base.tuple = &bdstslot->base.tupdata;
933 : : }
934 : 7721550 : }
935 : :
936 : : static HeapTuple
937 : 29413854 : tts_buffer_heap_get_heap_tuple(TupleTableSlot *slot)
938 : : {
939 : 29413854 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
940 : :
941 : : Assert(!TTS_EMPTY(slot));
942 : :
943 [ - + ]: 29413854 : if (!bslot->base.tuple)
944 : 0 : tts_buffer_heap_materialize(slot);
945 : :
946 : 29413854 : return bslot->base.tuple;
947 : : }
948 : :
949 : : static HeapTuple
950 : 7778341 : tts_buffer_heap_copy_heap_tuple(TupleTableSlot *slot)
951 : : {
952 : 7778341 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
953 : :
954 : : Assert(!TTS_EMPTY(slot));
955 : :
956 [ - + ]: 7778341 : if (!bslot->base.tuple)
957 : 0 : tts_buffer_heap_materialize(slot);
958 : :
959 : 7778341 : return heap_copytuple(bslot->base.tuple);
960 : : }
961 : :
962 : : static MinimalTuple
963 : 1896642 : tts_buffer_heap_copy_minimal_tuple(TupleTableSlot *slot, Size extra)
964 : : {
965 : 1896642 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
966 : :
967 : : Assert(!TTS_EMPTY(slot));
968 : :
969 [ - + ]: 1896642 : if (!bslot->base.tuple)
970 : 0 : tts_buffer_heap_materialize(slot);
971 : :
972 : 1896642 : return minimal_tuple_from_heap_tuple(bslot->base.tuple, extra);
973 : : }
974 : :
975 : : static inline void
976 : 106804829 : tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple,
977 : : Buffer buffer, bool transfer_pin)
978 : : {
979 : 106804829 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
980 : :
981 : : /*
982 : : * NB: We don't check the tuple version here, as this is an on-disk tuple
983 : : * that is protected otherwise (and will not be marked as versioned).
984 : : */
985 : :
986 [ + + ]: 106804829 : if (TTS_SHOULDFREE(slot))
987 : : {
988 : : /* materialized slot shouldn't have a buffer to release */
989 : : Assert(!BufferIsValid(bslot->buffer));
990 : :
991 : 239521 : heap_freetuple(bslot->base.tuple);
992 : 239521 : slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
993 : : }
994 : :
995 : 106804829 : slot->tts_flags &= ~TTS_FLAG_EMPTY;
996 : 106804829 : slot->tts_nvalid = 0;
997 : 106804829 : bslot->base.tuple = tuple;
998 : 106804829 : bslot->base.off = 0;
999 : 106804829 : slot->tts_tid = tuple->t_self;
1000 : :
1001 : : /*
1002 : : * If tuple is on a disk page, keep the page pinned as long as we hold a
1003 : : * pointer into it. We assume the caller already has such a pin. If
1004 : : * transfer_pin is true, we'll transfer that pin to this slot, if not
1005 : : * we'll pin it again ourselves.
1006 : : *
1007 : : * This is coded to optimize the case where the slot previously held a
1008 : : * tuple on the same disk page: in that case releasing and re-acquiring
1009 : : * the pin is a waste of cycles. This is a common situation during
1010 : : * seqscans, so it's worth troubling over.
1011 : : */
1012 [ + + ]: 106804829 : if (bslot->buffer != buffer)
1013 : : {
1014 [ + + ]: 13405613 : if (BufferIsValid(bslot->buffer))
1015 : 3337756 : ReleaseBuffer(bslot->buffer);
1016 : :
1017 : 13405613 : bslot->buffer = buffer;
1018 : :
1019 [ + + + - ]: 13405613 : if (!transfer_pin && BufferIsValid(buffer))
1020 : 12602119 : IncrBufferRefCount(buffer);
1021 : : }
1022 [ + + + - ]: 93399216 : else if (transfer_pin && BufferIsValid(buffer))
1023 : : {
1024 : : /*
1025 : : * In transfer_pin mode the caller won't know about the same-page
1026 : : * optimization, so we gotta release its pin.
1027 : : */
1028 : 2820109 : ReleaseBuffer(buffer);
1029 : : }
1030 : 106804829 : }
1031 : :
1032 : : /*
1033 : : * slot_deform_heap_tuple
1034 : : * Given a TupleTableSlot, extract data from the slot's physical tuple
1035 : : * into its Datum/isnull arrays. Data is extracted up through the
1036 : : * reqnatts'th column. If there are insufficient attributes in the given
1037 : : * tuple, then slot_getmissingattrs() is called to populate the
1038 : : * remainder. If reqnatts is above the number of attributes in the
1039 : : * slot's TupleDesc, an error is raised.
1040 : : *
1041 : : * This is essentially an incremental version of heap_deform_tuple:
1042 : : * on each call we extract attributes up to the one needed, without
1043 : : * re-computing information about previously extracted attributes.
1044 : : * slot->tts_nvalid is the number of attributes already extracted.
1045 : : *
1046 : : * This is marked as always inline, so the different offp for different types
1047 : : * of slots gets optimized away.
1048 : : *
1049 : : * support_cstring should be passed as a const to allow the compiler only
1050 : : * emit code during inlining for cstring deforming when it's required.
1051 : : * cstrings can exist in MinimalTuples, but not in HeapTuples.
1052 : : */
1053 : : static pg_always_inline void
1054 : 133182597 : slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
1055 : : int reqnatts, bool support_cstring)
1056 : : {
1057 : : CompactAttribute *cattrs;
1058 : : CompactAttribute *cattr;
1059 : 133182597 : TupleDesc tupleDesc = slot->tts_tupleDescriptor;
1060 : 133182597 : HeapTupleHeader tup = tuple->t_data;
1061 : : size_t attnum;
1062 : : int firstNonCacheOffsetAttr;
1063 : : int firstNonGuaranteedAttr;
1064 : : int firstNullAttr;
1065 : : int natts;
1066 : : Datum *values;
1067 : : bool *isnull;
1068 : : char *tp; /* ptr to tuple data */
1069 : : uint32 off; /* offset in tuple data */
1070 : :
1071 : : /* Did someone forget to call TupleDescFinalize()? */
1072 : : Assert(tupleDesc->firstNonCachedOffsetAttr >= 0);
1073 : :
1074 : 133182597 : isnull = slot->tts_isnull;
1075 : :
1076 : : /*
1077 : : * Some callers may form and deform tuples prior to NOT NULL constraints
1078 : : * being checked. Here we'd like to optimize the case where we only need
1079 : : * to fetch attributes before or up to the point where the attribute is
1080 : : * guaranteed to exist in the tuple. We rely on the slot flag being set
1081 : : * correctly to only enable this optimization when it's valid to do so.
1082 : : * This optimization allows us to save fetching the number of attributes
1083 : : * from the tuple and saves the additional cost of handling non-byval
1084 : : * attrs.
1085 : : */
1086 : 133182597 : firstNonGuaranteedAttr = Min(reqnatts, slot->tts_first_nonguaranteed);
1087 : :
1088 : 133182597 : firstNonCacheOffsetAttr = tupleDesc->firstNonCachedOffsetAttr;
1089 : :
1090 [ + + ]: 133182597 : if (HeapTupleHasNulls(tuple))
1091 : : {
1092 : 29844721 : natts = HeapTupleHeaderGetNatts(tup);
1093 : 29844721 : tp = (char *) tup + MAXALIGN(offsetof(HeapTupleHeaderData, t_bits) +
1094 : : BITMAPLEN(natts));
1095 : :
1096 : 29844721 : natts = Min(natts, reqnatts);
1097 [ + + ]: 29844721 : if (natts > firstNonGuaranteedAttr)
1098 : : {
1099 : 27843176 : uint8 *bp = tup->t_bits;
1100 : :
1101 : : /* Find the first NULL attr */
1102 : 27843176 : firstNullAttr = first_null_attr(bp, natts);
1103 : :
1104 : : /*
1105 : : * And populate the isnull array for all attributes being fetched
1106 : : * from the tuple.
1107 : : */
1108 : 27843176 : populate_isnull_array(bp, natts, isnull);
1109 : : }
1110 : : else
1111 : : {
1112 : : /* Otherwise all required columns are guaranteed to exist */
1113 : 2001545 : firstNullAttr = natts;
1114 : :
1115 : : /*
1116 : : * Check TupleDescFinalize() didn't get confused when setting
1117 : : * firstNonGuaranteedAttr. There should never be a NULL in a
1118 : : * guaranteed column.
1119 : : */
1120 : : Assert(first_null_attr(tup->t_bits, natts) >= firstNullAttr);
1121 : : }
1122 : : }
1123 : : else
1124 : : {
1125 : 103337876 : tp = (char *) tup + MAXALIGN(offsetof(HeapTupleHeaderData, t_bits));
1126 : :
1127 : : /*
1128 : : * We only need to look at the tuple's natts if we need more than the
1129 : : * guaranteed number of columns
1130 : : */
1131 [ + + ]: 103337876 : if (reqnatts > firstNonGuaranteedAttr)
1132 : 99098578 : natts = Min(HeapTupleHeaderGetNatts(tup), reqnatts);
1133 : : else
1134 : : {
1135 : : /* No need to access the number of attributes in the tuple */
1136 : 4239298 : natts = reqnatts;
1137 : : }
1138 : :
1139 : : /* All attrs can be fetched without checking for NULLs */
1140 : 103337876 : firstNullAttr = natts;
1141 : : }
1142 : :
1143 : 133182597 : attnum = slot->tts_nvalid;
1144 : 133182597 : values = slot->tts_values;
1145 : 133182597 : slot->tts_nvalid = reqnatts;
1146 : :
1147 : : /*
1148 : : * We store the tupleDesc's CompactAttribute array in 'cattrs' as gcc
1149 : : * seems to be unwilling to optimize accessing the CompactAttribute
1150 : : * element efficiently when accessing it via TupleDescCompactAttr().
1151 : : */
1152 : 133182597 : cattrs = tupleDesc->compact_attrs;
1153 : :
1154 : : /* Ensure we calculated tp correctly */
1155 : : Assert(tp == (char *) tup + tup->t_hoff);
1156 : :
1157 [ + + ]: 133182597 : if (attnum < firstNonGuaranteedAttr)
1158 : : {
1159 : : int attlen;
1160 : :
1161 : : do
1162 : : {
1163 : 40376663 : isnull[attnum] = false;
1164 : 40376663 : cattr = &cattrs[attnum];
1165 : 40376663 : attlen = cattr->attlen;
1166 : :
1167 : : /* We don't expect any non-byval types */
1168 [ - + ]: 40376663 : pg_assume(attlen > 0);
1169 : : Assert(cattr->attbyval == true);
1170 : :
1171 : 40376663 : off = cattr->attcacheoff;
1172 : 40376663 : values[attnum] = fetch_att_noerr(tp + off, true, attlen);
1173 : 40376663 : attnum++;
1174 [ + + ]: 40376663 : } while (attnum < firstNonGuaranteedAttr);
1175 : :
1176 : 23792280 : off += attlen;
1177 : :
1178 [ + + ]: 23792280 : if (attnum == reqnatts)
1179 : 6240843 : goto done;
1180 : : }
1181 : : else
1182 : : {
1183 : : /*
1184 : : * We may be incrementally deforming the tuple, so set 'off' to the
1185 : : * previously cached value. This may be 0, if the slot has just
1186 : : * received a new tuple.
1187 : : */
1188 : 109390317 : off = *offp;
1189 : :
1190 : : /* We expect *offp to be set to 0 when attnum == 0 */
1191 : : Assert(off == 0 || attnum > 0);
1192 : : }
1193 : :
1194 : : /* We can use attcacheoff up until the first NULL */
1195 : 126941754 : firstNonCacheOffsetAttr = Min(firstNonCacheOffsetAttr, firstNullAttr);
1196 : :
1197 : : /*
1198 : : * Handle the portion of the tuple that we have cached the offset for up
1199 : : * to the first NULL attribute. The offset is effectively fixed for
1200 : : * these, so we can use the CompactAttribute's attcacheoff.
1201 : : */
1202 [ + + ]: 126941754 : if (attnum < firstNonCacheOffsetAttr)
1203 : : {
1204 : : int attlen;
1205 : :
1206 : : do
1207 : : {
1208 : 368341749 : isnull[attnum] = false;
1209 : 368341749 : cattr = &cattrs[attnum];
1210 : 368341749 : attlen = cattr->attlen;
1211 : 368341749 : off = cattr->attcacheoff;
1212 : 736683498 : values[attnum] = fetch_att_noerr(tp + off,
1213 : 368341749 : cattr->attbyval,
1214 : : attlen);
1215 : 368341749 : attnum++;
1216 [ + + ]: 368341749 : } while (attnum < firstNonCacheOffsetAttr);
1217 : :
1218 : : /*
1219 : : * Point the offset after the end of the last attribute with a cached
1220 : : * offset. We expect the final cached offset attribute to have a
1221 : : * fixed width, so just add the attlen to the attcacheoff
1222 : : */
1223 : : Assert(attlen > 0);
1224 : 110613212 : off += attlen;
1225 : : }
1226 : :
1227 : : /*
1228 : : * Handle any portion of the tuple that doesn't have a fixed offset up
1229 : : * until the first NULL attribute. This loop only differs from the one
1230 : : * after it by the NULL checks.
1231 : : */
1232 [ + + ]: 159765223 : for (; attnum < firstNullAttr; attnum++)
1233 : : {
1234 : : int attlen;
1235 : :
1236 : 32823469 : isnull[attnum] = false;
1237 : 32823469 : cattr = &cattrs[attnum];
1238 : 32823469 : attlen = cattr->attlen;
1239 : :
1240 : : /*
1241 : : * Only emit the cstring-related code in align_fetch_then_add() when
1242 : : * cstring support is needed. We assume support_cstring will be
1243 : : * passed as a const to allow the compiler to eliminate this branch.
1244 : : */
1245 [ + + ]: 32823469 : if (!support_cstring)
1246 [ + + - + ]: 20686936 : pg_assume(attlen > 0 || attlen == -1);
1247 : :
1248 : : /* align 'off', fetch the datum, and increment off beyond the datum */
1249 : 32823469 : values[attnum] = align_fetch_then_add(tp,
1250 : : &off,
1251 : 32823469 : cattr->attbyval,
1252 : : attlen,
1253 : 32823469 : cattr->attalignby);
1254 : : }
1255 : :
1256 : : /*
1257 : : * Now handle any remaining attributes in the tuple up to the requested
1258 : : * attnum. This time, include NULL checks as we're now at the first NULL
1259 : : * attribute.
1260 : : */
1261 [ + + ]: 162915899 : for (; attnum < natts; attnum++)
1262 : : {
1263 : : int attlen;
1264 : :
1265 [ + + ]: 35974145 : if (isnull[attnum])
1266 : : {
1267 : 23811206 : values[attnum] = (Datum) 0;
1268 : 23811206 : continue;
1269 : : }
1270 : :
1271 : 12162939 : cattr = &cattrs[attnum];
1272 : 12162939 : attlen = cattr->attlen;
1273 : :
1274 : : /* As above, only emit cstring code when needed. */
1275 [ + + ]: 12162939 : if (!support_cstring)
1276 [ + + - + ]: 10494788 : pg_assume(attlen > 0 || attlen == -1);
1277 : :
1278 : : /* align 'off', fetch the datum, and increment off beyond the datum */
1279 : 12162939 : values[attnum] = align_fetch_then_add(tp,
1280 : : &off,
1281 : 12162939 : cattr->attbyval,
1282 : : attlen,
1283 : 12162939 : cattr->attalignby);
1284 : : }
1285 : :
1286 : : /* Fetch any missing attrs and raise an error if reqnatts is invalid */
1287 [ + + ]: 126941754 : if (unlikely(attnum < reqnatts))
1288 : : {
1289 : : /*
1290 : : * Cache the offset before calling the function to allow the compiler
1291 : : * to implement a tail-call optimization
1292 : : */
1293 : 4861 : *offp = off;
1294 : :
1295 : : Assert(HeapTupleHeaderGetNatts(tup) <= attnum);
1296 : :
1297 : : /*
1298 : : * Fetch all missing attributes. We pass natts rather than attnum as
1299 : : * if we're deforming attributes after having already deformed some
1300 : : * missing attributes, then the call to populate_isnull_array() may
1301 : : * have overwritten the previous tts_isnull values from what was
1302 : : * stored in the previous call to slot_getmissingattrs().
1303 : : */
1304 : 4861 : slot_getmissingattrs(slot, HeapTupleHeaderGetNatts(tup), reqnatts);
1305 : 4861 : return;
1306 : : }
1307 : 126936893 : done:
1308 : :
1309 : : /* Save current offset for next execution */
1310 : 133177736 : *offp = off;
1311 : : }
1312 : :
1313 : : const TupleTableSlotOps TTSOpsVirtual = {
1314 : : .base_slot_size = sizeof(VirtualTupleTableSlot),
1315 : : .init = tts_virtual_init,
1316 : : .release = tts_virtual_release,
1317 : : .clear = tts_virtual_clear,
1318 : : .getsomeattrs = tts_virtual_getsomeattrs,
1319 : : .getsysattr = tts_virtual_getsysattr,
1320 : : .materialize = tts_virtual_materialize,
1321 : : .is_current_xact_tuple = tts_virtual_is_current_xact_tuple,
1322 : : .copyslot = tts_virtual_copyslot,
1323 : :
1324 : : /*
1325 : : * A virtual tuple table slot can not "own" a heap tuple or a minimal
1326 : : * tuple.
1327 : : */
1328 : : .get_heap_tuple = NULL,
1329 : : .get_minimal_tuple = NULL,
1330 : : .copy_heap_tuple = tts_virtual_copy_heap_tuple,
1331 : : .copy_minimal_tuple = tts_virtual_copy_minimal_tuple
1332 : : };
1333 : :
1334 : : const TupleTableSlotOps TTSOpsHeapTuple = {
1335 : : .base_slot_size = sizeof(HeapTupleTableSlot),
1336 : : .init = tts_heap_init,
1337 : : .release = tts_heap_release,
1338 : : .clear = tts_heap_clear,
1339 : : .getsomeattrs = tts_heap_getsomeattrs,
1340 : : .getsysattr = tts_heap_getsysattr,
1341 : : .is_current_xact_tuple = tts_heap_is_current_xact_tuple,
1342 : : .materialize = tts_heap_materialize,
1343 : : .copyslot = tts_heap_copyslot,
1344 : : .get_heap_tuple = tts_heap_get_heap_tuple,
1345 : :
1346 : : /* A heap tuple table slot can not "own" a minimal tuple. */
1347 : : .get_minimal_tuple = NULL,
1348 : : .copy_heap_tuple = tts_heap_copy_heap_tuple,
1349 : : .copy_minimal_tuple = tts_heap_copy_minimal_tuple
1350 : : };
1351 : :
1352 : : const TupleTableSlotOps TTSOpsMinimalTuple = {
1353 : : .base_slot_size = sizeof(MinimalTupleTableSlot),
1354 : : .init = tts_minimal_init,
1355 : : .release = tts_minimal_release,
1356 : : .clear = tts_minimal_clear,
1357 : : .getsomeattrs = tts_minimal_getsomeattrs,
1358 : : .getsysattr = tts_minimal_getsysattr,
1359 : : .is_current_xact_tuple = tts_minimal_is_current_xact_tuple,
1360 : : .materialize = tts_minimal_materialize,
1361 : : .copyslot = tts_minimal_copyslot,
1362 : :
1363 : : /* A minimal tuple table slot can not "own" a heap tuple. */
1364 : : .get_heap_tuple = NULL,
1365 : : .get_minimal_tuple = tts_minimal_get_minimal_tuple,
1366 : : .copy_heap_tuple = tts_minimal_copy_heap_tuple,
1367 : : .copy_minimal_tuple = tts_minimal_copy_minimal_tuple
1368 : : };
1369 : :
1370 : : const TupleTableSlotOps TTSOpsBufferHeapTuple = {
1371 : : .base_slot_size = sizeof(BufferHeapTupleTableSlot),
1372 : : .init = tts_buffer_heap_init,
1373 : : .release = tts_buffer_heap_release,
1374 : : .clear = tts_buffer_heap_clear,
1375 : : .getsomeattrs = tts_buffer_heap_getsomeattrs,
1376 : : .getsysattr = tts_buffer_heap_getsysattr,
1377 : : .is_current_xact_tuple = tts_buffer_is_current_xact_tuple,
1378 : : .materialize = tts_buffer_heap_materialize,
1379 : : .copyslot = tts_buffer_heap_copyslot,
1380 : : .get_heap_tuple = tts_buffer_heap_get_heap_tuple,
1381 : :
1382 : : /* A buffer heap tuple table slot can not "own" a minimal tuple. */
1383 : : .get_minimal_tuple = NULL,
1384 : : .copy_heap_tuple = tts_buffer_heap_copy_heap_tuple,
1385 : : .copy_minimal_tuple = tts_buffer_heap_copy_minimal_tuple
1386 : : };
1387 : :
1388 : :
1389 : : /* ----------------------------------------------------------------
1390 : : * tuple table create/delete functions
1391 : : * ----------------------------------------------------------------
1392 : : */
1393 : :
1394 : : /* --------------------------------
1395 : : * MakeTupleTableSlot
1396 : : *
1397 : : * Basic routine to make an empty TupleTableSlot of given
1398 : : * TupleTableSlotType. If tupleDesc is specified the slot's descriptor is
1399 : : * fixed for its lifetime, gaining some efficiency. If that's
1400 : : * undesirable, pass NULL. 'flags' allows any of non-TTS_FLAGS_TRANSIENT
1401 : : * flags to be set in tts_flags.
1402 : : * --------------------------------
1403 : : */
1404 : : TupleTableSlot *
1405 : 15081466 : MakeTupleTableSlot(TupleDesc tupleDesc,
1406 : : const TupleTableSlotOps *tts_ops, uint16 flags)
1407 : : {
1408 : : Size basesz,
1409 : : allocsz;
1410 : : TupleTableSlot *slot;
1411 : :
1412 : 15081466 : basesz = tts_ops->base_slot_size;
1413 : :
1414 : : /* Ensure callers don't have any way to set transient flags permanently */
1415 : 15081466 : flags &= ~TTS_FLAGS_TRANSIENT;
1416 : :
1417 : : /*
1418 : : * When a fixed descriptor is specified, we can reduce overhead by
1419 : : * allocating the entire slot in one go.
1420 : : *
1421 : : * We round the size of tts_isnull up to the next highest multiple of 8.
1422 : : * This is needed as populate_isnull_array() operates on 8 elements at a
1423 : : * time when converting a tuple's NULL bitmap into a boolean array.
1424 : : */
1425 [ + + ]: 15081466 : if (tupleDesc)
1426 : 15044584 : allocsz = MAXALIGN(basesz) +
1427 : 15044584 : MAXALIGN(tupleDesc->natts * sizeof(Datum)) +
1428 : 15044584 : TYPEALIGN(8, tupleDesc->natts * sizeof(bool));
1429 : : else
1430 : 36882 : allocsz = basesz;
1431 : :
1432 : 15081466 : slot = palloc0(allocsz);
1433 : : /* const for optimization purposes, OK to modify at allocation time */
1434 : 15081466 : *((const TupleTableSlotOps **) &slot->tts_ops) = tts_ops;
1435 : 15081466 : slot->type = T_TupleTableSlot;
1436 : 15081466 : slot->tts_flags = TTS_FLAG_EMPTY | flags;
1437 [ + + ]: 15081466 : if (tupleDesc != NULL)
1438 : 15044584 : slot->tts_flags |= TTS_FLAG_FIXED;
1439 : 15081466 : slot->tts_tupleDescriptor = tupleDesc;
1440 : 15081466 : slot->tts_mcxt = CurrentMemoryContext;
1441 : 15081466 : slot->tts_nvalid = 0;
1442 : :
1443 [ + + ]: 15081466 : if (tupleDesc != NULL)
1444 : : {
1445 : 15044584 : slot->tts_values = (Datum *)
1446 : : (((char *) slot)
1447 : 15044584 : + MAXALIGN(basesz));
1448 : :
1449 : 15044584 : slot->tts_isnull = (bool *)
1450 : : (((char *) slot)
1451 : 15044584 : + MAXALIGN(basesz)
1452 : 15044584 : + MAXALIGN(tupleDesc->natts * sizeof(Datum)));
1453 : :
1454 [ + + ]: 15044584 : PinTupleDesc(tupleDesc);
1455 : :
1456 : : /*
1457 : : * Precalculate the maximum guaranteed attribute that has to exist in
1458 : : * every tuple which gets deformed into this slot. When the
1459 : : * TTS_FLAG_OBEYS_NOT_NULL_CONSTRAINTS flag is enabled, we simply take
1460 : : * the pre-calculated value from the tupleDesc, otherwise the
1461 : : * optimization is disabled, and we set the value to 0.
1462 : : */
1463 [ + + ]: 15044584 : if ((flags & TTS_FLAG_OBEYS_NOT_NULL_CONSTRAINTS) != 0)
1464 : 286231 : slot->tts_first_nonguaranteed = tupleDesc->firstNonGuaranteedAttr;
1465 : : else
1466 : 14758353 : slot->tts_first_nonguaranteed = 0;
1467 : : }
1468 : :
1469 : : /*
1470 : : * And allow slot type specific initialization.
1471 : : */
1472 : 15081466 : slot->tts_ops->init(slot);
1473 : :
1474 : 15081466 : return slot;
1475 : : }
1476 : :
1477 : : /* --------------------------------
1478 : : * ExecAllocTableSlot
1479 : : *
1480 : : * Create a tuple table slot within a tuple table (which is just a List).
1481 : : * --------------------------------
1482 : : */
1483 : : TupleTableSlot *
1484 : 1375970 : ExecAllocTableSlot(List **tupleTable, TupleDesc desc,
1485 : : const TupleTableSlotOps *tts_ops, uint16 flags)
1486 : : {
1487 : 1375970 : TupleTableSlot *slot = MakeTupleTableSlot(desc, tts_ops, flags);
1488 : :
1489 : 1375970 : *tupleTable = lappend(*tupleTable, slot);
1490 : :
1491 : 1375970 : return slot;
1492 : : }
1493 : :
1494 : : /* --------------------------------
1495 : : * ExecResetTupleTable
1496 : : *
1497 : : * This releases any resources (buffer pins, tupdesc refcounts)
1498 : : * held by the tuple table, and optionally releases the memory
1499 : : * occupied by the tuple table data structure.
1500 : : * It is expected that this routine be called by ExecEndPlan().
1501 : : * --------------------------------
1502 : : */
1503 : : void
1504 : 529701 : ExecResetTupleTable(List *tupleTable, /* tuple table */
1505 : : bool shouldFree) /* true if we should free memory */
1506 : : {
1507 : : ListCell *lc;
1508 : :
1509 [ + + + + : 2038024 : foreach(lc, tupleTable)
+ + ]
1510 : : {
1511 : 1508323 : TupleTableSlot *slot = lfirst_node(TupleTableSlot, lc);
1512 : :
1513 : : /* Always release resources and reset the slot to empty */
1514 : 1508323 : ExecClearTuple(slot);
1515 : 1508323 : slot->tts_ops->release(slot);
1516 [ + + ]: 1508323 : if (slot->tts_tupleDescriptor)
1517 : : {
1518 [ + + ]: 1508287 : ReleaseTupleDesc(slot->tts_tupleDescriptor);
1519 : 1508287 : slot->tts_tupleDescriptor = NULL;
1520 : : }
1521 : :
1522 : : /* If shouldFree, release memory occupied by the slot itself */
1523 [ + + ]: 1508323 : if (shouldFree)
1524 : : {
1525 [ - + ]: 4880 : if (!TTS_FIXED(slot))
1526 : : {
1527 [ # # ]: 0 : if (slot->tts_values)
1528 : 0 : pfree(slot->tts_values);
1529 [ # # ]: 0 : if (slot->tts_isnull)
1530 : 0 : pfree(slot->tts_isnull);
1531 : : }
1532 : 4880 : pfree(slot);
1533 : : }
1534 : : }
1535 : :
1536 : : /* If shouldFree, release the list structure */
1537 [ + + ]: 529701 : if (shouldFree)
1538 : 4794 : list_free(tupleTable);
1539 : 529701 : }
1540 : :
1541 : : /* --------------------------------
1542 : : * MakeSingleTupleTableSlot
1543 : : *
1544 : : * This is a convenience routine for operations that need a standalone
1545 : : * TupleTableSlot not gotten from the main executor tuple table. It makes
1546 : : * a single slot of given TupleTableSlotType and initializes it to use the
1547 : : * given tuple descriptor.
1548 : : * --------------------------------
1549 : : */
1550 : : TupleTableSlot *
1551 : 13705380 : MakeSingleTupleTableSlot(TupleDesc tupdesc,
1552 : : const TupleTableSlotOps *tts_ops)
1553 : : {
1554 : 13705380 : TupleTableSlot *slot = MakeTupleTableSlot(tupdesc, tts_ops, 0);
1555 : :
1556 : 13705380 : return slot;
1557 : : }
1558 : :
1559 : : /* --------------------------------
1560 : : * ExecDropSingleTupleTableSlot
1561 : : *
1562 : : * Release a TupleTableSlot made with MakeSingleTupleTableSlot.
1563 : : * DON'T use this on a slot that's part of a tuple table list!
1564 : : * --------------------------------
1565 : : */
1566 : : void
1567 : 13506360 : ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
1568 : : {
1569 : : /* This should match ExecResetTupleTable's processing of one slot */
1570 : : Assert(IsA(slot, TupleTableSlot));
1571 : 13506360 : ExecClearTuple(slot);
1572 : 13506360 : slot->tts_ops->release(slot);
1573 [ + - ]: 13506360 : if (slot->tts_tupleDescriptor)
1574 [ + + ]: 13506360 : ReleaseTupleDesc(slot->tts_tupleDescriptor);
1575 [ - + ]: 13506360 : if (!TTS_FIXED(slot))
1576 : : {
1577 [ # # ]: 0 : if (slot->tts_values)
1578 : 0 : pfree(slot->tts_values);
1579 [ # # ]: 0 : if (slot->tts_isnull)
1580 : 0 : pfree(slot->tts_isnull);
1581 : : }
1582 : 13506360 : pfree(slot);
1583 : 13506360 : }
1584 : :
1585 : :
1586 : : /* ----------------------------------------------------------------
1587 : : * tuple table slot accessor functions
1588 : : * ----------------------------------------------------------------
1589 : : */
1590 : :
1591 : : /* --------------------------------
1592 : : * ExecSetSlotDescriptor
1593 : : *
1594 : : * This function is used to set the tuple descriptor associated
1595 : : * with the slot's tuple. The passed descriptor must have lifespan
1596 : : * at least equal to the slot's. If it is a reference-counted descriptor
1597 : : * then the reference count is incremented for as long as the slot holds
1598 : : * a reference.
1599 : : * --------------------------------
1600 : : */
1601 : : void
1602 : 36846 : ExecSetSlotDescriptor(TupleTableSlot *slot, /* slot to change */
1603 : : TupleDesc tupdesc) /* new tuple descriptor */
1604 : : {
1605 : : Assert(!TTS_FIXED(slot));
1606 : :
1607 : : /* For safety, make sure slot is empty before changing it */
1608 : 36846 : ExecClearTuple(slot);
1609 : :
1610 : : /*
1611 : : * Release any old descriptor. Also release old Datum/isnull arrays if
1612 : : * present (we don't bother to check if they could be re-used).
1613 : : */
1614 [ - + ]: 36846 : if (slot->tts_tupleDescriptor)
1615 [ # # ]: 0 : ReleaseTupleDesc(slot->tts_tupleDescriptor);
1616 : :
1617 [ - + ]: 36846 : if (slot->tts_values)
1618 : 0 : pfree(slot->tts_values);
1619 [ - + ]: 36846 : if (slot->tts_isnull)
1620 : 0 : pfree(slot->tts_isnull);
1621 : :
1622 : : /*
1623 : : * Install the new descriptor; if it's refcounted, bump its refcount.
1624 : : */
1625 : 36846 : slot->tts_tupleDescriptor = tupdesc;
1626 [ - + ]: 36846 : PinTupleDesc(tupdesc);
1627 : :
1628 : : /*
1629 : : * Allocate Datum/isnull arrays of the appropriate size. These must have
1630 : : * the same lifetime as the slot, so allocate in the slot's own context.
1631 : : */
1632 : 36846 : slot->tts_values = (Datum *)
1633 : 36846 : MemoryContextAlloc(slot->tts_mcxt, tupdesc->natts * sizeof(Datum));
1634 : :
1635 : : /*
1636 : : * We round the size of tts_isnull up to the next highest multiple of 8.
1637 : : * This is needed as populate_isnull_array() operates on 8 elements at a
1638 : : * time when converting a tuple's NULL bitmap into a boolean array.
1639 : : */
1640 : 36846 : slot->tts_isnull = (bool *)
1641 : 36846 : MemoryContextAlloc(slot->tts_mcxt, TYPEALIGN(8, tupdesc->natts * sizeof(bool)));
1642 : 36846 : }
1643 : :
1644 : : /* --------------------------------
1645 : : * ExecStoreHeapTuple
1646 : : *
1647 : : * This function is used to store an on-the-fly physical tuple into a specified
1648 : : * slot in the tuple table.
1649 : : *
1650 : : * tuple: tuple to store
1651 : : * slot: TTSOpsHeapTuple type slot to store it in
1652 : : * shouldFree: true if ExecClearTuple should pfree() the tuple
1653 : : * when done with it
1654 : : *
1655 : : * shouldFree is normally set 'true' for tuples constructed on-the-fly. But it
1656 : : * can be 'false' when the referenced tuple is held in a tuple table slot
1657 : : * belonging to a lower-level executor Proc node. In this case the lower-level
1658 : : * slot retains ownership and responsibility for eventually releasing the
1659 : : * tuple. When this method is used, we must be certain that the upper-level
1660 : : * Proc node will lose interest in the tuple sooner than the lower-level one
1661 : : * does! If you're not certain, copy the lower-level tuple with heap_copytuple
1662 : : * and let the upper-level table slot assume ownership of the copy!
1663 : : *
1664 : : * Return value is just the passed-in slot pointer.
1665 : : *
1666 : : * If the target slot is not guaranteed to be TTSOpsHeapTuple type slot, use
1667 : : * the, more expensive, ExecForceStoreHeapTuple().
1668 : : * --------------------------------
1669 : : */
1670 : : TupleTableSlot *
1671 : 2974179 : ExecStoreHeapTuple(HeapTuple tuple,
1672 : : TupleTableSlot *slot,
1673 : : bool shouldFree)
1674 : : {
1675 : : /*
1676 : : * sanity checks
1677 : : */
1678 : : Assert(tuple != NULL);
1679 : : Assert(slot != NULL);
1680 : : Assert(slot->tts_tupleDescriptor != NULL);
1681 : :
1682 [ - + ]: 2974179 : if (unlikely(!TTS_IS_HEAPTUPLE(slot)))
1683 [ # # ]: 0 : elog(ERROR, "trying to store a heap tuple into wrong type of slot");
1684 : 2974179 : tts_heap_store_tuple(slot, tuple, shouldFree);
1685 : :
1686 : 2974179 : slot->tts_tableOid = tuple->t_tableOid;
1687 : :
1688 : 2974179 : return slot;
1689 : : }
1690 : :
1691 : : /* --------------------------------
1692 : : * ExecStoreBufferHeapTuple
1693 : : *
1694 : : * This function is used to store an on-disk physical tuple from a buffer
1695 : : * into a specified slot in the tuple table.
1696 : : *
1697 : : * tuple: tuple to store
1698 : : * slot: TTSOpsBufferHeapTuple type slot to store it in
1699 : : * buffer: disk buffer if tuple is in a disk page, else InvalidBuffer
1700 : : *
1701 : : * The tuple table code acquires a pin on the buffer which is held until the
1702 : : * slot is cleared, so that the tuple won't go away on us.
1703 : : *
1704 : : * Return value is just the passed-in slot pointer.
1705 : : *
1706 : : * If the target slot is not guaranteed to be TTSOpsBufferHeapTuple type slot,
1707 : : * use the, more expensive, ExecForceStoreHeapTuple().
1708 : : * --------------------------------
1709 : : */
1710 : : TupleTableSlot *
1711 : 103176865 : ExecStoreBufferHeapTuple(HeapTuple tuple,
1712 : : TupleTableSlot *slot,
1713 : : Buffer buffer)
1714 : : {
1715 : : /*
1716 : : * sanity checks
1717 : : */
1718 : : Assert(tuple != NULL);
1719 : : Assert(slot != NULL);
1720 : : Assert(slot->tts_tupleDescriptor != NULL);
1721 : : Assert(BufferIsValid(buffer));
1722 : :
1723 [ - + ]: 103176865 : if (unlikely(!TTS_IS_BUFFERTUPLE(slot)))
1724 [ # # ]: 0 : elog(ERROR, "trying to store an on-disk heap tuple into wrong type of slot");
1725 : 103176865 : tts_buffer_heap_store_tuple(slot, tuple, buffer, false);
1726 : :
1727 : 103176865 : slot->tts_tableOid = tuple->t_tableOid;
1728 : :
1729 : 103176865 : return slot;
1730 : : }
1731 : :
1732 : : /*
1733 : : * Like ExecStoreBufferHeapTuple, but transfer an existing pin from the caller
1734 : : * to the slot, i.e. the caller doesn't need to, and may not, release the pin.
1735 : : */
1736 : : TupleTableSlot *
1737 : 3623603 : ExecStorePinnedBufferHeapTuple(HeapTuple tuple,
1738 : : TupleTableSlot *slot,
1739 : : Buffer buffer)
1740 : : {
1741 : : /*
1742 : : * sanity checks
1743 : : */
1744 : : Assert(tuple != NULL);
1745 : : Assert(slot != NULL);
1746 : : Assert(slot->tts_tupleDescriptor != NULL);
1747 : : Assert(BufferIsValid(buffer));
1748 : :
1749 [ - + ]: 3623603 : if (unlikely(!TTS_IS_BUFFERTUPLE(slot)))
1750 [ # # ]: 0 : elog(ERROR, "trying to store an on-disk heap tuple into wrong type of slot");
1751 : 3623603 : tts_buffer_heap_store_tuple(slot, tuple, buffer, true);
1752 : :
1753 : 3623603 : slot->tts_tableOid = tuple->t_tableOid;
1754 : :
1755 : 3623603 : return slot;
1756 : : }
1757 : :
1758 : : /*
1759 : : * Store a minimal tuple into TTSOpsMinimalTuple type slot.
1760 : : *
1761 : : * If the target slot is not guaranteed to be TTSOpsMinimalTuple type slot,
1762 : : * use the, more expensive, ExecForceStoreMinimalTuple().
1763 : : */
1764 : : TupleTableSlot *
1765 : 40742307 : ExecStoreMinimalTuple(MinimalTuple mtup,
1766 : : TupleTableSlot *slot,
1767 : : bool shouldFree)
1768 : : {
1769 : : /*
1770 : : * sanity checks
1771 : : */
1772 : : Assert(mtup != NULL);
1773 : : Assert(slot != NULL);
1774 : : Assert(slot->tts_tupleDescriptor != NULL);
1775 : :
1776 [ - + ]: 40742307 : if (unlikely(!TTS_IS_MINIMALTUPLE(slot)))
1777 [ # # ]: 0 : elog(ERROR, "trying to store a minimal tuple into wrong type of slot");
1778 : 40742307 : tts_minimal_store_tuple(slot, mtup, shouldFree);
1779 : :
1780 : 40742307 : return slot;
1781 : : }
1782 : :
1783 : : /*
1784 : : * Store a HeapTuple into any kind of slot, performing conversion if
1785 : : * necessary.
1786 : : */
1787 : : void
1788 : 148132 : ExecForceStoreHeapTuple(HeapTuple tuple,
1789 : : TupleTableSlot *slot,
1790 : : bool shouldFree)
1791 : : {
1792 [ + + ]: 148132 : if (TTS_IS_HEAPTUPLE(slot))
1793 : : {
1794 : 267 : ExecStoreHeapTuple(tuple, slot, shouldFree);
1795 : : }
1796 [ + + ]: 147865 : else if (TTS_IS_BUFFERTUPLE(slot))
1797 : : {
1798 : : MemoryContext oldContext;
1799 : 8453 : BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
1800 : :
1801 : : /*
1802 : : * Normally buffer slots don't need checking, because the data should
1803 : : * come from an on-disk relation, which always should be protected
1804 : : * against concurrent modifications. But in this path that's not
1805 : : * really guaranteed to be the case - so better be paranoid.
1806 : : */
1807 [ + + ]: 8453 : if (HeapTupleHeaderIsVersionedDatum(tuple->t_data))
1808 : 1193 : heap_datum_check(tuple->t_data, slot->tts_tupleDescriptor);
1809 : :
1810 : 8449 : ExecClearTuple(slot);
1811 : 8449 : slot->tts_flags &= ~TTS_FLAG_EMPTY;
1812 : 8449 : oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
1813 : 8449 : bslot->base.tuple = heap_copytuple(tuple);
1814 : 8449 : slot->tts_flags |= TTS_FLAG_SHOULDFREE;
1815 : 8449 : slot->tts_tid = tuple->t_self;
1816 : 8449 : MemoryContextSwitchTo(oldContext);
1817 : :
1818 [ + + ]: 8449 : if (shouldFree)
1819 : 7213 : pfree(tuple);
1820 : : }
1821 : : else
1822 : : {
1823 : 139412 : ExecClearTuple(slot);
1824 : 139412 : heap_deform_tuple(tuple, slot->tts_tupleDescriptor,
1825 : : slot->tts_values, slot->tts_isnull);
1826 : 139412 : ExecStoreVirtualTuple(slot);
1827 : 139412 : slot->tts_tid = tuple->t_self;
1828 : :
1829 [ + + ]: 139412 : if (shouldFree)
1830 : : {
1831 : 138825 : ExecMaterializeSlot(slot);
1832 : 138825 : pfree(tuple);
1833 : : }
1834 : : }
1835 : 148128 : }
1836 : :
1837 : : /*
1838 : : * Store a MinimalTuple into any kind of slot, performing conversion if
1839 : : * necessary.
1840 : : */
1841 : : void
1842 : 4705516 : ExecForceStoreMinimalTuple(MinimalTuple mtup,
1843 : : TupleTableSlot *slot,
1844 : : bool shouldFree)
1845 : : {
1846 [ + + ]: 4705516 : if (TTS_IS_MINIMALTUPLE(slot))
1847 : : {
1848 : 2946632 : tts_minimal_store_tuple(slot, mtup, shouldFree);
1849 : : }
1850 : : else
1851 : : {
1852 : : HeapTupleData htup;
1853 : :
1854 : 1758884 : ExecClearTuple(slot);
1855 : :
1856 : 1758884 : htup.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
1857 : 1758884 : htup.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);
1858 : 1758884 : heap_deform_tuple(&htup, slot->tts_tupleDescriptor,
1859 : : slot->tts_values, slot->tts_isnull);
1860 : 1758884 : ExecStoreVirtualTuple(slot);
1861 : :
1862 [ + + ]: 1758884 : if (shouldFree)
1863 : : {
1864 : 958860 : ExecMaterializeSlot(slot);
1865 : 958860 : pfree(mtup);
1866 : : }
1867 : : }
1868 : 4705516 : }
1869 : :
1870 : : /* --------------------------------
1871 : : * ExecStoreVirtualTuple
1872 : : * Mark a slot as containing a virtual tuple.
1873 : : *
1874 : : * The protocol for loading a slot with virtual tuple data is:
1875 : : * * Call ExecClearTuple to mark the slot empty.
1876 : : * * Store data into the Datum/isnull arrays.
1877 : : * * Call ExecStoreVirtualTuple to mark the slot valid.
1878 : : * This is a bit unclean but it avoids one round of data copying.
1879 : : * --------------------------------
1880 : : */
1881 : : TupleTableSlot *
1882 : 20000198 : ExecStoreVirtualTuple(TupleTableSlot *slot)
1883 : : {
1884 : : /*
1885 : : * sanity checks
1886 : : */
1887 : : Assert(slot != NULL);
1888 : : Assert(slot->tts_tupleDescriptor != NULL);
1889 : : Assert(TTS_EMPTY(slot));
1890 : :
1891 : 20000198 : slot->tts_flags &= ~TTS_FLAG_EMPTY;
1892 : 20000198 : slot->tts_nvalid = slot->tts_tupleDescriptor->natts;
1893 : :
1894 : 20000198 : return slot;
1895 : : }
1896 : :
1897 : : /* --------------------------------
1898 : : * ExecStoreAllNullTuple
1899 : : * Set up the slot to contain a null in every column.
1900 : : *
1901 : : * At first glance this might sound just like ExecClearTuple, but it's
1902 : : * entirely different: the slot ends up full, not empty.
1903 : : * --------------------------------
1904 : : */
1905 : : TupleTableSlot *
1906 : 32310 : ExecStoreAllNullTuple(TupleTableSlot *slot)
1907 : : {
1908 : : /*
1909 : : * sanity checks
1910 : : */
1911 : : Assert(slot != NULL);
1912 : : Assert(slot->tts_tupleDescriptor != NULL);
1913 : :
1914 : : /* Clear any old contents */
1915 : 32310 : ExecClearTuple(slot);
1916 : :
1917 : : /*
1918 : : * Fill all the columns of the virtual tuple with nulls
1919 : : */
1920 [ + - + - : 218623 : MemSet(slot->tts_values, 0,
+ - + - +
+ ]
1921 : : slot->tts_tupleDescriptor->natts * sizeof(Datum));
1922 : 32310 : memset(slot->tts_isnull, true,
1923 : 32310 : slot->tts_tupleDescriptor->natts * sizeof(bool));
1924 : :
1925 : 32310 : return ExecStoreVirtualTuple(slot);
1926 : : }
1927 : :
1928 : : /*
1929 : : * Store a HeapTuple in datum form, into a slot. That always requires
1930 : : * deforming it and storing it in virtual form.
1931 : : *
1932 : : * Until the slot is materialized, the contents of the slot depend on the
1933 : : * datum.
1934 : : */
1935 : : void
1936 : 15 : ExecStoreHeapTupleDatum(Datum data, TupleTableSlot *slot)
1937 : : {
1938 : 15 : HeapTupleData tuple = {0};
1939 : : HeapTupleHeader td;
1940 : : bool was_datum;
1941 : :
1942 : 15 : td = DatumGetHeapTupleHeaderExt(data, &was_datum);
1943 : :
1944 : : /*
1945 : : * No known path (be it core or pgxn extensions) gets here with
1946 : : * pre-upgrade tuples, so it seems better to be paranoid and assert that
1947 : : * we are passed a versioned tuple.
1948 : : */
1949 : : Assert(was_datum &&
1950 : : (HeapTupleHeaderIsVersionedDatum(td) ||
1951 : : HeapTupleHeaderGetTypeId(td) == RECORDOID));
1952 : :
1953 : 15 : tuple.t_len = HeapTupleHeaderGetDatumLength(td);
1954 : 15 : tuple.t_data = td;
1955 : :
1956 : 15 : ExecClearTuple(slot);
1957 : :
1958 : : /*
1959 : : * Datum tuples do not have valid ctids, so there's no point in copying
1960 : : * them. Historically there was some code that pretended to do so, but it
1961 : : * never actually did anything. The only current user of this function is
1962 : : * ROW_MARK_COPY, which forms a wholerow attribute via
1963 : : * ExecEvalWholeRowVar(), which does not maintain ctid.
1964 : : */
1965 : :
1966 : 15 : heap_deform_tuple(&tuple, slot->tts_tupleDescriptor,
1967 : : slot->tts_values, slot->tts_isnull);
1968 : 12 : ExecStoreVirtualTuple(slot);
1969 : 12 : }
1970 : :
1971 : : /*
1972 : : * ExecFetchSlotHeapTuple - fetch HeapTuple representing the slot's content
1973 : : *
1974 : : * The returned HeapTuple represents the slot's content as closely as
1975 : : * possible.
1976 : : *
1977 : : * If materialize is true, the contents of the slots will be made independent
1978 : : * from the underlying storage (i.e. all buffer pins are released, memory is
1979 : : * allocated in the slot's context).
1980 : : *
1981 : : * If shouldFree is not-NULL it'll be set to true if the returned tuple has
1982 : : * been allocated in the calling memory context, and must be freed by the
1983 : : * caller (via explicit pfree() or a memory context reset).
1984 : : *
1985 : : * NB: If materialize is true, modifications of the returned tuple are
1986 : : * allowed. But it depends on the type of the slot whether such modifications
1987 : : * will also affect the slot's contents. While that is not the nicest
1988 : : * behaviour, all such modifications are in the process of being removed.
1989 : : */
1990 : : HeapTuple
1991 : 34735777 : ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
1992 : : {
1993 : : /*
1994 : : * sanity checks
1995 : : */
1996 : : Assert(slot != NULL);
1997 : : Assert(!TTS_EMPTY(slot));
1998 : :
1999 : : /* Materialize the tuple so that the slot "owns" it, if requested. */
2000 [ + + ]: 34735777 : if (materialize)
2001 : 16121559 : slot->tts_ops->materialize(slot);
2002 : :
2003 [ + + ]: 34735777 : if (slot->tts_ops->get_heap_tuple == NULL)
2004 : : {
2005 [ + - ]: 3075559 : if (shouldFree)
2006 : 3075559 : *shouldFree = true;
2007 : 3075559 : return slot->tts_ops->copy_heap_tuple(slot);
2008 : : }
2009 : : else
2010 : : {
2011 [ + + ]: 31660218 : if (shouldFree)
2012 : 29226992 : *shouldFree = false;
2013 : 31660218 : return slot->tts_ops->get_heap_tuple(slot);
2014 : : }
2015 : : }
2016 : :
2017 : : /* --------------------------------
2018 : : * ExecFetchSlotMinimalTuple
2019 : : * Fetch the slot's minimal physical tuple.
2020 : : *
2021 : : * If the given tuple table slot can hold a minimal tuple, indicated by a
2022 : : * non-NULL get_minimal_tuple callback, the function returns the minimal
2023 : : * tuple returned by that callback. It assumes that the minimal tuple
2024 : : * returned by the callback is "owned" by the slot i.e. the slot is
2025 : : * responsible for freeing the memory consumed by the tuple. Hence it sets
2026 : : * *shouldFree to false, indicating that the caller should not free the
2027 : : * memory consumed by the minimal tuple. In this case the returned minimal
2028 : : * tuple should be considered as read-only.
2029 : : *
2030 : : * If that callback is not supported, it calls copy_minimal_tuple callback
2031 : : * which is expected to return a copy of minimal tuple representing the
2032 : : * contents of the slot. In this case *shouldFree is set to true,
2033 : : * indicating the caller that it should free the memory consumed by the
2034 : : * minimal tuple. In this case the returned minimal tuple may be written
2035 : : * up.
2036 : : * --------------------------------
2037 : : */
2038 : : MinimalTuple
2039 : 14052564 : ExecFetchSlotMinimalTuple(TupleTableSlot *slot,
2040 : : bool *shouldFree)
2041 : : {
2042 : : /*
2043 : : * sanity checks
2044 : : */
2045 : : Assert(slot != NULL);
2046 : : Assert(!TTS_EMPTY(slot));
2047 : :
2048 [ + + ]: 14052564 : if (slot->tts_ops->get_minimal_tuple)
2049 : : {
2050 [ + - ]: 3342701 : if (shouldFree)
2051 : 3342701 : *shouldFree = false;
2052 : 3342701 : return slot->tts_ops->get_minimal_tuple(slot);
2053 : : }
2054 : : else
2055 : : {
2056 [ + - ]: 10709863 : if (shouldFree)
2057 : 10709863 : *shouldFree = true;
2058 : 10709863 : return slot->tts_ops->copy_minimal_tuple(slot, 0);
2059 : : }
2060 : : }
2061 : :
2062 : : /* --------------------------------
2063 : : * ExecFetchSlotHeapTupleDatum
2064 : : * Fetch the slot's tuple as a composite-type Datum.
2065 : : *
2066 : : * The result is always freshly palloc'd in the caller's memory context.
2067 : : * --------------------------------
2068 : : */
2069 : : Datum
2070 : 40444 : ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot)
2071 : : {
2072 : : HeapTuple tup;
2073 : : TupleDesc tupdesc;
2074 : : bool shouldFree;
2075 : : Datum ret;
2076 : :
2077 : : /* Fetch slot's contents in regular-physical-tuple form */
2078 : 40444 : tup = ExecFetchSlotHeapTuple(slot, false, &shouldFree);
2079 : 40444 : tupdesc = slot->tts_tupleDescriptor;
2080 : :
2081 : : /* Convert to Datum form */
2082 : 40444 : ret = heap_copy_tuple_as_datum(tup, tupdesc);
2083 : :
2084 [ + + ]: 40444 : if (shouldFree)
2085 : 40316 : pfree(tup);
2086 : :
2087 : 40444 : return ret;
2088 : : }
2089 : :
2090 : : /* ----------------------------------------------------------------
2091 : : * convenience initialization routines
2092 : : * ----------------------------------------------------------------
2093 : : */
2094 : :
2095 : : /* ----------------
2096 : : * ExecInitResultTypeTL
2097 : : *
2098 : : * Initialize result type, using the plan node's targetlist.
2099 : : * ----------------
2100 : : */
2101 : : void
2102 : 904471 : ExecInitResultTypeTL(PlanState *planstate)
2103 : : {
2104 : 904471 : TupleDesc tupDesc = ExecTypeFromTL(planstate->plan->targetlist);
2105 : :
2106 : 904471 : planstate->ps_ResultTupleDesc = tupDesc;
2107 : 904471 : }
2108 : :
2109 : : /* --------------------------------
2110 : : * ExecInit{Result,Scan,Extra}TupleSlot[TL]
2111 : : *
2112 : : * These are convenience routines to initialize the specified slot
2113 : : * in nodes inheriting the appropriate state. ExecInitExtraTupleSlot
2114 : : * is used for initializing special-purpose slots.
2115 : : * --------------------------------
2116 : : */
2117 : :
2118 : : /* ----------------
2119 : : * ExecInitResultTupleSlotTL
2120 : : *
2121 : : * Initialize result tuple slot, using the tuple descriptor previously
2122 : : * computed with ExecInitResultTypeTL().
2123 : : * ----------------
2124 : : */
2125 : : void
2126 : 619255 : ExecInitResultSlot(PlanState *planstate, const TupleTableSlotOps *tts_ops)
2127 : : {
2128 : : TupleTableSlot *slot;
2129 : :
2130 : 619255 : slot = ExecAllocTableSlot(&planstate->state->es_tupleTable,
2131 : : planstate->ps_ResultTupleDesc, tts_ops, 0);
2132 : 619255 : planstate->ps_ResultTupleSlot = slot;
2133 : :
2134 : 619255 : planstate->resultopsfixed = planstate->ps_ResultTupleDesc != NULL;
2135 : 619255 : planstate->resultops = tts_ops;
2136 : 619255 : planstate->resultopsset = true;
2137 : 619255 : }
2138 : :
2139 : : /* ----------------
2140 : : * ExecInitResultTupleSlotTL
2141 : : *
2142 : : * Initialize result tuple slot, using the plan node's targetlist.
2143 : : * ----------------
2144 : : */
2145 : : void
2146 : 443088 : ExecInitResultTupleSlotTL(PlanState *planstate,
2147 : : const TupleTableSlotOps *tts_ops)
2148 : : {
2149 : 443088 : ExecInitResultTypeTL(planstate);
2150 : 443088 : ExecInitResultSlot(planstate, tts_ops);
2151 : 443088 : }
2152 : :
2153 : : /* ----------------
2154 : : * ExecInitScanTupleSlot
2155 : : * ----------------
2156 : : */
2157 : : void
2158 : 466891 : ExecInitScanTupleSlot(EState *estate, ScanState *scanstate,
2159 : : TupleDesc tupledesc, const TupleTableSlotOps *tts_ops,
2160 : : uint16 flags)
2161 : : {
2162 : 466891 : scanstate->ss_ScanTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable,
2163 : : tupledesc, tts_ops, flags);
2164 : 466891 : scanstate->ps.scandesc = tupledesc;
2165 : 466891 : scanstate->ps.scanopsfixed = tupledesc != NULL;
2166 : 466891 : scanstate->ps.scanops = tts_ops;
2167 : 466891 : scanstate->ps.scanopsset = true;
2168 : 466891 : }
2169 : :
2170 : : /* ----------------
2171 : : * ExecInitExtraTupleSlot
2172 : : *
2173 : : * Return a newly created slot. If tupledesc is non-NULL the slot will have
2174 : : * that as its fixed tupledesc. Otherwise the caller needs to use
2175 : : * ExecSetSlotDescriptor() to set the descriptor before use.
2176 : : * ----------------
2177 : : */
2178 : : TupleTableSlot *
2179 : 284166 : ExecInitExtraTupleSlot(EState *estate,
2180 : : TupleDesc tupledesc,
2181 : : const TupleTableSlotOps *tts_ops)
2182 : : {
2183 : 284166 : return ExecAllocTableSlot(&estate->es_tupleTable, tupledesc, tts_ops, 0);
2184 : : }
2185 : :
2186 : : /* ----------------
2187 : : * ExecInitNullTupleSlot
2188 : : *
2189 : : * Build a slot containing an all-nulls tuple of the given type.
2190 : : * This is used as a substitute for an input tuple when performing an
2191 : : * outer join.
2192 : : * ----------------
2193 : : */
2194 : : TupleTableSlot *
2195 : 31116 : ExecInitNullTupleSlot(EState *estate, TupleDesc tupType,
2196 : : const TupleTableSlotOps *tts_ops)
2197 : : {
2198 : 31116 : TupleTableSlot *slot = ExecInitExtraTupleSlot(estate, tupType, tts_ops);
2199 : :
2200 : 31116 : return ExecStoreAllNullTuple(slot);
2201 : : }
2202 : :
2203 : : /* ---------------------------------------------------------------
2204 : : * Routines for setting/accessing attributes in a slot.
2205 : : * ---------------------------------------------------------------
2206 : : */
2207 : :
2208 : : /*
2209 : : * Fill in missing values for a TupleTableSlot.
2210 : : *
2211 : : * This is only exposed because it's needed for JIT compiled tuple
2212 : : * deforming. That exception aside, there should be no callers outside of this
2213 : : * file.
2214 : : */
2215 : : void
2216 : 4861 : slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, int lastAttNum)
2217 : : {
2218 : 4861 : AttrMissing *attrmiss = NULL;
2219 : :
2220 : : /* Check for invalid attnums */
2221 [ - + ]: 4861 : if (unlikely(lastAttNum > slot->tts_tupleDescriptor->natts))
2222 [ # # ]: 0 : elog(ERROR, "invalid attribute number %d", lastAttNum);
2223 : :
2224 [ + + ]: 4861 : if (slot->tts_tupleDescriptor->constr)
2225 : 3160 : attrmiss = slot->tts_tupleDescriptor->constr->missing;
2226 : :
2227 [ + + ]: 4861 : if (!attrmiss)
2228 : : {
2229 : : /* no missing values array at all, so just fill everything in as NULL */
2230 [ + + ]: 3831 : for (int attnum = startAttNum; attnum < lastAttNum; attnum++)
2231 : : {
2232 : 2020 : slot->tts_values[attnum] = (Datum) 0;
2233 : 2020 : slot->tts_isnull[attnum] = true;
2234 : : }
2235 : : }
2236 : : else
2237 : : {
2238 : : /* use attrmiss to set the missing values */
2239 [ + + ]: 7103 : for (int attnum = startAttNum; attnum < lastAttNum; attnum++)
2240 : : {
2241 : 4053 : slot->tts_values[attnum] = attrmiss[attnum].am_value;
2242 : 4053 : slot->tts_isnull[attnum] = !attrmiss[attnum].am_present;
2243 : : }
2244 : : }
2245 : 4861 : }
2246 : :
2247 : : /*
2248 : : * slot_getsomeattrs_int
2249 : : * external function to call getsomeattrs() for use in JIT
2250 : : */
2251 : : void
2252 : 0 : slot_getsomeattrs_int(TupleTableSlot *slot, int attnum)
2253 : : {
2254 : : /* Check for caller errors */
2255 : : Assert(slot->tts_nvalid < attnum); /* checked in slot_getsomeattrs */
2256 : : Assert(attnum > 0);
2257 : :
2258 : : /* Fetch as many attributes as possible from the underlying tuple. */
2259 : 0 : slot->tts_ops->getsomeattrs(slot, attnum);
2260 : :
2261 : : /*
2262 : : * Avoid putting new code here as that would prevent the compiler from
2263 : : * using the sibling call optimization for the above function.
2264 : : */
2265 : 0 : }
2266 : :
2267 : : /* ----------------------------------------------------------------
2268 : : * ExecTypeFromTL
2269 : : *
2270 : : * Generate a tuple descriptor for the result tuple of a targetlist.
2271 : : * (A parse/plan tlist must be passed, not an ExprState tlist.)
2272 : : * Note that resjunk columns, if any, are included in the result.
2273 : : *
2274 : : * Currently there are about 4 different places where we create
2275 : : * TupleDescriptors. They should all be merged, or perhaps
2276 : : * be rewritten to call BuildDesc().
2277 : : * ----------------------------------------------------------------
2278 : : */
2279 : : TupleDesc
2280 : 924932 : ExecTypeFromTL(List *targetList)
2281 : : {
2282 : 924932 : return ExecTypeFromTLInternal(targetList, false);
2283 : : }
2284 : :
2285 : : /* ----------------------------------------------------------------
2286 : : * ExecCleanTypeFromTL
2287 : : *
2288 : : * Same as above, but resjunk columns are omitted from the result.
2289 : : * ----------------------------------------------------------------
2290 : : */
2291 : : TupleDesc
2292 : 73032 : ExecCleanTypeFromTL(List *targetList)
2293 : : {
2294 : 73032 : return ExecTypeFromTLInternal(targetList, true);
2295 : : }
2296 : :
2297 : : static TupleDesc
2298 : 997964 : ExecTypeFromTLInternal(List *targetList, bool skipjunk)
2299 : : {
2300 : : TupleDesc typeInfo;
2301 : : ListCell *l;
2302 : : int len;
2303 : 997964 : int cur_resno = 1;
2304 : :
2305 [ + + ]: 997964 : if (skipjunk)
2306 : 73032 : len = ExecCleanTargetListLength(targetList);
2307 : : else
2308 : 924932 : len = ExecTargetListLength(targetList);
2309 : 997964 : typeInfo = CreateTemplateTupleDesc(len);
2310 : :
2311 [ + + + + : 5019058 : foreach(l, targetList)
+ + ]
2312 : : {
2313 : 4021094 : TargetEntry *tle = lfirst(l);
2314 : :
2315 [ + + + + ]: 4021094 : if (skipjunk && tle->resjunk)
2316 : 19735 : continue;
2317 : 12004077 : TupleDescInitEntry(typeInfo,
2318 : : cur_resno,
2319 : 4001359 : tle->resname,
2320 : 4001359 : exprType((Node *) tle->expr),
2321 : 4001359 : exprTypmod((Node *) tle->expr),
2322 : : 0);
2323 : 4001359 : TupleDescInitEntryCollation(typeInfo,
2324 : : cur_resno,
2325 : 4001359 : exprCollation((Node *) tle->expr));
2326 : 4001359 : cur_resno++;
2327 : : }
2328 : :
2329 : 997964 : TupleDescFinalize(typeInfo);
2330 : :
2331 : 997964 : return typeInfo;
2332 : : }
2333 : :
2334 : : /*
2335 : : * ExecTypeFromExprList - build a tuple descriptor from a list of Exprs
2336 : : *
2337 : : * This is roughly like ExecTypeFromTL, but we work from bare expressions
2338 : : * not TargetEntrys. No names are attached to the tupledesc's columns.
2339 : : */
2340 : : TupleDesc
2341 : 10328 : ExecTypeFromExprList(List *exprList)
2342 : : {
2343 : : TupleDesc typeInfo;
2344 : : ListCell *lc;
2345 : 10328 : int cur_resno = 1;
2346 : :
2347 : 10328 : typeInfo = CreateTemplateTupleDesc(list_length(exprList));
2348 : :
2349 [ + + + + : 28387 : foreach(lc, exprList)
+ + ]
2350 : : {
2351 : 18059 : Node *e = lfirst(lc);
2352 : :
2353 : 18059 : TupleDescInitEntry(typeInfo,
2354 : : cur_resno,
2355 : : NULL,
2356 : : exprType(e),
2357 : : exprTypmod(e),
2358 : : 0);
2359 : 18059 : TupleDescInitEntryCollation(typeInfo,
2360 : : cur_resno,
2361 : : exprCollation(e));
2362 : 18059 : cur_resno++;
2363 : : }
2364 : :
2365 : 10328 : TupleDescFinalize(typeInfo);
2366 : :
2367 : 10328 : return typeInfo;
2368 : : }
2369 : :
2370 : : /*
2371 : : * ExecTypeSetColNames - set column names in a RECORD TupleDesc
2372 : : *
2373 : : * Column names must be provided as an alias list (list of String nodes).
2374 : : */
2375 : : void
2376 : 3219 : ExecTypeSetColNames(TupleDesc typeInfo, List *namesList)
2377 : : {
2378 : 3219 : int colno = 0;
2379 : : ListCell *lc;
2380 : :
2381 : : /* It's only OK to change col names in a not-yet-blessed RECORD type */
2382 : : Assert(typeInfo->tdtypeid == RECORDOID);
2383 : : Assert(typeInfo->tdtypmod < 0);
2384 : :
2385 [ + + + + : 10879 : foreach(lc, namesList)
+ + ]
2386 : : {
2387 : 7660 : char *cname = strVal(lfirst(lc));
2388 : : Form_pg_attribute attr;
2389 : :
2390 : : /* Guard against too-long names list (probably can't happen) */
2391 [ - + ]: 7660 : if (colno >= typeInfo->natts)
2392 : 0 : break;
2393 : 7660 : attr = TupleDescAttr(typeInfo, colno);
2394 : 7660 : colno++;
2395 : :
2396 : : /*
2397 : : * Do nothing for empty aliases or dropped columns (these cases
2398 : : * probably can't arise in RECORD types, either)
2399 : : */
2400 [ + + - + ]: 7660 : if (cname[0] == '\0' || attr->attisdropped)
2401 : 16 : continue;
2402 : :
2403 : : /* OK, assign the column name */
2404 : 7644 : namestrcpy(&(attr->attname), cname);
2405 : : }
2406 : 3219 : }
2407 : :
2408 : : /*
2409 : : * BlessTupleDesc - make a completed tuple descriptor useful for SRFs
2410 : : *
2411 : : * Rowtype Datums returned by a function must contain valid type information.
2412 : : * This happens "for free" if the tupdesc came from a relcache entry, but
2413 : : * not if we have manufactured a tupdesc for a transient RECORD datatype.
2414 : : * In that case we have to notify typcache.c of the existence of the type.
2415 : : *
2416 : : * TupleDescFinalize() must be called on the TupleDesc before calling this
2417 : : * function.
2418 : : */
2419 : : TupleDesc
2420 : 89463 : BlessTupleDesc(TupleDesc tupdesc)
2421 : : {
2422 : : /* Did someone forget to call TupleDescFinalize()? */
2423 : : Assert(tupdesc->firstNonCachedOffsetAttr >= 0);
2424 : :
2425 [ + + ]: 89463 : if (tupdesc->tdtypeid == RECORDOID &&
2426 [ + + ]: 86564 : tupdesc->tdtypmod < 0)
2427 : 54483 : assign_record_type_typmod(tupdesc);
2428 : :
2429 : 89463 : return tupdesc; /* just for notational convenience */
2430 : : }
2431 : :
2432 : : /*
2433 : : * TupleDescGetAttInMetadata - Build an AttInMetadata structure based on the
2434 : : * supplied TupleDesc. AttInMetadata can be used in conjunction with C strings
2435 : : * to produce a properly formed tuple.
2436 : : */
2437 : : AttInMetadata *
2438 : 14667 : TupleDescGetAttInMetadata(TupleDesc tupdesc)
2439 : : {
2440 : 14667 : int natts = tupdesc->natts;
2441 : : int i;
2442 : : Oid atttypeid;
2443 : : Oid attinfuncid;
2444 : : FmgrInfo *attinfuncinfo;
2445 : : Oid *attioparams;
2446 : : int32 *atttypmods;
2447 : : AttInMetadata *attinmeta;
2448 : :
2449 : 14667 : attinmeta = palloc_object(AttInMetadata);
2450 : :
2451 : : /* "Bless" the tupledesc so that we can make rowtype datums with it */
2452 : 14667 : attinmeta->tupdesc = BlessTupleDesc(tupdesc);
2453 : :
2454 : : /*
2455 : : * Gather info needed later to call the "in" function for each attribute
2456 : : */
2457 : 14667 : attinfuncinfo = palloc0_array(FmgrInfo, natts);
2458 : 14667 : attioparams = palloc0_array(Oid, natts);
2459 : 14667 : atttypmods = palloc0_array(int32, natts);
2460 : :
2461 [ + + ]: 77773 : for (i = 0; i < natts; i++)
2462 : : {
2463 : 63106 : Form_pg_attribute att = TupleDescAttr(tupdesc, i);
2464 : :
2465 : : /* Ignore dropped attributes */
2466 [ + + ]: 63106 : if (!att->attisdropped)
2467 : : {
2468 : 62986 : atttypeid = att->atttypid;
2469 : 62986 : getTypeInputInfo(atttypeid, &attinfuncid, &attioparams[i]);
2470 : 62986 : fmgr_info(attinfuncid, &attinfuncinfo[i]);
2471 : 62986 : atttypmods[i] = att->atttypmod;
2472 : : }
2473 : : }
2474 : 14667 : attinmeta->attinfuncs = attinfuncinfo;
2475 : 14667 : attinmeta->attioparams = attioparams;
2476 : 14667 : attinmeta->atttypmods = atttypmods;
2477 : :
2478 : 14667 : return attinmeta;
2479 : : }
2480 : :
2481 : : /*
2482 : : * BuildTupleFromCStrings - build a HeapTuple given user data in C string form.
2483 : : * values is an array of C strings, one for each attribute of the return tuple.
2484 : : * A NULL string pointer indicates we want to create a NULL field.
2485 : : */
2486 : : HeapTuple
2487 : 1073826 : BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
2488 : : {
2489 : 1073826 : TupleDesc tupdesc = attinmeta->tupdesc;
2490 : 1073826 : int natts = tupdesc->natts;
2491 : : Datum *dvalues;
2492 : : bool *nulls;
2493 : : int i;
2494 : : HeapTuple tuple;
2495 : :
2496 : 1073826 : dvalues = palloc_array(Datum, natts);
2497 : 1073826 : nulls = palloc_array(bool, natts);
2498 : :
2499 : : /*
2500 : : * Call the "in" function for each non-dropped attribute, even for nulls,
2501 : : * to support domains.
2502 : : */
2503 [ + + ]: 16305464 : for (i = 0; i < natts; i++)
2504 : : {
2505 [ + - ]: 15231648 : if (!TupleDescCompactAttr(tupdesc, i)->attisdropped)
2506 : : {
2507 : : /* Non-dropped attributes */
2508 : 30463286 : dvalues[i] = InputFunctionCall(&attinmeta->attinfuncs[i],
2509 : 15231648 : values[i],
2510 : 15231648 : attinmeta->attioparams[i],
2511 : 15231648 : attinmeta->atttypmods[i]);
2512 [ + + ]: 15231638 : if (values[i] != NULL)
2513 : 10527884 : nulls[i] = false;
2514 : : else
2515 : 4703754 : nulls[i] = true;
2516 : : }
2517 : : else
2518 : : {
2519 : : /* Handle dropped attributes by setting to NULL */
2520 : 0 : dvalues[i] = (Datum) 0;
2521 : 0 : nulls[i] = true;
2522 : : }
2523 : : }
2524 : :
2525 : : /*
2526 : : * Form a tuple
2527 : : */
2528 : 1073816 : tuple = heap_form_tuple(tupdesc, dvalues, nulls);
2529 : :
2530 : : /*
2531 : : * Release locally palloc'd space. XXX would probably be good to pfree
2532 : : * values of pass-by-reference datums, as well.
2533 : : */
2534 : 1073816 : pfree(dvalues);
2535 : 1073816 : pfree(nulls);
2536 : :
2537 : 1073816 : return tuple;
2538 : : }
2539 : :
2540 : : /*
2541 : : * HeapTupleHeaderGetDatum - convert a HeapTupleHeader pointer to a Datum.
2542 : : *
2543 : : * This must *not* get applied to an on-disk tuple; the tuple should be
2544 : : * freshly made by heap_form_tuple or some wrapper routine for it (such as
2545 : : * BuildTupleFromCStrings). Be sure also that the tupledesc used to build
2546 : : * the tuple has a properly "blessed" rowtype.
2547 : : *
2548 : : * Formerly this was a macro equivalent to PointerGetDatum, relying on the
2549 : : * fact that heap_form_tuple fills in the appropriate tuple header fields
2550 : : * for a composite Datum. However, we now require that composite Datums not
2551 : : * contain any external TOAST pointers. We do not want heap_form_tuple itself
2552 : : * to enforce that; more specifically, the rule applies only to actual Datums
2553 : : * and not to HeapTuple structures. Therefore, HeapTupleHeaderGetDatum is
2554 : : * now a function that detects whether there are externally-toasted fields
2555 : : * and constructs a new tuple with inlined fields if so. We still need
2556 : : * heap_form_tuple to insert the Datum header fields, because otherwise this
2557 : : * code would have no way to obtain a tupledesc for the tuple.
2558 : : *
2559 : : * Note that if we do build a new tuple, it's palloc'd in the current
2560 : : * memory context. Beware of code that changes context between the initial
2561 : : * heap_form_tuple/etc call and calling HeapTuple(Header)GetDatum.
2562 : : *
2563 : : * For performance-critical callers, it could be worthwhile to take extra
2564 : : * steps to ensure that there aren't TOAST pointers in the output of
2565 : : * heap_form_tuple to begin with. It's likely however that the costs of the
2566 : : * typcache lookup and tuple disassembly/reassembly are swamped by TOAST
2567 : : * dereference costs, so that the benefits of such extra effort would be
2568 : : * minimal.
2569 : : *
2570 : : * XXX it would likely be better to create wrapper functions that produce
2571 : : * a composite Datum from the field values in one step. However, there's
2572 : : * enough code using the existing APIs that we couldn't get rid of this
2573 : : * hack anytime soon.
2574 : : */
2575 : : Datum
2576 : 676944 : HeapTupleHeaderGetDatum(HeapTupleHeader tuple)
2577 : : {
2578 : : Datum result;
2579 : : TupleDesc tupDesc;
2580 : :
2581 : : /*
2582 : : * We really never should get here with an !RECORDOID && unversioned
2583 : : * tuple. The header comment says that it should be freshly made tuples,
2584 : : * which create datum tuples marked as versioned.
2585 : : */
2586 : : Assert(HeapTupleHeaderIsDatum(tuple) &&
2587 : : (HeapTupleHeaderIsVersionedDatum(tuple) ||
2588 : : HeapTupleHeaderGetTypeId(tuple) == RECORDOID));
2589 : :
2590 : : /* No work if there are no external TOAST pointers in the tuple */
2591 [ + + ]: 676944 : if (!HeapTupleHeaderHasExternal(tuple))
2592 : 676928 : return PointerGetDatum(tuple);
2593 : :
2594 : : /* Use the type data saved by heap_form_tuple to look up the rowtype */
2595 : 16 : tupDesc = lookup_rowtype_tupdesc(HeapTupleHeaderGetTypeId(tuple),
2596 : : HeapTupleHeaderGetTypMod(tuple));
2597 : :
2598 : : /* And do the flattening */
2599 : 16 : result = toast_flatten_tuple_to_datum(tuple,
2600 : : HeapTupleHeaderGetDatumLength(tuple),
2601 : : tupDesc);
2602 : :
2603 [ + - ]: 12 : ReleaseTupleDesc(tupDesc);
2604 : :
2605 : 12 : return result;
2606 : : }
2607 : :
2608 : :
2609 : : /*
2610 : : * Functions for sending tuples to the frontend (or other specified destination)
2611 : : * as though it is a SELECT result. These are used by utility commands that
2612 : : * need to project directly to the destination and don't need or want full
2613 : : * table function capability. Currently used by EXPLAIN and SHOW ALL.
2614 : : */
2615 : : TupOutputState *
2616 : 21064 : begin_tup_output_tupdesc(DestReceiver *dest,
2617 : : TupleDesc tupdesc,
2618 : : const TupleTableSlotOps *tts_ops)
2619 : : {
2620 : : TupOutputState *tstate;
2621 : :
2622 : 21064 : tstate = palloc_object(TupOutputState);
2623 : :
2624 : 21064 : tstate->slot = MakeSingleTupleTableSlot(tupdesc, tts_ops);
2625 : 21064 : tstate->dest = dest;
2626 : :
2627 : 21064 : tstate->dest->rStartup(tstate->dest, (int) CMD_SELECT, tupdesc);
2628 : :
2629 : 21064 : return tstate;
2630 : : }
2631 : :
2632 : : /*
2633 : : * write a single tuple
2634 : : */
2635 : : void
2636 : 126674 : do_tup_output(TupOutputState *tstate, const Datum *values, const bool *isnull)
2637 : : {
2638 : 126674 : TupleTableSlot *slot = tstate->slot;
2639 : 126674 : int natts = slot->tts_tupleDescriptor->natts;
2640 : :
2641 : : /* make sure the slot is clear */
2642 : 126674 : ExecClearTuple(slot);
2643 : :
2644 : : /* insert data */
2645 : 126674 : memcpy(slot->tts_values, values, natts * sizeof(Datum));
2646 : 126674 : memcpy(slot->tts_isnull, isnull, natts * sizeof(bool));
2647 : :
2648 : : /* mark slot as containing a virtual tuple */
2649 : 126674 : ExecStoreVirtualTuple(slot);
2650 : :
2651 : : /* send the tuple to the receiver */
2652 : 126674 : (void) tstate->dest->receiveSlot(slot, tstate->dest);
2653 : :
2654 : : /* clean up */
2655 : 126674 : ExecClearTuple(slot);
2656 : 126674 : }
2657 : :
2658 : : /*
2659 : : * write a chunk of text, breaking at newline characters
2660 : : *
2661 : : * Should only be used with a single-TEXT-attribute tupdesc.
2662 : : */
2663 : : void
2664 : 17139 : do_text_output_multiline(TupOutputState *tstate, const char *txt)
2665 : : {
2666 : : Datum values[1];
2667 : 17139 : bool isnull[1] = {false};
2668 : :
2669 [ + + ]: 139116 : while (*txt)
2670 : : {
2671 : : const char *eol;
2672 : : int len;
2673 : :
2674 : 121977 : eol = strchr(txt, '\n');
2675 [ + - ]: 121977 : if (eol)
2676 : : {
2677 : 121977 : len = eol - txt;
2678 : 121977 : eol++;
2679 : : }
2680 : : else
2681 : : {
2682 : 0 : len = strlen(txt);
2683 : 0 : eol = txt + len;
2684 : : }
2685 : :
2686 : 121977 : values[0] = PointerGetDatum(cstring_to_text_with_len(txt, len));
2687 : 121977 : do_tup_output(tstate, values, isnull);
2688 : 121977 : pfree(DatumGetPointer(values[0]));
2689 : 121977 : txt = eol;
2690 : : }
2691 : 17139 : }
2692 : :
2693 : : void
2694 : 21064 : end_tup_output(TupOutputState *tstate)
2695 : : {
2696 : 21064 : tstate->dest->rShutdown(tstate->dest);
2697 : : /* note that destroying the dest is not ours to do */
2698 : 21064 : ExecDropSingleTupleTableSlot(tstate->slot);
2699 : 21064 : pfree(tstate);
2700 : 21064 : }
|