Skip to content
Snippets Groups Projects
Select Git revision
  • benchmark-tools
  • postgres-lambda
  • master default
  • REL9_4_25
  • REL9_5_20
  • REL9_6_16
  • REL_10_11
  • REL_11_6
  • REL_12_1
  • REL_12_0
  • REL_12_RC1
  • REL_12_BETA4
  • REL9_4_24
  • REL9_5_19
  • REL9_6_15
  • REL_10_10
  • REL_11_5
  • REL_12_BETA3
  • REL9_4_23
  • REL9_5_18
  • REL9_6_14
  • REL_10_9
  • REL_11_4
23 results

execTuples.c

Blame
    • Peter Eisentraut's avatar
      414c5a2e
      Per-column collation support · 414c5a2e
      Peter Eisentraut authored
      This adds collation support for columns and domains, a COLLATE clause
      to override it per expression, and B-tree index support.
      
      Peter Eisentraut
      reviewed by Pavel Stehule, Itagaki Takahiro, Robert Haas, Noah Misch
      414c5a2e
      History
      Per-column collation support
      Peter Eisentraut authored
      This adds collation support for columns and domains, a COLLATE clause
      to override it per expression, and B-tree index support.
      
      Peter Eisentraut
      reviewed by Pavel Stehule, Itagaki Takahiro, Robert Haas, Noah Misch
    execTuples.c 33.70 KiB
    /*-------------------------------------------------------------------------
     *
     * execTuples.c
     *	  Routines dealing with TupleTableSlots.  These are used for resource
     *	  management associated with tuples (eg, releasing buffer pins for
     *	  tuples in disk buffers, or freeing the memory occupied by transient
     *	  tuples).	Slots also provide access abstraction that lets us implement
     *	  "virtual" tuples to reduce data-copying overhead.
     *
     *	  Routines dealing with the type information for tuples. Currently,
     *	  the type information for a tuple is an array of FormData_pg_attribute.
     *	  This information is needed by routines manipulating tuples
     *	  (getattribute, formtuple, etc.).
     *
     * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
     * Portions Copyright (c) 1994, Regents of the University of California
     *
     *
     * IDENTIFICATION
     *	  src/backend/executor/execTuples.c
     *
     *-------------------------------------------------------------------------
     */
    /*
     * INTERFACE ROUTINES
     *
     *	 SLOT CREATION/DESTRUCTION
     *		MakeTupleTableSlot		- create an empty slot
     *		ExecAllocTableSlot		- create a slot within a tuple table
     *		ExecResetTupleTable		- clear and optionally delete a tuple table
     *		MakeSingleTupleTableSlot - make a standalone slot, set its descriptor
     *		ExecDropSingleTupleTableSlot - destroy a standalone slot
     *
     *	 SLOT ACCESSORS
     *		ExecSetSlotDescriptor	- set a slot's tuple descriptor
     *		ExecStoreTuple			- store a physical tuple in the slot
     *		ExecStoreMinimalTuple	- store a minimal physical tuple in the slot
     *		ExecClearTuple			- clear contents of a slot
     *		ExecStoreVirtualTuple	- mark slot as containing a virtual tuple
     *		ExecCopySlotTuple		- build a physical tuple from a slot
     *		ExecCopySlotMinimalTuple - build a minimal physical tuple from a slot
     *		ExecMaterializeSlot		- convert virtual to physical storage
     *		ExecCopySlot			- copy one slot's contents to another
     *
     *	 CONVENIENCE INITIALIZATION ROUTINES
     *		ExecInitResultTupleSlot    \	convenience routines to initialize
     *		ExecInitScanTupleSlot		\	the various tuple slots for nodes
     *		ExecInitExtraTupleSlot		/	which store copies of tuples.
     *		ExecInitNullTupleSlot	   /
     *
     *	 Routines that probably belong somewhere else:
     *		ExecTypeFromTL			- form a TupleDesc from a target list
     *
     *	 EXAMPLE OF HOW TABLE ROUTINES WORK
     *		Suppose we have a query such as SELECT emp.name FROM emp and we have
     *		a single SeqScan node in the query plan.
     *
     *		At ExecutorStart()
     *		----------------
     *		- ExecInitSeqScan() calls ExecInitScanTupleSlot() and
     *		  ExecInitResultTupleSlot() to construct TupleTableSlots
     *		  for the tuples returned by the access methods and the
     *		  tuples resulting from performing target list projections.
     *
     *		During ExecutorRun()
     *		----------------
     *		- SeqNext() calls ExecStoreTuple() to place the tuple returned
     *		  by the access methods into the scan tuple slot.
     *
     *		- ExecSeqScan() calls ExecStoreTuple() to take the result
     *		  tuple from ExecProject() and place it into the result tuple slot.
     *
     *		- ExecutePlan() calls ExecSelect(), which passes the result slot
     *		  to printtup(), which uses slot_getallattrs() to extract the
     *		  individual Datums for printing.
     *
     *		At ExecutorEnd()
     *		----------------
     *		- EndPlan() calls ExecResetTupleTable() to clean up any remaining
     *		  tuples left over from executing the query.
     *
     *		The important thing to watch in the executor code is how pointers
     *		to the slots containing tuples are passed instead of the tuples
     *		themselves.  This facilitates the communication of related information
     *		(such as whether or not a tuple should be pfreed, what buffer contains
     *		this tuple, the tuple's tuple descriptor, etc).  It also allows us
     *		to avoid physically constructing projection tuples in many cases.
     */
    #include "postgres.h"
    
    #include "funcapi.h"
    #include "catalog/pg_type.h"
    #include "nodes/nodeFuncs.h"
    #include "storage/bufmgr.h"
    #include "utils/builtins.h"
    #include "utils/lsyscache.h"
    #include "utils/typcache.h"
    
    
    static TupleDesc ExecTypeFromTLInternal(List *targetList,
    					   bool hasoid, bool skipjunk);
    
    
    /* ----------------------------------------------------------------
     *				  tuple table create/delete functions
     * ----------------------------------------------------------------
     */
    
    /* --------------------------------
     *		MakeTupleTableSlot
     *
     *		Basic routine to make an empty TupleTableSlot.
     * --------------------------------
     */
    TupleTableSlot *
    MakeTupleTableSlot(void)
    {
    	TupleTableSlot *slot = makeNode(TupleTableSlot);
    
    	slot->tts_isempty = true;
    	slot->tts_shouldFree = false;
    	slot->tts_shouldFreeMin = false;
    	slot->tts_tuple = NULL;
    	slot->tts_tupleDescriptor = NULL;
    	slot->tts_mcxt = CurrentMemoryContext;
    	slot->tts_buffer = InvalidBuffer;
    	slot->tts_nvalid = 0;
    	slot->tts_values = NULL;
    	slot->tts_isnull = NULL;
    	slot->tts_mintuple = NULL;
    
    	return slot;
    }
    
    /* --------------------------------
     *		ExecAllocTableSlot
     *
     *		Create a tuple table slot within a tuple table (which is just a List).
     * --------------------------------
     */
    TupleTableSlot *
    ExecAllocTableSlot(List **tupleTable)
    {
    	TupleTableSlot *slot = MakeTupleTableSlot();
    
    	*tupleTable = lappend(*tupleTable, slot);
    
    	return slot;
    }
    
    /* --------------------------------
     *		ExecResetTupleTable
     *
     *		This releases any resources (buffer pins, tupdesc refcounts)
     *		held by the tuple table, and optionally releases the memory
     *		occupied by the tuple table data structure.
     *		It is expected that this routine be called by EndPlan().
     * --------------------------------
     */
    void
    ExecResetTupleTable(List *tupleTable,	/* tuple table */
    					bool shouldFree)	/* true if we should free memory */
    {
    	ListCell   *lc;
    
    	foreach(lc, tupleTable)
    	{
    		TupleTableSlot *slot = (TupleTableSlot *) lfirst(lc);
    
    		/* Sanity checks */
    		Assert(IsA(slot, TupleTableSlot));
    
    		/* Always release resources and reset the slot to empty */
    		ExecClearTuple(slot);
    		if (slot->tts_tupleDescriptor)
    		{
    			ReleaseTupleDesc(slot->tts_tupleDescriptor);
    			slot->tts_tupleDescriptor = NULL;
    		}
    
    		/* If shouldFree, release memory occupied by the slot itself */
    		if (shouldFree)
    		{
    			if (slot->tts_values)
    				pfree(slot->tts_values);
    			if (slot->tts_isnull)
    				pfree(slot->tts_isnull);
    			pfree(slot);
    		}
    	}
    
    	/* If shouldFree, release the list structure */
    	if (shouldFree)
    		list_free(tupleTable);
    }
    
    /* --------------------------------
     *		MakeSingleTupleTableSlot
     *
     *		This is a convenience routine for operations that need a
     *		standalone TupleTableSlot not gotten from the main executor
     *		tuple table.  It makes a single slot and initializes it
     *		to use the given tuple descriptor.
     * --------------------------------
     */
    TupleTableSlot *
    MakeSingleTupleTableSlot(TupleDesc tupdesc)
    {
    	TupleTableSlot *slot = MakeTupleTableSlot();
    
    	ExecSetSlotDescriptor(slot, tupdesc);
    
    	return slot;
    }
    
    /* --------------------------------
     *		ExecDropSingleTupleTableSlot
     *
     *		Release a TupleTableSlot made with MakeSingleTupleTableSlot.
     *		DON'T use this on a slot that's part of a tuple table list!
     * --------------------------------
     */
    void
    ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
    {
    	/* This should match ExecResetTupleTable's processing of one slot */
    	Assert(IsA(slot, TupleTableSlot));
    	ExecClearTuple(slot);
    	if (slot->tts_tupleDescriptor)
    		ReleaseTupleDesc(slot->tts_tupleDescriptor);
    	if (slot->tts_values)
    		pfree(slot->tts_values);
    	if (slot->tts_isnull)
    		pfree(slot->tts_isnull);
    	pfree(slot);
    }
    
    
    /* ----------------------------------------------------------------
     *				  tuple table slot accessor functions
     * ----------------------------------------------------------------
     */
    
    /* --------------------------------
     *		ExecSetSlotDescriptor
     *
     *		This function is used to set the tuple descriptor associated
     *		with the slot's tuple.  The passed descriptor must have lifespan
     *		at least equal to the slot's.  If it is a reference-counted descriptor
     *		then the reference count is incremented for as long as the slot holds
     *		a reference.
     * --------------------------------
     */
    void
    ExecSetSlotDescriptor(TupleTableSlot *slot,		/* slot to change */
    					  TupleDesc tupdesc)		/* new tuple descriptor */
    {
    	/* For safety, make sure slot is empty before changing it */
    	ExecClearTuple(slot);
    
    	/*
    	 * Release any old descriptor.	Also release old Datum/isnull arrays if
    	 * present (we don't bother to check if they could be re-used).
    	 */
    	if (slot->tts_tupleDescriptor)
    		ReleaseTupleDesc(slot->tts_tupleDescriptor);
    
    	if (slot->tts_values)
    		pfree(slot->tts_values);
    	if (slot->tts_isnull)
    		pfree(slot->tts_isnull);
    
    	/*
    	 * Install the new descriptor; if it's refcounted, bump its refcount.
    	 */
    	slot->tts_tupleDescriptor = tupdesc;
    	PinTupleDesc(tupdesc);
    
    	/*
    	 * Allocate Datum/isnull arrays of the appropriate size.  These must have
    	 * the same lifetime as the slot, so allocate in the slot's own context.
    	 */
    	slot->tts_values = (Datum *)
    		MemoryContextAlloc(slot->tts_mcxt, tupdesc->natts * sizeof(Datum));
    	slot->tts_isnull = (bool *)
    		MemoryContextAlloc(slot->tts_mcxt, tupdesc->natts * sizeof(bool));
    }
    
    /* --------------------------------
     *		ExecStoreTuple
     *
     *		This function is used to store a physical tuple into a specified
     *		slot in the tuple table.
     *
     *		tuple:	tuple to store
     *		slot:	slot to store it in
     *		buffer: disk buffer if tuple is in a disk page, else InvalidBuffer
     *		shouldFree: true if ExecClearTuple should pfree() the tuple
     *					when done with it
     *
     * If 'buffer' is not InvalidBuffer, the tuple table code acquires a pin
     * on the buffer which is held until the slot is cleared, so that the tuple
     * won't go away on us.
     *
     * shouldFree is normally set 'true' for tuples constructed on-the-fly.
     * It must always be 'false' for tuples that are stored in disk pages,
     * since we don't want to try to pfree those.
     *
     * Another case where it is 'false' is when the referenced tuple is held
     * in a tuple table slot belonging to a lower-level executor Proc node.
     * In this case the lower-level slot retains ownership and responsibility
     * for eventually releasing the tuple.	When this method is used, we must
     * be certain that the upper-level Proc node will lose interest in the tuple
     * sooner than the lower-level one does!  If you're not certain, copy the
     * lower-level tuple with heap_copytuple and let the upper-level table
     * slot assume ownership of the copy!
     *
     * Return value is just the passed-in slot pointer.
     *
     * NOTE: before PostgreSQL 8.1, this function would accept a NULL tuple
     * pointer and effectively behave like ExecClearTuple (though you could
     * still specify a buffer to pin, which would be an odd combination).
     * This saved a couple lines of code in a few places, but seemed more likely
     * to mask logic errors than to be really useful, so it's now disallowed.
     * --------------------------------
     */
    TupleTableSlot *
    ExecStoreTuple(HeapTuple tuple,
    			   TupleTableSlot *slot,
    			   Buffer buffer,
    			   bool shouldFree)
    {
    	/*
    	 * sanity checks
    	 */
    	Assert(tuple != NULL);
    	Assert(slot != NULL);
    	Assert(slot->tts_tupleDescriptor != NULL);
    	/* passing shouldFree=true for a tuple on a disk page is not sane */
    	Assert(BufferIsValid(buffer) ? (!shouldFree) : true);
    
    	/*
    	 * Free any old physical tuple belonging to the slot.
    	 */
    	if (slot->tts_shouldFree)
    		heap_freetuple(slot->tts_tuple);
    	if (slot->tts_shouldFreeMin)
    		heap_free_minimal_tuple(slot->tts_mintuple);
    
    	/*
    	 * Store the new tuple into the specified slot.
    	 */
    	slot->tts_isempty = false;
    	slot->tts_shouldFree = shouldFree;
    	slot->tts_shouldFreeMin = false;
    	slot->tts_tuple = tuple;
    	slot->tts_mintuple = NULL;
    
    	/* Mark extracted state invalid */
    	slot->tts_nvalid = 0;
    
    	/*
    	 * If tuple is on a disk page, keep the page pinned as long as we hold a
    	 * pointer into it.  We assume the caller already has such a pin.
    	 *
    	 * This is coded to optimize the case where the slot previously held a
    	 * tuple on the same disk page: in that case releasing and re-acquiring
    	 * the pin is a waste of cycles.  This is a common situation during
    	 * seqscans, so it's worth troubling over.
    	 */
    	if (slot->tts_buffer != buffer)
    	{
    		if (BufferIsValid(slot->tts_buffer))
    			ReleaseBuffer(slot->tts_buffer);
    		slot->tts_buffer = buffer;
    		if (BufferIsValid(buffer))
    			IncrBufferRefCount(buffer);
    	}
    
    	return slot;
    }
    
    /* --------------------------------
     *		ExecStoreMinimalTuple
     *
     *		Like ExecStoreTuple, but insert a "minimal" tuple into the slot.
     *
     * No 'buffer' parameter since minimal tuples are never stored in relations.
     * --------------------------------
     */
    TupleTableSlot *
    ExecStoreMinimalTuple(MinimalTuple mtup,
    					  TupleTableSlot *slot,
    					  bool shouldFree)
    {
    	/*
    	 * sanity checks
    	 */
    	Assert(mtup != NULL);
    	Assert(slot != NULL);
    	Assert(slot->tts_tupleDescriptor != NULL);
    
    	/*
    	 * Free any old physical tuple belonging to the slot.
    	 */
    	if (slot->tts_shouldFree)
    		heap_freetuple(slot->tts_tuple);
    	if (slot->tts_shouldFreeMin)
    		heap_free_minimal_tuple(slot->tts_mintuple);
    
    	/*
    	 * Drop the pin on the referenced buffer, if there is one.
    	 */
    	if (BufferIsValid(slot->tts_buffer))
    		ReleaseBuffer(slot->tts_buffer);
    
    	slot->tts_buffer = InvalidBuffer;
    
    	/*
    	 * Store the new tuple into the specified slot.
    	 */
    	slot->tts_isempty = false;
    	slot->tts_shouldFree = false;
    	slot->tts_shouldFreeMin = shouldFree;
    	slot->tts_tuple = &slot->tts_minhdr;
    	slot->tts_mintuple = mtup;
    
    	slot->tts_minhdr.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
    	slot->tts_minhdr.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);
    	/* no need to set t_self or t_tableOid since we won't allow access */
    
    	/* Mark extracted state invalid */
    	slot->tts_nvalid = 0;
    
    	return slot;
    }
    
    /* --------------------------------
     *		ExecClearTuple
     *
     *		This function is used to clear out a slot in the tuple table.
     *
     *		NB: only the tuple is cleared, not the tuple descriptor (if any).
     * --------------------------------
     */
    TupleTableSlot *				/* return: slot passed */
    ExecClearTuple(TupleTableSlot *slot)	/* slot in which to store tuple */
    {
    	/*
    	 * sanity checks
    	 */
    	Assert(slot != NULL);
    
    	/*
    	 * Free the old physical tuple if necessary.
    	 */
    	if (slot->tts_shouldFree)
    		heap_freetuple(slot->tts_tuple);
    	if (slot->tts_shouldFreeMin)
    		heap_free_minimal_tuple(slot->tts_mintuple);
    
    	slot->tts_tuple = NULL;
    	slot->tts_mintuple = NULL;
    	slot->tts_shouldFree = false;
    	slot->tts_shouldFreeMin = false;
    
    	/*
    	 * Drop the pin on the referenced buffer, if there is one.
    	 */
    	if (BufferIsValid(slot->tts_buffer))
    		ReleaseBuffer(slot->tts_buffer);
    
    	slot->tts_buffer = InvalidBuffer;
    
    	/*
    	 * Mark it empty.
    	 */
    	slot->tts_isempty = true;
    	slot->tts_nvalid = 0;
    
    	return slot;
    }
    
    /* --------------------------------
     *		ExecStoreVirtualTuple
     *			Mark a slot as containing a virtual tuple.
     *
     * The protocol for loading a slot with virtual tuple data is:
     *		* Call ExecClearTuple to mark the slot empty.
     *		* Store data into the Datum/isnull arrays.
     *		* Call ExecStoreVirtualTuple to mark the slot valid.
     * This is a bit unclean but it avoids one round of data copying.
     * --------------------------------
     */
    TupleTableSlot *
    ExecStoreVirtualTuple(TupleTableSlot *slot)
    {
    	/*
    	 * sanity checks
    	 */
    	Assert(slot != NULL);
    	Assert(slot->tts_tupleDescriptor != NULL);
    	Assert(slot->tts_isempty);
    
    	slot->tts_isempty = false;
    	slot->tts_nvalid = slot->tts_tupleDescriptor->natts;
    
    	return slot;
    }
    
    /* --------------------------------
     *		ExecStoreAllNullTuple
     *			Set up the slot to contain a null in every column.
     *
     * At first glance this might sound just like ExecClearTuple, but it's
     * entirely different: the slot ends up full, not empty.
     * --------------------------------
     */
    TupleTableSlot *
    ExecStoreAllNullTuple(TupleTableSlot *slot)
    {
    	/*
    	 * sanity checks
    	 */
    	Assert(slot != NULL);
    	Assert(slot->tts_tupleDescriptor != NULL);
    
    	/* Clear any old contents */
    	ExecClearTuple(slot);
    
    	/*
    	 * Fill all the columns of the virtual tuple with nulls
    	 */
    	MemSet(slot->tts_values, 0,
    		   slot->tts_tupleDescriptor->natts * sizeof(Datum));
    	memset(slot->tts_isnull, true,
    		   slot->tts_tupleDescriptor->natts * sizeof(bool));
    
    	return ExecStoreVirtualTuple(slot);
    }
    
    /* --------------------------------
     *		ExecCopySlotTuple
     *			Obtain a copy of a slot's regular physical tuple.  The copy is
     *			palloc'd in the current memory context.
     *			The slot itself is undisturbed.
     *
     *		This works even if the slot contains a virtual or minimal tuple;
     *		however the "system columns" of the result will not be meaningful.
     * --------------------------------
     */
    HeapTuple
    ExecCopySlotTuple(TupleTableSlot *slot)
    {
    	/*
    	 * sanity checks
    	 */
    	Assert(slot != NULL);
    	Assert(!slot->tts_isempty);
    
    	/*
    	 * If we have a physical tuple (either format) then just copy it.
    	 */
    	if (TTS_HAS_PHYSICAL_TUPLE(slot))
    		return heap_copytuple(slot->tts_tuple);
    	if (slot->tts_mintuple)
    		return heap_tuple_from_minimal_tuple(slot->tts_mintuple);
    
    	/*
    	 * Otherwise we need to build a tuple from the Datum array.
    	 */
    	return heap_form_tuple(slot->tts_tupleDescriptor,
    						   slot->tts_values,
    						   slot->tts_isnull);
    }
    
    /* --------------------------------
     *		ExecCopySlotMinimalTuple
     *			Obtain a copy of a slot's minimal physical tuple.  The copy is
     *			palloc'd in the current memory context.
     *			The slot itself is undisturbed.
     * --------------------------------
     */
    MinimalTuple
    ExecCopySlotMinimalTuple(TupleTableSlot *slot)
    {
    	/*
    	 * sanity checks
    	 */
    	Assert(slot != NULL);
    	Assert(!slot->tts_isempty);
    
    	/*
    	 * If we have a physical tuple then just copy it.  Prefer to copy
    	 * tts_mintuple since that's a tad cheaper.
    	 */
    	if (slot->tts_mintuple)
    		return heap_copy_minimal_tuple(slot->tts_mintuple);
    	if (slot->tts_tuple)
    		return minimal_tuple_from_heap_tuple(slot->tts_tuple);
    
    	/*
    	 * Otherwise we need to build a tuple from the Datum array.
    	 */
    	return heap_form_minimal_tuple(slot->tts_tupleDescriptor,
    								   slot->tts_values,
    								   slot->tts_isnull);
    }
    
    /* --------------------------------
     *		ExecFetchSlotTuple
     *			Fetch the slot's regular physical tuple.
     *
     *		If the slot contains a virtual tuple, we convert it to physical
     *		form.  The slot retains ownership of the physical tuple.
     *		If it contains a minimal tuple we convert to regular form and store
     *		that in addition to the minimal tuple (not instead of, because
     *		callers may hold pointers to Datums within the minimal tuple).
     *
     * The main difference between this and ExecMaterializeSlot() is that this
     * does not guarantee that the contained tuple is local storage.
     * Hence, the result must be treated as read-only.
     * --------------------------------
     */
    HeapTuple
    ExecFetchSlotTuple(TupleTableSlot *slot)
    {
    	/*
    	 * sanity checks
    	 */
    	Assert(slot != NULL);
    	Assert(!slot->tts_isempty);
    
    	/*
    	 * If we have a regular physical tuple then just return it.
    	 */
    	if (TTS_HAS_PHYSICAL_TUPLE(slot))
    		return slot->tts_tuple;
    
    	/*
    	 * Otherwise materialize the slot...
    	 */
    	return ExecMaterializeSlot(slot);
    }
    
    /* --------------------------------
     *		ExecFetchSlotMinimalTuple
     *			Fetch the slot's minimal physical tuple.
     *
     *		If the slot contains a virtual tuple, we convert it to minimal
     *		physical form.	The slot retains ownership of the minimal tuple.
     *		If it contains a regular tuple we convert to minimal form and store
     *		that in addition to the regular tuple (not instead of, because
     *		callers may hold pointers to Datums within the regular tuple).
     *
     * As above, the result must be treated as read-only.
     * --------------------------------
     */
    MinimalTuple
    ExecFetchSlotMinimalTuple(TupleTableSlot *slot)
    {
    	MemoryContext oldContext;
    
    	/*
    	 * sanity checks
    	 */
    	Assert(slot != NULL);
    	Assert(!slot->tts_isempty);
    
    	/*
    	 * If we have a minimal physical tuple (local or not) then just return it.
    	 */
    	if (slot->tts_mintuple)
    		return slot->tts_mintuple;
    
    	/*
    	 * Otherwise, copy or build a minimal tuple, and store it into the slot.
    	 *
    	 * We may be called in a context that is shorter-lived than the tuple
    	 * slot, but we have to ensure that the materialized tuple will survive
    	 * anyway.
    	 */
    	oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
    	slot->tts_mintuple = ExecCopySlotMinimalTuple(slot);
    	slot->tts_shouldFreeMin = true;
    	MemoryContextSwitchTo(oldContext);
    
    	/*
    	 * Note: we may now have a situation where we have a local minimal tuple
    	 * attached to a virtual or non-local physical tuple.  There seems no harm
    	 * in that at the moment, but if any materializes, we should change this
    	 * function to force the slot into minimal-tuple-only state.
    	 */
    
    	return slot->tts_mintuple;
    }
    
    /* --------------------------------
     *		ExecFetchSlotTupleDatum
     *			Fetch the slot's tuple as a composite-type Datum.
     *
     *		We convert the slot's contents to local physical-tuple form,
     *		and fill in the Datum header fields.  Note that the result
     *		always points to storage owned by the slot.
     * --------------------------------
     */
    Datum
    ExecFetchSlotTupleDatum(TupleTableSlot *slot)
    {
    	HeapTuple	tup;
    	HeapTupleHeader td;
    	TupleDesc	tupdesc;
    
    	/* Make sure we can scribble on the slot contents ... */
    	tup = ExecMaterializeSlot(slot);
    	/* ... and set up the composite-Datum header fields, in case not done */
    	td = tup->t_data;
    	tupdesc = slot->tts_tupleDescriptor;
    	HeapTupleHeaderSetDatumLength(td, tup->t_len);
    	HeapTupleHeaderSetTypeId(td, tupdesc->tdtypeid);
    	HeapTupleHeaderSetTypMod(td, tupdesc->tdtypmod);
    	return PointerGetDatum(td);
    }
    
    /* --------------------------------
     *		ExecMaterializeSlot
     *			Force a slot into the "materialized" state.
     *
     *		This causes the slot's tuple to be a local copy not dependent on
     *		any external storage.  A pointer to the contained tuple is returned.
     *
     *		A typical use for this operation is to prepare a computed tuple
     *		for being stored on disk.  The original data may or may not be
     *		virtual, but in any case we need a private copy for heap_insert
     *		to scribble on.
     * --------------------------------
     */
    HeapTuple
    ExecMaterializeSlot(TupleTableSlot *slot)
    {
    	MemoryContext oldContext;
    
    	/*
    	 * sanity checks
    	 */
    	Assert(slot != NULL);
    	Assert(!slot->tts_isempty);
    
    	/*
    	 * If we have a regular physical tuple, and it's locally palloc'd, we have
    	 * nothing to do.
    	 */
    	if (slot->tts_tuple && slot->tts_shouldFree)
    		return slot->tts_tuple;
    
    	/*
    	 * Otherwise, copy or build a physical tuple, and store it into the slot.
    	 *
    	 * We may be called in a context that is shorter-lived than the tuple
    	 * slot, but we have to ensure that the materialized tuple will survive
    	 * anyway.
    	 */
    	oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
    	slot->tts_tuple = ExecCopySlotTuple(slot);
    	slot->tts_shouldFree = true;
    	MemoryContextSwitchTo(oldContext);
    
    	/*
    	 * Drop the pin on the referenced buffer, if there is one.
    	 */
    	if (BufferIsValid(slot->tts_buffer))
    		ReleaseBuffer(slot->tts_buffer);
    
    	slot->tts_buffer = InvalidBuffer;
    
    	/*
    	 * Mark extracted state invalid.  This is important because the slot is
    	 * not supposed to depend any more on the previous external data; we
    	 * mustn't leave any dangling pass-by-reference datums in tts_values.
    	 * However, we have not actually invalidated any such datums, if there
    	 * happen to be any previously fetched from the slot.  (Note in particular
    	 * that we have not pfree'd tts_mintuple, if there is one.)
    	 */
    	slot->tts_nvalid = 0;
    
    	/*
    	 * On the same principle of not depending on previous remote storage,
    	 * forget the mintuple if it's not local storage.  (If it is local
    	 * storage, we must not pfree it now, since callers might have already
    	 * fetched datum pointers referencing it.)
    	 */
    	if (!slot->tts_shouldFreeMin)
    		slot->tts_mintuple = NULL;
    
    	return slot->tts_tuple;
    }
    
    /* --------------------------------
     *		ExecCopySlot
     *			Copy the source slot's contents into the destination slot.
     *
     *		The destination acquires a private copy that will not go away
     *		if the source is cleared.
     *
     *		The caller must ensure the slots have compatible tupdescs.
     * --------------------------------
     */
    TupleTableSlot *
    ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
    {
    	HeapTuple	newTuple;
    	MemoryContext oldContext;
    
    	/*
    	 * There might be ways to optimize this when the source is virtual, but
    	 * for now just always build a physical copy.  Make sure it is in the
    	 * right context.
    	 */
    	oldContext = MemoryContextSwitchTo(dstslot->tts_mcxt);
    	newTuple = ExecCopySlotTuple(srcslot);
    	MemoryContextSwitchTo(oldContext);
    
    	return ExecStoreTuple(newTuple, dstslot, InvalidBuffer, true);
    }
    
    
    /* ----------------------------------------------------------------
     *				convenience initialization routines
     * ----------------------------------------------------------------
     */
    
    /* --------------------------------
     *		ExecInit{Result,Scan,Extra}TupleSlot
     *
     *		These are convenience routines to initialize the specified slot
     *		in nodes inheriting the appropriate state.	ExecInitExtraTupleSlot
     *		is used for initializing special-purpose slots.
     * --------------------------------
     */
    
    /* ----------------
     *		ExecInitResultTupleSlot
     * ----------------
     */
    void
    ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
    {
    	planstate->ps_ResultTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable);
    }
    
    /* ----------------
     *		ExecInitScanTupleSlot
     * ----------------
     */
    void
    ExecInitScanTupleSlot(EState *estate, ScanState *scanstate)
    {
    	scanstate->ss_ScanTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable);
    }
    
    /* ----------------
     *		ExecInitExtraTupleSlot
     * ----------------
     */
    TupleTableSlot *
    ExecInitExtraTupleSlot(EState *estate)
    {
    	return ExecAllocTableSlot(&estate->es_tupleTable);
    }
    
    /* ----------------
     *		ExecInitNullTupleSlot
     *
     * Build a slot containing an all-nulls tuple of the given type.
     * This is used as a substitute for an input tuple when performing an
     * outer join.
     * ----------------
     */
    TupleTableSlot *
    ExecInitNullTupleSlot(EState *estate, TupleDesc tupType)
    {
    	TupleTableSlot *slot = ExecInitExtraTupleSlot(estate);
    
    	ExecSetSlotDescriptor(slot, tupType);
    
    	return ExecStoreAllNullTuple(slot);
    }
    
    /* ----------------------------------------------------------------
     *		ExecTypeFromTL
     *
     *		Generate a tuple descriptor for the result tuple of a targetlist.
     *		(A parse/plan tlist must be passed, not an ExprState tlist.)
     *		Note that resjunk columns, if any, are included in the result.
     *
     *		Currently there are about 4 different places where we create
     *		TupleDescriptors.  They should all be merged, or perhaps
     *		be rewritten to call BuildDesc().
     * ----------------------------------------------------------------
     */
    TupleDesc
    ExecTypeFromTL(List *targetList, bool hasoid)
    {
    	return ExecTypeFromTLInternal(targetList, hasoid, false);
    }
    
    /* ----------------------------------------------------------------
     *		ExecCleanTypeFromTL
     *
     *		Same as above, but resjunk columns are omitted from the result.
     * ----------------------------------------------------------------
     */
    TupleDesc
    ExecCleanTypeFromTL(List *targetList, bool hasoid)
    {
    	return ExecTypeFromTLInternal(targetList, hasoid, true);
    }
    
    static TupleDesc
    ExecTypeFromTLInternal(List *targetList, bool hasoid, bool skipjunk)
    {
    	TupleDesc	typeInfo;
    	ListCell   *l;
    	int			len;
    	int			cur_resno = 1;
    
    	if (skipjunk)
    		len = ExecCleanTargetListLength(targetList);
    	else
    		len = ExecTargetListLength(targetList);
    	typeInfo = CreateTemplateTupleDesc(len, hasoid);
    
    	foreach(l, targetList)
    	{
    		TargetEntry *tle = lfirst(l);
    
    		if (skipjunk && tle->resjunk)
    			continue;
    		TupleDescInitEntry(typeInfo,
    						   cur_resno,
    						   tle->resname,
    						   exprType((Node *) tle->expr),
    						   exprTypmod((Node *) tle->expr),
    						   0);
    		TupleDescInitEntryCollation(typeInfo,
    									cur_resno,
    									exprCollation((Node *) tle->expr));
    		cur_resno++;
    	}
    
    	return typeInfo;
    }
    
    /*
     * ExecTypeFromExprList - build a tuple descriptor from a list of Exprs
     *
     * Here we must make up an arbitrary set of field names.
     */
    TupleDesc
    ExecTypeFromExprList(List *exprList)
    {
    	TupleDesc	typeInfo;
    	ListCell   *l;
    	int			cur_resno = 1;
    	char		fldname[NAMEDATALEN];
    
    	typeInfo = CreateTemplateTupleDesc(list_length(exprList), false);
    
    	foreach(l, exprList)
    	{
    		Node	   *e = lfirst(l);
    
    		sprintf(fldname, "f%d", cur_resno);
    
    		TupleDescInitEntry(typeInfo,
    						   cur_resno,
    						   fldname,
    						   exprType(e),
    						   exprTypmod(e),
    						   0);
    		TupleDescInitEntryCollation(typeInfo,
    									cur_resno,
    									exprCollation(e));
    		cur_resno++;
    	}
    
    	return typeInfo;
    }
    
    /*
     * BlessTupleDesc - make a completed tuple descriptor useful for SRFs
     *
     * Rowtype Datums returned by a function must contain valid type information.
     * This happens "for free" if the tupdesc came from a relcache entry, but
     * not if we have manufactured a tupdesc for a transient RECORD datatype.
     * In that case we have to notify typcache.c of the existence of the type.
     */
    TupleDesc
    BlessTupleDesc(TupleDesc tupdesc)
    {
    	if (tupdesc->tdtypeid == RECORDOID &&
    		tupdesc->tdtypmod < 0)
    		assign_record_type_typmod(tupdesc);
    
    	return tupdesc;				/* just for notational convenience */
    }
    
    /*
     * TupleDescGetSlot - Initialize a slot based on the supplied tupledesc
     *
     * Note: this is obsolete; it is sufficient to call BlessTupleDesc on
     * the tupdesc.  We keep it around just for backwards compatibility with
     * existing user-written SRFs.
     */
    TupleTableSlot *
    TupleDescGetSlot(TupleDesc tupdesc)
    {
    	TupleTableSlot *slot;
    
    	/* The useful work is here */
    	BlessTupleDesc(tupdesc);
    
    	/* Make a standalone slot */
    	slot = MakeSingleTupleTableSlot(tupdesc);
    
    	/* Return the slot */
    	return slot;
    }
    
    /*
     * TupleDescGetAttInMetadata - Build an AttInMetadata structure based on the
     * supplied TupleDesc. AttInMetadata can be used in conjunction with C strings
     * to produce a properly formed tuple.
     */
    AttInMetadata *
    TupleDescGetAttInMetadata(TupleDesc tupdesc)
    {
    	int			natts = tupdesc->natts;
    	int			i;
    	Oid			atttypeid;
    	Oid			attinfuncid;
    	FmgrInfo   *attinfuncinfo;
    	Oid		   *attioparams;
    	int32	   *atttypmods;
    	AttInMetadata *attinmeta;
    
    	attinmeta = (AttInMetadata *) palloc(sizeof(AttInMetadata));
    
    	/* "Bless" the tupledesc so that we can make rowtype datums with it */
    	attinmeta->tupdesc = BlessTupleDesc(tupdesc);
    
    	/*
    	 * Gather info needed later to call the "in" function for each attribute
    	 */
    	attinfuncinfo = (FmgrInfo *) palloc0(natts * sizeof(FmgrInfo));
    	attioparams = (Oid *) palloc0(natts * sizeof(Oid));
    	atttypmods = (int32 *) palloc0(natts * sizeof(int32));
    
    	for (i = 0; i < natts; i++)
    	{
    		/* Ignore dropped attributes */
    		if (!tupdesc->attrs[i]->attisdropped)
    		{
    			atttypeid = tupdesc->attrs[i]->atttypid;
    			getTypeInputInfo(atttypeid, &attinfuncid, &attioparams[i]);
    			fmgr_info(attinfuncid, &attinfuncinfo[i]);
    			atttypmods[i] = tupdesc->attrs[i]->atttypmod;
    		}
    	}
    	attinmeta->attinfuncs = attinfuncinfo;
    	attinmeta->attioparams = attioparams;
    	attinmeta->atttypmods = atttypmods;
    
    	return attinmeta;
    }
    
    /*
     * BuildTupleFromCStrings - build a HeapTuple given user data in C string form.
     * values is an array of C strings, one for each attribute of the return tuple.
     * A NULL string pointer indicates we want to create a NULL field.
     */
    HeapTuple
    BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
    {
    	TupleDesc	tupdesc = attinmeta->tupdesc;
    	int			natts = tupdesc->natts;
    	Datum	   *dvalues;
    	bool	   *nulls;
    	int			i;
    	HeapTuple	tuple;
    
    	dvalues = (Datum *) palloc(natts * sizeof(Datum));
    	nulls = (bool *) palloc(natts * sizeof(bool));
    
    	/* Call the "in" function for each non-dropped attribute */
    	for (i = 0; i < natts; i++)
    	{
    		if (!tupdesc->attrs[i]->attisdropped)
    		{
    			/* Non-dropped attributes */
    			dvalues[i] = InputFunctionCall(&attinmeta->attinfuncs[i],
    										   values[i],
    										   attinmeta->attioparams[i],
    										   attinmeta->atttypmods[i]);
    			if (values[i] != NULL)
    				nulls[i] = false;
    			else
    				nulls[i] = true;
    		}
    		else
    		{
    			/* Handle dropped attributes by setting to NULL */
    			dvalues[i] = (Datum) 0;
    			nulls[i] = true;
    		}
    	}
    
    	/*
    	 * Form a tuple
    	 */
    	tuple = heap_form_tuple(tupdesc, dvalues, nulls);
    
    	/*
    	 * Release locally palloc'd space.  XXX would probably be good to pfree
    	 * values of pass-by-reference datums, as well.
    	 */
    	pfree(dvalues);
    	pfree(nulls);
    
    	return tuple;
    }
    
    /*
     * Functions for sending tuples to the frontend (or other specified destination)
     * as though it is a SELECT result. These are used by utility commands that
     * need to project directly to the destination and don't need or want full
     * table function capability. Currently used by EXPLAIN and SHOW ALL.
     */
    TupOutputState *
    begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc)
    {
    	TupOutputState *tstate;
    
    	tstate = (TupOutputState *) palloc(sizeof(TupOutputState));
    
    	tstate->slot = MakeSingleTupleTableSlot(tupdesc);
    	tstate->dest = dest;
    
    	(*tstate->dest->rStartup) (tstate->dest, (int) CMD_SELECT, tupdesc);
    
    	return tstate;
    }
    
    /*
     * write a single tuple
     */
    void
    do_tup_output(TupOutputState *tstate, Datum *values, bool *isnull)
    {
    	TupleTableSlot *slot = tstate->slot;
    	int			natts = slot->tts_tupleDescriptor->natts;
    
    	/* make sure the slot is clear */
    	ExecClearTuple(slot);
    
    	/* insert data */
    	memcpy(slot->tts_values, values, natts * sizeof(Datum));
    	memcpy(slot->tts_isnull, isnull, natts * sizeof(bool));
    
    	/* mark slot as containing a virtual tuple */
    	ExecStoreVirtualTuple(slot);
    
    	/* send the tuple to the receiver */
    	(*tstate->dest->receiveSlot) (slot, tstate->dest);
    
    	/* clean up */
    	ExecClearTuple(slot);
    }
    
    /*
     * write a chunk of text, breaking at newline characters
     *
     * Should only be used with a single-TEXT-attribute tupdesc.
     */
    void
    do_text_output_multiline(TupOutputState *tstate, char *text)
    {
    	Datum		values[1];
    	bool		isnull[1] = {false};
    
    	while (*text)
    	{
    		char	   *eol;
    		int			len;
    
    		eol = strchr(text, '\n');
    		if (eol)
    		{
    			len = eol - text;
    
    			eol++;
    		}
    		else
    		{
    			len = strlen(text);
    			eol += len;
    		}
    
    		values[0] = PointerGetDatum(cstring_to_text_with_len(text, len));
    		do_tup_output(tstate, values, isnull);
    		pfree(DatumGetPointer(values[0]));
    		text = eol;
    	}
    }
    
    void
    end_tup_output(TupOutputState *tstate)
    {
    	(*tstate->dest->rShutdown) (tstate->dest);
    	/* note that destroying the dest is not ours to do */
    	ExecDropSingleTupleTableSlot(tstate->slot);
    	pfree(tstate);
    }