diff options
Diffstat (limited to 'src/backend/access')
-rw-r--r-- | src/backend/access/brin/brin.c | 1 | ||||
-rw-r--r-- | src/backend/access/gin/ginutil.c | 1 | ||||
-rw-r--r-- | src/backend/access/gist/gist.c | 1 | ||||
-rw-r--r-- | src/backend/access/gist/gistutil.c | 100 | ||||
-rw-r--r-- | src/backend/access/hash/hash.c | 1 | ||||
-rw-r--r-- | src/backend/access/index/amapi.c | 27 | ||||
-rw-r--r-- | src/backend/access/nbtree/nbtree.c | 1 | ||||
-rw-r--r-- | src/backend/access/nbtree/nbtutils.c | 26 | ||||
-rw-r--r-- | src/backend/access/spgist/spgutils.c | 1 |
9 files changed, 156 insertions, 3 deletions
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 89bad0521b6..b194d33cc5c 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -102,6 +102,7 @@ brinhandler(PG_FUNCTION_ARGS) amroutine->amcanreturn = NULL; amroutine->amcostestimate = brincostestimate; amroutine->amoptions = brinoptions; + amroutine->amproperty = NULL; amroutine->amvalidate = brinvalidate; amroutine->ambeginscan = brinbeginscan; amroutine->amrescan = brinrescan; diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c index a2450f4687e..d9146488c44 100644 --- a/src/backend/access/gin/ginutil.c +++ b/src/backend/access/gin/ginutil.c @@ -57,6 +57,7 @@ ginhandler(PG_FUNCTION_ARGS) amroutine->amcanreturn = NULL; amroutine->amcostestimate = gincostestimate; amroutine->amoptions = ginoptions; + amroutine->amproperty = NULL; amroutine->amvalidate = ginvalidate; amroutine->ambeginscan = ginbeginscan; amroutine->amrescan = ginrescan; diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index e8034b9cd6d..9a417ca2f42 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -79,6 +79,7 @@ gisthandler(PG_FUNCTION_ARGS) amroutine->amcanreturn = gistcanreturn; amroutine->amcostestimate = gistcostestimate; amroutine->amoptions = gistoptions; + amroutine->amproperty = gistproperty; amroutine->amvalidate = gistvalidate; amroutine->ambeginscan = gistbeginscan; amroutine->amrescan = gistrescan; 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 <math.h> #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" /* @@ -837,6 +840,103 @@ gistoptions(Datum reloptions, bool validate) } /* + * 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 * sequence of LSNs for that purpose. diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c index 30c82e191c6..07496f81562 100644 --- a/src/backend/access/hash/hash.c +++ b/src/backend/access/hash/hash.c @@ -75,6 +75,7 @@ hashhandler(PG_FUNCTION_ARGS) amroutine->amcanreturn = NULL; amroutine->amcostestimate = hashcostestimate; amroutine->amoptions = hashoptions; + amroutine->amproperty = NULL; amroutine->amvalidate = hashvalidate; amroutine->ambeginscan = hashbeginscan; amroutine->amrescan = hashrescan; diff --git a/src/backend/access/index/amapi.c b/src/backend/access/index/amapi.c index d347ebcba45..28f6cde8967 100644 --- a/src/backend/access/index/amapi.c +++ b/src/backend/access/index/amapi.c @@ -47,9 +47,12 @@ GetIndexAmRoutine(Oid amhandler) /* * 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) +GetIndexAmRoutineByAmId(Oid amoid, bool noerror) { HeapTuple tuple; Form_pg_am amform; @@ -58,25 +61,43 @@ GetIndexAmRoutineByAmId(Oid amoid) /* 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 index access method */ + /* 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); @@ -107,7 +128,7 @@ amvalidate(PG_FUNCTION_ARGS) ReleaseSysCache(classtup); - amroutine = GetIndexAmRoutineByAmId(amoid); + amroutine = GetIndexAmRoutineByAmId(amoid, false); if (amroutine->amvalidate == NULL) elog(ERROR, "function amvalidate is not defined for index access method %u", diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 1f479735c20..4668c5ee59f 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -108,6 +108,7 @@ bthandler(PG_FUNCTION_ARGS) amroutine->amcanreturn = btcanreturn; amroutine->amcostestimate = btcostestimate; amroutine->amoptions = btoptions; + amroutine->amproperty = btproperty; amroutine->amvalidate = btvalidate; amroutine->ambeginscan = btbeginscan; amroutine->amrescan = btrescan; diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index 83c553ca279..5d335c7f97c 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -2041,3 +2041,29 @@ btoptions(Datum reloptions, bool validate) { return default_reloptions(reloptions, validate, RELOPT_KIND_BTREE); } + +/* + * btproperty() -- Check boolean properties of indexes. + * + * This is optional, but handling AMPROP_RETURNABLE here saves opening the rel + * to call btcanreturn. + */ +bool +btproperty(Oid index_oid, int attno, + IndexAMProperty prop, const char *propname, + bool *res, bool *isnull) +{ + switch (prop) + { + case AMPROP_RETURNABLE: + /* answer only for columns, not AM or whole index */ + if (attno == 0) + return false; + /* otherwise, btree can always return data */ + *res = true; + return true; + + default: + return false; /* punt to generic code */ + } +} diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c index bc679bf75a0..d570ae5992a 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -58,6 +58,7 @@ spghandler(PG_FUNCTION_ARGS) amroutine->amcanreturn = spgcanreturn; amroutine->amcostestimate = spgcostestimate; amroutine->amoptions = spgoptions; + amroutine->amproperty = NULL; amroutine->amvalidate = spgvalidate; amroutine->ambeginscan = spgbeginscan; amroutine->amrescan = spgrescan; |