summaryrefslogtreecommitdiffstats
path: root/src/backend/access/index/amapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/index/amapi.c')
-rw-r--r--src/backend/access/index/amapi.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/src/backend/access/index/amapi.c b/src/backend/access/index/amapi.c
new file mode 100644
index 0000000..4e3d7b0
--- /dev/null
+++ b/src/backend/access/index/amapi.c
@@ -0,0 +1,143 @@
+/*-------------------------------------------------------------------------
+ *
+ * amapi.c
+ * Support routines for API for Postgres index access methods.
+ *
+ * Copyright (c) 2015-2020, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/access/index/amapi.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/amapi.h"
+#include "access/htup_details.h"
+#include "catalog/pg_am.h"
+#include "catalog/pg_opclass.h"
+#include "utils/builtins.h"
+#include "utils/syscache.h"
+
+
+/*
+ * GetIndexAmRoutine - call the specified access method handler routine to get
+ * its IndexAmRoutine struct, which will be palloc'd in the caller's context.
+ *
+ * Note that if the amhandler function is built-in, this will not involve
+ * any catalog access. It's therefore safe to use this while bootstrapping
+ * indexes for the system catalogs. relcache.c relies on that.
+ */
+IndexAmRoutine *
+GetIndexAmRoutine(Oid amhandler)
+{
+ Datum datum;
+ IndexAmRoutine *routine;
+
+ datum = OidFunctionCall0(amhandler);
+ routine = (IndexAmRoutine *) DatumGetPointer(datum);
+
+ if (routine == NULL || !IsA(routine, IndexAmRoutine))
+ elog(ERROR, "index access method handler function %u did not return an IndexAmRoutine struct",
+ amhandler);
+
+ return routine;
+}
+
+/*
+ * GetIndexAmRoutineByAmId - look up the handler of the index access method
+ * with the given OID, and get its IndexAmRoutine struct.
+ *
+ * If the given OID isn't a valid index access method, returns NULL if
+ * noerror is true, else throws error.
+ */
+IndexAmRoutine *
+GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
+{
+ HeapTuple tuple;
+ Form_pg_am amform;
+ regproc amhandler;
+
+ /* Get handler function OID for the access method */
+ tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
+ if (!HeapTupleIsValid(tuple))
+ {
+ if (noerror)
+ return NULL;
+ elog(ERROR, "cache lookup failed for access method %u",
+ amoid);
+ }
+ amform = (Form_pg_am) GETSTRUCT(tuple);
+
+ /* Check if it's an index access method as opposed to some other AM */
+ if (amform->amtype != AMTYPE_INDEX)
+ {
+ if (noerror)
+ {
+ ReleaseSysCache(tuple);
+ return NULL;
+ }
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("access method \"%s\" is not of type %s",
+ NameStr(amform->amname), "INDEX")));
+ }
+
+ amhandler = amform->amhandler;
+
+ /* Complain if handler OID is invalid */
+ if (!RegProcedureIsValid(amhandler))
+ {
+ if (noerror)
+ {
+ ReleaseSysCache(tuple);
+ return NULL;
+ }
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("index 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 GetIndexAmRoutine(amhandler);
+}
+
+
+/*
+ * Ask appropriate access method to validate the specified opclass.
+ */
+Datum
+amvalidate(PG_FUNCTION_ARGS)
+{
+ Oid opclassoid = PG_GETARG_OID(0);
+ bool result;
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid amoid;
+ IndexAmRoutine *amroutine;
+
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+
+ amoid = classform->opcmethod;
+
+ ReleaseSysCache(classtup);
+
+ amroutine = GetIndexAmRoutineByAmId(amoid, false);
+
+ if (amroutine->amvalidate == NULL)
+ elog(ERROR, "function amvalidate is not defined for index access method %u",
+ amoid);
+
+ result = amroutine->amvalidate(opclassoid);
+
+ pfree(amroutine);
+
+ PG_RETURN_BOOL(result);
+}