From 8bc00e8dc5e12caa6995b62346fd4c9f555eaba0 Mon Sep 17 00:00:00 2001
From: Hari <haribabuk@fast.au.fujitsu.com>
Date: Thu, 1 Jun 2017 22:01:38 +1000
Subject: [PATCH 05/10] Adding storageam handler to slot

Storage am handler to slot and also changing
the slot structure according to new access methods
---
 src/backend/access/common/heaptuple.c |  25 +++--
 src/backend/executor/execTuples.c     | 172 +++++++++++++++++-----------------
 src/include/access/htup_details.h     |  12 +++
 src/include/executor/tuptable.h       |  50 ++++++----
 src/include/nodes/nodes.h             |   1 +
 5 files changed, 145 insertions(+), 115 deletions(-)

diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index c0086de..f04c870 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -1033,7 +1033,8 @@ heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc,
 static void
 slot_deform_tuple(TupleTableSlot *slot, int natts)
 {
-	HeapTuple	tuple = slot->tts_tuple;
+	HeapamTuple *stuple = (HeapamTuple *) slot->tts_storage;
+	HeapTuple	tuple = stuple ? stuple->hst_heaptuple : NULL;
 	TupleDesc	tupleDesc = slot->tts_tupleDescriptor;
 	Datum	   *values = slot->tts_values;
 	bool	   *isnull = slot->tts_isnull;
@@ -1060,8 +1061,8 @@ slot_deform_tuple(TupleTableSlot *slot, int natts)
 	else
 	{
 		/* Restore state from previous execution */
-		off = slot->tts_off;
-		slow = slot->tts_slow;
+		off = stuple->hst_off;
+		slow = stuple->hst_slow;
 	}
 
 	tp = (char *) tup + tup->t_hoff;
@@ -1121,8 +1122,8 @@ slot_deform_tuple(TupleTableSlot *slot, int natts)
 	 * Save state for next execution
 	 */
 	slot->tts_nvalid = attnum;
-	slot->tts_off = off;
-	slot->tts_slow = slow;
+	stuple->hst_off = off;
+	stuple->hst_slow = slow;
 }
 
 /*
@@ -1140,7 +1141,8 @@ slot_deform_tuple(TupleTableSlot *slot, int natts)
 Datum
 slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
 {
-	HeapTuple	tuple = slot->tts_tuple;
+	HeapamTuple *stuple = (HeapamTuple *) slot->tts_storage;
+	HeapTuple	tuple = stuple ? stuple->hst_heaptuple : NULL;
 	TupleDesc	tupleDesc = slot->tts_tupleDescriptor;
 	HeapTupleHeader tup;
 
@@ -1236,6 +1238,7 @@ slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
 void
 slot_getallattrs(TupleTableSlot *slot)
 {
+	HeapamTuple	*stuple;
 	int			tdesc_natts = slot->tts_tupleDescriptor->natts;
 	int			attnum;
 	HeapTuple	tuple;
@@ -1248,7 +1251,8 @@ slot_getallattrs(TupleTableSlot *slot)
 	 * otherwise we had better have a physical tuple (tts_nvalid should equal
 	 * natts in all virtual-tuple cases)
 	 */
-	tuple = slot->tts_tuple;
+	stuple = (HeapamTuple *) slot->tts_storage;
+	tuple = stuple->hst_heaptuple;
 	if (tuple == NULL)			/* internal error */
 		elog(ERROR, "cannot extract attribute from empty tuple slot");
 
