From 8df9ac913811220bbcbfefa57e2204362c481cb9 Mon Sep 17 00:00:00 2001
From: kommih <haribabuk@fast.au.fujitsu.com>
Date: Thu, 27 Sep 2018 15:54:49 +1000
Subject: [PATCH 2/3] check_default_table_access_method hook to verify the
 access method

---
 src/backend/access/table/tableamapi.c | 88 +++++++++++++++++++++++++++
 src/backend/utils/misc/guc.c          |  3 +-
 src/include/access/tableam.h          |  4 ++
 3 files changed, 93 insertions(+), 2 deletions(-)

diff --git a/src/backend/access/table/tableamapi.c b/src/backend/access/table/tableamapi.c
index 7f08500ef4..d4eb889bd2 100644
--- a/src/backend/access/table/tableamapi.c
+++ b/src/backend/access/table/tableamapi.c
@@ -14,11 +14,14 @@
 
 #include "access/htup_details.h"
 #include "access/tableam.h"
+#include "access/xact.h"
 #include "catalog/pg_am.h"
 #include "catalog/pg_proc.h"
+#include "utils/fmgroids.h"
 #include "utils/syscache.h"
 #include "utils/memutils.h"
 
+static Oid get_table_am_oid(const char *tableamname, bool missing_ok);
 
 TupleTableSlot*
 table_gimmegimmeslot(Relation relation, List **reglist)
@@ -97,3 +100,88 @@ GetTableAmRoutineByAmId(Oid amoid)
 	/* And finally, call the handler function to get the API struct. */
 	return GetTableAmRoutine(amhandler);
 }
+
+/*
+ * get_table_am_oid - given a table access method name, look up the OID
+ *
+ * If missing_ok is false, throw an error if table access method name not
+ * found. If true, just return InvalidOid.
+ */
+static Oid
+get_table_am_oid(const char *tableamname, bool missing_ok)
+{
+	Oid			result;
+	Relation	rel;
+	TableScanDesc scandesc;
+	HeapTuple	tuple;
+	ScanKeyData entry[1];
+
+	/*
+	 * Search pg_tablespace.  We use a heapscan here even though there is an
+	 * index on name, on the theory that pg_tablespace will usually have just
+	 * a few entries and so an indexed lookup is a waste of effort.
+	 */
+	rel = heap_open(AccessMethodRelationId, AccessShareLock);
+
+	ScanKeyInit(&entry[0],
+				Anum_pg_am_amname,
+				BTEqualStrategyNumber, F_NAMEEQ,
+				CStringGetDatum(tableamname));
+	scandesc = table_beginscan_catalog(rel, 1, entry);
+	tuple = heap_scan_getnext(scandesc, ForwardScanDirection);
+
+	/* We assume that there can be at most one matching tuple */
+	if (HeapTupleIsValid(tuple) &&
+			((Form_pg_am) GETSTRUCT(tuple))->amtype == AMTYPE_TABLE)
+		result = HeapTupleGetOid(tuple);
+	else
+		result = InvalidOid;
+
+	table_endscan(scandesc);
+	heap_close(rel, AccessShareLock);
+
+	if (!OidIsValid(result) && !missing_ok)
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_OBJECT),
+				 errmsg("table access method \"%s\" does not exist",
+						 tableamname)));
+
+	return result;
+}
+
+/* check_hook: validate new default_table_access_method */
+bool
+check_default_table_access_method(char **newval, void **extra, GucSource source)
+{
+	/*
+	 * If we aren't inside a transaction, we cannot do database access so
+	 * cannot verify the name.  Must accept the value on faith.
+	 */
+	if (IsTransactionState())
+	{
+		if (**newval != '\0' &&
+			!OidIsValid(get_table_am_oid(*newval, true)))
+		{
+			/*
+			 * When source == PGC_S_TEST, don't throw a hard error for a
+			 * nonexistent table access method, only a NOTICE.
+			 * See comments in guc.h.
+			 */
+			if (source == PGC_S_TEST)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_UNDEFINED_OBJECT),
+						 errmsg("Table access method \"%s\" does not exist",
+								*newval)));
+			}
+			else
+			{
+				GUC_check_errdetail("Table access method \"%s\" does not exist.",
+									*newval);
+				return false;
+			}
+		}
+	}
+
+	return true;
+}
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 3b996c8088..94b135a48b 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -3336,8 +3336,7 @@ static struct config_string ConfigureNamesString[] =
 		},
 		&default_table_access_method,
 		DEFAULT_TABLE_ACCESS_METHOD,
-		/* PBORKED: a check hook would be good */
-		NULL, NULL, NULL
+		check_default_table_access_method, NULL, NULL
 	},
 
 	{
diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h
index d0a5f59aa9..691f687ade 100644
--- a/src/include/access/tableam.h
+++ b/src/include/access/tableam.h
@@ -23,6 +23,7 @@
 #include "nodes/execnodes.h"
 #include "nodes/nodes.h"
 #include "fmgr.h"
+#include "utils/guc.h"
 #include "utils/rel.h"
 #include "utils/snapmgr.h"
 #include "utils/snapshot.h"
@@ -714,4 +715,7 @@ extern const TableAmRoutine * GetTableAmRoutine(Oid amhandler);
 extern const TableAmRoutine * GetTableAmRoutineByAmId(Oid amoid);
 extern const TableAmRoutine * GetHeapamTableAmRoutine(void);
 
+extern bool check_default_table_access_method(char **newval, void **extra,
+									GucSource source);
+
 #endif		/* TABLEAM_H */
-- 
2.18.0.windows.1

