diff options
Diffstat (limited to 'src/backend/access/spgist')
-rw-r--r-- | src/backend/access/spgist/Makefile | 2 | ||||
-rw-r--r-- | src/backend/access/spgist/spginsert.c | 33 | ||||
-rw-r--r-- | src/backend/access/spgist/spgscan.c | 67 | ||||
-rw-r--r-- | src/backend/access/spgist/spgutils.c | 60 | ||||
-rw-r--r-- | src/backend/access/spgist/spgvacuum.c | 21 | ||||
-rw-r--r-- | src/backend/access/spgist/spgvalidate.c | 129 |
6 files changed, 214 insertions, 98 deletions
diff --git a/src/backend/access/spgist/Makefile b/src/backend/access/spgist/Makefile index 918da1fccaf..14948a531ee 100644 --- a/src/backend/access/spgist/Makefile +++ b/src/backend/access/spgist/Makefile @@ -12,7 +12,7 @@ subdir = src/backend/access/spgist top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global -OBJS = spgutils.o spginsert.o spgscan.o spgvacuum.o \ +OBJS = spgutils.o spginsert.o spgscan.o spgvacuum.o spgvalidate.o \ spgdoinsert.o spgxlog.o \ spgtextproc.o spgquadtreeproc.o spgkdtreeproc.o diff --git a/src/backend/access/spgist/spginsert.c b/src/backend/access/spgist/spginsert.c index 0e6a180cc9e..44fd644e421 100644 --- a/src/backend/access/spgist/spginsert.c +++ b/src/backend/access/spgist/spginsert.c @@ -65,12 +65,9 @@ spgistBuildCallback(Relation index, HeapTuple htup, Datum *values, /* * Build an SP-GiST index. */ -Datum -spgbuild(PG_FUNCTION_ARGS) +IndexBuildResult * +spgbuild(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; SpGistBuildState buildstate; @@ -151,16 +148,15 @@ spgbuild(PG_FUNCTION_ARGS) result = (IndexBuildResult *) palloc0(sizeof(IndexBuildResult)); result->heap_tuples = result->index_tuples = reltuples; - PG_RETURN_POINTER(result); + return result; } /* * Build an empty SPGiST index in the initialization fork */ -Datum -spgbuildempty(PG_FUNCTION_ARGS) +void +spgbuildempty(Relation index) { - Relation index = (Relation) PG_GETARG_POINTER(0); Page page; /* Construct metapage. */ @@ -201,25 +197,16 @@ spgbuildempty(PG_FUNCTION_ARGS) * checkpoint may have moved the redo pointer past our xlog record. */ smgrimmedsync(index->rd_smgr, INIT_FORKNUM); - - PG_RETURN_VOID(); } /* * Insert one new tuple into an SPGiST index. */ -Datum -spginsert(PG_FUNCTION_ARGS) +bool +spginsert(Relation index, Datum *values, bool *isnull, + ItemPointer ht_ctid, Relation heapRel, + IndexUniqueCheck checkUnique) { - Relation index = (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 SpGistState spgstate; MemoryContext oldCtx; MemoryContext insertCtx; @@ -251,5 +238,5 @@ spginsert(PG_FUNCTION_ARGS) MemoryContextDelete(insertCtx); /* return false since we've not done any unique check */ - PG_RETURN_BOOL(false); + return false; } diff --git a/src/backend/access/spgist/spgscan.c b/src/backend/access/spgist/spgscan.c index 48e678c970e..620e7461998 100644 --- a/src/backend/access/spgist/spgscan.c +++ b/src/backend/access/spgist/spgscan.c @@ -173,13 +173,9 @@ spgPrepareScanKeys(IndexScanDesc scan) } } -Datum -spgbeginscan(PG_FUNCTION_ARGS) +IndexScanDesc +spgbeginscan(Relation rel, int keysz, int orderbysz) { - Relation rel = (Relation) PG_GETARG_POINTER(0); - int keysz = PG_GETARG_INT32(1); - - /* ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2); */ IndexScanDesc scan; SpGistScanOpaque so; @@ -202,15 +198,14 @@ spgbeginscan(PG_FUNCTION_ARGS) scan->opaque = so; - PG_RETURN_POINTER(scan); + return scan; } -Datum -spgrescan(PG_FUNCTION_ARGS) +void +spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, + ScanKey orderbys, int norderbys) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque; - ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1); /* copy scankeys into local storage */ if (scankey && scan->numberOfKeys > 0) @@ -224,33 +219,14 @@ spgrescan(PG_FUNCTION_ARGS) /* set up starting stack entries */ resetSpGistScanOpaque(so); - - PG_RETURN_VOID(); } -Datum -spgendscan(PG_FUNCTION_ARGS) +void +spgendscan(IndexScanDesc scan) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque; MemoryContextDelete(so->tempCxt); - - PG_RETURN_VOID(); -} - -Datum -spgmarkpos(PG_FUNCTION_ARGS) -{ - elog(ERROR, "SPGiST does not support mark/restore"); - PG_RETURN_VOID(); -} - -Datum -spgrestrpos(PG_FUNCTION_ARGS) -{ - elog(ERROR, "SPGiST does not support mark/restore"); - PG_RETURN_VOID(); } /* @@ -571,11 +547,9 @@ storeBitmap(SpGistScanOpaque so, ItemPointer heapPtr, so->ntids++; } -Datum -spggetbitmap(PG_FUNCTION_ARGS) +int64 +spggetbitmap(IndexScanDesc scan, TIDBitmap *tbm) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1); SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque; /* Copy want_itup to *so so we don't need to pass it around separately */ @@ -586,7 +560,7 @@ spggetbitmap(PG_FUNCTION_ARGS) spgWalk(scan->indexRelation, so, true, storeBitmap); - PG_RETURN_INT64(so->ntids); + return so->ntids; } /* storeRes subroutine for gettuple case */ @@ -610,11 +584,9 @@ storeGettuple(SpGistScanOpaque so, ItemPointer heapPtr, so->nPtrs++; } -Datum -spggettuple(PG_FUNCTION_ARGS) +bool +spggettuple(IndexScanDesc scan, ScanDirection dir) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1); SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque; if (dir != ForwardScanDirection) @@ -632,7 +604,7 @@ spggettuple(PG_FUNCTION_ARGS) scan->xs_recheck = so->recheck[so->iPtr]; scan->xs_itup = so->indexTups[so->iPtr]; so->iPtr++; - PG_RETURN_BOOL(true); + return true; } if (so->want_itup) @@ -651,19 +623,16 @@ spggettuple(PG_FUNCTION_ARGS) break; /* must have completed scan */ } - PG_RETURN_BOOL(false); + return false; } -Datum -spgcanreturn(PG_FUNCTION_ARGS) +bool +spgcanreturn(Relation index, int attno) { - Relation index = (Relation) PG_GETARG_POINTER(0); - - /* int i = PG_GETARG_INT32(1); */ SpGistCache *cache; /* We can do it if the opclass config function says so */ cache = spgGetCache(index); - PG_RETURN_BOOL(cache->config.canReturnData); + return cache->config.canReturnData; } diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c index 9ba077686a9..201203f91a3 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -15,7 +15,6 @@ #include "postgres.h" -#include "access/genam.h" #include "access/reloptions.h" #include "access/spgist_private.h" #include "access/transam.h" @@ -23,9 +22,54 @@ #include "storage/bufmgr.h" #include "storage/indexfsm.h" #include "storage/lmgr.h" +#include "utils/index_selfuncs.h" #include "utils/lsyscache.h" +/* + * SP-GiST handler function: return IndexAmRoutine with access method parameters + * and callbacks. + */ +Datum +spghandler(PG_FUNCTION_ARGS) +{ + IndexAmRoutine *amroutine = makeNode(IndexAmRoutine); + + amroutine->amstrategies = 0; + amroutine->amsupport = 5; + amroutine->amcanorder = false; + amroutine->amcanorderbyop = false; + amroutine->amcanbackward = false; + amroutine->amcanunique = false; + amroutine->amcanmulticol = false; + amroutine->amoptionalkey = true; + amroutine->amsearcharray = false; + amroutine->amsearchnulls = true; + amroutine->amstorage = false; + amroutine->amclusterable = false; + amroutine->ampredlocks = false; + amroutine->amkeytype = InvalidOid; + + amroutine->ambuild = spgbuild; + amroutine->ambuildempty = spgbuildempty; + amroutine->aminsert = spginsert; + amroutine->ambulkdelete = spgbulkdelete; + amroutine->amvacuumcleanup = spgvacuumcleanup; + amroutine->amcanreturn = spgcanreturn; + amroutine->amcostestimate = spgcostestimate; + amroutine->amoptions = spgoptions; + amroutine->amvalidate = spgvalidate; + amroutine->ambeginscan = spgbeginscan; + amroutine->amrescan = spgrescan; + amroutine->amgettuple = spggettuple; + amroutine->amgetbitmap = spggetbitmap; + amroutine->amendscan = spgendscan; + amroutine->ammarkpos = NULL; + amroutine->amrestrpos = NULL; + + PG_RETURN_POINTER(amroutine); +} + /* Fill in a SpGistTypeDesc struct with info about the specified data type */ static void fillTypeDesc(SpGistTypeDesc *desc, Oid type) @@ -489,18 +533,10 @@ SpGistInitMetapage(Page page) /* * reloptions processing for SPGiST */ -Datum -spgoptions(PG_FUNCTION_ARGS) +bytea * +spgoptions(Datum reloptions, bool validate) { - Datum reloptions = PG_GETARG_DATUM(0); - bool validate = PG_GETARG_BOOL(1); - bytea *result; - - result = default_reloptions(reloptions, validate, RELOPT_KIND_SPGIST); - - if (result) - PG_RETURN_BYTEA_P(result); - PG_RETURN_NULL(); + return default_reloptions(reloptions, validate, RELOPT_KIND_SPGIST); } /* diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c index c2d4f0a68a6..15b867f24cb 100644 --- a/src/backend/access/spgist/spgvacuum.c +++ b/src/backend/access/spgist/spgvacuum.c @@ -881,13 +881,10 @@ spgvacuumscan(spgBulkDeleteState *bds) * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ -Datum -spgbulkdelete(PG_FUNCTION_ARGS) +IndexBulkDeleteResult * +spgbulkdelete(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); spgBulkDeleteState bds; /* allocate stats if first time through, else re-use existing struct */ @@ -900,7 +897,7 @@ spgbulkdelete(PG_FUNCTION_ARGS) spgvacuumscan(&bds); - PG_RETURN_POINTER(stats); + return stats; } /* Dummy callback to delete no tuples during spgvacuumcleanup */ @@ -915,17 +912,15 @@ dummy_callback(ItemPointer itemptr, void *state) * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ -Datum -spgvacuumcleanup(PG_FUNCTION_ARGS) +IndexBulkDeleteResult * +spgvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) { - IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0); - IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1); Relation index = info->index; spgBulkDeleteState bds; /* No-op in ANALYZE ONLY mode */ if (info->analyze_only) - PG_RETURN_POINTER(stats); + return stats; /* * We don't need to scan the index if there was a preceding bulkdelete @@ -959,5 +954,5 @@ spgvacuumcleanup(PG_FUNCTION_ARGS) stats->num_index_tuples = info->num_heap_tuples; } - PG_RETURN_POINTER(stats); + return stats; } diff --git a/src/backend/access/spgist/spgvalidate.c b/src/backend/access/spgist/spgvalidate.c new file mode 100644 index 00000000000..c2d2d466d94 --- /dev/null +++ b/src/backend/access/spgist/spgvalidate.c @@ -0,0 +1,129 @@ +/*------------------------------------------------------------------------- + * + * spgvalidate.c + * Opclass validator for SP-GiST. + * + * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/access/spgist/spgvalidate.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/htup_details.h" +#include "access/spgist_private.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 an SP-GiST opclass. + */ +bool +spgvalidate(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 > SPGISTNProc) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("spgist 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("spgist opfamily %u contains invalid strategy number %d for operator %u", + opfamilyoid, + oprform->amopstrategy, oprform->amopopr))); + + /* spgist doesn't support ORDER BY operators */ + if (oprform->amoppurpose != AMOP_SEARCH || + OidIsValid(oprform->amopsortfamily)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("spgist opfamily %u contains invalid ORDER BY specification for operator %u", + opfamilyoid, oprform->amopopr))); + + /* Count operators that are specifically for the named opclass */ + if (oprform->amoplefttype == opcintype && + oprform->amoprighttype == opcintype) + numclassops++; + } + + /* Check that the named opclass is complete */ + if (numclassops == 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("spgist opclass %u is missing operator(s)", + opclassoid))); + for (i = 1; i <= SPGISTNProc; i++) + { + if ((classfuncbits & (1 << i)) != 0) + continue; /* got it */ + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("spgist opclass %u is missing required support function %d", + opclassoid, i))); + } + + ReleaseCatCacheList(proclist); + ReleaseCatCacheList(oprlist); + + return true; +} |