diff options
Diffstat (limited to 'src/backend/access/gist/gistvalidate.c')
-rw-r--r-- | src/backend/access/gist/gistvalidate.c | 133 |
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; +} |