From ed0097e4f9e6b1227935e01fa67f12a238b66064 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 13 Aug 2016 18:31:14 -0400 Subject: Add SQL-accessible functions for inspecting index AM properties. Per discussion, we should provide such functions to replace the lost ability to discover AM properties by inspecting pg_am (cf commit 65c5fcd35). The added functionality is also meant to displace any code that was looking directly at pg_index.indoption, since we'd rather not believe that the bit meanings in that field are part of any client API contract. As future-proofing, define the SQL API to not assume that properties that are currently AM-wide or index-wide will remain so unless they logically must be; instead, expose them only when inquiring about a specific index or even specific index column. Also provide the ability for an index AM to override the behavior. In passing, document pg_am.amtype, overlooked in commit 473b93287. Andrew Gierth, with kibitzing by me and others Discussion: <87mvl5on7n.fsf@news-spur.riddles.org.uk> --- src/backend/access/gist/gistutil.c | 100 +++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) (limited to 'src/backend/access/gist/gistutil.c') diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index fac166d4c29..26d4a646947 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -16,10 +16,13 @@ #include #include "access/gist_private.h" +#include "access/htup_details.h" #include "access/reloptions.h" +#include "catalog/pg_opclass.h" #include "storage/indexfsm.h" #include "storage/lmgr.h" #include "utils/builtins.h" +#include "utils/syscache.h" /* @@ -836,6 +839,103 @@ gistoptions(Datum reloptions, bool validate) return (bytea *) rdopts; } +/* + * gistproperty() -- Check boolean properties of indexes. + * + * This is optional for most AMs, but is required for GiST because the core + * property code doesn't support AMPROP_DISTANCE_ORDERABLE. We also handle + * AMPROP_RETURNABLE here to save opening the rel to call gistcanreturn. + */ +bool +gistproperty(Oid index_oid, int attno, + IndexAMProperty prop, const char *propname, + bool *res, bool *isnull) +{ + HeapTuple tuple; + Form_pg_index rd_index; + Form_pg_opclass rd_opclass; + Datum datum; + bool disnull; + oidvector *indclass; + Oid opclass, + opfamily, + opcintype; + int16 procno; + + /* Only answer column-level inquiries */ + if (attno == 0) + return false; + + /* + * Currently, GiST distance-ordered scans require that there be a distance + * function in the opclass with the default types (i.e. the one loaded + * into the relcache entry, see initGISTstate). So we assume that if such + * a function exists, then there's a reason for it (rather than grubbing + * through all the opfamily's operators to find an ordered one). + * + * Essentially the same code can test whether we support returning the + * column data, since that's true if the opclass provides a fetch proc. + */ + + switch (prop) + { + case AMPROP_DISTANCE_ORDERABLE: + procno = GIST_DISTANCE_PROC; + break; + case AMPROP_RETURNABLE: + procno = GIST_FETCH_PROC; + break; + default: + return false; + } + + /* First we need to know the column's opclass. */ + + tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid)); + if (!HeapTupleIsValid(tuple)) + { + *isnull = true; + return true; + } + rd_index = (Form_pg_index) GETSTRUCT(tuple); + + /* caller is supposed to guarantee this */ + Assert(attno > 0 && attno <= rd_index->indnatts); + + datum = SysCacheGetAttr(INDEXRELID, tuple, + Anum_pg_index_indclass, &disnull); + Assert(!disnull); + + indclass = ((oidvector *) DatumGetPointer(datum)); + opclass = indclass->values[attno - 1]; + + ReleaseSysCache(tuple); + + /* Now look up the opclass family and input datatype. */ + + tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass)); + if (!HeapTupleIsValid(tuple)) + { + *isnull = true; + return true; + } + rd_opclass = (Form_pg_opclass) GETSTRUCT(tuple); + + opfamily = rd_opclass->opcfamily; + opcintype = rd_opclass->opcintype; + + ReleaseSysCache(tuple); + + /* And now we can check whether the function is provided. */ + + *res = SearchSysCacheExists4(AMPROCNUM, + ObjectIdGetDatum(opfamily), + ObjectIdGetDatum(opcintype), + ObjectIdGetDatum(opcintype), + Int16GetDatum(procno)); + return true; +} + /* * Temporary and unlogged GiST indexes are not WAL-logged, but we need LSNs * to detect concurrent page splits anyway. This function provides a fake -- cgit v1.2.3