text: /*-------------------------------------------------------------------------
   *
   * execTuples.c
   *	  Routines dealing with the executor tuple tables.	These are used to
   *	  ensure that the executor frees copies of tuples (made by
   *	  ExecTargetList) properly.
   *
   *	  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-2009, PostgreSQL Global Development Group
   * Portions Copyright (c) 1994, Regents of the University of California
   *
   *
   * IDENTIFICATION
   *	  $PostgreSQL$
   *
   *-------------------------------------------------------------------------
   */
  /*
   * INTERFACE ROUTINES
   *
   *	 TABLE CREATE/DELETE
   *		ExecCreateTupleTable	- create a new tuple table
   *		ExecDropTupleTable		- destroy a table
   *		MakeSingleTupleTableSlot - make a single-slot table
   *		ExecDropSingleTupleTableSlot - destroy same
   *
   *	 SLOT RESERVATION
   *		ExecAllocTableSlot		- find an available slot in the table
   *
   *	 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()
   *		----------------
   *		- InitPlan() calls ExecCreateTupleTable() to create the tuple
   *		  table which will hold tuples processed by the executor.
   *
   *		- ExecInitSeqScan() calls ExecInitScanTupleSlot() and
   *		  ExecInitResultTupleSlot() to reserve places in the tuple
   *		  table 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 ExecDropTupleTable() 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/lsyscache.h"
  #include "utils/typcache.h"
  
  
  static TupleDesc ExecTypeFromTLInternal(List *targetList,
  					   bool hasoid, bool skipjunk);
  
  
  /* ----------------------------------------------------------------
   *				  tuple table create/delete functions
   * ----------------------------------------------------------------
   */
  
  /* --------------------------------
   *		ExecCreateTupleTable
   *
   *		This creates a new tuple table of the specified size.
   *
   *		This should be used by InitPlan() to allocate the table.
   *		The table's address will be stored in the EState structure.
   * --------------------------------
   */
  TupleTable
  ExecCreateTupleTable(int tableSize)
  {
  	TupleTable	newtable;
  	int			i;
  
  	/*
  	 * sanity checks
  	 */
  	Assert(tableSize >= 1);
  
  	/*
  	 * allocate the table itself
  	 */
  	newtable = (TupleTable) palloc(sizeof(TupleTableData) +
  								   (tableSize - 1) *sizeof(TupleTableSlot));
  	newtable->size = tableSize;
  	newtable->next = 0;
  
  	/*
  	 * initialize all the slots to empty states
  	 */
  	for (i = 0; i < tableSize; i++)
  	{
  		TupleTableSlot *slot = &(newtable->array[i]);
  
  		slot->type = T_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 newtable;
  }
  
  /* --------------------------------
   *		ExecDropTupleTable
   *
   *		This frees the storage used by the tuple table itself
   *		and optionally frees the contents of the table also.
   *		It is expected that this routine be called by EndPlan().
   * --------------------------------
   */
  void
  ExecDropTupleTable(TupleTable table,	/* tuple table */
  				   bool shouldFree)		/* true if we should free slot
  										 * contents */
  {
  	/*
  	 * sanity checks
  	 */
  	Assert(table != NULL);
  
  	/*
  	 * first free all the valid pointers in the tuple array and drop refcounts
  	 * of any referenced buffers, if that's what the caller wants.  (There is
  	 * probably no good reason for the caller ever not to want it!)
  	 */
  	if (shouldFree)
  	{
  		int			next = table->next;
  		int			i;
  
  		for (i = 0; i < next; i++)
  		{
  			TupleTableSlot *slot = &(table->array[i]);
  
  			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);
  		}
  	}
  
  	/*
  	 * finally free the tuple table itself.
  	 */
  	pfree(table);
  }
  
  /* --------------------------------
   *		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 as
   *		though by ExecSetSlotDescriptor(slot, tupdesc).
   * --------------------------------
   */
  TupleTableSlot *
  MakeSingleTupleTableSlot(TupleDesc tupdesc)
  {
  	TupleTableSlot *slot = makeNode(TupleTableSlot);
  
  	/* This should match ExecCreateTupleTable() */
  	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;
  
  	ExecSetSlotDescriptor(slot, tupdesc);
  
  	return slot;
  }
  
  /* --------------------------------
   *		ExecDropSingleTupleTableSlot
   *
   *		Release a TupleTableSlot made with MakeSingleTupleTableSlot.
   * --------------------------------
   */
  void
  ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
  {
  	/*
  	 * sanity checks
  	 */
  	Assert(slot != NULL);
  
  	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 reservation functions
   * ----------------------------------------------------------------
   */
  
  /* --------------------------------
   *		ExecAllocTableSlot
   *
   *		This routine is used to reserve slots in the table for
   *		use by the various plan nodes.	It is expected to be
   *		called by the node init routines (ex: ExecInitNestLoop)
   *		once per slot needed by the node.  Not all nodes need
   *		slots (some just pass tuples around).
   * --------------------------------
   */
  TupleTableSlot *
  ExecAllocTableSlot(TupleTable table)
  {
  	int			slotnum;		/* new slot number */
  
  	/*
  	 * sanity checks
  	 */
  	Assert(table != NULL);
  
  	/*
  	 * We expect that the table was made big enough to begin with. We cannot
  	 * reallocate it on the fly since previous plan nodes have already got
  	 * pointers to individual entries.
  	 */
  	if (table->next >= table->size)
  		elog(ERROR, "plan requires more slots than are available");
  
  	slotnum = table->next;
  	table->next++;
  
  	return &(table->array[slotnum]);
  }
  
  /* ----------------------------------------------------------------
   *				  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);
  	}
  
  	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);
  	}
  
  	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->metadata = TupleDescGetAttInMetadata(tupdesc);
  	tstate->slot = MakeSingleTupleTableSlot(tupdesc);
  	tstate->dest = dest;
  
  	(*tstate->dest->rStartup) (tstate->dest, (int) CMD_SELECT, tupdesc);
  
  	return tstate;
  }
  
  /*
   * write a single tuple
   *
   * values is a list of the external C string representations of the values
   * to be projected.
   *
   * XXX This could be made more efficient, since in reality we probably only
   * need a virtual tuple.
   */
  void
  do_tup_output(TupOutputState *tstate, char **values)
  {
  	/* build a tuple from the input strings using the tupdesc */
  	HeapTuple	tuple = BuildTupleFromCStrings(tstate->metadata, values);
  
  	/* put it in a slot */
  	ExecStoreTuple(tuple, tstate->slot, InvalidBuffer, true);
  
  	/* send the tuple to the receiver */
  	(*tstate->dest->receiveSlot) (tstate->slot, tstate->dest);
  
  	/* clean up */
  	ExecClearTuple(tstate->slot);
  }
  
  /*
   * write a chunk of text, breaking at newline characters
   *
   * NB: scribbles on its input!
   *
   * Should only be used with a single-TEXT-attribute tupdesc.
   */
  void
  do_text_output_multiline(TupOutputState *tstate, char *text)
  {
  	while (*text)
  	{
  		char	   *eol;
  
  		eol = strchr(text, '\n');
  		if (eol)
  			*eol++ = '\0';
  		else
  			eol = text +strlen(text);
  
  		do_tup_output(tstate, &text);
  		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);
  	/* XXX worth cleaning up the attinmetadata? */
  	pfree(tstate);
  }
  