From 8094682bf16e25873376b29ffd0f8edae9a6d735 Mon Sep 17 00:00:00 2001
From: Hari <haribabuk@fast.au.fujitsu.com>
Date: Thu, 1 Jun 2017 15:22:04 +1000
Subject: [PATCH 03/10] Storage access method API functions

---
 src/backend/access/heap/Makefile       |   3 +-
 src/backend/access/heap/storageamapi.c | 103 +++++++++++++++
 src/include/access/storageamapi.h      | 228 +++++++++++++++++++++++++++++++++
 3 files changed, 333 insertions(+), 1 deletion(-)
 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..35e7b92 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 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/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/storageamapi.h b/src/include/access/storageamapi.h
new file mode 100644
index 0000000..87130c9
--- /dev/null
+++ b/src/include/access/storageamapi.h
@@ -0,0 +1,228 @@
+/*---------------------------------------------------------------------
+ *
+ * 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/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 HeapScanDesc (*scan_begin_function) (Relation relation,
+												 Snapshot snapshot,
+												 int nkeys,
+												 ScanKey key);
+typedef HeapScanDesc (*scan_begin_catalog_function) (Relation relation,
+												 int nkeys,
+												 ScanKey key);
+typedef HeapScanDesc (*scan_begin_strat_function) (Relation relation,
+													   Snapshot snapshot,
+													   int nkeys,
+													   ScanKey key,
+													   bool allow_strat,
+													   bool allow_sync);
+typedef HeapScanDesc (*scan_begin_bm_function) (Relation relation,
+													Snapshot snapshot,
+													int nkeys,
+													ScanKey key);
+typedef HeapScanDesc (*scan_begin_sampling_function) (Relation relation,
+														  Snapshot snapshot,
+														  int nkeys,
+														  ScanKey key,
+														  bool allow_strat,
+														  bool allow_sync,
+														  bool allow_pagemode);
+typedef void (*scan_setlimits_function) (HeapScanDesc sscan, BlockNumber startBlk, BlockNumber numBlks);
+
+/* must return a TupleTableSlot? */
+typedef StorageTuple (*scan_getnext_function) (HeapScanDesc scan,
+											ScanDirection direction);
+
+typedef void (*scan_end_function) (HeapScanDesc scan);
+
+
+typedef void (*scan_getpage_function) (HeapScanDesc scan, BlockNumber page);
+typedef void (*scan_rescan_function) (HeapScanDesc scan, ScanKey key);
+typedef void (*scan_rescan_set_params_function) (HeapScanDesc scan, ScanKey key,
+					 bool allow_strat, bool allow_sync, bool allow_pagemode);
+typedef void (*scan_update_snapshot_function) (HeapScanDesc scan, Snapshot snapshot);
+
+typedef Oid (*tuple_insert_function) (Relation relation,
+									  TupleTableSlot *tupslot,
+									  CommandId cid,
+									  int options,
+									  BulkInsertState bistate,
+									  ItemPointer iptr);
+
+typedef HTSU_Result (*tuple_delete_function) (Relation relation,
+											  ItemPointer tid,
+											  CommandId cid,
+											  Snapshot crosscheck,
+											  bool wait,
+											  HeapUpdateFailureData *hufd);
+
+typedef HTSU_Result (*tuple_update_function) (Relation relation,
+											  ItemPointer otid,
+											  TupleTableSlot *slot,
+											  CommandId cid,
+											  Snapshot crosscheck,
+											  bool wait,
+											  HeapUpdateFailureData *hufd,
+											  LockTupleMode *lockmode,
+											  ItemPointer iptr);
+typedef bool (*tuple_fetch_function) (Relation relation,
+									ItemPointer tid,
+									Snapshot snapshot,
+									StorageTuple *tuple,
+									Buffer *userbuf,
+									bool keep_buf,
+									Relation stats_relation);
+
+typedef HTSU_Result (*tuple_lock_function) (Relation relation,
+											ItemPointer tid,
+											StorageTuple tuple,
+											CommandId cid,
+											LockTupleMode mode,
+											LockWaitPolicy wait_policy,
+											bool follow_update,
+											Buffer *buffer,
+											HeapUpdateFailureData *hufd);
+
+typedef TransactionId (*tuple_get_xmin_function) (StorageTuple tuple);
+
+typedef TransactionId (*tuple_get_updated_xid_function) (StorageTuple tuple);
+
+typedef CommandId (*tuple_get_cmin_function) (StorageTuple tuple);
+
+typedef ItemPointer (*tuple_get_itempointer_function) (StorageTuple tuple);
+
+typedef ItemPointerData (*tuple_get_ctid_function) (StorageTuple tuple);
+
+typedef void (*slot_set_tuple_oid_function) (TupleTableSlot *slot, Oid tupleoid);
+
+typedef StorageTuple (*tuple_from_datum_function) (Datum data, Oid tableoid);
+
+typedef bool (* tuple_is_heaponly_function) (StorageTuple tuple);
+
+typedef void (*slot_store_tuple_function) (TupleTableSlot *slot,
+										   StorageTuple tuple,
+										   bool shouldFree);
+typedef void (*slot_clear_tuple_function) (TupleTableSlot *slot);
+typedef void (*slot_materialize_tuple_function) (TupleTableSlot *slot);
+typedef Datum (*slot_getattr_function) (TupleTableSlot *slot,
+										int attnum, bool *isnull);
+typedef void (*slot_getallattrs_function) (TupleTableSlot *slot);
+typedef void (*slot_getsomeattrs_function) (TupleTableSlot *slot, int attnum);
+typedef bool (*slot_attisnull_function) (TupleTableSlot *slot, int attnum);
+
+typedef HeapTuple (*slot_copy_tuple_function) (TupleTableSlot *slot);
+typedef MinimalTuple (*slot_copy_min_tuple_function) (TupleTableSlot *slot);
+typedef HeapTuple (*slot_get_tuple_function) (TupleTableSlot *slot);
+typedef bool (*slot_is_physical_tuple_function) (TupleTableSlot *slot);
+
+typedef void (*slot_update_tableoid_function) (TupleTableSlot *slot, Oid tableoid);
+
+typedef void (*tuple_set_speculative_token_function) (TupleTableSlot *slot,
+								   uint32 specToken);
+typedef void (*speculative_finish_function) (Relation rel,
+											 TupleTableSlot *slot);
+typedef void (*speculative_abort_function) (Relation rel,
+											TupleTableSlot *slot);
+
+
+/*
+ * 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_function scan_begin;
+	scan_begin_catalog_function scan_begin_catalog;
+	scan_begin_strat_function scan_begin_strat;
+	scan_begin_bm_function scan_begin_bm;
+	scan_begin_sampling_function scan_begin_sampling;
+	scan_setlimits_function scansetlimits;
+	scan_getnext_function scan_getnext;
+	scan_end_function scan_end;
+	scan_getpage_function scan_getpage;
+	scan_rescan_function scan_rescan;
+	scan_rescan_set_params_function scan_rescan_set_params;
+	scan_update_snapshot_function scan_update_snapshot;
+
+	// 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_function		tuple_insert;	/* heap_insert */
+	tuple_update_function		tuple_update;	/* heap_update */
+	tuple_delete_function		tuple_delete;	/* heap_delete */
+	tuple_fetch_function		tuple_fetch;	/* heap_fetch */
+	tuple_lock_function			tuple_lock;		/* heap_lock_tuple */
+
+	tuple_get_xmin_function		tuple_get_xmin;	/* HeapTupleHeaderGetXmin */
+	tuple_get_updated_xid_function tuple_get_updated_xid;
+	tuple_get_cmin_function     tuple_get_cmin; /* HeapTupleHeaderGetCmin */
+	tuple_get_itempointer_function tuple_get_itempointer;
+	tuple_get_ctid_function 	tuple_get_ctid;
+	tuple_is_heaponly_function	tuple_is_heaponly;
+	tuple_from_datum_function	tuple_from_datum;
+
+	/* Operations on TupleTableSlot */
+	slot_store_tuple_function	slot_store_tuple;
+	slot_getattr_function		slot_getattr;
+	slot_getallattrs_function	slot_getallattrs;
+	slot_getsomeattrs_function  slot_getsomeattrs;
+	slot_attisnull_function		slot_attisnull;
+	slot_clear_tuple_function	slot_clear_tuple;
+	slot_materialize_tuple_function slot_materialize_tuple;
+	slot_copy_tuple_function     slot_copy_tuple;
+	slot_get_tuple_function      slot_get_tuple;
+	slot_copy_min_tuple_function slot_copy_min_tuple;
+	slot_is_physical_tuple_function slot_is_physical_tuple;
+	slot_update_tableoid_function slot_update_tableoid;
+	slot_set_tuple_oid_function slot_set_tuple_oid;
+
+	/*
+	 * 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:
+	 */
+	tuple_set_speculative_token_function tuple_set_speculative_token;	/* HeapTupleHeaderSetSpeculativeToken */
+	speculative_finish_function	speculative_finish;
+	speculative_abort_function	speculative_abort;
+} StorageAmRoutine;
+
+extern StorageAmRoutine *GetStorageAmRoutine(Oid amhandler);
+extern StorageAmRoutine *GetStorageAmRoutineByAmId(Oid amoid);
+
+extern StorageAmRoutine *GetHeapamStorageAmRoutine(void);
+
+extern void heap_abort_speculative(Relation relation, HeapTuple tuple);
+
+#endif		/* STORAGEAMAPI_H */
-- 
2.7.4.windows.1

