From 0be15e2d9f0023068d44815e28708f0c42d6d430 Mon Sep 17 00:00:00 2001
From: Hari Babu <haribabuk@fast.au.fujitsu.com>
Date: Wed, 30 Aug 2017 12:41:15 +1000
Subject: [PATCH 2/7] Storage AM API hooks and related functions

---
 src/backend/access/heap/Makefile         |   3 +-
 src/backend/access/heap/heapam_storage.c |  58 ++++++++
 src/backend/access/heap/storageamapi.c   | 103 ++++++++++++++
 src/include/access/htup.h                |  21 +++
 src/include/access/storageamapi.h        | 237 +++++++++++++++++++++++++++++++
 src/include/catalog/pg_proc.h            |   5 +
 src/include/nodes/nodes.h                |   1 +
 src/include/utils/tqual.h                |   9 --
 8 files changed, 427 insertions(+), 10 deletions(-)
 create mode 100644 src/backend/access/heap/heapam_storage.c
 create mode 100644 src/backend/access/heap/storageamapi.c
 create mode 100644 src/include/access/storageamapi.h

diff --git a/src/backend/access/heap/Makefile b/src/backend/access/heap/Makefile
index b83d496..02a3909 100644
--- a/src/backend/access/heap/Makefile
+++ b/src/backend/access/heap/Makefile
@@ -12,6 +12,7 @@ subdir = src/backend/access/heap
 top_builddir = ../../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = heapam.o hio.o pruneheap.o rewriteheap.o syncscan.o tuptoaster.o visibilitymap.o
+OBJS = heapam.o hio.o heapam_storage.o pruneheap.o rewriteheap.o storageamapi.o \
+	syncscan.o tuptoaster.o visibilitymap.o
 
 include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/access/heap/heapam_storage.c b/src/backend/access/heap/heapam_storage.c
