mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +03:00
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 commit65c5fcd35
). 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 commit473b93287
. Andrew Gierth, with kibitzing by me and others Discussion: <87mvl5on7n.fsf@news-spur.riddles.org.uk>
This commit is contained in:
@ -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;
|
||||
|
@ -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"
|
||||
|
||||
|
||||
/*
|
||||
@ -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
|
||||
|
Reference in New Issue
Block a user