aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/gist/gistvalidate.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/gist/gistvalidate.c')
-rw-r--r--src/backend/access/gist/gistvalidate.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/src/backend/access/gist/gistvalidate.c b/src/backend/access/gist/gistvalidate.c
new file mode 100644
index 00000000000..86b5aeaec5c
--- /dev/null
+++ b/src/backend/access/gist/gistvalidate.c
@@ -0,0 +1,133 @@
+/*-------------------------------------------------------------------------
+ *
+ * gistvalidate.c
+ * Opclass validator for GiST.
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ * src/backend/access/gist/gistvalidate.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/gist_private.h"
+#include "access/htup_details.h"
+#include "catalog/pg_amop.h"
+#include "catalog/pg_amproc.h"
+#include "catalog/pg_opclass.h"
+#include "utils/catcache.h"
+#include "utils/syscache.h"
+
+
+/*
+ * Validator for a GiST opclass.
+ */
+bool
+gistvalidate(Oid opclassoid)
+{
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid;
+ Oid opcintype;
+ int numclassops;
+ int32 classfuncbits;
+ CatCList *proclist,
+ *oprlist;
+ int i;
+
+ /* Fetch opclass information */
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+
+ opfamilyoid = classform->opcfamily;
+ opcintype = classform->opcintype;
+
+ ReleaseSysCache(classtup);
+
+ /* Fetch all operators and support functions of the opfamily */
+ oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
+ proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
+
+ /* We'll track the ops and functions belonging to the named opclass */
+ numclassops = 0;
+ classfuncbits = 0;
+
+ /* Check support functions */
+ for (i = 0; i < proclist->n_members; i++)
+ {
+ HeapTuple proctup = &proclist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ /* Check that only allowed procedure numbers exist */
+ if (procform->amprocnum < 1 ||
+ procform->amprocnum > GISTNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("gist opfamily %u contains invalid support number %d for procedure %u",
+ opfamilyoid,
+ procform->amprocnum, procform->amproc)));
+
+ /* Remember functions that are specifically for the named opclass */
+ if (procform->amproclefttype == opcintype &&
+ procform->amprocrighttype == opcintype)
+ classfuncbits |= (1 << procform->amprocnum);
+ }
+
+ /* Check operators */
+ for (i = 0; i < oprlist->n_members; i++)
+ {
+ HeapTuple oprtup = &oprlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+
+ /* TODO: Check that only allowed strategy numbers exist */
+ if (oprform->amopstrategy < 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("gist opfamily %u contains invalid strategy number %d for operator %u",
+ opfamilyoid,
+ oprform->amopstrategy, oprform->amopopr)));
+
+ /* GiST supports ORDER BY operators, but must have distance proc */
+ if (oprform->amoppurpose != AMOP_SEARCH &&
+ oprform->amoplefttype == opcintype &&
+ oprform->amoprighttype == opcintype &&
+ (classfuncbits & (1 << GIST_DISTANCE_PROC)) == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("gist opfamily %u contains unsupported ORDER BY specification for operator %u",
+ opfamilyoid, oprform->amopopr)));
+
+ /* Count operators that are specifically for the named opclass */
+ /* XXX we consider only lefttype here */
+ if (oprform->amoplefttype == opcintype)
+ numclassops++;
+ }
+
+ /* Check that the named opclass is complete */
+ if (numclassops == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("gist opclass %u is missing operator(s)",
+ opclassoid)));
+ for (i = 1; i <= GISTNProcs; i++)
+ {
+ if ((classfuncbits & (1 << i)) != 0)
+ continue; /* got it */
+ if (i == GIST_DISTANCE_PROC || i == GIST_FETCH_PROC)
+ continue; /* optional methods */
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("gist opclass %u is missing required support function %d",
+ opclassoid, i)));
+ }
+
+ ReleaseCatCacheList(proclist);
+ ReleaseCatCacheList(oprlist);
+
+ return true;
+}