new file mode 100644
index 0000000..fbffb3a
--- /dev/null
+++ b/src/backend/access/heap/heapam_storage.c
@@ -0,0 +1,58 @@
+/*-------------------------------------------------------------------------
+ *
+ * heapam_storage.c
+ *	  heap storage access method code
+ *
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/backend/access/heap/heapam_storage.c
+ *
+ *
+ * NOTES
+ *	  This file contains the heap_ routines which implement
+ *	  the POSTGRES heap access method used for all POSTGRES
+ *	  relations.
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "access/heapam_xlog.h"
+#include "access/hio.h"
+#include "access/htup_details.h"
+#include "access/multixact.h"
+#include "access/relscan.h"
+#include "access/storageamapi.h"
+#include "access/subtrans.h"
+#include "access/tuptoaster.h"
+#include "access/valid.h"
+#include "access/visibilitymap.h"
+#include "access/xloginsert.h"
+#include "access/xact.h"
+#include "catalog/catalog.h"
+#include "miscadmin.h"
+#include "pgstat.h"
+#include "storage/bufmgr.h"
+#include "storage/lmgr.h"
+#include "storage/predicate.h"
+#include "storage/procarray.h"
+#include "storage/smgr.h"
+#include "storage/spin.h"
+#include "utils/builtins.h"
+#include "utils/inval.h"
+#include "utils/rel.h"
+#include "utils/tqual.h"
+
+
+Datum
+heapam_storage_handler(PG_FUNCTION_ARGS)
+{
+	StorageAmRoutine *amroutine = makeNode(StorageAmRoutine);
+
+
+	PG_RETURN_POINTER(amroutine);
+}
diff --git a/src/backend/access/heap/storageamapi.c b/src/backend/access/heap/storageamapi.c
new file mode 100644
index 0000000..def2029
--- /dev/null
+++ b/src/backend/access/heap/storageamapi.c
@@ -0,0 +1,103 @@
+/*----------------------------------------------------------------------
+ *
+ * storageamapi.c
+ *		Support routines for API for Postgres storage access methods
+ *
+ * FIXME: looks like this should be in amapi.c.
+ *
+ * Copyright (c) 2016, PostgreSQL Global Development Group
+ *
+ * src/backend/access/heap/storageamapi.c
+ *----------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/htup_details.h"
+#include "access/storageamapi.h"
+#include "catalog/pg_am.h"
+#include "catalog/pg_proc.h"
+#include "utils/syscache.h"
+#include "utils/memutils.h"
+
+
+/*
+ * GetStorageAmRoutine
+ *		Call the specified access method handler routine to get its
+ *		StorageAmRoutine struct, which will be palloc'd in the caller's
+ *		memory context.
+ */
+StorageAmRoutine *
+GetStorageAmRoutine(Oid amhandler)
+{
+	Datum		datum;
+	StorageAmRoutine *routine;
+
+	datum = OidFunctionCall0(amhandler);
+	routine = (StorageAmRoutine *) DatumGetPointer(datum);
+
+	if (routine == NULL || !IsA(routine, StorageAmRoutine))
+		elog(ERROR, "storage access method handler %u did not return a StorageAmRoutine struct",
+			 amhandler);
+
+	return routine;
+}
+
+/* A crock */
+StorageAmRoutine *
+GetHeapamStorageAmRoutine(void)
+{
+	Datum datum;
+	static StorageAmRoutine *HeapamStorageAmRoutine = NULL;
+
+	if (HeapamStorageAmRoutine == NULL)
+	{
+		MemoryContext	oldcxt;
+
+		oldcxt = MemoryContextSwitchTo(TopMemoryContext);
+		datum = OidFunctionCall0(HEAPAM_STORAGE_AM_HANDLER_OID);
+		HeapamStorageAmRoutine = (StorageAmRoutine *) DatumGetPointer(datum);
+		MemoryContextSwitchTo(oldcxt);
+	}
+
+	return HeapamStorageAmRoutine;
+}
+
+/*
+ * GetStorageAmRoutineByAmId - look up the handler of the storage access
+ * method with the given OID, and get its StorageAmRoutine struct.
+ */
+StorageAmRoutine *
+GetStorageAmRoutineByAmId(Oid amoid)
+{
+	regproc     amhandler;
+	HeapTuple   tuple;
+	Form_pg_am  amform;
+
+	/* Get handler function OID for the access method */
+	tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "cache lookup failed for access method %u",
+			 amoid);
+	amform = (Form_pg_am) GETSTRUCT(tuple);
+
+	/* Check that it is a storage access method */
+	if (amform->amtype != AMTYPE_STORAGE)
+		ereport(ERROR,
+				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+				 errmsg("access method \"%s\" is not of type %s",
+						NameStr(amform->amname), "STORAGE")));
+
+	amhandler = amform->amhandler;
+
+	/* Complain if handler OID is invalid */
+	if (!RegProcedureIsValid(amhandler))
+		ereport(ERROR,
+				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+				 errmsg("storage access method \"%s\" does not have a handler",
+						NameStr(amform->amname))));
+
+	ReleaseSysCache(tuple);
+
+	/* And finally, call the handler function to get the API struct. */
+	return GetStorageAmRoutine(amhandler);
+}
diff --git a/src/include/access/htup.h b/src/include/access/htup.h
index 61b3e68..6459435 100644
--- a/src/include/access/htup.h
+++ b/src/include/access/htup.h
@@ -26,6 +26,27 @@ typedef struct MinimalTupleData MinimalTupleData;
 
 typedef MinimalTupleData *MinimalTuple;
 
