diff options
Diffstat (limited to 'src/backend/access/gist')
-rw-r--r-- | src/backend/access/gist/Makefile | 2 | ||||
-rw-r--r-- | src/backend/access/gist/gist.c | 76 | ||||
-rw-r--r-- | src/backend/access/gist/gistbuild.c | 9 | ||||
-rw-r--r-- | src/backend/access/gist/gistget.c | 35 | ||||
-rw-r--r-- | src/backend/access/gist/gistscan.c | 41 | ||||
-rw-r--r-- | src/backend/access/gist/gistutil.c | 11 | ||||
-rw-r--r-- | src/backend/access/gist/gistvacuum.c | 21 | ||||
-rw-r--r-- | src/backend/access/gist/gistvalidate.c | 133 |
8 files changed, 225 insertions, 103 deletions
diff --git a/src/backend/access/gist/Makefile b/src/backend/access/gist/Makefile index cc9468ffb19..21875bf7aee 100644 --- a/src/backend/access/gist/Makefile +++ b/src/backend/access/gist/Makefile @@ -13,6 +13,6 @@ top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global OBJS = gist.o gistutil.o gistxlog.o gistvacuum.o gistget.o gistscan.o \ - gistproc.o gistsplit.o gistbuild.o gistbuildbuffers.o + gistproc.o gistsplit.o gistbuild.o gistbuildbuffers.o gistvalidate.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index 834d9d33358..996363c2ded 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -14,17 +14,15 @@ */ #include "postgres.h" -#include "access/genam.h" #include "access/gist_private.h" -#include "access/xloginsert.h" -#include "catalog/index.h" +#include "access/gistscan.h" #include "catalog/pg_collation.h" #include "miscadmin.h" -#include "storage/bufmgr.h" -#include "storage/indexfsm.h" +#include "utils/index_selfuncs.h" #include "utils/memutils.h" #include "utils/rel.h" + /* non-export function prototypes */ static void gistfixsplit(GISTInsertState *state, GISTSTATE *giststate); static bool gistinserttuple(GISTInsertState *state, GISTInsertStack *stack, @@ -50,6 +48,50 @@ static void gistvacuumpage(Relation rel, Page page, Buffer buffer); /* + * GiST handler function: return IndexAmRoutine with access method parameters + * and callbacks. + */ +Datum +gisthandler(PG_FUNCTION_ARGS) +{ + IndexAmRoutine *amroutine = makeNode(IndexAmRoutine); + + amroutine->amstrategies = 0; + amroutine->amsupport = 9; + amroutine->amcanorder = false; + amroutine->amcanorderbyop = true; + amroutine->amcanbackward = false; + amroutine->amcanunique = false; + amroutine->amcanmulticol = true; + amroutine->amoptionalkey = true; + amroutine->amsearcharray = false; + amroutine->amsearchnulls = true; + amroutine->amstorage = true; + amroutine->amclusterable = true; + amroutine->ampredlocks = false; + amroutine->amkeytype = InvalidOid; + + amroutine->ambuild = gistbuild; + amroutine->ambuildempty = gistbuildempty; + amroutine->aminsert = gistinsert; + amroutine->ambulkdelete = gistbulkdelete; + amroutine->amvacuumcleanup = gistvacuumcleanup; + amroutine->amcanreturn = gistcanreturn; + amroutine->amcostestimate = gistcostestimate; + amroutine->amoptions = gistoptions; + amroutine->amvalidate = gistvalidate; + amroutine->ambeginscan = gistbeginscan; + amroutine->amrescan = gistrescan; + amroutine->amgettuple = gistgettuple; + amroutine->amgetbitmap = gistgetbitmap; + amroutine->amendscan = gistendscan; + amroutine->ammarkpos = NULL; + amroutine->amrestrpos = NULL; + + PG_RETURN_POINTER(amroutine); +} + +/* * Create and return a temporary memory context for use by GiST. We * _always_ invoke user-provided methods in a temporary memory * context, so that memory leaks in those functions cannot cause @@ -70,10 +112,9 @@ createTempGistContext(void) /* * gistbuildempty() -- build an empty gist index in the initialization fork */ -Datum -gistbuildempty(PG_FUNCTION_ARGS) +void +gistbuildempty(Relation index) { - Relation index = (Relation) PG_GETARG_POINTER(0); Buffer buffer; /* Initialize the root page */ @@ -89,8 +130,6 @@ gistbuildempty(PG_FUNCTION_ARGS) /* Unlock and release the buffer */ UnlockReleaseBuffer(buffer); - - PG_RETURN_VOID(); } /* @@ -99,18 +138,11 @@ gistbuildempty(PG_FUNCTION_ARGS) * This is the public interface routine for tuple insertion in GiSTs. * It doesn't do any work; just locks the relation and passes the buck. */ -Datum -gistinsert(PG_FUNCTION_ARGS) +bool +gistinsert(Relation r, Datum *values, bool *isnull, + ItemPointer ht_ctid, Relation heapRel, + IndexUniqueCheck checkUnique) { - Relation r = (Relation) PG_GETARG_POINTER(0); - Datum *values = (Datum *) PG_GETARG_POINTER(1); - bool *isnull = (bool *) PG_GETARG_POINTER(2); - ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3); - -#ifdef NOT_USED - Relation heapRel = (Relation) PG_GETARG_POINTER(4); - IndexUniqueCheck checkUnique = (IndexUniqueCheck) PG_GETARG_INT32(5); -#endif IndexTuple itup; GISTSTATE *giststate; MemoryContext oldCxt; @@ -136,7 +168,7 @@ gistinsert(PG_FUNCTION_ARGS) MemoryContextSwitchTo(oldCxt); freeGISTstate(giststate); - PG_RETURN_BOOL(false); + return false; } diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 98ea0cb2d14..4e43a6932a4 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -109,12 +109,9 @@ static BlockNumber gistGetParent(GISTBuildState *buildstate, BlockNumber child); * but switches to more efficient buffering build algorithm after a certain * number of tuples (unless buffering mode is disabled). */ -Datum -gistbuild(PG_FUNCTION_ARGS) +IndexBuildResult * +gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) { - Relation heap = (Relation) PG_GETARG_POINTER(0); - Relation index = (Relation) PG_GETARG_POINTER(1); - IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2); IndexBuildResult *result; double reltuples; GISTBuildState buildstate; @@ -232,7 +229,7 @@ gistbuild(PG_FUNCTION_ARGS) result->heap_tuples = reltuples; result->index_tuples = (double) buildstate.indtuples; - PG_RETURN_POINTER(result); + return result; } /* diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c index 21f9de511ff..41b83431b61 100644 --- a/src/backend/access/gist/gistget.c +++ b/src/backend/access/gist/gistget.c @@ -618,18 +618,16 @@ getNextNearest(IndexScanDesc scan) /* * gistgettuple() -- Get the next tuple in the scan */ -Datum -gistgettuple(PG_FUNCTION_ARGS) +bool +gistgettuple(IndexScanDesc scan, ScanDirection dir) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1); GISTScanOpaque so = (GISTScanOpaque) scan->opaque; if (dir != ForwardScanDirection) elog(ERROR, "GiST only supports forward scan direction"); if (!so->qual_ok) - PG_RETURN_BOOL(false); + return false; if (so->firstCall) { @@ -651,7 +649,7 @@ gistgettuple(PG_FUNCTION_ARGS) if (scan->numberOfOrderBys > 0) { /* Must fetch tuples in strict distance order */ - PG_RETURN_BOOL(getNextNearest(scan)); + return getNextNearest(scan); } else { @@ -688,7 +686,7 @@ gistgettuple(PG_FUNCTION_ARGS) so->curPageData++; - PG_RETURN_BOOL(true); + return true; } /* @@ -726,7 +724,7 @@ gistgettuple(PG_FUNCTION_ARGS) item = getNextGISTSearchItem(so); if (!item) - PG_RETURN_BOOL(false); + return false; CHECK_FOR_INTERRUPTS(); @@ -750,17 +748,15 @@ gistgettuple(PG_FUNCTION_ARGS) /* * gistgetbitmap() -- Get a bitmap of all heap tuple locations */ -Datum -gistgetbitmap(PG_FUNCTION_ARGS) +int64 +gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1); GISTScanOpaque so = (GISTScanOpaque) scan->opaque; int64 ntids = 0; GISTSearchItem fakeItem; if (!so->qual_ok) - PG_RETURN_INT64(0); + return 0; pgstat_count_index_scan(scan->indexRelation); @@ -791,7 +787,7 @@ gistgetbitmap(PG_FUNCTION_ARGS) pfree(item); } - PG_RETURN_INT64(ntids); + return ntids; } /* @@ -799,14 +795,11 @@ gistgetbitmap(PG_FUNCTION_ARGS) * * Opclasses that implement a fetch function support index-only scans. */ -Datum -gistcanreturn(PG_FUNCTION_ARGS) +bool +gistcanreturn(Relation index, int attno) { - Relation index = (Relation) PG_GETARG_POINTER(0); - int attno = PG_GETARG_INT32(1); - if (OidIsValid(index_getprocid(index, attno, GIST_FETCH_PROC))) - PG_RETURN_BOOL(true); + return true; else - PG_RETURN_BOOL(false); + return false; } diff --git a/src/backend/access/gist/gistscan.c b/src/backend/access/gist/gistscan.c index 8ab41838361..31758a1c8fe 100644 --- a/src/backend/access/gist/gistscan.c +++ b/src/backend/access/gist/gistscan.c @@ -54,12 +54,9 @@ pairingheap_GISTSearchItem_cmp(const pairingheap_node *a, const pairingheap_node * Index AM API functions for scanning GiST indexes */ -Datum -gistbeginscan(PG_FUNCTION_ARGS) +IndexScanDesc +gistbeginscan(Relation r, int nkeys, int norderbys) { - Relation r = (Relation) PG_GETARG_POINTER(0); - int nkeys = PG_GETARG_INT32(1); - int norderbys = PG_GETARG_INT32(2); IndexScanDesc scan; GISTSTATE *giststate; GISTScanOpaque so; @@ -107,16 +104,13 @@ gistbeginscan(PG_FUNCTION_ARGS) MemoryContextSwitchTo(oldCxt); - PG_RETURN_POINTER(scan); + return scan; } -Datum -gistrescan(PG_FUNCTION_ARGS) +void +gistrescan(IndexScanDesc scan, ScanKey key, int nkeys, + ScanKey orderbys, int norderbys) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - ScanKey key = (ScanKey) PG_GETARG_POINTER(1); - ScanKey orderbys = (ScanKey) PG_GETARG_POINTER(3); - /* nkeys and norderbys arguments are ignored */ GISTScanOpaque so = (GISTScanOpaque) scan->opaque; bool first_time; @@ -314,28 +308,11 @@ gistrescan(PG_FUNCTION_ARGS) if (!first_time) pfree(fn_extras); } - - PG_RETURN_VOID(); -} - -Datum -gistmarkpos(PG_FUNCTION_ARGS) -{ - elog(ERROR, "GiST does not support mark/restore"); - PG_RETURN_VOID(); } -Datum -gistrestrpos(PG_FUNCTION_ARGS) +void +gistendscan(IndexScanDesc scan) { - elog(ERROR, "GiST does not support mark/restore"); - PG_RETURN_VOID(); -} - -Datum -gistendscan(PG_FUNCTION_ARGS) -{ - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); GISTScanOpaque so = (GISTScanOpaque) scan->opaque; /* @@ -343,6 +320,4 @@ gistendscan(PG_FUNCTION_ARGS) * as well as the queueCxt if there is a separate context for it. */ freeGISTstate(so->giststate); - - PG_RETURN_VOID(); } diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index 0995e0355cf..fac166d4c29 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -808,11 +808,9 @@ gistNewBuffer(Relation r) return buffer; } -Datum -gistoptions(PG_FUNCTION_ARGS) +bytea * +gistoptions(Datum reloptions, bool validate) { - Datum reloptions = PG_GETARG_DATUM(0); - bool validate = PG_GETARG_BOOL(1); relopt_value *options; GiSTOptions *rdopts; int numoptions; @@ -826,7 +824,7 @@ gistoptions(PG_FUNCTION_ARGS) /* if none set, we're done */ if (numoptions == 0) - PG_RETURN_NULL(); + return NULL; rdopts = allocateReloptStruct(sizeof(GiSTOptions), options, numoptions); @@ -835,8 +833,7 @@ gistoptions(PG_FUNCTION_ARGS) pfree(options); - PG_RETURN_BYTEA_P(rdopts); - + return (bytea *) rdopts; } /* diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c index 346f6d96f4d..7947ff9dbe6 100644 --- a/src/backend/access/gist/gistvacuum.c +++ b/src/backend/access/gist/gistvacuum.c @@ -25,11 +25,9 @@ /* * VACUUM cleanup: update FSM */ -Datum -gistvacuumcleanup(PG_FUNCTION_ARGS) +IndexBulkDeleteResult * +gistvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) { - IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0); - IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1); Relation rel = info->index; BlockNumber npages, blkno; @@ -38,7 +36,7 @@ gistvacuumcleanup(PG_FUNCTION_ARGS) /* No-op in ANALYZE ONLY mode */ if (info->analyze_only) - PG_RETURN_POINTER(stats); + return stats; /* Set up all-zero stats if gistbulkdelete wasn't called */ if (stats == NULL) @@ -98,7 +96,7 @@ gistvacuumcleanup(PG_FUNCTION_ARGS) if (needLock) UnlockRelationForExtension(rel, ExclusiveLock); - PG_RETURN_POINTER(stats); + return stats; } typedef struct GistBDItem @@ -137,13 +135,10 @@ pushStackIfSplited(Page page, GistBDItem *stack) * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ -Datum -gistbulkdelete(PG_FUNCTION_ARGS) +IndexBulkDeleteResult * +gistbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, void *callback_state) { - IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0); - IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1); - IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2); - void *callback_state = (void *) PG_GETARG_POINTER(3); Relation rel = info->index; GistBDItem *stack, *ptr; @@ -276,5 +271,5 @@ gistbulkdelete(PG_FUNCTION_ARGS) vacuum_delay_point(); } - PG_RETURN_POINTER(stats); + return stats; } 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; +} |