@@ -1280,6 +1284,7 @@ slot_getallattrs(TupleTableSlot *slot)
 void
 slot_getsomeattrs(TupleTableSlot *slot, int attnum)
 {
+	HeapamTuple *stuple;
 	HeapTuple	tuple;
 	int			attno;
 
@@ -1295,7 +1300,8 @@ slot_getsomeattrs(TupleTableSlot *slot, int attnum)
 	 * otherwise we had better have a physical tuple (tts_nvalid should equal
 	 * natts in all virtual-tuple cases)
 	 */
-	tuple = slot->tts_tuple;
+	stuple = slot->tts_storage; /* XXX SlotGetTupleStorage(slot) ??? */
+	tuple = stuple->hst_heaptuple;
 	if (tuple == NULL)			/* internal error */
 		elog(ERROR, "cannot extract attribute from empty tuple slot");
 
@@ -1327,7 +1333,8 @@ slot_getsomeattrs(TupleTableSlot *slot, int attnum)
 bool
 slot_attisnull(TupleTableSlot *slot, int attnum)
 {
-	HeapTuple	tuple = slot->tts_tuple;
+	HeapamTuple *stuple = slot->tts_storage;
+	HeapTuple	tuple = stuple ? stuple->hst_heaptuple : NULL;
 	TupleDesc	tupleDesc = slot->tts_tupleDescriptor;
 
 	/*
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index c4a9553..6912163 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -82,8 +82,10 @@
 #include "postgres.h"
 
 #include "access/htup_details.h"
+#include "access/storageamapi.h"
 #include "access/tuptoaster.h"
 #include "funcapi.h"
+#include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
 #include "nodes/nodeFuncs.h"
 #include "storage/bufmgr.h"
@@ -113,16 +115,17 @@ 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;
+	slot->tts_tupleOid = InvalidOid;
+	slot->tts_tableOid = InvalidOid;
+	slot->tts_storageam = GetStorageAmRoutine(HEAPAM_STORAGE_AM_HANDLER_OID);
+	slot->tts_storage = NULL;
 
 	return slot;
 }
@@ -247,6 +250,7 @@ void
 ExecSetSlotDescriptor(TupleTableSlot *slot,		/* slot to change */
 					  TupleDesc tupdesc)		/* new tuple descriptor */
 {
+
 	/* For safety, make sure slot is empty before changing it */
 	ExecClearTuple(slot);
 
@@ -279,6 +283,30 @@ ExecSetSlotDescriptor(TupleTableSlot *slot,		/* slot to change */
 }
 
 /* --------------------------------
+ *		ExecSetSlotStorageRoutine
+ *
+ *		This function sets the storage AM routine pointer for the slot.
+ *
+ *		XXX should this be part of ExecSetSlotDescriptor?
+ * --------------------------------
+ */
+void
+ExecSetSlotStorageRoutine(TupleTableSlot *slot,
+						  StorageAmRoutine *routine)
+{
+	if (slot->tts_storageam)
+	{
+		/* XXX do we need any cleanup here? */
+	}
+
+	/*
+	 * XXX maybe we need refcounts for StorageAmRoutine objects?
+	 * or perhaps we need to copy here?
+	 */
+	slot->tts_storageam = routine;
+}
+
+/* --------------------------------
  *		ExecStoreTuple
  *
  *		This function is used to store a physical tuple into a specified
@@ -294,19 +322,6 @@ ExecSetSlotDescriptor(TupleTableSlot *slot,		/* slot to change */
  * 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
@@ -317,7 +332,7 @@ ExecSetSlotDescriptor(TupleTableSlot *slot,		/* slot to change */
  * --------------------------------
  */
 TupleTableSlot *
-ExecStoreTuple(HeapTuple tuple,
+ExecStoreTuple(void *tuple,
 			   TupleTableSlot *slot,
 			   Buffer buffer,
 			   bool shouldFree)
@@ -328,47 +343,29 @@ ExecStoreTuple(HeapTuple tuple,
 	Assert(tuple != NULL);
 	Assert(slot != NULL);
 	Assert(slot->tts_tupleDescriptor != NULL);
+	Assert(slot->tts_storageam != 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);
+	slot->tts_storageam->slot_clear_tuple(slot);	/* XXX ?? */
 
 	/*
-	 * Store the new tuple into the specified slot.
+	 * Store the new tuple into the specified slot, and mark the slot as no
+	 * longer empty.  This clears any previously stored physical tuple.
 	 */
+	/* XXX should we pass the buffer down to the storageAM perhaps? */
+	slot->tts_storageam->slot_store_tuple(slot, tuple, shouldFree);
+
 	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;
 }
 
@@ -395,10 +392,7 @@ ExecStoreMinimalTuple(MinimalTuple mtup,
 	/*
 	 * 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);
+	slot->tts_storageam->slot_clear_tuple(slot);	/* XXX ?? */
 
 	/*
 	 * Drop the pin on the referenced buffer, if there is one.
@@ -412,9 +406,15 @@ ExecStoreMinimalTuple(MinimalTuple mtup,
 	 * 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;
+
+	/*
+	 * Store the new tuple into the specified slot, and mark the slot as no
+	 * longer empty.  This clears any previously stored physical tuple.
+	 */
+	/* XXX should we pass the buffer down to the storageAM perhaps? */
+	slot->tts_storageam->slot_store_tuple(slot, &slot->tts_minhdr, false);
+
 	slot->tts_mintuple = mtup;
 
 	slot->tts_minhdr.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
@@ -444,25 +444,20 @@ ExecClearTuple(TupleTableSlot *slot)	/* slot in which to store tuple */
 	Assert(slot != NULL);
 
 	/*
-	 * Free the old physical tuple if necessary.
+	 * Tell the storage AM to release any resource associated with the slot.
 	 */
-	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;
+	slot->tts_storageam->slot_clear_tuple(slot);
 
 	/*
 	 * Drop the pin on the referenced buffer, if there is one.
+	 *
+	 * XXX probably this belongs in the storage AM rather than here.
 	 */
 	if (BufferIsValid(slot->tts_buffer))
 		ReleaseBuffer(slot->tts_buffer);
 
 	slot->tts_buffer = InvalidBuffer;
+	slot->tts_mintuple = NULL;
 
 	/*
 	 * Mark it empty.
@@ -541,7 +536,7 @@ ExecStoreAllNullTuple(TupleTableSlot *slot)
  *		however the "system columns" of the result will not be meaningful.
  * --------------------------------
  */
-HeapTuple
+StorageTuple
 ExecCopySlotTuple(TupleTableSlot *slot)
 {
 	/*
@@ -553,8 +548,8 @@ ExecCopySlotTuple(TupleTableSlot *slot)
 	/*
 	 * 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_storage && slot->tts_storageam->slot_is_physical_tuple(slot))
+		return slot->tts_storageam->slot_copy_tuple(slot);
 	if (slot->tts_mintuple)
 		return heap_tuple_from_minimal_tuple(slot->tts_mintuple);
 
@@ -588,8 +583,9 @@ ExecCopySlotMinimalTuple(TupleTableSlot *slot)
 	 */
 	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);
+
+	if (slot->tts_storage)
+		return slot->tts_storageam->slot_copy_min_tuple(slot);
 
 	/*
 	 * Otherwise we need to build a tuple from the Datum array.
@@ -614,7 +610,7 @@ ExecCopySlotMinimalTuple(TupleTableSlot *slot)
  * Hence, the result must be treated as read-only.
  * --------------------------------
  */
-HeapTuple
+StorageTuple
 ExecFetchSlotTuple(TupleTableSlot *slot)
 {
 	/*
@@ -624,15 +620,9 @@ ExecFetchSlotTuple(TupleTableSlot *slot)
 	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);
+	return ExecHeapifySlot(slot);
 }
 
 /* --------------------------------
@@ -697,7 +687,7 @@ ExecFetchSlotMinimalTuple(TupleTableSlot *slot)
 Datum
 ExecFetchSlotTupleDatum(TupleTableSlot *slot)
 {
-	HeapTuple	tup;
+	StorageTuple	tup;
 	TupleDesc	tupdesc;
 
 	/* Fetch slot's contents in regular-physical-tuple form */
@@ -713,18 +703,19 @@ ExecFetchSlotTupleDatum(TupleTableSlot *slot)
  *			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.
+ *		any external storage.
  *
  *		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.
+ *		to scribble on.  XXX is this comment good?
  * --------------------------------
  */
-HeapTuple
+void
 ExecMaterializeSlot(TupleTableSlot *slot)
 {
 	MemoryContext oldContext;
+	StorageTuple tuple;
 
 	/*
 	 * sanity checks
@@ -732,12 +723,14 @@ ExecMaterializeSlot(TupleTableSlot *slot)
 	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;
+	if (slot->tts_storage &&
+			slot->tts_storageam->slot_is_physical_tuple(slot))
+		return;
 
 	/*
 	 * Otherwise, copy or build a physical tuple, and store it into the slot.
@@ -747,8 +740,8 @@ ExecMaterializeSlot(TupleTableSlot *slot)
 	 * anyway.
 	 */
 	oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
-	slot->tts_tuple = ExecCopySlotTuple(slot);
-	slot->tts_shouldFree = true;
+	tuple = ExecCopySlotTuple(slot);
+	slot->tts_storageam->slot_store_tuple(slot, tuple, true);
 	MemoryContextSwitchTo(oldContext);
 
 	/*
@@ -777,8 +770,15 @@ ExecMaterializeSlot(TupleTableSlot *slot)
 	 */
 	if (!slot->tts_shouldFreeMin)
 		slot->tts_mintuple = NULL;
+}
+
+StorageTuple
+ExecHeapifySlot(TupleTableSlot *slot)
+{
+	ExecMaterializeSlot(slot);
+	Assert(slot->tts_storage != NULL);
 
-	return slot->tts_tuple;
+	return slot->tts_storageam->slot_get_tuple(slot);
 }
 
 /* --------------------------------
@@ -794,7 +794,7 @@ ExecMaterializeSlot(TupleTableSlot *slot)
 TupleTableSlot *
 ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
 {
-	HeapTuple	newTuple;
+	StorageTuple	newTuple;
 	MemoryContext oldContext;
 
 	/*
@@ -1107,11 +1107,11 @@ TupleDescGetAttInMetadata(TupleDesc tupdesc)
 }
 
 /*
- * BuildTupleFromCStrings - build a HeapTuple given user data in C string form.
+ * BuildTupleFromCStrings - build a StorageTuple 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
+StorageTuple
 BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
 {
 	TupleDesc	tupdesc = attinmeta->tupdesc;
@@ -1119,7 +1119,7 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
 	Datum	   *dvalues;
 	bool	   *nulls;
 	int			i;
-	HeapTuple	tuple;
+	StorageTuple	tuple;
 
 	dvalues = (Datum *) palloc(natts * sizeof(Datum));
 	nulls = (bool *) palloc(natts * sizeof(bool));
@@ -1175,7 +1175,7 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
  * for a composite Datum.  However, we now require that composite Datums not
  * contain any external TOAST pointers.  We do not want heap_form_tuple itself
  * to enforce that; more specifically, the rule applies only to actual Datums
- * and not to HeapTuple structures.  Therefore, HeapTupleHeaderGetDatum is
+ * and not to StorageTuple structures.  Therefore, HeapTupleHeaderGetDatum is
  * now a function that detects whether there are externally-toasted fields
  * and constructs a new tuple with inlined fields if so.  We still need
  * heap_form_tuple to insert the Datum header fields, because otherwise this
@@ -1183,7 +1183,7 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
  *
  * Note that if we do build a new tuple, it's palloc'd in the current
  * memory context.  Beware of code that changes context between the initial
- * heap_form_tuple/etc call and calling HeapTuple(Header)GetDatum.
+ * heap_form_tuple/etc call and calling StorageTuple(Header)GetDatum.
  *
  * For performance-critical callers, it could be worthwhile to take extra
  * steps to ensure that there aren't TOAST pointers in the output of
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index e365f4f..a8ab945 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -21,6 +21,18 @@
 #include "storage/bufpage.h"
 
 /*
+ * Opaque tuple representation for executor's TupleTableSlot tts_storage
+ * (XXX This should probably live in a separate header)
+ */
+typedef struct HeapamTuple
+{
+	HeapTuple	hst_heaptuple;
+	bool		hst_slow;
+	bool		hst_shouldFree;
+	long		hst_off;
+} HeapamTuple;
+
+/*
  * MaxTupleAttributeNumber limits the number of (user) columns in a tuple.
  * The key limit on this value is that the size of the fixed overhead for
  * a tuple, plus the size of the null-values bitmap (at 1 bit per column),
diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h
index 32489ef..7521739 100644
--- a/src/include/executor/tuptable.h
+++ b/src/include/executor/tuptable.h
@@ -18,9 +18,25 @@
 #include "access/tupdesc.h"
 #include "storage/buf.h"
 
+/*
+ * Forward declare StorageAmRoutine to avoid including storageamapi.h here
+ */
+struct StorageAmRoutine;
+
+/*
+ * Forward declare StorageTuple to avoid including storageamapi.h here
+ */
+typedef void *StorageTuple;
+
 /*----------
  * The executor stores tuples in a "tuple table" which is a List of
- * independent TupleTableSlots.  There are several cases we need to handle:
+ * independent TupleTableSlots.
+ *
+ * XXX The "html-commented out" text below no longer reflects reality, as
+ * physical tuples are now responsibility of storage AMs.  But we have kept
+ * "minimal tuples".  Adjust this comment!
+ *
+ * <!-- There are several cases we need to handle:
  *		1. physical tuple in a disk buffer page
  *		2. physical tuple constructed in palloc'ed memory
  *		3. "minimal" physical tuple constructed in palloc'ed memory
@@ -56,6 +72,7 @@
  * had the fatal defect of invalidating any pass-by-reference Datums pointing
  * into the existing slot contents.)  Both copies must contain identical data
  * payloads when this is the case.
+ * -->
  *
  * The Datum/isnull arrays of a TupleTableSlot serve double duty.  When the
  * slot contains a virtual tuple, they are the authoritative data.  When the
@@ -79,15 +96,6 @@
  * mechanism to do more.  However, the slot will increment the tupdesc
  * reference count if a reference-counted tupdesc is supplied.)
  *
- * When tts_shouldFree is true, the physical tuple is "owned" by the slot
- * and should be freed when the slot's reference to the tuple is dropped.
- *
- * If tts_buffer is not InvalidBuffer, then the slot is holding a pin
- * on the indicated buffer page; drop the pin when we release the
- * slot's reference to that buffer.  (tts_shouldFree should always be
- * false in such a case, since presumably tts_tuple is pointing at the
- * buffer page.)
- *
  * tts_nvalid indicates the number of valid columns in the tts_values/isnull
  * arrays.  When the slot is holding a "virtual" tuple this must be equal
  * to the descriptor's natts.  When the slot is holding a physical tuple
@@ -114,24 +122,22 @@ typedef struct TupleTableSlot
 {
 	NodeTag		type;
 	bool		tts_isempty;	/* true = slot is empty */
-	bool		tts_shouldFree; /* should pfree tts_tuple? */
 	bool		tts_shouldFreeMin;		/* should pfree tts_mintuple? */
-	bool		tts_slow;		/* saved state for slot_deform_tuple */
-	HeapTuple	tts_tuple;		/* physical tuple, or NULL if virtual */
 	TupleDesc	tts_tupleDescriptor;	/* slot's tuple descriptor */
+	Oid			tts_tableOid;	/* XXX describe */
+	Oid			tts_tupleOid;	/* XXX describe */
+	Buffer		tts_buffer;
 	MemoryContext tts_mcxt;		/* slot itself is in this context */
-	Buffer		tts_buffer;		/* tuple's buffer, or InvalidBuffer */
 	int			tts_nvalid;		/* # of valid values in tts_values */
+	uint32		tts_speculativeToken;	/* XXX describe */
 	Datum	   *tts_values;		/* current per-attribute values */
 	bool	   *tts_isnull;		/* current per-attribute isnull flags */
 	MinimalTuple tts_mintuple;	/* minimal tuple, or NULL if none */
 	HeapTupleData tts_minhdr;	/* workspace for minimal-tuple-only case */
-	long		tts_off;		/* saved state for slot_deform_tuple */
+	struct StorageAmRoutine *tts_storageam;	/* storage AM */
+	void	   *tts_storage;	/* storage AM's opaque space */
 } TupleTableSlot;
 
-#define TTS_HAS_PHYSICAL_TUPLE(slot)  \
-	((slot)->tts_tuple != NULL && (slot)->tts_tuple != &((slot)->tts_minhdr))
-
 /*
  * TupIsNull -- is a TupleTableSlot empty?
  */
@@ -144,8 +150,11 @@ extern TupleTableSlot *ExecAllocTableSlot(List **tupleTable);
 extern void ExecResetTupleTable(List *tupleTable, bool shouldFree);
 extern TupleTableSlot *MakeSingleTupleTableSlot(TupleDesc tupdesc);
 extern void ExecDropSingleTupleTableSlot(TupleTableSlot *slot);
-extern void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc);
-extern TupleTableSlot *ExecStoreTuple(HeapTuple tuple,
+extern void ExecSetSlotDescriptor(TupleTableSlot *slot,
+								  TupleDesc tupdesc);
+extern void ExecSetSlotStorageRoutine(TupleTableSlot *slot,
+						  struct StorageAmRoutine *routine);
+extern TupleTableSlot *ExecStoreTuple(void *tuple,
 			   TupleTableSlot *slot,
 			   Buffer buffer,
 			   bool shouldFree);
@@ -161,6 +170,7 @@ extern HeapTuple ExecFetchSlotTuple(TupleTableSlot *slot);
 extern MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot);
 extern Datum ExecFetchSlotTupleDatum(TupleTableSlot *slot);
 extern HeapTuple ExecMaterializeSlot(TupleTableSlot *slot);
+extern StorageTuple ExecHeapifySlot(TupleTableSlot *slot);
 extern TupleTableSlot *ExecCopySlot(TupleTableSlot *dstslot,
 			 TupleTableSlot *srcslot);
 
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index f59d719..ac3375e 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -496,6 +496,7 @@ typedef enum NodeTag
 	T_InlineCodeBlock,			/* in nodes/parsenodes.h */
 	T_FdwRoutine,				/* in foreign/fdwapi.h */
 	T_IndexAmRoutine,			/* in access/amapi.h */
+	T_StorageAmRoutine,			/* in access/storageamapi.h */
 	T_TsmRoutine,				/* in access/tsmapi.h */
 	T_ForeignKeyCacheInfo		/* in utils/rel.h */
 } NodeTag;
-- 
2.7.4.windows.1