+typedef enum tuple_visibility_type
+{
+	MVCC_VISIBILITY = 0, 		/* HeapTupleSatisfiesMVCC */
+	SELF_VISIBILITY,				/* HeapTupleSatisfiesSelf */
+	ANY_VISIBILITY,				/* HeapTupleSatisfiesAny */
+	TOAST_VISIBILITY,			/* HeapTupleSatisfiesToast */
+	DIRTY_VISIBILITY,			/* HeapTupleSatisfiesDirty */
+	HISTORIC_MVCC_VISIBILITY,	/* HeapTupleSatisfiesHistoricMVCC */
+
+	END_OF_VISIBILITY
+} tuple_visibility_type;
+
+/* Result codes for HeapTupleSatisfiesVacuum */
+typedef enum
+{
+	HEAPTUPLE_DEAD,				/* tuple is dead and deletable */
+	HEAPTUPLE_LIVE,				/* tuple is live (committed, no deleter) */
+	HEAPTUPLE_RECENTLY_DEAD,	/* tuple is dead, but not deletable yet */
+	HEAPTUPLE_INSERT_IN_PROGRESS,	/* inserting xact is still in progress */
+	HEAPTUPLE_DELETE_IN_PROGRESS	/* deleting xact is still in progress */
+} HTSV_Result;
 
 /*
  * HeapTupleData is an in-memory data structure that points to a tuple.
diff --git a/src/include/access/storageamapi.h b/src/include/access/storageamapi.h
new file mode 100644
index 0000000..95fe028
--- /dev/null
+++ b/src/include/access/storageamapi.h
@@ -0,0 +1,237 @@
+/*---------------------------------------------------------------------
+ *
+ * storageamapi.h
+ *		API for Postgres storage access methods
+ *
+ * Copyright (c) 2016, PostgreSQL Global Development Group
+ *
+ * src/include/access/storageamapi.h
+ *---------------------------------------------------------------------
+ */
+#ifndef STORAGEAMAPI_H
+#define STORAGEAMAPI_H
+
+#include "access/htup.h"
+#include "access/heapam.h"
+#include "access/sdir.h"
+#include "access/skey.h"
+#include "executor/tuptable.h"
+#include "utils/relcache.h"
+#include "utils/snapshot.h"
+
+/* A physical tuple coming from a storage AM scan */
+typedef void *StorageTuple;
+
+typedef union tuple_data
+{
+	TransactionId xid;
+	CommandId cid;
+	ItemPointerData tid;
+} tuple_data;
+
+typedef enum tuple_data_flags
+{
+	XMIN = 0,
+	UPDATED_XID,
+	CMIN,
+	TID,
+	CTID
+} tuple_data_flags;
+
+
+typedef HeapScanDesc (*scan_begin_hook) (Relation relation,
+										Snapshot snapshot,
+										int nkeys, ScanKey key,
+										ParallelHeapScanDesc parallel_scan,
+										bool allow_strat,
+										bool allow_sync,
+										bool allow_pagemode,
+										bool is_bitmapscan,
+										bool is_samplescan,
+										bool temp_snap);
+typedef void (*scan_setlimits_hook) (HeapScanDesc sscan, BlockNumber startBlk, BlockNumber numBlks);
+
+/* must return a TupleTableSlot? */
+typedef StorageTuple (*scan_getnext_hook) (HeapScanDesc scan,
+											ScanDirection direction);
+
+typedef TupleTableSlot* (*scan_getnext_slot_hook) (HeapScanDesc scan,
+										ScanDirection direction, TupleTableSlot *slot);
+
+typedef void (*scan_end_hook) (HeapScanDesc scan);
+
+
+typedef void (*scan_getpage_hook) (HeapScanDesc scan, BlockNumber page);
+typedef void (*scan_rescan_hook) (HeapScanDesc scan, ScanKey key, bool set_params,
+					bool allow_strat, bool allow_sync, bool allow_pagemode);
+typedef void (*scan_update_snapshot_hook) (HeapScanDesc scan, Snapshot snapshot);
+
+typedef bool (*hot_search_buffer_hook) (ItemPointer tid, Relation relation,
+					   Buffer buffer, Snapshot snapshot, HeapTuple heapTuple,
+					   bool *all_dead, bool first_call);
+
+typedef Oid (*tuple_insert_hook) (Relation relation,
+									  TupleTableSlot *tupslot,
+									  CommandId cid,
+									  int options,
+									  BulkInsertState bistate);
+
+typedef HTSU_Result (*tuple_delete_hook) (Relation relation,
+											  ItemPointer tid,
+											  CommandId cid,
+											  Snapshot crosscheck,
+											  bool wait,
+											  HeapUpdateFailureData *hufd);
+
+typedef HTSU_Result (*tuple_update_hook) (Relation relation,
+											  ItemPointer otid,
+											  TupleTableSlot *slot,
+											  CommandId cid,
+											  Snapshot crosscheck,
+											  bool wait,
+											  HeapUpdateFailureData *hufd,
+											  LockTupleMode *lockmode);
+
+typedef bool (*tuple_fetch_hook) (Relation relation,
+									ItemPointer tid,
+									Snapshot snapshot,
+									StorageTuple *tuple,
+									Buffer *userbuf,
+									bool keep_buf,
+									Relation stats_relation);
+
+typedef HTSU_Result (*tuple_lock_hook) (Relation relation,
+											ItemPointer tid,
+											StorageTuple *tuple,
+											CommandId cid,
+											LockTupleMode mode,
+											LockWaitPolicy wait_policy,
+											bool follow_update,
+											Buffer *buffer,
+											HeapUpdateFailureData *hufd);
+
+typedef void (*multi_insert_hook) (Relation relation, HeapTuple *tuples, int ntuples,
+				  CommandId cid, int options, BulkInsertState bistate);
+
+typedef bool (*tuple_freeze_hook) (HeapTupleHeader tuple, TransactionId cutoff_xid,
+				  TransactionId cutoff_multi);
+
+typedef void (*tuple_get_latest_tid_hook) (Relation relation,
+											Snapshot snapshot,
+											ItemPointer tid);
+
+typedef tuple_data (*get_tuple_data_hook) (StorageTuple tuple, tuple_data_flags flags);
+
+typedef StorageTuple (*tuple_from_datum_hook) (Datum data, Oid tableoid);
+
+typedef bool (*tuple_is_heaponly_hook) (StorageTuple tuple);
+
+typedef void (*slot_store_tuple_hook) (TupleTableSlot *slot,
+										   StorageTuple tuple,
+										   bool shouldFree,
+										   bool minumumtuple);
+typedef void (*slot_clear_tuple_hook) (TupleTableSlot *slot);
+typedef Datum (*slot_getattr_hook) (TupleTableSlot *slot,
+										int attnum, bool *isnull);
+typedef void (*slot_virtualize_tuple_hook) (TupleTableSlot *slot, int16 upto);
+
+typedef HeapTuple (*slot_tuple_hook) (TupleTableSlot *slot, bool palloc_copy);
+typedef MinimalTuple (*slot_min_tuple_hook) (TupleTableSlot *slot, bool palloc_copy);
+
+typedef void (*slot_update_tableoid_hook) (TupleTableSlot *slot, Oid tableoid);
+
+typedef void (*speculative_finish_hook) (Relation rel,
+											 TupleTableSlot *slot);
+typedef void (*speculative_abort_hook) (Relation rel,
+											TupleTableSlot *slot);
+
+typedef void (*relation_sync_hook) (Relation relation);
+
+typedef bool (*snapshot_satisfies_hook) (StorageTuple htup, Snapshot snapshot, Buffer buffer);
+typedef HTSU_Result (*snapshot_satisfies_update_hook) (StorageTuple htup, CommandId curcid, Buffer buffer);
+typedef HTSV_Result (*snapshot_satisfies_vacuum_hook) (StorageTuple htup, TransactionId OldestXmin, Buffer buffer);
+
+typedef struct StorageSlotAmRoutine
+{
+	/* Operations on TupleTableSlot */
+	slot_store_tuple_hook	slot_store_tuple;
+	slot_virtualize_tuple_hook	slot_virtualize_tuple;
+	slot_clear_tuple_hook	slot_clear_tuple;
+	slot_getattr_hook	slot_getattr;
+	slot_tuple_hook     slot_tuple;
+	slot_min_tuple_hook      slot_min_tuple;
+	slot_update_tableoid_hook slot_update_tableoid;
+} StorageSlotAmRoutine;
+
+typedef StorageSlotAmRoutine* (*slot_storageam_hook) (void);
+
+/*
+ * API struct for a storage AM.  Note this must be stored in a single palloc'd
+ * chunk of memory.
+ *
+ * XXX currently all functions are together in a single struct.  Would it be
+ * worthwhile to split the slot-accessor functions to a different struct?
+ * That way, MinimalTuple could be handled without a complete StorageAmRoutine
+ * for them -- it'd only have a few functions in TupleTableSlotAmRoutine or so.
+ */
+typedef struct StorageAmRoutine
+{
+	NodeTag		type;
+
+	/* Operations on relation scans */
+	scan_begin_hook scan_begin;
+	scan_setlimits_hook scansetlimits;
+	scan_getnext_hook scan_getnext;
+	scan_getnext_slot_hook scan_getnextslot;
+	scan_end_hook scan_end;
+	scan_getpage_hook scan_getpage;
+	scan_rescan_hook scan_rescan;
+	scan_update_snapshot_hook scan_update_snapshot;
+	hot_search_buffer_hook hot_search_buffer; /* heap_hot_search_buffer */
+
+	// heap_sync_function		heap_sync;		/* heap_sync */
+	/* not implemented */
+	//	parallelscan_estimate_function	parallelscan_estimate;	/* heap_parallelscan_estimate */
+	//	parallelscan_initialize_function parallelscan_initialize;	/* heap_parallelscan_initialize */
+	//	parallelscan_begin_function	parallelscan_begin;	/* heap_beginscan_parallel */
+
+	/* Operations on physical tuples */
+	tuple_insert_hook		tuple_insert;	/* heap_insert */
+	tuple_update_hook		tuple_update;	/* heap_update */
+	tuple_delete_hook		tuple_delete;	/* heap_delete */
+	tuple_fetch_hook		tuple_fetch;	/* heap_fetch */
+	tuple_lock_hook			tuple_lock;		/* heap_lock_tuple */
+	multi_insert_hook		multi_insert;	/* heap_multi_insert */
+	tuple_freeze_hook       tuple_freeze;	/* heap_freeze_tuple */
+	tuple_get_latest_tid_hook tuple_get_latest_tid; /* heap_get_latest_tid */
+
+	get_tuple_data_hook		get_tuple_data;
+	tuple_is_heaponly_hook	tuple_is_heaponly;
+	tuple_from_datum_hook	tuple_from_datum;
+
+
+	slot_storageam_hook	slot_storageam;
+
+	/*
+	 * Speculative insertion support operations
+	 *
+	 * Setting a tuple's speculative token is a slot-only operation, so no need
+	 * for a storage AM method, but after inserting a tuple containing a
+	 * speculative token, the insertion must be completed by these routines:
+	 */
+	speculative_finish_hook	speculative_finish;
+	speculative_abort_hook	speculative_abort;
+
+
+	relation_sync_hook	relation_sync;	/* heap_sync */
+
+	snapshot_satisfies_hook snapshot_satisfies[END_OF_VISIBILITY];
+	snapshot_satisfies_update_hook snapshot_satisfiesUpdate; /* HeapTupleSatisfiesUpdate */
+	snapshot_satisfies_vacuum_hook snapshot_satisfiesVacuum; /* HeapTupleSatisfiesVacuum */
+} StorageAmRoutine;
+
+extern StorageAmRoutine *GetStorageAmRoutine(Oid amhandler);
+extern StorageAmRoutine *GetStorageAmRoutineByAmId(Oid amoid);
+extern StorageAmRoutine *GetHeapamStorageAmRoutine(void);
+
+#endif		/* STORAGEAMAPI_H */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index a38a954..1065671 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -549,6 +549,11 @@ DESCR("convert int4 to float4");
 DATA(insert OID = 319 (  int4			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1  0 23 "700" _null_ _null_ _null_ _null_ _null_	ftoi4 _null_ _null_ _null_ ));
 DESCR("convert float4 to int4");
 
