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