+/* Storage access method handlers */
+DATA(insert OID = 425 (  heapam_storage_handler		PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 3998 "2281" _null_ _null_ _null_ _null_ _null_	heapam_storage_handler _null_ _null_ _null_ ));
+DESCR("row-oriented storage access method handler");
+#define HEAPAM_STORAGE_AM_HANDLER_OID	425
+
 /* Index access method handlers */
 DATA(insert OID = 330 (  bthandler		PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 325 "2281" _null_ _null_ _null_ _null_ _null_	bthandler _null_ _null_ _null_ ));
 DESCR("btree index access method handler");
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 27bd4f3..108df9b 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;
diff --git a/src/include/utils/tqual.h b/src/include/utils/tqual.h
index 036d989..0fb2e1c 100644
--- a/src/include/utils/tqual.h
+++ b/src/include/utils/tqual.h
@@ -45,15 +45,6 @@ extern PGDLLIMPORT SnapshotData CatalogSnapshotData;
 #define HeapTupleSatisfiesVisibility(tuple, snapshot, buffer) \
 	((*(snapshot)->satisfies) (tuple, snapshot, buffer))
 
-/* Result codes for HeapTupleSatisfiesVacuum */
-typedef enum
-{
-	HEAPTUPLE_DEAD,				/* tuple is dead and deletable */
-	HEAPTUPLE_LIVE,				/* tuple is live (committed, no deleter) */
-	HEAPTUPLE_RECENTLY_DEAD,	/* tuple is dead, but not deletable yet */
-	HEAPTUPLE_INSERT_IN_PROGRESS,	/* inserting xact is still in progress */
-	HEAPTUPLE_DELETE_IN_PROGRESS	/* deleting xact is still in progress */
-} HTSV_Result;
 
 /* These are the "satisfies" test routines for the various snapshot types */
 extern bool HeapTupleSatisfiesMVCC(HeapTuple htup,
-- 
1.8.3.1

