diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 99337b0..40e4a48 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -35,6 +35,105 @@ /* + * BRIN handler function: return IndexAmRoutine with access method parameters + * and callbacks. + */ +Datum +brinhandler(PG_FUNCTION_ARGS) +{ + IndexAmRoutine *amroutine = makeNode(IndexAmRoutine); + + amroutine->amstrategies = 0; + amroutine->amsupport = 15; + amroutine->amcanorder = false; + amroutine->amcanorderbyop = false; + amroutine->amcanbackward = false; + amroutine->amcanunique = false; + amroutine->amcanmulticol = true; + amroutine->amoptionalkey = true; + amroutine->amsearcharray = false; + amroutine->amsearchnulls = true; + amroutine->amstorage = true; + amroutine->amclusterable = false; + amroutine->ampredlocks = false; + amroutine->amkeytype = 0; + + amroutine->aminsert = brininsert; + amroutine->ambeginscan = brinbeginscan; + amroutine->amgettuple = NULL; + amroutine->amgetbitmap = bringetbitmap; + amroutine->amrescan = brinrescan; + amroutine->amendscan = brinendscan; + amroutine->ammarkpos = brinmarkpos; + amroutine->amrestrpos = brinrestrpos; + amroutine->ambuild = brinbuild; + amroutine->ambuildempty = brinbuildempty; + amroutine->ambulkdelete = brinbulkdelete; + amroutine->amvacuumcleanup = brinvacuumcleanup; + amroutine->amcanreturn = NULL; + amroutine->amcostestimate = brincostestimate; + amroutine->amoptions = brinoptions; + amroutine->amvalidate = brinvalidate; + + PG_RETURN_POINTER(amroutine); +} + +void +brinvalidate(OpClassInfo *opclass) +{ + ListCell *l; + bool procsPresent[BRIN_NPROC]; + int i; + + memset(procsPresent, 0, sizeof(procsPresent)); + + foreach(l, opclass->procedures) + { + OpFamilyMember *proc = (OpFamilyMember *) lfirst(l); + + if (proc->lefttype != opclass->intype || + proc->righttype != opclass->intype) + continue; + + if (proc->number < 1 || proc->number > BRIN_NPROC) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("Invalid support number for BRIN: %u", + proc->number))); + + if (procsPresent[proc->number - 1]) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("BRIN support number %u was defined more than once", + proc->number))); + + procsPresent[proc->number - 1] = true; + } + + /* + * Don't use BRIN_NPROC because some procnumbers + * are reserved for future use + */ + for (i = 0; i < BRIN_PROCNUM_UNION; i++) + { + if (!procsPresent[i]) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("BRIN support number %u is required", i + 1))); + } + + foreach(l, opclass->operators) + { + OpFamilyMember *opr = (OpFamilyMember *) lfirst(l); + + if (OidIsValid(opr->sortfamily)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("BRIN doesn't support order by operators"))); + } +} + +/* * We use a BrinBuildState during initial construction of a BRIN index. * The running state is kept in a BrinMemTuple. */ @@ -80,15 +179,11 @@ static void brin_vacuum_scan(Relation idxrel, BufferAccessStrategy strategy); * If the range is not currently summarized (i.e. the revmap returns NULL for * it), there's nothing to do. */ -Datum -brininsert(PG_FUNCTION_ARGS) +bool +brininsert(Relation idxRel, Datum *values, bool *nulls, + ItemPointer heaptid, Relation heapRel, + IndexUniqueCheck checkUnique) { - Relation idxRel = (Relation) PG_GETARG_POINTER(0); - Datum *values = (Datum *) PG_GETARG_POINTER(1); - bool *nulls = (bool *) PG_GETARG_POINTER(2); - ItemPointer heaptid = (ItemPointer) PG_GETARG_POINTER(3); - - /* we ignore the rest of our arguments */ BlockNumber pagesPerRange; BrinDesc *bdesc = NULL; BrinRevmap *revmap; @@ -226,7 +321,7 @@ brininsert(PG_FUNCTION_ARGS) MemoryContextDelete(tupcxt); } - return BoolGetDatum(false); + return false; } /* @@ -236,12 +331,9 @@ brininsert(PG_FUNCTION_ARGS) * index was built with. Note that since this cannot be changed while we're * holding lock on index, it's not necessary to recompute it during brinrescan. */ -Datum -brinbeginscan(PG_FUNCTION_ARGS) +IndexScanDesc +brinbeginscan(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; BrinOpaque *opaque; @@ -252,7 +344,7 @@ brinbeginscan(PG_FUNCTION_ARGS) opaque->bo_bdesc = brin_build_desc(r); scan->opaque = opaque; - PG_RETURN_POINTER(scan); + return scan; } /* @@ -267,11 +359,9 @@ brinbeginscan(PG_FUNCTION_ARGS) * unsummarized. Pages in those ranges need to be returned regardless of scan * keys. */ -Datum -bringetbitmap(PG_FUNCTION_ARGS) +int64 +bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1); Relation idxRel = scan->indexRelation; Buffer buf = InvalidBuffer; BrinDesc *bdesc; @@ -451,20 +541,16 @@ bringetbitmap(PG_FUNCTION_ARGS) * returns, but we don't have a precise idea of the number of heap tuples * involved. */ - PG_RETURN_INT64(totalpages * 10); + return totalpages * 10; } /* * Re-initialize state for a BRIN index scan */ -Datum -brinrescan(PG_FUNCTION_ARGS) +void +brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, + ScanKey orderbys, int norderbys) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1); - - /* other arguments ignored */ - /* * Other index AMs preprocess the scan keys at this point, or sometime * early during the scan; this lets them optimize by removing redundant @@ -476,38 +562,31 @@ brinrescan(PG_FUNCTION_ARGS) if (scankey && scan->numberOfKeys > 0) memmove(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData)); - - PG_RETURN_VOID(); } /* * Close down a BRIN index scan */ -Datum -brinendscan(PG_FUNCTION_ARGS) +void +brinendscan(IndexScanDesc scan) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); BrinOpaque *opaque = (BrinOpaque *) scan->opaque; brinRevmapTerminate(opaque->bo_rmAccess); brin_free_desc(opaque->bo_bdesc); pfree(opaque); - - PG_RETURN_VOID(); } -Datum -brinmarkpos(PG_FUNCTION_ARGS) +void +brinmarkpos(IndexScanDesc scan) { elog(ERROR, "BRIN does not support mark/restore"); - PG_RETURN_VOID(); } -Datum -brinrestrpos(PG_FUNCTION_ARGS) +void +brinrestrpos(IndexScanDesc scan) { elog(ERROR, "BRIN does not support mark/restore"); - PG_RETURN_VOID(); } /* @@ -579,12 +658,9 @@ brinbuildCallback(Relation index, /* * brinbuild() -- build a new BRIN index. */ -Datum -brinbuild(PG_FUNCTION_ARGS) +IndexBuildResult * +brinbuild(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; double idxtuples; @@ -663,13 +739,12 @@ brinbuild(PG_FUNCTION_ARGS) result->heap_tuples = reltuples; result->index_tuples = idxtuples; - PG_RETURN_POINTER(result); + return result; } -Datum -brinbuildempty(PG_FUNCTION_ARGS) +void +brinbuildempty(Relation index) { - Relation index = (Relation) PG_GETARG_POINTER(0); Buffer metabuf; /* An empty BRIN index has a metapage only. */ @@ -686,8 +761,6 @@ brinbuildempty(PG_FUNCTION_ARGS) END_CRIT_SECTION(); UnlockReleaseBuffer(metabuf); - - PG_RETURN_VOID(); } /* @@ -699,35 +772,29 @@ brinbuildempty(PG_FUNCTION_ARGS) * tuple is deleted), meaning the need to re-run summarization on the affected * range. Would need to add an extra flag in brintuples for that. */ -Datum -brinbulkdelete(PG_FUNCTION_ARGS) +IndexBulkDeleteResult * +brinbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, void *callback_state) { - /* other arguments are not currently used */ - IndexBulkDeleteResult *stats = - (IndexBulkDeleteResult *) PG_GETARG_POINTER(1); - /* allocate stats if first time through, else re-use existing struct */ if (stats == NULL) stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult)); - PG_RETURN_POINTER(stats); + return stats; } /* * This routine is in charge of "vacuuming" a BRIN index: we just summarize * ranges that are currently unsummarized. */ -Datum -brinvacuumcleanup(PG_FUNCTION_ARGS) +IndexBulkDeleteResult * +brinvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) { - IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0); - IndexBulkDeleteResult *stats = - (IndexBulkDeleteResult *) PG_GETARG_POINTER(1); Relation heapRel; /* No-op in ANALYZE ONLY mode */ if (info->analyze_only) - PG_RETURN_POINTER(stats); + return stats; if (!stats) stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult)); @@ -744,17 +811,15 @@ brinvacuumcleanup(PG_FUNCTION_ARGS) heap_close(heapRel, AccessShareLock); - PG_RETURN_POINTER(stats); + return stats; } /* * reloptions processor for BRIN indexes */ -Datum -brinoptions(PG_FUNCTION_ARGS) +bytea * +brinoptions(Datum reloptions, bool validate) { - Datum reloptions = PG_GETARG_DATUM(0); - bool validate = PG_GETARG_BOOL(1); relopt_value *options; BrinOptions *rdopts; int numoptions; @@ -767,7 +832,7 @@ brinoptions(PG_FUNCTION_ARGS) /* if none set, we're done */ if (numoptions == 0) - PG_RETURN_NULL(); + return NULL; rdopts = allocateReloptStruct(sizeof(BrinOptions), options, numoptions); @@ -776,7 +841,7 @@ brinoptions(PG_FUNCTION_ARGS) pfree(options); - PG_RETURN_BYTEA_P(rdopts); + return (bytea *)rdopts; } /* diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index d817eba..978d2dc 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -891,7 +891,7 @@ untransformRelOptions(Datum options) * in the case of the tuple corresponding to an index, or InvalidOid otherwise. */ bytea * -extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, Oid amoptions) +extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, amoptions_function amoptions) { bytea *options; bool isnull; @@ -1379,34 +1379,15 @@ heap_reloptions(char relkind, Datum reloptions, bool validate) * validate error flag */ bytea * -index_reloptions(RegProcedure amoptions, Datum reloptions, bool validate) +index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate) { - FmgrInfo flinfo; - FunctionCallInfoData fcinfo; - Datum result; - - Assert(RegProcedureIsValid(amoptions)); + Assert(amoptions); /* Assume function is strict */ if (!PointerIsValid(DatumGetPointer(reloptions))) return NULL; - /* Can't use OidFunctionCallN because we might get a NULL result */ - fmgr_info(amoptions, &flinfo); - - InitFunctionCallInfoData(fcinfo, &flinfo, 2, InvalidOid, NULL, NULL); - - fcinfo.arg[0] = reloptions; - fcinfo.arg[1] = BoolGetDatum(validate); - fcinfo.argnull[0] = false; - fcinfo.argnull[1] = false; - - result = FunctionCallInvoke(&fcinfo); - - if (fcinfo.isnull || DatumGetPointer(result) == NULL) - return NULL; - - return DatumGetByteaP(result); + return amoptions(reloptions, validate); } /* diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c index 54b2db8..29b22d6 100644 --- a/src/backend/access/gin/ginget.c +++ b/src/backend/access/gin/ginget.c @@ -1772,11 +1772,9 @@ scanPendingInsert(IndexScanDesc scan, TIDBitmap *tbm, int64 *ntids) #define GinIsVoidRes(s) ( ((GinScanOpaque) scan->opaque)->isVoidRes ) -Datum -gingetbitmap(PG_FUNCTION_ARGS) +int64 +gingetbitmap(IndexScanDesc scan, TIDBitmap *tbm) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1); GinScanOpaque so = (GinScanOpaque) scan->opaque; int64 ntids; ItemPointerData iptr; @@ -1827,5 +1825,5 @@ gingetbitmap(PG_FUNCTION_ARGS) ntids++; } - PG_RETURN_INT64(ntids); + return ntids; } diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c index 49e9185..92701b9 100644 --- a/src/backend/access/gin/gininsert.c +++ b/src/backend/access/gin/gininsert.c @@ -306,12 +306,9 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values, MemoryContextSwitchTo(oldCtx); } -Datum -ginbuild(PG_FUNCTION_ARGS) +IndexBuildResult * +ginbuild(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; GinBuildState buildstate; @@ -429,16 +426,15 @@ ginbuild(PG_FUNCTION_ARGS) result->heap_tuples = reltuples; result->index_tuples = buildstate.indtuples; - PG_RETURN_POINTER(result); + return result; } /* * ginbuildempty() -- build an empty gin index in the initialization fork */ -Datum -ginbuildempty(PG_FUNCTION_ARGS) +void +ginbuildempty(Relation index) { - Relation index = (Relation) PG_GETARG_POINTER(0); Buffer RootBuffer, MetaBuffer; @@ -463,8 +459,6 @@ ginbuildempty(PG_FUNCTION_ARGS) /* Unlock and release the buffers. */ UnlockReleaseBuffer(MetaBuffer); UnlockReleaseBuffer(RootBuffer); - - PG_RETURN_VOID(); } /* @@ -489,18 +483,11 @@ ginHeapTupleInsert(GinState *ginstate, OffsetNumber attnum, item, 1, NULL); } -Datum -gininsert(PG_FUNCTION_ARGS) +bool +gininsert(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 GinState ginstate; MemoryContext oldCtx; MemoryContext insertCtx; @@ -541,5 +528,5 @@ gininsert(PG_FUNCTION_ARGS) MemoryContextSwitchTo(oldCtx); MemoryContextDelete(insertCtx); - PG_RETURN_BOOL(false); + return false; } diff --git a/src/backend/access/gin/ginscan.c b/src/backend/access/gin/ginscan.c index ac3a92b..d97a9db 100644 --- a/src/backend/access/gin/ginscan.c +++ b/src/backend/access/gin/ginscan.c @@ -21,12 +21,9 @@ #include "utils/rel.h" -Datum -ginbeginscan(PG_FUNCTION_ARGS) +IndexScanDesc +ginbeginscan(Relation rel, int nkeys, int norderbys) { - Relation rel = (Relation) PG_GETARG_POINTER(0); - int nkeys = PG_GETARG_INT32(1); - int norderbys = PG_GETARG_INT32(2); IndexScanDesc scan; GinScanOpaque so; @@ -53,7 +50,7 @@ ginbeginscan(PG_FUNCTION_ARGS) scan->opaque = so; - PG_RETURN_POINTER(scan); + return scan; } /* @@ -417,13 +414,10 @@ ginNewScanKey(IndexScanDesc scan) pgstat_count_index_scan(scan->indexRelation); } -Datum -ginrescan(PG_FUNCTION_ARGS) +void +ginrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, + ScanKey orderbys, int norderbys) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1); - - /* remaining arguments are ignored */ GinScanOpaque so = (GinScanOpaque) scan->opaque; ginFreeScanKeys(so); @@ -433,15 +427,12 @@ ginrescan(PG_FUNCTION_ARGS) memmove(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData)); } - - PG_RETURN_VOID(); } -Datum -ginendscan(PG_FUNCTION_ARGS) +void +ginendscan(IndexScanDesc scan) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); GinScanOpaque so = (GinScanOpaque) scan->opaque; ginFreeScanKeys(so); @@ -450,20 +441,16 @@ ginendscan(PG_FUNCTION_ARGS) MemoryContextDelete(so->keyCtx); pfree(so); - - PG_RETURN_VOID(); } -Datum -ginmarkpos(PG_FUNCTION_ARGS) +void +ginmarkpos(IndexScanDesc scan) { elog(ERROR, "GIN does not support mark/restore"); - PG_RETURN_VOID(); } -Datum -ginrestrpos(PG_FUNCTION_ARGS) +void +ginrestrpos(IndexScanDesc scan) { elog(ERROR, "GIN does not support mark/restore"); - PG_RETURN_VOID(); } diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c index cb4e32f..91a194f 100644 --- a/src/backend/access/gin/ginutil.c +++ b/src/backend/access/gin/ginutil.c @@ -22,9 +22,121 @@ #include "miscadmin.h" #include "storage/indexfsm.h" #include "storage/lmgr.h" +#include "utils/selfuncs.h" /* + * GIN handler function: return IndexAmRoutine with access method parameters + * and callbacks. + */ +Datum +ginhandler(PG_FUNCTION_ARGS) +{ + IndexAmRoutine *amroutine = makeNode(IndexAmRoutine); + + amroutine->amstrategies = 0; + amroutine->amsupport = 6; + amroutine->amcanorder = false; + amroutine->amcanorderbyop = false; + amroutine->amcanbackward = false; + amroutine->amcanunique = false; + amroutine->amcanmulticol = true; + amroutine->amoptionalkey = true; + amroutine->amsearcharray = false; + amroutine->amsearchnulls = false; + amroutine->amstorage = true; + amroutine->amclusterable = false; + amroutine->ampredlocks = false; + amroutine->amkeytype = 0; + + amroutine->aminsert = gininsert; + amroutine->ambeginscan = ginbeginscan; + amroutine->amgettuple = NULL; + amroutine->amgetbitmap = gingetbitmap; + amroutine->amrescan = ginrescan; + amroutine->amendscan = ginendscan; + amroutine->ammarkpos = ginmarkpos; + amroutine->amrestrpos = ginrestrpos; + amroutine->ambuild = ginbuild; + amroutine->ambuildempty = ginbuildempty; + amroutine->ambulkdelete = ginbulkdelete; + amroutine->amvacuumcleanup = ginvacuumcleanup; + amroutine->amcanreturn = NULL; + amroutine->amcostestimate = gincostestimate; + amroutine->amoptions = ginoptions; + amroutine->amvalidate = ginvalidate; + + PG_RETURN_POINTER(amroutine); +} + +void +ginvalidate(OpClassInfo *opclass) +{ + ListCell *l; + bool procsPresent[GINNProcs]; + int i; + + memset(procsPresent, 0, sizeof(procsPresent)); + + foreach(l, opclass->procedures) + { + OpFamilyMember *proc = (OpFamilyMember *) lfirst(l); + + if (proc->lefttype != opclass->intype || + proc->righttype != opclass->intype) + continue; + + if (proc->number < 1 || proc->number > GINNProcs) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("Invalid support number for GIN: %u", + proc->number))); + + if (procsPresent[proc->number - 1]) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("GIN support number %u was defined more than once", + proc->number))); + + procsPresent[proc->number - 1] = true; + } + + for (i = 0; i < GINNProcs; i++) + { + if (i+1 == GIN_COMPARE_PARTIAL_PROC) + continue; /* optional method */ + if (i+1 == GIN_CONSISTENT_PROC || i+1 == GIN_TRICONSISTENT_PROC) + continue; /* don't need to have both, see check below loop */ + + if (!procsPresent[i]) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("GIN support number %u is required", i + 1))); + } + + if (!procsPresent[GIN_CONSISTENT_PROC - 1] + && !procsPresent[GIN_TRICONSISTENT_PROC - 1]) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("At least one of consistent support (number %u) " + "and triconsistent cupport (number %u) is " + "is required", + GIN_CONSISTENT_PROC, GIN_TRICONSISTENT_PROC))); + } + + foreach(l, opclass->operators) + { + OpFamilyMember *opr = (OpFamilyMember *) lfirst(l); + + if (OidIsValid(opr->sortfamily)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("GIN doesn't support order by operators"))); + } +} + +/* * initGinState: fill in an empty GinState struct to describe the index * * Note: assorted subsidiary data is allocated in the CurrentMemoryContext. @@ -516,11 +628,9 @@ ginExtractEntries(GinState *ginstate, OffsetNumber attnum, return entries; } -Datum -ginoptions(PG_FUNCTION_ARGS) +bytea * +ginoptions(Datum reloptions, bool validate) { - Datum reloptions = PG_GETARG_DATUM(0); - bool validate = PG_GETARG_BOOL(1); relopt_value *options; GinOptions *rdopts; int numoptions; @@ -535,7 +645,7 @@ ginoptions(PG_FUNCTION_ARGS) /* if none set, we're done */ if (numoptions == 0) - PG_RETURN_NULL(); + return NULL; rdopts = allocateReloptStruct(sizeof(GinOptions), options, numoptions); @@ -544,7 +654,7 @@ ginoptions(PG_FUNCTION_ARGS) pfree(options); - PG_RETURN_BYTEA_P(rdopts); + return (bytea *)rdopts; } /* diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c index 323cfb0..5b38607 100644 --- a/src/backend/access/gin/ginvacuum.c +++ b/src/backend/access/gin/ginvacuum.c @@ -513,13 +513,10 @@ ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint3 return (tmppage == origpage) ? NULL : tmppage; } -Datum -ginbulkdelete(PG_FUNCTION_ARGS) +IndexBulkDeleteResult * +ginbulkdelete(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 index = info->index; BlockNumber blkno = GIN_ROOT_BLKNO; GinVacuumState gvs; @@ -634,14 +631,12 @@ ginbulkdelete(PG_FUNCTION_ARGS) MemoryContextDelete(gvs.tmpCxt); - PG_RETURN_POINTER(gvs.result); + return gvs.result; } -Datum -ginvacuumcleanup(PG_FUNCTION_ARGS) +IndexBulkDeleteResult * +ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) { - IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0); - IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1); Relation index = info->index; bool needLock; BlockNumber npages, @@ -661,7 +656,7 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) initGinState(&ginstate, index); ginInsertCleanup(&ginstate, true, true, stats); } - PG_RETURN_POINTER(stats); + return stats; } /* @@ -746,5 +741,5 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) if (needLock) UnlockRelationForExtension(index, ExclusiveLock); - PG_RETURN_POINTER(stats); + return stats; } diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index 53bccf6..817b8be 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -16,6 +16,7 @@ #include "access/genam.h" #include "access/gist_private.h" +#include "access/gistscan.h" #include "access/xloginsert.h" #include "catalog/index.h" #include "catalog/pg_collation.h" @@ -24,6 +25,7 @@ #include "storage/indexfsm.h" #include "utils/memutils.h" #include "utils/rel.h" +#include "utils/selfuncs.h" /* non-export function prototypes */ static void gistfixsplit(GISTInsertState *state, GISTSTATE *giststate); @@ -38,6 +40,104 @@ static void gistfinishsplit(GISTInsertState *state, GISTInsertStack *stack, GISTSTATE *giststate, List *splitinfo, bool releasebuf); 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 = 0; + + amroutine->aminsert = gistinsert; + amroutine->ambeginscan = gistbeginscan; + amroutine->amgettuple = gistgettuple; + amroutine->amgetbitmap = gistgetbitmap; + amroutine->amrescan = gistrescan; + amroutine->amendscan = gistendscan; + amroutine->ammarkpos = gistmarkpos; + amroutine->amrestrpos = gistrestrpos; + amroutine->ambuild = gistbuild; + amroutine->ambuildempty = gistbuildempty; + amroutine->ambulkdelete = gistbulkdelete; + amroutine->amvacuumcleanup = gistvacuumcleanup; + amroutine->amcanreturn = gistcanreturn; + amroutine->amcostestimate = gistcostestimate; + amroutine->amoptions = gistoptions; + amroutine->amvalidate = gistvalidate; + + PG_RETURN_POINTER(amroutine); +} + +void +gistvalidate(OpClassInfo *opclass) +{ + ListCell *l; + bool procsPresent[GISTNProcs]; + int i; + + memset(procsPresent, 0, sizeof(procsPresent)); + + foreach(l, opclass->procedures) + { + OpFamilyMember *proc = (OpFamilyMember *) lfirst(l); + + if (proc->lefttype != opclass->intype || + proc->righttype != opclass->intype) + continue; + + if (proc->number < 1 || proc->number > GISTNProcs) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("Invalid support number for GiST: %u", + proc->number))); + + if (procsPresent[proc->number - 1]) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("GiST support number %u was defined more than once", + proc->number))); + + procsPresent[proc->number - 1] = true; + } + + for (i = 0; i < GISTNProcs; i++) + { + if (i+1 == GIST_DISTANCE_PROC || i+1 == GIST_FETCH_PROC) + continue; /* optional methods */ + if (!procsPresent[i]) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("GiST support number %u is required", i + 1))); + } + + foreach(l, opclass->operators) + { + OpFamilyMember *opr = (OpFamilyMember *) lfirst(l); + + if (OidIsValid(opr->sortfamily) + && !procsPresent[GIST_DISTANCE_PROC - 1]) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("GiST distance support function %u is required " + "for order by operators", GIST_DISTANCE_PROC))); + } +} #define ROTATEDIST(d) do { \ SplitedPageLayout *tmp=(SplitedPageLayout*)palloc(sizeof(SplitedPageLayout)); \ @@ -70,10 +170,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 +188,6 @@ gistbuildempty(PG_FUNCTION_ARGS) /* Unlock and release the buffer */ UnlockReleaseBuffer(buffer); - - PG_RETURN_VOID(); } /* @@ -99,18 +196,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 +226,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 ff888e2..08a029c 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 ce8e582..1adf92f 100644 --- a/src/backend/access/gist/gistget.c +++ b/src/backend/access/gist/gistget.c @@ -618,11 +618,9 @@ 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) @@ -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 a17c5bc..22f0c68 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,15 +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; @@ -314,28 +309,23 @@ gistrescan(PG_FUNCTION_ARGS) if (!first_time) pfree(fn_extras); } - - PG_RETURN_VOID(); } -Datum -gistmarkpos(PG_FUNCTION_ARGS) +void +gistmarkpos(IndexScanDesc scan) { elog(ERROR, "GiST does not support mark/restore"); - PG_RETURN_VOID(); } -Datum -gistrestrpos(PG_FUNCTION_ARGS) +void +gistrestrpos(IndexScanDesc scan) { elog(ERROR, "GiST does not support mark/restore"); - PG_RETURN_VOID(); } -Datum -gistendscan(PG_FUNCTION_ARGS) +void +gistendscan(IndexScanDesc scan) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); GISTScanOpaque so = (GISTScanOpaque) scan->opaque; /* @@ -343,6 +333,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 7d596a3..45f6246 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,7 +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 a0b0eeb..e0ce620 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/hash/hash.c b/src/backend/access/hash/hash.c index 24b06a5..286596b 100644 --- a/src/backend/access/hash/hash.c +++ b/src/backend/access/hash/hash.c @@ -18,6 +18,7 @@ #include "postgres.h" +#include "access/amapi.h" #include "access/hash.h" #include "access/relscan.h" #include "catalog/index.h" @@ -26,6 +27,7 @@ #include "optimizer/plancat.h" #include "storage/bufmgr.h" #include "utils/rel.h" +#include "utils/selfuncs.h" /* Working state for hashbuild and its callback */ @@ -42,16 +44,107 @@ static void hashbuildCallback(Relation index, bool tupleIsAlive, void *state); +/* + * Hash handler function: return IndexAmRoutine with access method parameters + * and callbacks. + */ +Datum +hashhandler(PG_FUNCTION_ARGS) +{ + IndexAmRoutine *amroutine = makeNode(IndexAmRoutine); + + amroutine->amstrategies = 1; + amroutine->amsupport = 1; + amroutine->amcanorder = false; + amroutine->amcanorderbyop = false; + amroutine->amcanbackward = true; + amroutine->amcanunique = false; + amroutine->amcanmulticol = false; + amroutine->amoptionalkey = false; + amroutine->amsearcharray = false; + amroutine->amsearchnulls = false; + amroutine->amstorage = false; + amroutine->amclusterable = false; + amroutine->ampredlocks = false; + amroutine->amkeytype = INT4OID; + + amroutine->aminsert = hashinsert; + amroutine->ambeginscan = hashbeginscan; + amroutine->amgettuple = hashgettuple; + amroutine->amgetbitmap = hashgetbitmap; + amroutine->amrescan = hashrescan; + amroutine->amendscan = hashendscan; + amroutine->ammarkpos = hashmarkpos; + amroutine->amrestrpos = hashrestrpos; + amroutine->ambuild = hashbuild; + amroutine->ambuildempty = hashbuildempty; + amroutine->ambulkdelete = hashbulkdelete; + amroutine->amvacuumcleanup = hashvacuumcleanup; + amroutine->amcanreturn = NULL; + amroutine->amcostestimate = hashcostestimate; + amroutine->amoptions = hashoptions; + amroutine->amvalidate = hashvalidate; + + PG_RETURN_POINTER(amroutine); +} + +void +hashvalidate(OpClassInfo *opclass) +{ + ListCell *l; + + foreach(l, opclass->procedures) + { + OpFamilyMember *proc = (OpFamilyMember *) lfirst(l); + + if (proc->number != HASHPROC) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("Invalid support number for hash: %u", + proc->number))); + } + + foreach(l, opclass->operators) + { + OpFamilyMember *opr = (OpFamilyMember *) lfirst(l); + bool leftFound = false, rightFound = false; + ListCell *ll; + + if (OidIsValid(opr->sortfamily)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("Hash doesn't support order by operators"))); + + if (opr->number < 1 || opr->number > HTMaxStrategyNumber) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("Invalid strategy number for hash: %u", + opr->number))); + + foreach(ll, opclass->procedures) + { + OpFamilyMember *proc = (OpFamilyMember *) lfirst(ll); + + if (proc->lefttype == opr->lefttype) + leftFound = true; + if (proc->lefttype == opr->righttype) + rightFound = true; + } + + if (!leftFound || !rightFound) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("No hash procedure found for operator: %u", + opr->object))); + } +} /* * hashbuild() -- build a new hash index. */ -Datum -hashbuild(PG_FUNCTION_ARGS) +IndexBuildResult * +hashbuild(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; BlockNumber relpages; double reltuples; @@ -112,20 +205,16 @@ hashbuild(PG_FUNCTION_ARGS) result->heap_tuples = reltuples; result->index_tuples = buildstate.indtuples; - PG_RETURN_POINTER(result); + return result; } /* * hashbuildempty() -- build an empty hash index in the initialization fork */ -Datum -hashbuildempty(PG_FUNCTION_ARGS) +void +hashbuildempty(Relation index) { - Relation index = (Relation) PG_GETARG_POINTER(0); - _hash_metapinit(index, 0, INIT_FORKNUM); - - PG_RETURN_VOID(); } /* @@ -167,18 +256,11 @@ hashbuildCallback(Relation index, * Hash on the heap tuple's key, form an index tuple with hash code. * Find the appropriate location for the new tuple, and put it there. */ -Datum -hashinsert(PG_FUNCTION_ARGS) +bool +hashinsert(Relation rel, Datum *values, bool *isnull, + ItemPointer ht_ctid, Relation heapRel, + IndexUniqueCheck checkUnique) { - Relation rel = (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; /* @@ -191,7 +273,7 @@ hashinsert(PG_FUNCTION_ARGS) * chosen in 1986, not of the way nulls are handled here. */ if (isnull[0]) - PG_RETURN_BOOL(false); + return false; /* generate an index tuple */ itup = _hash_form_tuple(rel, values, isnull); @@ -201,18 +283,16 @@ hashinsert(PG_FUNCTION_ARGS) pfree(itup); - PG_RETURN_BOOL(false); + return false; } /* * hashgettuple() -- Get the next tuple in the scan. */ -Datum -hashgettuple(PG_FUNCTION_ARGS) +bool +hashgettuple(IndexScanDesc scan, ScanDirection dir) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1); HashScanOpaque so = (HashScanOpaque) scan->opaque; Relation rel = scan->indexRelation; Buffer buf; @@ -314,18 +394,16 @@ hashgettuple(PG_FUNCTION_ARGS) /* Return current heap TID on success */ scan->xs_ctup.t_self = so->hashso_heappos; - PG_RETURN_BOOL(res); + return res; } /* * hashgetbitmap() -- get all tuples at once */ -Datum -hashgetbitmap(PG_FUNCTION_ARGS) +int64 +hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1); HashScanOpaque so = (HashScanOpaque) scan->opaque; bool res; int64 ntids = 0; @@ -362,19 +440,16 @@ hashgetbitmap(PG_FUNCTION_ARGS) res = _hash_next(scan, ForwardScanDirection); } - PG_RETURN_INT64(ntids); + return ntids; } /* * hashbeginscan() -- start a scan on a hash index */ -Datum -hashbeginscan(PG_FUNCTION_ARGS) +IndexScanDesc +hashbeginscan(Relation rel, int nkeys, int norderbys) { - Relation rel = (Relation) PG_GETARG_POINTER(0); - int nkeys = PG_GETARG_INT32(1); - int norderbys = PG_GETARG_INT32(2); IndexScanDesc scan; HashScanOpaque so; @@ -396,19 +471,16 @@ hashbeginscan(PG_FUNCTION_ARGS) /* register scan in case we change pages it's using */ _hash_regscan(scan); - PG_RETURN_POINTER(scan); + return scan; } /* * hashrescan() -- rescan an index relation */ -Datum -hashrescan(PG_FUNCTION_ARGS) +void +hashrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, + ScanKey orderbys, int norderbys) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1); - - /* remaining arguments are ignored */ HashScanOpaque so = (HashScanOpaque) scan->opaque; Relation rel = scan->indexRelation; @@ -434,17 +506,14 @@ hashrescan(PG_FUNCTION_ARGS) scan->numberOfKeys * sizeof(ScanKeyData)); so->hashso_bucket_valid = false; } - - PG_RETURN_VOID(); } /* * hashendscan() -- close down a scan */ -Datum -hashendscan(PG_FUNCTION_ARGS) +void +hashendscan(IndexScanDesc scan) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); HashScanOpaque so = (HashScanOpaque) scan->opaque; Relation rel = scan->indexRelation; @@ -463,28 +532,24 @@ hashendscan(PG_FUNCTION_ARGS) pfree(so); scan->opaque = NULL; - - PG_RETURN_VOID(); } /* * hashmarkpos() -- save current scan position */ -Datum -hashmarkpos(PG_FUNCTION_ARGS) +void +hashmarkpos(IndexScanDesc scan) { elog(ERROR, "hash does not support mark/restore"); - PG_RETURN_VOID(); } /* * hashrestrpos() -- restore scan to last saved position */ -Datum -hashrestrpos(PG_FUNCTION_ARGS) +void +hashrestrpos(IndexScanDesc scan) { elog(ERROR, "hash does not support mark/restore"); - PG_RETURN_VOID(); } /* @@ -494,13 +559,10 @@ hashrestrpos(PG_FUNCTION_ARGS) * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ -Datum -hashbulkdelete(PG_FUNCTION_ARGS) +IndexBulkDeleteResult * +hashbulkdelete(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; double tuples_removed; double num_index_tuples; @@ -670,7 +732,7 @@ loop_top: stats->tuples_removed += tuples_removed; /* hashvacuumcleanup will fill in num_pages */ - PG_RETURN_POINTER(stats); + return stats; } /* @@ -678,24 +740,22 @@ loop_top: * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ -Datum -hashvacuumcleanup(PG_FUNCTION_ARGS) +IndexBulkDeleteResult * +hashvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) { - IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0); - IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1); Relation rel = info->index; BlockNumber num_pages; /* If hashbulkdelete wasn't called, return NULL signifying no change */ /* Note: this covers the analyze_only case too */ if (stats == NULL) - PG_RETURN_POINTER(NULL); + return NULL; /* update statistics */ num_pages = RelationGetNumberOfBlocks(rel); stats->num_pages = num_pages; - PG_RETURN_POINTER(stats); + return stats; } diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c index 3d66216..85236e2 100644 --- a/src/backend/access/hash/hashutil.c +++ b/src/backend/access/hash/hashutil.c @@ -217,18 +217,16 @@ _hash_checkpage(Relation rel, Buffer buf, int flags) } } -Datum -hashoptions(PG_FUNCTION_ARGS) +bytea * +hashoptions(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_HASH); if (result) - PG_RETURN_BYTEA_P(result); - PG_RETURN_NULL(); + return result; + return NULL; } /* diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c index 2b27e73..ebf9313 100644 --- a/src/backend/access/index/indexam.c +++ b/src/backend/access/index/indexam.c @@ -65,6 +65,7 @@ #include "postgres.h" +#include "access/amapi.h" #include "access/relscan.h" #include "access/transam.h" #include "access/xlog.h" @@ -92,49 +93,32 @@ * ---------------------------------------------------------------- */ #define RELATION_CHECKS \ -( \ - AssertMacro(RelationIsValid(indexRelation)), \ - AssertMacro(PointerIsValid(indexRelation->rd_am)), \ - AssertMacro(!ReindexIsProcessingIndex(RelationGetRelid(indexRelation))) \ -) - -#define SCAN_CHECKS \ -( \ - AssertMacro(IndexScanIsValid(scan)), \ - AssertMacro(RelationIsValid(scan->indexRelation)), \ - AssertMacro(PointerIsValid(scan->indexRelation->rd_am)) \ -) - -#define GET_REL_PROCEDURE(pname) \ -do { \ - procedure = &indexRelation->rd_aminfo->pname; \ - if (!OidIsValid(procedure->fn_oid)) \ - { \ - RegProcedure procOid = indexRelation->rd_am->pname; \ - if (!RegProcedureIsValid(procOid)) \ - elog(ERROR, "invalid %s regproc", CppAsString(pname)); \ - fmgr_info_cxt(procOid, procedure, indexRelation->rd_indexcxt); \ - } \ -} while(0) - -#define GET_UNCACHED_REL_PROCEDURE(pname) \ do { \ - if (!RegProcedureIsValid(indexRelation->rd_am->pname)) \ - elog(ERROR, "invalid %s regproc", CppAsString(pname)); \ - fmgr_info(indexRelation->rd_am->pname, &procedure); \ -} while(0) + Assert(RelationIsValid(indexRelation)); \ + Assert(indexRelation->amroutine); \ + Assert(!ReindexIsProcessingIndex(RelationGetRelid(indexRelation))); \ +} while (0) -#define GET_SCAN_PROCEDURE(pname) \ +#define SCAN_CHECKS \ do { \ - procedure = &scan->indexRelation->rd_aminfo->pname; \ - if (!OidIsValid(procedure->fn_oid)) \ - { \ - RegProcedure procOid = scan->indexRelation->rd_am->pname; \ - if (!RegProcedureIsValid(procOid)) \ - elog(ERROR, "invalid %s regproc", CppAsString(pname)); \ - fmgr_info_cxt(procOid, procedure, scan->indexRelation->rd_indexcxt); \ - } \ -} while(0) + Assert(IndexScanIsValid(scan)); \ + Assert(RelationIsValid(scan->indexRelation)); \ + Assert(scan->indexRelation->amroutine); \ +} while (0) + +#define CHECK_PROCEDURE(pname) \ +if (!indexRelation->amroutine->pname) \ +{ \ + elog(ERROR, "%s is undefined for %s", \ + CppAsString(pname), RelationGetRelationName(indexRelation)); \ +} \ + +#define CHECK_SCAN_PROCEDURE(pname) \ +if (!scan->indexRelation->amroutine->pname) \ +{ \ + elog(ERROR, "%s is undefined for %s", \ + CppAsString(pname), RelationGetRelationName(scan->indexRelation)); \ +} \ static IndexScanDesc index_beginscan_internal(Relation indexRelation, int nkeys, int norderbys, Snapshot snapshot); @@ -210,26 +194,17 @@ index_insert(Relation indexRelation, Relation heapRelation, IndexUniqueCheck checkUnique) { - FmgrInfo *procedure; - RELATION_CHECKS; - GET_REL_PROCEDURE(aminsert); + CHECK_PROCEDURE(aminsert); - if (!(indexRelation->rd_am->ampredlocks)) + if (!(indexRelation->amroutine->ampredlocks)) CheckForSerializableConflictIn(indexRelation, (HeapTuple) NULL, InvalidBuffer); - /* - * have the am's insert proc do all the work. - */ - return DatumGetBool(FunctionCall6(procedure, - PointerGetDatum(indexRelation), - PointerGetDatum(values), - PointerGetDatum(isnull), - PointerGetDatum(heap_t_ctid), - PointerGetDatum(heapRelation), - Int32GetDatum((int32) checkUnique))); + return indexRelation->amroutine->aminsert(indexRelation, values, isnull, + heap_t_ctid, heapRelation, + checkUnique); } /* @@ -289,12 +264,11 @@ index_beginscan_internal(Relation indexRelation, int nkeys, int norderbys, Snapshot snapshot) { IndexScanDesc scan; - FmgrInfo *procedure; RELATION_CHECKS; - GET_REL_PROCEDURE(ambeginscan); + CHECK_PROCEDURE(ambeginscan); - if (!(indexRelation->rd_am->ampredlocks)) + if (!(indexRelation->amroutine->ampredlocks)) PredicateLockRelation(indexRelation, snapshot); /* @@ -305,11 +279,8 @@ index_beginscan_internal(Relation indexRelation, /* * Tell the AM to open a scan. */ - scan = (IndexScanDesc) - DatumGetPointer(FunctionCall3(procedure, - PointerGetDatum(indexRelation), - Int32GetDatum(nkeys), - Int32GetDatum(norderbys))); + scan = indexRelation->amroutine->ambeginscan(indexRelation, nkeys, + norderbys); return scan; } @@ -331,10 +302,8 @@ index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys) { - FmgrInfo *procedure; - SCAN_CHECKS; - GET_SCAN_PROCEDURE(amrescan); + CHECK_SCAN_PROCEDURE(amrescan); Assert(nkeys == scan->numberOfKeys); Assert(norderbys == scan->numberOfOrderBys); @@ -350,12 +319,8 @@ index_rescan(IndexScanDesc scan, scan->kill_prior_tuple = false; /* for safety */ - FunctionCall5(procedure, - PointerGetDatum(scan), - PointerGetDatum(keys), - Int32GetDatum(nkeys), - PointerGetDatum(orderbys), - Int32GetDatum(norderbys)); + scan->indexRelation->amroutine->amrescan(scan, keys, nkeys, + orderbys, norderbys); } /* ---------------- @@ -365,10 +330,8 @@ index_rescan(IndexScanDesc scan, void index_endscan(IndexScanDesc scan) { - FmgrInfo *procedure; - SCAN_CHECKS; - GET_SCAN_PROCEDURE(amendscan); + CHECK_SCAN_PROCEDURE(amendscan); /* Release any held pin on a heap page */ if (BufferIsValid(scan->xs_cbuf)) @@ -378,7 +341,7 @@ index_endscan(IndexScanDesc scan) } /* End the AM's scan */ - FunctionCall1(procedure, PointerGetDatum(scan)); + scan->indexRelation->amroutine->amendscan(scan); /* Release index refcount acquired by index_beginscan */ RelationDecrementReferenceCount(scan->indexRelation); @@ -394,12 +357,10 @@ index_endscan(IndexScanDesc scan) void index_markpos(IndexScanDesc scan) { - FmgrInfo *procedure; - SCAN_CHECKS; - GET_SCAN_PROCEDURE(ammarkpos); + CHECK_SCAN_PROCEDURE(ammarkpos); - FunctionCall1(procedure, PointerGetDatum(scan)); + scan->indexRelation->amroutine->ammarkpos(scan); } /* ---------------- @@ -421,18 +382,16 @@ index_markpos(IndexScanDesc scan) void index_restrpos(IndexScanDesc scan) { - FmgrInfo *procedure; - Assert(IsMVCCSnapshot(scan->xs_snapshot)); SCAN_CHECKS; - GET_SCAN_PROCEDURE(amrestrpos); + CHECK_SCAN_PROCEDURE(amrestrpos); scan->xs_continue_hot = false; scan->kill_prior_tuple = false; /* for safety */ - FunctionCall1(procedure, PointerGetDatum(scan)); + scan->indexRelation->amroutine->amrestrpos(scan); } /* ---------------- @@ -445,11 +404,10 @@ index_restrpos(IndexScanDesc scan) ItemPointer index_getnext_tid(IndexScanDesc scan, ScanDirection direction) { - FmgrInfo *procedure; bool found; SCAN_CHECKS; - GET_SCAN_PROCEDURE(amgettuple); + CHECK_SCAN_PROCEDURE(amgettuple); Assert(TransactionIdIsValid(RecentGlobalXmin)); @@ -459,9 +417,7 @@ index_getnext_tid(IndexScanDesc scan, ScanDirection direction) * scan->xs_recheck and possibly scan->xs_itup, though we pay no attention * to those fields here. */ - found = DatumGetBool(FunctionCall2(procedure, - PointerGetDatum(scan), - Int32GetDatum(direction))); + found = scan->indexRelation->amroutine->amgettuple(scan, direction); /* Reset kill flag immediately for safety */ scan->kill_prior_tuple = false; @@ -635,12 +591,11 @@ index_getnext(IndexScanDesc scan, ScanDirection direction) int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap) { - FmgrInfo *procedure; int64 ntids; Datum d; SCAN_CHECKS; - GET_SCAN_PROCEDURE(amgetbitmap); + CHECK_SCAN_PROCEDURE(amgetbitmap); /* just make sure this is false... */ scan->kill_prior_tuple = false; @@ -648,9 +603,7 @@ index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap) /* * have the am's getbitmap proc do all the work. */ - d = FunctionCall2(procedure, - PointerGetDatum(scan), - PointerGetDatum(bitmap)); + d = scan->indexRelation->amroutine->amgetbitmap(scan, bitmap); ntids = DatumGetInt64(d); @@ -680,20 +633,12 @@ index_bulk_delete(IndexVacuumInfo *info, void *callback_state) { Relation indexRelation = info->index; - FmgrInfo procedure; - IndexBulkDeleteResult *result; RELATION_CHECKS; - GET_UNCACHED_REL_PROCEDURE(ambulkdelete); + CHECK_PROCEDURE(ambulkdelete); - result = (IndexBulkDeleteResult *) - DatumGetPointer(FunctionCall4(&procedure, - PointerGetDatum(info), - PointerGetDatum(stats), - PointerGetDatum((Pointer) callback), - PointerGetDatum(callback_state))); - - return result; + return indexRelation->amroutine->ambulkdelete(info, stats, + callback, callback_state); } /* ---------------- @@ -707,18 +652,11 @@ index_vacuum_cleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) { Relation indexRelation = info->index; - FmgrInfo procedure; - IndexBulkDeleteResult *result; RELATION_CHECKS; - GET_UNCACHED_REL_PROCEDURE(amvacuumcleanup); - - result = (IndexBulkDeleteResult *) - DatumGetPointer(FunctionCall2(&procedure, - PointerGetDatum(info), - PointerGetDatum(stats))); + CHECK_PROCEDURE(amvacuumcleanup); - return result; + return indexRelation->amroutine->amvacuumcleanup(info, stats); } /* ---------------- @@ -731,19 +669,13 @@ index_vacuum_cleanup(IndexVacuumInfo *info, bool index_can_return(Relation indexRelation, int attno) { - FmgrInfo *procedure; - RELATION_CHECKS; /* amcanreturn is optional; assume FALSE if not provided by AM */ - if (!RegProcedureIsValid(indexRelation->rd_am->amcanreturn)) + if (!indexRelation->amroutine->amcanreturn) return false; - GET_REL_PROCEDURE(amcanreturn); - - return DatumGetBool(FunctionCall2(procedure, - PointerGetDatum(indexRelation), - Int32GetDatum(attno))); + return indexRelation->amroutine->amcanreturn(indexRelation, attno); } /* ---------------- @@ -781,7 +713,7 @@ index_getprocid(Relation irel, int nproc; int procindex; - nproc = irel->rd_am->amsupport; + nproc = irel->amroutine->amsupport; Assert(procnum > 0 && procnum <= (uint16) nproc); @@ -815,7 +747,7 @@ index_getprocinfo(Relation irel, int nproc; int procindex; - nproc = irel->rd_am->amsupport; + nproc = irel->amroutine->amsupport; Assert(procnum > 0 && procnum <= (uint16) nproc); diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index cf4a6dc..fa933f6 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -76,14 +76,107 @@ static void btvacuumpage(BTVacState *vstate, BlockNumber blkno, /* - * btbuild() -- build a new btree index. + * Btree handler function: return IndexAmRoutine with access method parameters + * and callbacks. */ Datum -btbuild(PG_FUNCTION_ARGS) +bthandler(PG_FUNCTION_ARGS) +{ + IndexAmRoutine *amroutine = makeNode(IndexAmRoutine); + + amroutine->amstrategies = 5; + amroutine->amsupport = 2; + amroutine->amcanorder = true; + amroutine->amcanorderbyop = false; + amroutine->amcanbackward = true; + amroutine->amcanunique = true; + amroutine->amcanmulticol = true; + amroutine->amoptionalkey = true; + amroutine->amsearcharray = true; + amroutine->amsearchnulls = true; + amroutine->amstorage = false; + amroutine->amclusterable = true; + amroutine->ampredlocks = true; + amroutine->amkeytype = 0; + + amroutine->aminsert = btinsert; + amroutine->ambeginscan = btbeginscan; + amroutine->amgettuple = btgettuple; + amroutine->amgetbitmap = btgetbitmap; + amroutine->amrescan = btrescan; + amroutine->amendscan = btendscan; + amroutine->ammarkpos = btmarkpos; + amroutine->amrestrpos = btrestrpos; + amroutine->ambuild = btbuild; + amroutine->ambuildempty = btbuildempty; + amroutine->ambulkdelete = btbulkdelete; + amroutine->amvacuumcleanup = btvacuumcleanup; + amroutine->amcanreturn = btcanreturn; + amroutine->amcostestimate = btcostestimate; + amroutine->amoptions = btoptions; + amroutine->amvalidate = btvalidate; + + PG_RETURN_POINTER(amroutine); +} + +void +btvalidate(OpClassInfo *opclass) +{ + ListCell *l; + + foreach(l, opclass->procedures) + { + OpFamilyMember *proc = (OpFamilyMember *) lfirst(l); + + if (proc->number != BTORDER_PROC + && proc->number != BTSORTSUPPORT_PROC) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("Invalid support number for btree: %u", + proc->number))); + } + + foreach(l, opclass->operators) + { + OpFamilyMember *opr = (OpFamilyMember *) lfirst(l); + bool found = false; + ListCell *ll; + + if (OidIsValid(opr->sortfamily)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("Btree doesn't support order by operators"))); + + if (opr->number < 1 || opr->number > BTMaxStrategyNumber) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("Invalid strategy number for btree: %u", + opr->number))); + + foreach(ll, opclass->procedures) + { + OpFamilyMember *proc = (OpFamilyMember *) lfirst(ll); + + if (proc->number == BTORDER_PROC + && proc->lefttype == opr->lefttype + && proc->righttype == opr->righttype) + found = true; + } + + if (!found) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("No ordering procedure found for operator: %u", + opr->object))); + } +} + +/* + * btbuild() -- build a new btree index. + */ +IndexBuildResult * +btbuild(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; BTBuildState buildstate; @@ -155,7 +248,7 @@ btbuild(PG_FUNCTION_ARGS) result->heap_tuples = reltuples; result->index_tuples = buildstate.indtuples; - PG_RETURN_POINTER(result); + return result; } /* @@ -190,11 +283,10 @@ btbuildCallback(Relation index, /* * btbuildempty() -- build an empty btree index in the initialization fork */ -Datum -btbuildempty(PG_FUNCTION_ARGS) +void +btbuildempty(Relation index) { - Relation index = (Relation) PG_GETARG_POINTER(0); - Page metapage; + Page metapage; /* Construct metapage. */ metapage = (Page) palloc(BLCKSZ); @@ -214,8 +306,6 @@ btbuildempty(PG_FUNCTION_ARGS) * checkpoint may have moved the redo pointer past our xlog record. */ smgrimmedsync(index->rd_smgr, INIT_FORKNUM); - - PG_RETURN_VOID(); } /* @@ -224,15 +314,11 @@ btbuildempty(PG_FUNCTION_ARGS) * Descend the tree recursively, find the appropriate location for our * new tuple, and put it there. */ -Datum -btinsert(PG_FUNCTION_ARGS) +bool +btinsert(Relation rel, Datum *values, bool *isnull, + ItemPointer ht_ctid, Relation heapRel, + IndexUniqueCheck checkUnique) { - Relation rel = (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); - Relation heapRel = (Relation) PG_GETARG_POINTER(4); - IndexUniqueCheck checkUnique = (IndexUniqueCheck) PG_GETARG_INT32(5); bool result; IndexTuple itup; @@ -244,17 +330,15 @@ btinsert(PG_FUNCTION_ARGS) pfree(itup); - PG_RETURN_BOOL(result); + return result; } /* * btgettuple() -- Get the next tuple in the scan. */ -Datum -btgettuple(PG_FUNCTION_ARGS) +bool +btgettuple(IndexScanDesc scan, ScanDirection dir) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1); BTScanOpaque so = (BTScanOpaque) scan->opaque; bool res; @@ -270,7 +354,7 @@ btgettuple(PG_FUNCTION_ARGS) { /* punt if we have any unsatisfiable array keys */ if (so->numArrayKeys < 0) - PG_RETURN_BOOL(false); + return false; _bt_start_array_keys(scan, dir); } @@ -320,17 +404,15 @@ btgettuple(PG_FUNCTION_ARGS) /* ... otherwise see if we have more array keys to deal with */ } while (so->numArrayKeys && _bt_advance_array_keys(scan, dir)); - PG_RETURN_BOOL(res); + return res; } /* * btgetbitmap() -- gets all matching tuples, and adds them to a bitmap */ -Datum -btgetbitmap(PG_FUNCTION_ARGS) +int64 +btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1); BTScanOpaque so = (BTScanOpaque) scan->opaque; int64 ntids = 0; ItemPointer heapTid; @@ -342,7 +424,7 @@ btgetbitmap(PG_FUNCTION_ARGS) { /* punt if we have any unsatisfiable array keys */ if (so->numArrayKeys < 0) - PG_RETURN_INT64(ntids); + return ntids; _bt_start_array_keys(scan, ForwardScanDirection); } @@ -380,18 +462,15 @@ btgetbitmap(PG_FUNCTION_ARGS) /* Now see if we have more array keys to deal with */ } while (so->numArrayKeys && _bt_advance_array_keys(scan, ForwardScanDirection)); - PG_RETURN_INT64(ntids); + return ntids; } /* * btbeginscan() -- start a scan on a btree index */ -Datum -btbeginscan(PG_FUNCTION_ARGS) +IndexScanDesc +btbeginscan(Relation rel, int nkeys, int norderbys) { - Relation rel = (Relation) PG_GETARG_POINTER(0); - int nkeys = PG_GETARG_INT32(1); - int norderbys = PG_GETARG_INT32(2); IndexScanDesc scan; BTScanOpaque so; @@ -429,19 +508,16 @@ btbeginscan(PG_FUNCTION_ARGS) scan->opaque = so; - PG_RETURN_POINTER(scan); + return scan; } /* * btrescan() -- rescan an index relation */ -Datum -btrescan(PG_FUNCTION_ARGS) +void +btrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, + ScanKey orderbys, int norderbys) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1); - - /* remaining arguments are ignored */ BTScanOpaque so = (BTScanOpaque) scan->opaque; /* we aren't holding any read locks, but gotta drop the pins */ @@ -492,17 +568,14 @@ btrescan(PG_FUNCTION_ARGS) /* If any keys are SK_SEARCHARRAY type, set up array-key info */ _bt_preprocess_array_keys(scan); - - PG_RETURN_VOID(); } /* * btendscan() -- close down a scan */ -Datum -btendscan(PG_FUNCTION_ARGS) +void +btendscan(IndexScanDesc scan) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); BTScanOpaque so = (BTScanOpaque) scan->opaque; /* we aren't holding any read locks, but gotta drop the pins */ @@ -531,17 +604,14 @@ btendscan(PG_FUNCTION_ARGS) pfree(so->currTuples); /* so->markTuples should not be pfree'd, see btrescan */ pfree(so); - - PG_RETURN_VOID(); } /* * btmarkpos() -- save current scan position */ -Datum -btmarkpos(PG_FUNCTION_ARGS) +void +btmarkpos(IndexScanDesc scan) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); BTScanOpaque so = (BTScanOpaque) scan->opaque; /* There may be an old mark with a pin (but no lock). */ @@ -564,17 +634,14 @@ btmarkpos(PG_FUNCTION_ARGS) /* Also record the current positions of any array keys */ if (so->numArrayKeys) _bt_mark_array_keys(scan); - - PG_RETURN_VOID(); } /* * btrestrpos() -- restore scan to last saved position */ -Datum -btrestrpos(PG_FUNCTION_ARGS) +void +btrestrpos(IndexScanDesc scan) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); BTScanOpaque so = (BTScanOpaque) scan->opaque; /* Restore the marked positions of any array keys */ @@ -642,8 +709,6 @@ btrestrpos(PG_FUNCTION_ARGS) else BTScanPosInvalidate(so->currPos); } - - PG_RETURN_VOID(); } /* @@ -653,13 +718,10 @@ btrestrpos(PG_FUNCTION_ARGS) * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ -Datum -btbulkdelete(PG_FUNCTION_ARGS) +IndexBulkDeleteResult * +btbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, void *callback_state) { - IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0); - IndexBulkDeleteResult *volatile 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; BTCycleId cycleid; @@ -678,7 +740,7 @@ btbulkdelete(PG_FUNCTION_ARGS) PG_END_ENSURE_ERROR_CLEANUP(_bt_end_vacuum_callback, PointerGetDatum(rel)); _bt_end_vacuum(rel); - PG_RETURN_POINTER(stats); + return stats; } /* @@ -686,15 +748,12 @@ btbulkdelete(PG_FUNCTION_ARGS) * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ -Datum -btvacuumcleanup(PG_FUNCTION_ARGS) +IndexBulkDeleteResult * +btvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) { - IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0); - IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1); - /* No-op in ANALYZE ONLY mode */ if (info->analyze_only) - PG_RETURN_POINTER(stats); + return stats; /* * If btbulkdelete was called, we need not do anything, just return the @@ -726,7 +785,7 @@ btvacuumcleanup(PG_FUNCTION_ARGS) stats->num_index_tuples = info->num_heap_tuples; } - PG_RETURN_POINTER(stats); + return stats; } /* @@ -1127,8 +1186,8 @@ restart: * * btrees always do, so this is trivial. */ -Datum -btcanreturn(PG_FUNCTION_ARGS) +bool +btcanreturn(Relation index, int attno) { PG_RETURN_BOOL(true); } diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index 91331ba..2fec62d 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -2058,15 +2058,13 @@ BTreeShmemInit(void) Assert(found); } -Datum -btoptions(PG_FUNCTION_ARGS) +bytea * +btoptions(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_BTREE); if (result) - PG_RETURN_BYTEA_P(result); - PG_RETURN_NULL(); + return result; + return NULL; } diff --git a/src/backend/access/spgist/spginsert.c b/src/backend/access/spgist/spginsert.c index bceee8d..c95ae3d 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 8a0d909..1e73690 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,15 @@ 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 +220,26 @@ 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) +void +spgmarkpos(IndexScanDesc scan) { elog(ERROR, "SPGiST does not support mark/restore"); - PG_RETURN_VOID(); } -Datum -spgrestrpos(PG_FUNCTION_ARGS) +void +spgrestrpos(IndexScanDesc scan) { elog(ERROR, "SPGiST does not support mark/restore"); - PG_RETURN_VOID(); } /* @@ -571,11 +560,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 +573,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 +597,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 +617,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 +636,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 f38287c..3de4494 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -24,8 +24,104 @@ #include "storage/indexfsm.h" #include "storage/lmgr.h" #include "utils/lsyscache.h" +#include "utils/selfuncs.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 = 0; + + amroutine->aminsert = spginsert; + amroutine->ambeginscan = spgbeginscan; + amroutine->amgettuple = spggettuple; + amroutine->amgetbitmap = spggetbitmap; + amroutine->amrescan = spgrescan; + amroutine->amendscan = spgendscan; + amroutine->ammarkpos = spgmarkpos; + amroutine->amrestrpos = spgrestrpos; + amroutine->ambuild = spgbuild; + amroutine->ambuildempty = spgbuildempty; + amroutine->ambulkdelete = spgbulkdelete; + amroutine->amvacuumcleanup = spgvacuumcleanup; + amroutine->amcanreturn = spgcanreturn; + amroutine->amcostestimate = spgcostestimate; + amroutine->amoptions = spgoptions; + amroutine->amvalidate = spgvalidate; + + PG_RETURN_POINTER(amroutine); +} + +void +spgvalidate(OpClassInfo *opclass) +{ + ListCell *l; + bool procsPresent[SPGISTNProc]; + int i; + + memset(procsPresent, 0, sizeof(procsPresent)); + + foreach(l, opclass->procedures) + { + OpFamilyMember *proc = (OpFamilyMember *) lfirst(l); + + if (proc->lefttype != opclass->intype || + proc->righttype != opclass->intype) + continue; + + if (proc->number < 1 || proc->number > SPGISTNProc) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("Invalid support number for SP-GiST: %u", + proc->number))); + + if (procsPresent[proc->number - 1]) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("SP-GiST support number %u was defined more than once", + proc->number))); + + procsPresent[proc->number - 1] = true; + } + + for (i = 0; i < SPGISTNProc; i++) + { + if (!procsPresent[i]) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("SP-GiST support number %u is required", i + 1))); + } + + foreach(l, opclass->operators) + { + OpFamilyMember *opr = (OpFamilyMember *) lfirst(l); + + if (OidIsValid(opr->sortfamily)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("SP-GiST doesn't support order by operators"))); + } +} + /* Fill in a SpGistTypeDesc struct with info about the specified data type */ static void fillTypeDesc(SpGistTypeDesc *desc, Oid type) @@ -489,18 +585,16 @@ 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 (bytea *)result; + return NULL; } /* diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c index 06c0b0a..c3856a1 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/catalog/index.c b/src/backend/catalog/index.c index e59b163..8ace03d 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -23,6 +23,7 @@ #include +#include "access/amapi.h" #include "access/multixact.h" #include "access/relscan.h" #include "access/sysattr.h" @@ -277,20 +278,14 @@ ConstructTupleDescriptor(Relation heapRelation, int numatts = indexInfo->ii_NumIndexAttrs; ListCell *colnames_item = list_head(indexColNames); ListCell *indexpr_item = list_head(indexInfo->ii_Expressions); - HeapTuple amtuple; - Form_pg_am amform; + IndexAmRoutine *amroutine; TupleDesc heapTupDesc; TupleDesc indexTupDesc; int natts; /* #atts in heap rel --- for error checks */ int i; /* We need access to the index AM's pg_am tuple */ - amtuple = SearchSysCache1(AMOID, - ObjectIdGetDatum(accessMethodObjectId)); - if (!HeapTupleIsValid(amtuple)) - elog(ERROR, "cache lookup failed for access method %u", - accessMethodObjectId); - amform = (Form_pg_am) GETSTRUCT(amtuple); + amroutine = GetIndexAmRoutine(accessMethodObjectId); /* ... and to the table's tuple descriptor */ heapTupDesc = RelationGetDescr(heapRelation); @@ -437,7 +432,7 @@ ConstructTupleDescriptor(Relation heapRelation, if (OidIsValid(opclassTup->opckeytype)) keyType = opclassTup->opckeytype; else - keyType = amform->amkeytype; + keyType = amroutine->amkeytype; ReleaseSysCache(tuple); if (OidIsValid(keyType) && keyType != to->atttypid) @@ -459,8 +454,6 @@ ConstructTupleDescriptor(Relation heapRelation, } } - ReleaseSysCache(amtuple); - return indexTupDesc; } @@ -1988,7 +1981,6 @@ index_build(Relation heapRelation, bool isprimary, bool isreindex) { - RegProcedure procedure; IndexBuildResult *stats; Oid save_userid; int save_sec_context; @@ -1998,10 +1990,8 @@ index_build(Relation heapRelation, * sanity checks */ Assert(RelationIsValid(indexRelation)); - Assert(PointerIsValid(indexRelation->rd_am)); - - procedure = indexRelation->rd_am->ambuild; - Assert(RegProcedureIsValid(procedure)); + Assert(PointerIsValid(indexRelation->amroutine)); + Assert(PointerIsValid(indexRelation->amroutine->ambuild)); ereport(DEBUG1, (errmsg("building index \"%s\" on table \"%s\"", @@ -2021,11 +2011,8 @@ index_build(Relation heapRelation, /* * Call the access method's build procedure */ - stats = (IndexBuildResult *) - DatumGetPointer(OidFunctionCall3(procedure, - PointerGetDatum(heapRelation), - PointerGetDatum(indexRelation), - PointerGetDatum(indexInfo))); + stats = indexRelation->amroutine->ambuild(heapRelation, indexRelation, + indexInfo); Assert(PointerIsValid(stats)); /* @@ -2038,11 +2025,9 @@ index_build(Relation heapRelation, if (indexRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED && !smgrexists(indexRelation->rd_smgr, INIT_FORKNUM)) { - RegProcedure ambuildempty = indexRelation->rd_am->ambuildempty; - RelationOpenSmgr(indexRelation); smgrcreate(indexRelation->rd_smgr, INIT_FORKNUM, false); - OidFunctionCall1(ambuildempty, PointerGetDatum(indexRelation)); + indexRelation->amroutine->ambuildempty(indexRelation); } /* diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index 7ab4874..7a7fd95 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -17,6 +17,7 @@ */ #include "postgres.h" +#include "access/amapi.h" #include "access/multixact.h" #include "access/relscan.h" #include "access/rewriteheap.h" @@ -433,7 +434,7 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck, LOCKMOD RelationGetRelationName(OldHeap)))); /* Index AM must allow clustering */ - if (!OldIndex->rd_am->amclusterable) + if (!OldIndex->amroutine->amclusterable) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot cluster on index \"%s\" because access method does not support clustering", diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index b450bcf..9951993 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -15,6 +15,7 @@ #include "postgres.h" +#include "access/amapi.h" #include "access/htup_details.h" #include "access/reloptions.h" #include "access/xact.h" @@ -125,6 +126,7 @@ CheckIndexCompatible(Oid oldId, HeapTuple tuple; Form_pg_index indexForm; Form_pg_am accessMethodForm; + IndexAmRoutine *amRoutine; bool amcanorder; int16 *coloptions; IndexInfo *indexInfo; @@ -160,7 +162,9 @@ CheckIndexCompatible(Oid oldId, accessMethodName))); accessMethodId = HeapTupleGetOid(tuple); accessMethodForm = (Form_pg_am) GETSTRUCT(tuple); - amcanorder = accessMethodForm->amcanorder; + amRoutine = (IndexAmRoutine *)DatumGetPointer( + OidFunctionCall0(accessMethodForm->amhandler)); + amcanorder = amRoutine->amcanorder; ReleaseSysCache(tuple); /* @@ -315,8 +319,9 @@ DefineIndex(Oid relationId, Relation indexRelation; HeapTuple tuple; Form_pg_am accessMethodForm; + IndexAmRoutine *amRoutine; bool amcanorder; - RegProcedure amoptions; + amoptions_function amoptions; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -489,30 +494,32 @@ DefineIndex(Oid relationId, } accessMethodId = HeapTupleGetOid(tuple); accessMethodForm = (Form_pg_am) GETSTRUCT(tuple); + amRoutine = (IndexAmRoutine *)DatumGetPointer( + OidFunctionCall0(accessMethodForm->amhandler)); if (strcmp(accessMethodName, "hash") == 0 && RelationNeedsWAL(rel)) ereport(WARNING, (errmsg("hash indexes are not WAL-logged and their use is discouraged"))); - if (stmt->unique && !accessMethodForm->amcanunique) + if (stmt->unique && !amRoutine->amcanunique) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("access method \"%s\" does not support unique indexes", accessMethodName))); - if (numberOfAttributes > 1 && !accessMethodForm->amcanmulticol) + if (numberOfAttributes > 1 && !amRoutine->amcanmulticol) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("access method \"%s\" does not support multicolumn indexes", accessMethodName))); - if (stmt->excludeOpNames && !OidIsValid(accessMethodForm->amgettuple)) + if (stmt->excludeOpNames && !OidIsValid(amRoutine->amgettuple)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("access method \"%s\" does not support exclusion constraints", accessMethodName))); - amcanorder = accessMethodForm->amcanorder; - amoptions = accessMethodForm->amoptions; + amcanorder = amRoutine->amcanorder; + amoptions = amRoutine->amoptions; ReleaseSysCache(tuple); diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c index 3375f10..672a4a2 100644 --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -42,6 +42,7 @@ #include "parser/parse_oper.h" #include "parser/parse_type.h" #include "utils/builtins.h" +#include "utils/catcache.h" #include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/rel.h" @@ -334,13 +335,14 @@ DefineOpClass(CreateOpClassStmt *stmt) ListCell *l; Relation rel; HeapTuple tup; - Form_pg_am pg_am; Datum values[Natts_pg_opclass]; bool nulls[Natts_pg_opclass]; AclResult aclresult; NameData opcName; ObjectAddress myself, referenced; + IndexAmRoutine *amroutine; + OpClassInfo opclassinfo; /* Convert list of names to a name and namespace */ namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname, @@ -361,13 +363,15 @@ DefineOpClass(CreateOpClassStmt *stmt) stmt->amname))); amoid = HeapTupleGetOid(tup); - pg_am = (Form_pg_am) GETSTRUCT(tup); - maxOpNumber = pg_am->amstrategies; + + amroutine = GetIndexAmRoutine(amoid); + + maxOpNumber = amroutine->amstrategies; /* if amstrategies is zero, just enforce that op numbers fit in int16 */ if (maxOpNumber <= 0) maxOpNumber = SHRT_MAX; - maxProcNumber = pg_am->amsupport; - amstorage = pg_am->amstorage; + maxProcNumber = amroutine->amsupport; + amstorage = amroutine->amstorage; /* XXX Should we make any privilege check against the AM? */ @@ -582,6 +586,12 @@ DefineOpClass(CreateOpClassStmt *stmt) stmt->amname))); } + opclassinfo.intype = typeoid; + opclassinfo.keytype = storageoid; + opclassinfo.procedures = procedures; + opclassinfo.operators = operators; + amroutine->amvalidate(&opclassinfo); + rel = heap_open(OperatorClassRelationId, RowExclusiveLock); /* @@ -718,6 +728,90 @@ DefineOpClass(CreateOpClassStmt *stmt) return myself; } +/* + * Collect opfamily information for opclass validation. + */ +static void +getOpFamilyInfo(OpClassInfo *opclassinfo, Oid opfamilyoid) +{ + CatCList *catlist; + int i; + + opclassinfo->operators = NIL; + opclassinfo->procedures = NIL; + + /* Find operators */ + catlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid); + for (i = 0; i < catlist->n_members; i++) + { + HeapTuple oprtup = &catlist->members[i]->tuple; + Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup); + OpFamilyMember *opmember = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember)); + + opmember->object = oprform->amopopr; + opmember->number = oprform->amopstrategy; + opmember->lefttype = oprform->amoplefttype; + opmember->righttype = oprform->amoprighttype; + opmember->sortfamily = oprform->amopsortfamily; + + opclassinfo->operators = lappend(opclassinfo->operators, opmember); + } + ReleaseCatCacheList(catlist); + + /* Find support functions */ + catlist = SearchSysCacheList1(AMPROCNUM, opfamilyoid); + for (i = 0; i < catlist->n_members; i++) + { + HeapTuple proctup = &catlist->members[i]->tuple; + Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup); + OpFamilyMember *procmember = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember)); + + procmember->object = procform->amproc; + procmember->number = procform->amprocnum; + procmember->lefttype = procform->amproclefttype; + procmember->righttype = procform->amprocrighttype; + + opclassinfo->procedures = lappend(opclassinfo->procedures, procmember); + } + ReleaseCatCacheList(catlist); +} + +/* + * Ask access method to validate given opclass. + */ +Datum +amvalidate(PG_FUNCTION_ARGS) +{ + OpClassInfo opclassinfo; + HeapTuple classtup; + Form_pg_opclass classform; + Oid opclassoid = PG_GETARG_OID(0), + opfamilyoid, + amoid; + IndexAmRoutine *amroutine; + + classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid)); + + if (!HeapTupleIsValid(classtup)) + elog(ERROR, "cache lookup failed for operator class %u", opclassoid); + + classform = (Form_pg_opclass) GETSTRUCT(classtup); + opclassinfo.intype = classform->opcintype; + opclassinfo.keytype = classform->opckeytype; + opfamilyoid = classform->opcfamily; + amoid = classform->opcmethod; + + ReleaseSysCache(classtup); + + getOpFamilyInfo(&opclassinfo, opfamilyoid); + + amroutine = GetIndexAmRoutine(amoid); + + amroutine->amvalidate(&opclassinfo); + + PG_RETURN_BOOL(true); +} + /* * DefineOpFamily @@ -776,7 +870,7 @@ AlterOpFamily(AlterOpFamilyStmt *stmt) int maxOpNumber, /* amstrategies value */ maxProcNumber; /* amsupport value */ HeapTuple tup; - Form_pg_am pg_am; + IndexAmRoutine *amroutine; /* Get necessary info about access method */ tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname)); @@ -787,16 +881,16 @@ AlterOpFamily(AlterOpFamilyStmt *stmt) stmt->amname))); amoid = HeapTupleGetOid(tup); - pg_am = (Form_pg_am) GETSTRUCT(tup); - maxOpNumber = pg_am->amstrategies; + amroutine = GetIndexAmRoutine(amoid); + ReleaseSysCache(tup); + maxOpNumber = amroutine->amstrategies; /* if amstrategies is zero, just enforce that op numbers fit in int16 */ if (maxOpNumber <= 0) maxOpNumber = SHRT_MAX; - maxProcNumber = pg_am->amsupport; + maxProcNumber = amroutine->amsupport; /* XXX Should we make any privilege check against the AM? */ - ReleaseSysCache(tup); /* Look up the opfamily */ opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false); @@ -1099,21 +1193,15 @@ assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid) * the family has been created but not yet populated with the required * operators.) */ - HeapTuple amtup; - Form_pg_am pg_am; + IndexAmRoutine *amroutine; - amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid)); - if (amtup == NULL) - elog(ERROR, "cache lookup failed for access method %u", amoid); - pg_am = (Form_pg_am) GETSTRUCT(amtup); + amroutine = GetIndexAmRoutine(amoid); - if (!pg_am->amcanorderbyop) + if (!amroutine->amcanorderbyop) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("access method \"%s\" does not support ordering operators", - NameStr(pg_am->amname)))); - - ReleaseSysCache(amtup); + get_am_name(amoid)))); } else { diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 126b119..c4cc9b4 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -9363,7 +9363,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, (void) view_reloptions(newOptions, true); break; case RELKIND_INDEX: - (void) index_reloptions(rel->rd_am->amoptions, newOptions, true); + (void) index_reloptions(rel->amroutine->amoptions, newOptions, true); break; default: ereport(ERROR, @@ -10954,7 +10954,7 @@ ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode RelationGetRelationName(indexRel), RelationGetRelationName(rel)))); /* The AM must support uniqueness, and the index must in fact be unique. */ - if (!indexRel->rd_am->amcanunique || !indexRel->rd_index->indisunique) + if (!indexRel->amroutine->amcanunique || !indexRel->rd_index->indisunique) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot use non-unique index \"%s\" as replica identity", diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c index 93e1e9a..13fc2e2 100644 --- a/src/backend/executor/execAmi.c +++ b/src/backend/executor/execAmi.c @@ -12,6 +12,7 @@ */ #include "postgres.h" +#include "access/amapi.h" #include "access/htup_details.h" #include "executor/execdebug.h" #include "executor/nodeAgg.h" @@ -528,6 +529,7 @@ IndexSupportsBackwardScan(Oid indexid) HeapTuple ht_am; Form_pg_class idxrelrec; Form_pg_am amrec; + IndexAmRoutine *amroutine; /* Fetch the pg_class tuple of the index relation */ ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexid)); @@ -541,9 +543,11 @@ IndexSupportsBackwardScan(Oid indexid) elog(ERROR, "cache lookup failed for access method %u", idxrelrec->relam); amrec = (Form_pg_am) GETSTRUCT(ht_am); + amroutine = (IndexAmRoutine *)DatumGetPointer(OidFunctionCall0(amrec->amhandler)); - result = amrec->amcanbackward; + result = amroutine->amcanbackward; + pfree(amroutine); ReleaseSysCache(ht_idxrel); ReleaseSysCache(ht_am); diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index c0f14db..2de0579 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -1436,7 +1436,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Assert(rightop != NULL); - if (index->rd_am->amsearcharray) + if (index->amroutine->amsearcharray) { /* Index AM will handle this like a simple operator */ flags |= SK_SEARCHARRAY; diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index d107d76..6853899 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -368,14 +368,8 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count) * the fraction of main-table tuples we will have to retrieve) and its * correlation to the main-table tuple order. */ - OidFunctionCall7(index->amcostestimate, - PointerGetDatum(root), - PointerGetDatum(path), - Float8GetDatum(loop_count), - PointerGetDatum(&indexStartupCost), - PointerGetDatum(&indexTotalCost), - PointerGetDatum(&indexSelectivity), - PointerGetDatum(&indexCorrelation)); + index->amroutine->amcostestimate(root, path, loop_count, &indexStartupCost, + &indexTotalCost, &indexSelectivity, &indexCorrelation); /* * Save amcostestimate's results for possible use in bitmap scan planning. diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 9442e5f..d3d5d43 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -223,13 +223,13 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, } info->relam = indexRelation->rd_rel->relam; - info->amcostestimate = indexRelation->rd_am->amcostestimate; - info->amcanorderbyop = indexRelation->rd_am->amcanorderbyop; - info->amoptionalkey = indexRelation->rd_am->amoptionalkey; - info->amsearcharray = indexRelation->rd_am->amsearcharray; - info->amsearchnulls = indexRelation->rd_am->amsearchnulls; - info->amhasgettuple = OidIsValid(indexRelation->rd_am->amgettuple); - info->amhasgetbitmap = OidIsValid(indexRelation->rd_am->amgetbitmap); + info->amroutine = indexRelation->amroutine; + info->amcanorderbyop = indexRelation->amroutine->amcanorderbyop; + info->amoptionalkey = indexRelation->amroutine->amoptionalkey; + info->amsearcharray = indexRelation->amroutine->amsearcharray; + info->amsearchnulls = indexRelation->amroutine->amsearchnulls; + info->amhasgettuple = OidIsValid(indexRelation->amroutine->amgettuple); + info->amhasgetbitmap = OidIsValid(indexRelation->amroutine->amgetbitmap); /* * Fetch the ordering information for the index, if any. @@ -240,7 +240,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, * If it's a btree index, we can use its opfamily OIDs * directly as the sort ordering opfamily OIDs. */ - Assert(indexRelation->rd_am->amcanorder); + Assert(indexRelation->amroutine->amcanorder); info->sortopfamily = info->opfamily; info->reverse_sort = (bool *) palloc(sizeof(bool) * ncolumns); @@ -254,7 +254,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0; } } - else if (indexRelation->rd_am->amcanorder) + else if (indexRelation->amroutine->amcanorder) { /* * Otherwise, identify the corresponding btree opfamilies by diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 16d40c7..0031511 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -26,6 +26,7 @@ #include "postgres.h" +#include "access/amapi.h" #include "access/htup_details.h" #include "access/reloptions.h" #include "catalog/dependency.h" @@ -1258,7 +1259,7 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx, iparam->nulls_ordering = SORTBY_NULLS_DEFAULT; /* Adjust options if necessary */ - if (amrec->amcanorder) + if (source_idx->amroutine->amcanorder) { /* * If it supports sort ordering, copy DESC and NULLS opts. Don't diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 94e748e..63d6f0d 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -2420,7 +2420,7 @@ extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc) ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW || ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE); - relopts = extractRelOptions(tup, pg_class_desc, InvalidOid); + relopts = extractRelOptions(tup, pg_class_desc, NULL); if (relopts == NULL) return NULL; diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c index 5b809aa..bdd451d 100644 --- a/src/backend/utils/adt/pseudotypes.c +++ b/src/backend/utils/adt/pseudotypes.c @@ -401,6 +401,33 @@ tsm_handler_out(PG_FUNCTION_ARGS) /* + * index_am_handler_in - input routine for pseudo-type INDEX_AM_HANDLER. + */ +Datum +index_am_handler_in(PG_FUNCTION_ARGS) +{ + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot accept a value of type index_am_handler"))); + + PG_RETURN_VOID(); /* keep compiler quiet */ +} + +/* + * index_am_handler_out - output routine for pseudo-type INDEX_AM_HANDLER. + */ +Datum +index_am_handler_out(PG_FUNCTION_ARGS) +{ + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot display a value of type index_am_handler"))); + + PG_RETURN_VOID(); /* keep compiler quiet */ +} + + +/* * internal_in - input routine for pseudo-type INTERNAL. */ Datum diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 51391f6..7d9577a 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -19,6 +19,7 @@ #include #include +#include "access/amapi.h" #include "access/htup_details.h" #include "access/sysattr.h" #include "catalog/dependency.h" @@ -1167,6 +1168,7 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, if (!attrsOnly && (!colno || colno == keyno + 1)) { Oid indcoll; + IndexAmRoutine *amroutine; /* Add collation, if not default for column */ indcoll = indcollation->values[keyno]; @@ -1177,8 +1179,11 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, /* Add the operator class name, if not default */ get_opclass_name(indclass->values[keyno], keycoltype, &buf); + amroutine = (IndexAmRoutine *)DatumGetPointer( + OidFunctionCall0(amrec->amhandler)); + /* Add options if relevant */ - if (amrec->amcanorder) + if (amroutine->amcanorder) { /* if it supports sort ordering, report DESC and NULLS opts */ if (opt & INDOPTION_DESC) diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 37fad86..9a83e10 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -6443,16 +6443,11 @@ add_predicate_to_quals(IndexOptInfo *index, List *indexQuals) } -Datum -btcostestimate(PG_FUNCTION_ARGS) +void +btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, + Cost *indexStartupCost, Cost *indexTotalCost, + Selectivity *indexSelectivity, double *indexCorrelation) { - PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0); - IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1); - double loop_count = PG_GETARG_FLOAT8(2); - Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3); - Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4); - Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5); - double *indexCorrelation = (double *) PG_GETARG_POINTER(6); IndexOptInfo *index = path->indexinfo; List *qinfos; GenericCosts costs; @@ -6741,20 +6736,13 @@ btcostestimate(PG_FUNCTION_ARGS) *indexTotalCost = costs.indexTotalCost; *indexSelectivity = costs.indexSelectivity; *indexCorrelation = costs.indexCorrelation; - - PG_RETURN_VOID(); } -Datum -hashcostestimate(PG_FUNCTION_ARGS) +void +hashcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, + Cost *indexStartupCost, Cost *indexTotalCost, + Selectivity *indexSelectivity, double *indexCorrelation) { - PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0); - IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1); - double loop_count = PG_GETARG_FLOAT8(2); - Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3); - Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4); - Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5); - double *indexCorrelation = (double *) PG_GETARG_POINTER(6); List *qinfos; GenericCosts costs; @@ -6794,20 +6782,13 @@ hashcostestimate(PG_FUNCTION_ARGS) *indexTotalCost = costs.indexTotalCost; *indexSelectivity = costs.indexSelectivity; *indexCorrelation = costs.indexCorrelation; - - PG_RETURN_VOID(); } -Datum -gistcostestimate(PG_FUNCTION_ARGS) +void +gistcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, + Cost *indexStartupCost, Cost *indexTotalCost, + Selectivity *indexSelectivity, double *indexCorrelation) { - PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0); - IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1); - double loop_count = PG_GETARG_FLOAT8(2); - Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3); - Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4); - Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5); - double *indexCorrelation = (double *) PG_GETARG_POINTER(6); IndexOptInfo *index = path->indexinfo; List *qinfos; GenericCosts costs; @@ -6860,20 +6841,13 @@ gistcostestimate(PG_FUNCTION_ARGS) *indexTotalCost = costs.indexTotalCost; *indexSelectivity = costs.indexSelectivity; *indexCorrelation = costs.indexCorrelation; - - PG_RETURN_VOID(); } -Datum -spgcostestimate(PG_FUNCTION_ARGS) +void +spgcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, + Cost *indexStartupCost, Cost *indexTotalCost, + Selectivity *indexSelectivity, double *indexCorrelation) { - PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0); - IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1); - double loop_count = PG_GETARG_FLOAT8(2); - Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3); - Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4); - Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5); - double *indexCorrelation = (double *) PG_GETARG_POINTER(6); IndexOptInfo *index = path->indexinfo; List *qinfos; GenericCosts costs; @@ -6926,8 +6900,6 @@ spgcostestimate(PG_FUNCTION_ARGS) *indexTotalCost = costs.indexTotalCost; *indexSelectivity = costs.indexSelectivity; *indexCorrelation = costs.indexCorrelation; - - PG_RETURN_VOID(); } @@ -7222,16 +7194,11 @@ gincost_scalararrayopexpr(PlannerInfo *root, /* * GIN has search behavior completely different from other index types */ -Datum -gincostestimate(PG_FUNCTION_ARGS) +void +gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count, + Cost *indexStartupCost, Cost *indexTotalCost, + Selectivity *indexSelectivity, double *indexCorrelation) { - PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0); - IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1); - double loop_count = PG_GETARG_FLOAT8(2); - Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3); - Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4); - Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5); - double *indexCorrelation = (double *) PG_GETARG_POINTER(6); IndexOptInfo *index = path->indexinfo; List *indexQuals = path->indexquals; List *indexOrderBys = path->indexorderbys; @@ -7382,7 +7349,7 @@ gincostestimate(PG_FUNCTION_ARGS) *indexStartupCost = 0; *indexTotalCost = 0; *indexSelectivity = 0; - PG_RETURN_VOID(); + return; } if (counts.haveFullScan || indexQuals == NIL) @@ -7504,23 +7471,16 @@ gincostestimate(PG_FUNCTION_ARGS) *indexStartupCost += qual_arg_cost; *indexTotalCost += qual_arg_cost; *indexTotalCost += (numTuples * *indexSelectivity) * (cpu_index_tuple_cost + qual_op_cost); - - PG_RETURN_VOID(); } /* * BRIN has search behavior completely different from other index types */ -Datum -brincostestimate(PG_FUNCTION_ARGS) +void +brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count, + Cost *indexStartupCost, Cost *indexTotalCost, + Selectivity *indexSelectivity, double *indexCorrelation) { - PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0); - IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1); - double loop_count = PG_GETARG_FLOAT8(2); - Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3); - Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4); - Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5); - double *indexCorrelation = (double *) PG_GETARG_POINTER(6); IndexOptInfo *index = path->indexinfo; List *indexQuals = path->indexquals; List *indexOrderBys = path->indexorderbys; @@ -7573,6 +7533,4 @@ brincostestimate(PG_FUNCTION_ARGS) *indexTotalCost += (numTuples * *indexSelectivity) * (cpu_index_tuple_cost + qual_op_cost); /* XXX what about pages_per_range? */ - - PG_RETURN_VOID(); } diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 9c3d096..9febc95 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -445,7 +445,7 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple) options = extractRelOptions(tuple, GetPgClassDescriptor(), relation->rd_rel->relkind == RELKIND_INDEX ? - relation->rd_am->amoptions : InvalidOid); + relation->amroutine->amoptions : NULL); /* * Copy parsed data into CacheMemoryContext. To guard against the @@ -1160,13 +1160,58 @@ RelationInitPhysicalAddr(Relation relation) } /* + * Get IndexAmRoutine structure from access method oid. + */ +IndexAmRoutine * +GetIndexAmRoutine(Oid amoid) +{ + IndexAmRoutine *result; + HeapTuple tuple; + regproc amhandler; + + tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for access method %u", + amoid); + amhandler = ((Form_pg_am)GETSTRUCT(tuple))->amhandler; + + if (!RegProcedureIsValid(amhandler)) + elog(ERROR, "invalid %u regproc", amhandler); + + result = (IndexAmRoutine *)DatumGetPointer(OidFunctionCall0(amhandler)); + + if (result == NULL || !IsA(result, IndexAmRoutine)) + elog(ERROR, "index access method handler function %u did not return an IndexAmRoutine struct", + amhandler); + + ReleaseSysCache(tuple); + + return result; +} + +/* + * Initialize IndexAmRoutine for relation. + */ +void +InitIndexAmRoutine(Relation relation) +{ + IndexAmRoutine *result, *tmp; + + result = (IndexAmRoutine *)MemoryContextAlloc(CacheMemoryContext, + sizeof(IndexAmRoutine)); + tmp = (IndexAmRoutine *)DatumGetPointer( + OidFunctionCall0(relation->rd_am->amhandler)); + memcpy(result, tmp, sizeof(IndexAmRoutine)); + relation->amroutine = result; +} + +/* * Initialize index-access-method support data for an index relation */ void RelationInitIndexAccessInfo(Relation relation) { HeapTuple tuple; - Form_pg_am aform; Datum indcollDatum; Datum indclassDatum; Datum indoptionDatum; @@ -1178,6 +1223,7 @@ RelationInitIndexAccessInfo(Relation relation) MemoryContext oldcontext; int natts; uint16 amsupport; + Form_pg_am aform; /* * Make a copy of the pg_index entry for the index. Since pg_index @@ -1202,16 +1248,18 @@ RelationInitIndexAccessInfo(Relation relation) if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for access method %u", relation->rd_rel->relam); - aform = (Form_pg_am) MemoryContextAlloc(CacheMemoryContext, sizeof *aform); + aform = (Form_pg_am)MemoryContextAlloc(CacheMemoryContext, sizeof *aform); memcpy(aform, GETSTRUCT(tuple), sizeof *aform); ReleaseSysCache(tuple); relation->rd_am = aform; + InitIndexAmRoutine(relation); + natts = relation->rd_rel->relnatts; if (natts != relation->rd_index->indnatts) elog(ERROR, "relnatts disagrees with indnatts for index %u", RelationGetRelid(relation)); - amsupport = aform->amsupport; + amsupport = relation->amroutine->amsupport; /* * Make the private context to hold index access info. The reason we need @@ -4743,7 +4791,6 @@ load_relcache_init_file(bool shared) Oid *opfamily; Oid *opcintype; RegProcedure *support; - int nsupport; int16 *indoption; Oid *indcollation; @@ -4771,6 +4818,7 @@ load_relcache_init_file(bool shared) if (fread(am, 1, len, fp) != len) goto read_failed; rel->rd_am = am; + rel->amroutine = NULL; /* * prepare index info context --- parameters should match @@ -4832,12 +4880,13 @@ load_relcache_init_file(bool shared) rel->rd_indoption = indoption; + InitIndexAmRoutine(rel); + /* set up zeroed fmgr-info vectors */ rel->rd_aminfo = (RelationAmInfo *) MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo)); - nsupport = relform->relnatts * am->amsupport; rel->rd_supportinfo = (FmgrInfo *) - MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo)); + MemoryContextAllocZero(indexcxt, relform->relnatts * rel->amroutine->amsupport * sizeof(FmgrInfo)); } else { @@ -5106,7 +5155,7 @@ write_relcache_init_file(bool shared) /* next, write the vector of support procedure OIDs */ write_item(rel->rd_support, - relform->relnatts * (am->amsupport * sizeof(RegProcedure)), + relform->relnatts * (rel->amroutine->amsupport * sizeof(RegProcedure)), fp); /* next, write the vector of collation OIDs */ diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h new file mode 100644 index 0000000..2e0257a --- /dev/null +++ b/src/include/access/amapi.h @@ -0,0 +1,169 @@ +/*------------------------------------------------------------------------- + * + * amapi.h + * API for access methods + * + * Copyright (c) 2015, PostgreSQL Global Development Group + * + * src/include/access/amapi.h + * + *------------------------------------------------------------------------- + */ +#ifndef AMAPI_H +#define AMAPI_H + +#include "access/genam.h" +#include "catalog/opfam_internal.h" +#include "nodes/relation.h" + +/* + * Callback function signatures --- see indexam.sgml for more info. + */ + +/* "insert this tuple" function */ +typedef bool +(*aminsert_function) (Relation indexRelation, + Datum *values, + bool *isnull, + ItemPointer heap_tid, + Relation heapRelation, + IndexUniqueCheck checkUnique); + +/* "prepare for index scan" function */ +typedef IndexScanDesc +(*ambeginscan_function) (Relation indexRelation, + int nkeys, + int norderbys); + +/* "next valid tuple" function, or NULL */ +typedef bool +(*amgettuple_function) (IndexScanDesc scan, + ScanDirection direction); + +/* "fetch all valid tuples" function, or NULL */ +typedef int64 +(*amgetbitmap_function) (IndexScanDesc scan, + TIDBitmap *tbm); + +/* "(re)start index scan" function */ +typedef void +(*amrescan_function) (IndexScanDesc scan, + ScanKey keys, + int nkeys, + ScanKey orderbys, + int norderbys); + +/* "end index scan" function */ +typedef void +(*amendscan_function) (IndexScanDesc scan); + +/* "mark current scan position" function */ +typedef void +(*ammarkpos_function) (IndexScanDesc scan); + +/* "restore marked scan position" function */ +typedef void +(*amrestrpos_function) (IndexScanDesc scan); + +/* "build new index" function */ +typedef IndexBuildResult * +(*ambuild_function) (Relation heapRelation, + Relation indexRelation, + IndexInfo *indexInfo); + +/* "build empty index" function */ +typedef void +(*ambuildempty_function) (Relation indexRelation); + +/* bulk-delete function */ +typedef IndexBulkDeleteResult * +(*ambulkdelete_function) (IndexVacuumInfo *info, + IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, + void *callback_state); + +/* post-VACUUM cleanup function */ +typedef IndexBulkDeleteResult * +(*amvacuumcleanup_function) (IndexVacuumInfo *info, + IndexBulkDeleteResult *stats); + +/* can indexscan return IndexTuples? */ +typedef bool +(*amcanreturn_function) (Relation indexRelation, int attno); + +/* estimate cost of an indexscan */ +typedef void +(*amcostestimate_function) (PlannerInfo *root, + IndexPath *path, + double loop_count, + Cost *indexStartupCost, + Cost *indexTotalCost, + Selectivity *indexSelectivity, + double *indexCorrelation); + +/* parse AM-specific parameters */ +typedef bytea * +(*amoptions_function) (Datum reloptions, + bool validate); + +/* validate oplass */ +typedef void +(*amvalidate_function) (OpClassInfo *opclass); + + +struct IndexAmRoutine +{ + NodeTag type; + + /* + * Total number of strategies (operators) by which we can traverse/search + * this AM. Zero if AM does not have a fixed set of strategy assignments. + */ + int16 amstrategies; + /* total number of support functions that this AM uses */ + int16 amsupport; + /* does AM support order by column value? */ + bool amcanorder; + /* does AM support order by operator result? */ + bool amcanorderbyop; + /* does AM support backward scan? */ + bool amcanbackward; + /* does AM support UNIQUE indexes? */ + bool amcanunique; + /* does AM support multi-column indexes? */ + bool amcanmulticol; + /* can query omit key for the first column? */ + bool amoptionalkey; + /* can AM handle ScalarArrayOpExpr quals? */ + bool amsearcharray; + /* can AM search for NULL/NOT NULL entries? */ + bool amsearchnulls; + /* can storage type differ from column type? */ + bool amstorage; + /* does AM support cluster command? */ + bool amclusterable; + /* does AM handle predicate locks? */ + bool ampredlocks; + /* type of data in index, or InvalidOid */ + Oid amkeytype; + + /* interface functions */ + aminsert_function aminsert; + ambeginscan_function ambeginscan; + amgettuple_function amgettuple; + amgetbitmap_function amgetbitmap; + amrescan_function amrescan; + amendscan_function amendscan; + ammarkpos_function ammarkpos; + amrestrpos_function amrestrpos; + ambuild_function ambuild; + ambuildempty_function ambuildempty; + ambulkdelete_function ambulkdelete; + amvacuumcleanup_function amvacuumcleanup; + amcanreturn_function amcanreturn; + amcostestimate_function amcostestimate; + amoptions_function amoptions; + amvalidate_function amvalidate; +}; + +#endif /* AMAPI_H */ diff --git a/src/include/access/brin.h b/src/include/access/brin.h index e72fb2d..5ae5722 100644 --- a/src/include/access/brin.h +++ b/src/include/access/brin.h @@ -10,6 +10,7 @@ #ifndef BRIN_H #define BRIN_H +#include "access/amapi.h" #include "fmgr.h" #include "nodes/execnodes.h" #include "utils/relcache.h" @@ -18,19 +19,33 @@ /* * prototypes for functions in brin.c (external entry points for BRIN) */ -extern Datum brinbuild(PG_FUNCTION_ARGS); -extern Datum brinbuildempty(PG_FUNCTION_ARGS); -extern Datum brininsert(PG_FUNCTION_ARGS); -extern Datum brinbeginscan(PG_FUNCTION_ARGS); -extern Datum bringetbitmap(PG_FUNCTION_ARGS); -extern Datum brinrescan(PG_FUNCTION_ARGS); -extern Datum brinendscan(PG_FUNCTION_ARGS); -extern Datum brinmarkpos(PG_FUNCTION_ARGS); -extern Datum brinrestrpos(PG_FUNCTION_ARGS); -extern Datum brinbulkdelete(PG_FUNCTION_ARGS); -extern Datum brinvacuumcleanup(PG_FUNCTION_ARGS); -extern Datum brincostestimate(PG_FUNCTION_ARGS); -extern Datum brinoptions(PG_FUNCTION_ARGS); +extern Datum brinhandler(PG_FUNCTION_ARGS); +extern void brinvalidate(OpClassInfo *opclass); +extern IndexBuildResult *brinbuild(Relation heap, Relation index, + IndexInfo *indexInfo); +extern void brinbuildempty(Relation index); +extern bool brininsert(Relation idxRel, Datum *values, bool *nulls, + ItemPointer heaptid, Relation heapRel, + IndexUniqueCheck checkUnique); +extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys); +extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm); +extern void brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, + ScanKey orderbys, int norderbys); +extern void brinendscan(IndexScanDesc scan); +extern void brinmarkpos(IndexScanDesc scan); +extern void brinrestrpos(IndexScanDesc scan); +extern IndexBulkDeleteResult *brinbulkdelete(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, + void *callback_state); +extern IndexBulkDeleteResult *brinvacuumcleanup(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats); +extern void brincostestimate(PlannerInfo *root, IndexPath *path, + double loop_count, Cost *indexStartupCost, + Cost *indexTotalCost, + Selectivity *indexSelectivity, + double *indexCorrelation); +extern bytea *brinoptions(Datum reloptions, bool validate); /* * Storage type for BRIN's reloptions diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h index 6be199e..2f8fe17 100644 --- a/src/include/access/brin_internal.h +++ b/src/include/access/brin_internal.h @@ -72,6 +72,7 @@ typedef struct BrinDesc #define BRIN_PROCNUM_CONSISTENT 3 #define BRIN_PROCNUM_UNION 4 /* procedure numbers up to 10 are reserved for BRIN future expansion */ +#define BRIN_NPROC 15 #undef BRIN_DEBUG diff --git a/src/include/access/genam.h b/src/include/access/genam.h index d9d05a0..2f4ad91 100644 --- a/src/include/access/genam.h +++ b/src/include/access/genam.h @@ -111,7 +111,6 @@ typedef enum IndexUniqueCheck UNIQUE_CHECK_EXISTING /* Check if existing tuple is unique */ } IndexUniqueCheck; - /* * generalized index_ interface routines (in indexam.c) */ diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h index 5021887..a77d43f 100644 --- a/src/include/access/gin_private.h +++ b/src/include/access/gin_private.h @@ -10,7 +10,7 @@ #ifndef GIN_PRIVATE_H #define GIN_PRIVATE_H -#include "access/genam.h" +#include "access/amapi.h" #include "access/gin.h" #include "access/itup.h" #include "fmgr.h" @@ -593,7 +593,9 @@ typedef struct ginxlogDeleteListPages /* ginutil.c */ -extern Datum ginoptions(PG_FUNCTION_ARGS); +extern Datum ginhandler(PG_FUNCTION_ARGS); +extern void ginvalidate(OpClassInfo *opclass); +extern bytea *ginoptions(Datum reloptions, bool validate); extern void initGinState(GinState *state, Relation index); extern Buffer GinNewBuffer(Relation index); extern void GinInitBuffer(Buffer b, uint32 f); @@ -614,9 +616,12 @@ extern Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple, GinNullCategory *category); /* gininsert.c */ -extern Datum ginbuild(PG_FUNCTION_ARGS); -extern Datum ginbuildempty(PG_FUNCTION_ARGS); -extern Datum gininsert(PG_FUNCTION_ARGS); +extern IndexBuildResult *ginbuild(Relation heap, Relation index, + IndexInfo *indexInfo); +extern void ginbuildempty(Relation index); +extern bool gininsert(Relation index, Datum *values, bool *isnull, + ItemPointer ht_ctid, Relation heapRel, + IndexUniqueCheck checkUnique); extern void ginEntryInsert(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, @@ -867,23 +872,28 @@ typedef struct GinScanOpaqueData typedef GinScanOpaqueData *GinScanOpaque; -extern Datum ginbeginscan(PG_FUNCTION_ARGS); -extern Datum ginendscan(PG_FUNCTION_ARGS); -extern Datum ginrescan(PG_FUNCTION_ARGS); -extern Datum ginmarkpos(PG_FUNCTION_ARGS); -extern Datum ginrestrpos(PG_FUNCTION_ARGS); +extern IndexScanDesc ginbeginscan(Relation rel, int nkeys, int norderbys); +extern void ginendscan(IndexScanDesc scan); +extern void ginrescan(IndexScanDesc scan, ScanKey key, int nkeys, + ScanKey orderbys, int norderbys); +extern void ginmarkpos(IndexScanDesc scan); +extern void ginrestrpos(IndexScanDesc scan); extern void ginNewScanKey(IndexScanDesc scan); extern void ginFreeScanKeys(GinScanOpaque so); /* ginget.c */ -extern Datum gingetbitmap(PG_FUNCTION_ARGS); +extern int64 gingetbitmap(IndexScanDesc scan, TIDBitmap *tbm); /* ginlogic.c */ extern void ginInitConsistentFunction(GinState *ginstate, GinScanKey key); /* ginvacuum.c */ -extern Datum ginbulkdelete(PG_FUNCTION_ARGS); -extern Datum ginvacuumcleanup(PG_FUNCTION_ARGS); +extern IndexBulkDeleteResult *ginbulkdelete(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, + void *callback_state); +extern IndexBulkDeleteResult *ginvacuumcleanup(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats); extern ItemPointer ginVacuumItemPointers(GinVacuumState *gvs, ItemPointerData *items, int nitem, int *nremaining); diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 1a77982..35fb34a 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -14,6 +14,7 @@ #ifndef GIST_PRIVATE_H #define GIST_PRIVATE_H +#include "access/amapi.h" #include "access/gist.h" #include "access/itup.h" #include "access/xlogreader.h" @@ -426,9 +427,13 @@ typedef struct GiSTOptions } GiSTOptions; /* gist.c */ -extern Datum gistbuildempty(PG_FUNCTION_ARGS); -extern Datum gistinsert(PG_FUNCTION_ARGS); -extern Datum gistcanreturn(PG_FUNCTION_ARGS); +extern Datum gisthandler(PG_FUNCTION_ARGS); +extern void gistvalidate(OpClassInfo *opclass); +extern void gistbuildempty(Relation index); +extern bool gistinsert(Relation r, Datum *values, bool *isnull, + ItemPointer ht_ctid, Relation heapRel, + IndexUniqueCheck checkUnique); +extern bool gistcanreturn(Relation index, int attno); extern MemoryContext createTempGistContext(void); extern GISTSTATE *initGISTstate(Relation index); extern void freeGISTstate(GISTSTATE *giststate); @@ -474,8 +479,8 @@ extern XLogRecPtr gistXLogSplit(RelFileNode node, Buffer leftchild, bool markfollowright); /* gistget.c */ -extern Datum gistgettuple(PG_FUNCTION_ARGS); -extern Datum gistgetbitmap(PG_FUNCTION_ARGS); +extern bool gistgettuple(IndexScanDesc scan, ScanDirection dir); +extern int64 gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm); /* gistutil.c */ @@ -485,7 +490,7 @@ extern Datum gistgetbitmap(PG_FUNCTION_ARGS); #define GIST_MIN_FILLFACTOR 10 #define GIST_DEFAULT_FILLFACTOR 90 -extern Datum gistoptions(PG_FUNCTION_ARGS); +extern bytea *gistoptions(Datum reloptions, bool validate); extern bool gistfitpage(IndexTuple *itvec, int len); extern bool gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace); extern void gistcheckpage(Relation rel, Buffer buf); @@ -534,8 +539,12 @@ extern void gistMakeUnionKey(GISTSTATE *giststate, int attno, extern XLogRecPtr gistGetFakeLSN(Relation rel); /* gistvacuum.c */ -extern Datum gistbulkdelete(PG_FUNCTION_ARGS); -extern Datum gistvacuumcleanup(PG_FUNCTION_ARGS); +extern IndexBulkDeleteResult *gistbulkdelete(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, + void *callback_state); +extern IndexBulkDeleteResult *gistvacuumcleanup(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats); /* gistsplit.c */ extern void gistSplitByKey(Relation r, Page page, IndexTuple *itup, @@ -544,7 +553,8 @@ extern void gistSplitByKey(Relation r, Page page, IndexTuple *itup, int attno); /* gistbuild.c */ -extern Datum gistbuild(PG_FUNCTION_ARGS); +extern IndexBuildResult *gistbuild(Relation heap, Relation index, + IndexInfo *indexInfo); extern void gistValidateBufferingOption(char *value); /* gistbuildbuffers.c */ diff --git a/src/include/access/gistscan.h b/src/include/access/gistscan.h index 15cb3d1..0e6afe9 100644 --- a/src/include/access/gistscan.h +++ b/src/include/access/gistscan.h @@ -16,10 +16,11 @@ #include "fmgr.h" -extern Datum gistbeginscan(PG_FUNCTION_ARGS); -extern Datum gistrescan(PG_FUNCTION_ARGS); -extern Datum gistmarkpos(PG_FUNCTION_ARGS); -extern Datum gistrestrpos(PG_FUNCTION_ARGS); -extern Datum gistendscan(PG_FUNCTION_ARGS); +extern IndexScanDesc gistbeginscan(Relation r, int nkeys, int norderbys); +extern void gistrescan(IndexScanDesc scan, ScanKey key, int nkeys, + ScanKey orderbys, int norderbys); +extern void gistmarkpos(IndexScanDesc scan); +extern void gistrestrpos(IndexScanDesc scan); +extern void gistendscan(IndexScanDesc scan); #endif /* GISTSCAN_H */ diff --git a/src/include/access/hash.h b/src/include/access/hash.h index 97cb859..9595c6b 100644 --- a/src/include/access/hash.h +++ b/src/include/access/hash.h @@ -17,7 +17,7 @@ #ifndef HASH_H #define HASH_H -#include "access/genam.h" +#include "access/amapi.h" #include "access/itup.h" #include "access/sdir.h" #include "access/xlogreader.h" @@ -243,19 +243,29 @@ typedef HashMetaPageData *HashMetaPage; /* public routines */ -extern Datum hashbuild(PG_FUNCTION_ARGS); -extern Datum hashbuildempty(PG_FUNCTION_ARGS); -extern Datum hashinsert(PG_FUNCTION_ARGS); -extern Datum hashbeginscan(PG_FUNCTION_ARGS); -extern Datum hashgettuple(PG_FUNCTION_ARGS); -extern Datum hashgetbitmap(PG_FUNCTION_ARGS); -extern Datum hashrescan(PG_FUNCTION_ARGS); -extern Datum hashendscan(PG_FUNCTION_ARGS); -extern Datum hashmarkpos(PG_FUNCTION_ARGS); -extern Datum hashrestrpos(PG_FUNCTION_ARGS); -extern Datum hashbulkdelete(PG_FUNCTION_ARGS); -extern Datum hashvacuumcleanup(PG_FUNCTION_ARGS); -extern Datum hashoptions(PG_FUNCTION_ARGS); +extern Datum hashhandler(PG_FUNCTION_ARGS); +extern void hashvalidate(OpClassInfo *opclass); +extern IndexBuildResult *hashbuild(Relation heap, Relation index, + IndexInfo *indexInfo); +extern void hashbuildempty(Relation index); +extern bool hashinsert(Relation rel, Datum *values, bool *isnull, + ItemPointer ht_ctid, Relation heapRel, + IndexUniqueCheck checkUnique); +extern IndexScanDesc hashbeginscan(Relation rel, int nkeys, int norderbys); +extern bool hashgettuple(IndexScanDesc scan, ScanDirection dir); +extern int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm); +extern void hashrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, + ScanKey orderbys, int norderbys); +extern void hashendscan(IndexScanDesc scan); +extern void hashmarkpos(IndexScanDesc scan); +extern void hashrestrpos(IndexScanDesc scan); +extern IndexBulkDeleteResult *hashbulkdelete(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, + void *callback_state); +extern IndexBulkDeleteResult *hashvacuumcleanup(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats); +extern bytea *hashoptions(Datum reloptions, bool validate); /* * Datatype-specific hash functions in hashfunc.c. diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index 9e48efd..4fab0a3 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -14,13 +14,14 @@ #ifndef NBTREE_H #define NBTREE_H -#include "access/genam.h" +#include "access/amapi.h" #include "access/itup.h" #include "access/sdir.h" #include "access/xlogreader.h" #include "catalog/pg_index.h" #include "lib/stringinfo.h" #include "storage/bufmgr.h" +#include "utils/selfuncs.h" /* There's room for a 16-bit vacuum cycle ID in BTPageOpaqueData */ typedef uint16 BTCycleId; @@ -652,20 +653,31 @@ typedef BTScanOpaqueData *BTScanOpaque; /* * prototypes for functions in nbtree.c (external entry points for btree) */ -extern Datum btbuild(PG_FUNCTION_ARGS); -extern Datum btbuildempty(PG_FUNCTION_ARGS); -extern Datum btinsert(PG_FUNCTION_ARGS); -extern Datum btbeginscan(PG_FUNCTION_ARGS); -extern Datum btgettuple(PG_FUNCTION_ARGS); -extern Datum btgetbitmap(PG_FUNCTION_ARGS); -extern Datum btrescan(PG_FUNCTION_ARGS); -extern Datum btendscan(PG_FUNCTION_ARGS); -extern Datum btmarkpos(PG_FUNCTION_ARGS); -extern Datum btrestrpos(PG_FUNCTION_ARGS); -extern Datum btbulkdelete(PG_FUNCTION_ARGS); -extern Datum btvacuumcleanup(PG_FUNCTION_ARGS); -extern Datum btcanreturn(PG_FUNCTION_ARGS); -extern Datum btoptions(PG_FUNCTION_ARGS); +extern Datum bthandler(PG_FUNCTION_ARGS); +extern void btvalidate(OpClassInfo *opclass); +extern IndexBuildResult *btbuild(Relation heap, Relation index, + IndexInfo *indexInfo); +extern void btbuildempty(Relation index); +extern bool btinsert(Relation rel, Datum *values, bool *isnull, + ItemPointer ht_ctid, Relation heapRel, + IndexUniqueCheck checkUnique); +extern IndexScanDesc btbeginscan(Relation indexRelation, + int nkeys, int norderbys); +extern bool btgettuple(IndexScanDesc scan, ScanDirection dir); +extern int64 btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm); +extern void btrescan(IndexScanDesc scan, ScanKey keys, int nkeys, + ScanKey orderbys, int norderbys); +extern void btendscan(IndexScanDesc scan); +extern void btmarkpos(IndexScanDesc scan); +extern void btrestrpos(IndexScanDesc scan); +extern IndexBulkDeleteResult *btbulkdelete(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, + void *callback_state); +extern IndexBulkDeleteResult *btvacuumcleanup(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats); +extern bool btcanreturn(Relation index, int attno); +extern bytea *btoptions(Datum reloptions, bool validate); /* * prototypes for functions in nbtinsert.c diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 2a3cbcd..7de02d2 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -19,6 +19,7 @@ #ifndef RELOPTIONS_H #define RELOPTIONS_H +#include "access/amapi.h" #include "access/htup.h" #include "access/tupdesc.h" #include "nodes/pg_list.h" @@ -258,7 +259,7 @@ extern Datum transformRelOptions(Datum oldOptions, List *defList, bool ignoreOids, bool isReset); extern List *untransformRelOptions(Datum options); extern bytea *extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, - Oid amoptions); + amoptions_function amoptions); extern relopt_value *parseRelOptions(Datum options, bool validate, relopt_kind kind, int *numrelopts); extern void *allocateReloptStruct(Size base, relopt_value *options, @@ -272,7 +273,7 @@ extern bytea *default_reloptions(Datum reloptions, bool validate, relopt_kind kind); extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate); extern bytea *view_reloptions(Datum reloptions, bool validate); -extern bytea *index_reloptions(RegProcedure amoptions, Datum reloptions, +extern bytea *index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate); extern bytea *attribute_reloptions(Datum reloptions, bool validate); extern bytea *tablespace_reloptions(Datum reloptions, bool validate); diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h index 0cb8fd9..ba2c1c1 100644 --- a/src/include/access/spgist.h +++ b/src/include/access/spgist.h @@ -14,7 +14,7 @@ #ifndef SPGIST_H #define SPGIST_H -#include "access/skey.h" +#include "access/amapi.h" #include "access/xlogreader.h" #include "fmgr.h" #include "lib/stringinfo.h" @@ -174,27 +174,39 @@ typedef struct spgLeafConsistentOut } spgLeafConsistentOut; +/* spgutils.c */ +extern Datum spghandler(PG_FUNCTION_ARGS); +extern void spgvalidate(OpClassInfo *opclass); + /* spginsert.c */ -extern Datum spgbuild(PG_FUNCTION_ARGS); -extern Datum spgbuildempty(PG_FUNCTION_ARGS); -extern Datum spginsert(PG_FUNCTION_ARGS); +extern IndexBuildResult *spgbuild(Relation heap, Relation index, + IndexInfo *indexInfo); +extern void spgbuildempty(Relation indexRelation); +extern bool spginsert(Relation index, Datum *values, bool *isnull, + ItemPointer ht_ctid, Relation heapRel, + IndexUniqueCheck checkUnique); /* spgscan.c */ -extern Datum spgbeginscan(PG_FUNCTION_ARGS); -extern Datum spgendscan(PG_FUNCTION_ARGS); -extern Datum spgrescan(PG_FUNCTION_ARGS); -extern Datum spgmarkpos(PG_FUNCTION_ARGS); -extern Datum spgrestrpos(PG_FUNCTION_ARGS); -extern Datum spggetbitmap(PG_FUNCTION_ARGS); -extern Datum spggettuple(PG_FUNCTION_ARGS); -extern Datum spgcanreturn(PG_FUNCTION_ARGS); +extern IndexScanDesc spgbeginscan(Relation rel, int keysz, int orderbysz); +extern void spgendscan(IndexScanDesc scan); +extern void spgrescan(IndexScanDesc scan, ScanKey key, int nkeys, + ScanKey orderbys, int norderbys); +extern void spgmarkpos(IndexScanDesc scan); +extern void spgrestrpos(IndexScanDesc scan); +extern int64 spggetbitmap(IndexScanDesc scan, TIDBitmap *tbm); +extern bool spggettuple(IndexScanDesc scan, ScanDirection dir); +extern bool spgcanreturn(Relation index, int attno); /* spgutils.c */ -extern Datum spgoptions(PG_FUNCTION_ARGS); +extern bytea *spgoptions(Datum reloptions, bool validate); /* spgvacuum.c */ -extern Datum spgbulkdelete(PG_FUNCTION_ARGS); -extern Datum spgvacuumcleanup(PG_FUNCTION_ARGS); +extern IndexBulkDeleteResult *spgbulkdelete(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, + void *callback_state); +extern IndexBulkDeleteResult *spgvacuumcleanup(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats); /* spgxlog.c */ extern void spg_redo(XLogReaderState *record); diff --git a/src/include/catalog/opfam_internal.h b/src/include/catalog/opfam_internal.h index 32195a7..5cc0208 100644 --- a/src/include/catalog/opfam_internal.h +++ b/src/include/catalog/opfam_internal.h @@ -25,4 +25,16 @@ typedef struct Oid sortfamily; /* ordering operator's sort opfamily, or 0 */ } OpFamilyMember; +/* + * Opclass data for validation by access method. + */ +typedef struct +{ + Oid intype; /* input datatype */ + Oid keytype; /* key datatype */ + List *procedures; /* list of OpFamilyMember */ + List *operators; /* list of OpFamilyMember */ +} OpClassInfo; + + #endif /* OPFAM_INTERNAL_H */ diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h index 8a28b8e..f19a873 100644 --- a/src/include/catalog/pg_am.h +++ b/src/include/catalog/pg_am.h @@ -34,39 +34,7 @@ CATALOG(pg_am,2601) { NameData amname; /* access method name */ - int16 amstrategies; /* total number of strategies (operators) by - * which we can traverse/search this AM. Zero - * if AM does not have a fixed set of strategy - * assignments. */ - int16 amsupport; /* total number of support functions that this - * AM uses */ - bool amcanorder; /* does AM support order by column value? */ - bool amcanorderbyop; /* does AM support order by operator result? */ - bool amcanbackward; /* does AM support backward scan? */ - bool amcanunique; /* does AM support UNIQUE indexes? */ - bool amcanmulticol; /* does AM support multi-column indexes? */ - bool amoptionalkey; /* can query omit key for the first column? */ - bool amsearcharray; /* can AM handle ScalarArrayOpExpr quals? */ - bool amsearchnulls; /* can AM search for NULL/NOT NULL entries? */ - bool amstorage; /* can storage type differ from column type? */ - bool amclusterable; /* does AM support cluster command? */ - bool ampredlocks; /* does AM handle predicate locks? */ - Oid amkeytype; /* type of data in index, or InvalidOid */ - regproc aminsert; /* "insert this tuple" function */ - regproc ambeginscan; /* "prepare for index scan" function */ - regproc amgettuple; /* "next valid tuple" function, or 0 */ - regproc amgetbitmap; /* "fetch all valid tuples" function, or 0 */ - regproc amrescan; /* "(re)start index scan" function */ - regproc amendscan; /* "end index scan" function */ - regproc ammarkpos; /* "mark current scan position" function */ - regproc amrestrpos; /* "restore marked scan position" function */ - regproc ambuild; /* "build new index" function */ - regproc ambuildempty; /* "build empty index" function */ - regproc ambulkdelete; /* bulk-delete function */ - regproc amvacuumcleanup; /* post-VACUUM cleanup function */ - regproc amcanreturn; /* can indexscan return IndexTuples? */ - regproc amcostestimate; /* estimate cost of an indexscan */ - regproc amoptions; /* parse AM-specific parameters */ + regproc amhandler; /* handler function */ } FormData_pg_am; /* ---------------- @@ -80,59 +48,31 @@ typedef FormData_pg_am *Form_pg_am; * compiler constants for pg_am * ---------------- */ -#define Natts_pg_am 30 +#define Natts_pg_am 2 #define Anum_pg_am_amname 1 -#define Anum_pg_am_amstrategies 2 -#define Anum_pg_am_amsupport 3 -#define Anum_pg_am_amcanorder 4 -#define Anum_pg_am_amcanorderbyop 5 -#define Anum_pg_am_amcanbackward 6 -#define Anum_pg_am_amcanunique 7 -#define Anum_pg_am_amcanmulticol 8 -#define Anum_pg_am_amoptionalkey 9 -#define Anum_pg_am_amsearcharray 10 -#define Anum_pg_am_amsearchnulls 11 -#define Anum_pg_am_amstorage 12 -#define Anum_pg_am_amclusterable 13 -#define Anum_pg_am_ampredlocks 14 -#define Anum_pg_am_amkeytype 15 -#define Anum_pg_am_aminsert 16 -#define Anum_pg_am_ambeginscan 17 -#define Anum_pg_am_amgettuple 18 -#define Anum_pg_am_amgetbitmap 19 -#define Anum_pg_am_amrescan 20 -#define Anum_pg_am_amendscan 21 -#define Anum_pg_am_ammarkpos 22 -#define Anum_pg_am_amrestrpos 23 -#define Anum_pg_am_ambuild 24 -#define Anum_pg_am_ambuildempty 25 -#define Anum_pg_am_ambulkdelete 26 -#define Anum_pg_am_amvacuumcleanup 27 -#define Anum_pg_am_amcanreturn 28 -#define Anum_pg_am_amcostestimate 29 -#define Anum_pg_am_amoptions 30 +#define Anum_pg_am_amhandler 2 /* ---------------- * initial contents of pg_am * ---------------- */ -DATA(insert OID = 403 ( btree 5 2 t f t t t t t t f t t 0 btinsert btbeginscan btgettuple btgetbitmap btrescan btendscan btmarkpos btrestrpos btbuild btbuildempty btbulkdelete btvacuumcleanup btcanreturn btcostestimate btoptions )); +DATA(insert OID = 403 ( btree bthandler )); DESCR("b-tree index access method"); #define BTREE_AM_OID 403 -DATA(insert OID = 405 ( hash 1 1 f f t f f f f f f f f 23 hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbuildempty hashbulkdelete hashvacuumcleanup - hashcostestimate hashoptions )); +DATA(insert OID = 405 ( hash hashhandler )); DESCR("hash index access method"); #define HASH_AM_OID 405 -DATA(insert OID = 783 ( gist 0 9 f t f f t t f t t t f 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbuildempty gistbulkdelete gistvacuumcleanup gistcanreturn gistcostestimate gistoptions )); +DATA(insert OID = 783 ( gist gisthandler )); DESCR("GiST index access method"); #define GIST_AM_OID 783 -DATA(insert OID = 2742 ( gin 0 6 f f f f t t f f t f f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbuildempty ginbulkdelete ginvacuumcleanup - gincostestimate ginoptions )); +DATA(insert OID = 2742 ( gin ginhandler )); DESCR("GIN index access method"); #define GIN_AM_OID 2742 -DATA(insert OID = 4000 ( spgist 0 5 f f f f f t f t f f f 0 spginsert spgbeginscan spggettuple spggetbitmap spgrescan spgendscan spgmarkpos spgrestrpos spgbuild spgbuildempty spgbulkdelete spgvacuumcleanup spgcanreturn spgcostestimate spgoptions )); +DATA(insert OID = 4000 ( spgist spghandler )); DESCR("SP-GiST index access method"); #define SPGIST_AM_OID 4000 -DATA(insert OID = 3580 ( brin 0 15 f f f f t t f t t f f 0 brininsert brinbeginscan - bringetbitmap brinrescan brinendscan brinmarkpos brinrestrpos brinbuild brinbuildempty brinbulkdelete brinvacuumcleanup - brincostestimate brinoptions )); +DATA(insert OID = 3580 ( brin brinhandler )); DESCR("block range index (BRIN) access method"); #define BRIN_AM_OID 3580 diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index eb55b3a..587aaac 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -547,63 +547,6 @@ DESCR("convert int4 to float4"); DATA(insert OID = 319 ( int4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "700" _null_ _null_ _null_ _null_ _null_ ftoi4 _null_ _null_ _null_ )); DESCR("convert float4 to int4"); -DATA(insert OID = 330 ( btgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgettuple _null_ _null_ _null_ )); -DESCR("btree(internal)"); -DATA(insert OID = 636 ( btgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgetbitmap _null_ _null_ _null_ )); -DESCR("btree(internal)"); -DATA(insert OID = 331 ( btinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btinsert _null_ _null_ _null_ )); -DESCR("btree(internal)"); -DATA(insert OID = 333 ( btbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbeginscan _null_ _null_ _null_ )); -DESCR("btree(internal)"); -DATA(insert OID = 334 ( btrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btrescan _null_ _null_ _null_ )); -DESCR("btree(internal)"); -DATA(insert OID = 335 ( btendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btendscan _null_ _null_ _null_ )); -DESCR("btree(internal)"); -DATA(insert OID = 336 ( btmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btmarkpos _null_ _null_ _null_ )); -DESCR("btree(internal)"); -DATA(insert OID = 337 ( btrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btrestrpos _null_ _null_ _null_ )); -DESCR("btree(internal)"); -DATA(insert OID = 338 ( btbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbuild _null_ _null_ _null_ )); -DESCR("btree(internal)"); -DATA(insert OID = 328 ( btbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btbuildempty _null_ _null_ _null_ )); -DESCR("btree(internal)"); -DATA(insert OID = 332 ( btbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbulkdelete _null_ _null_ _null_ )); -DESCR("btree(internal)"); -DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ btvacuumcleanup _null_ _null_ _null_ )); -DESCR("btree(internal)"); -DATA(insert OID = 276 ( btcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ btcanreturn _null_ _null_ _null_ )); -DESCR("btree(internal)"); -DATA(insert OID = 1268 ( btcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btcostestimate _null_ _null_ _null_ )); -DESCR("btree(internal)"); -DATA(insert OID = 2785 ( btoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ btoptions _null_ _null_ _null_ )); -DESCR("btree(internal)"); - -DATA(insert OID = 3789 ( bringetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ bringetbitmap _null_ _null_ _null_ )); -DESCR("brin(internal)"); -DATA(insert OID = 3790 ( brininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brininsert _null_ _null_ _null_ )); -DESCR("brin(internal)"); -DATA(insert OID = 3791 ( brinbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbeginscan _null_ _null_ _null_ )); -DESCR("brin(internal)"); -DATA(insert OID = 3792 ( brinrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinrescan _null_ _null_ _null_ )); -DESCR("brin(internal)"); -DATA(insert OID = 3793 ( brinendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinendscan _null_ _null_ _null_ )); -DESCR("brin(internal)"); -DATA(insert OID = 3794 ( brinmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinmarkpos _null_ _null_ _null_ )); -DESCR("brin(internal)"); -DATA(insert OID = 3795 ( brinrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinrestrpos _null_ _null_ _null_ )); -DESCR("brin(internal)"); -DATA(insert OID = 3796 ( brinbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbuild _null_ _null_ _null_ )); -DESCR("brin(internal)"); -DATA(insert OID = 3797 ( brinbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinbuildempty _null_ _null_ _null_ )); -DESCR("brin(internal)"); -DATA(insert OID = 3798 ( brinbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbulkdelete _null_ _null_ _null_ )); -DESCR("brin(internal)"); -DATA(insert OID = 3799 ( brinvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ brinvacuumcleanup _null_ _null_ _null_ )); -DESCR("brin(internal)"); -DATA(insert OID = 3800 ( brincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brincostestimate _null_ _null_ _null_ )); -DESCR("brin(internal)"); -DATA(insert OID = 3801 ( brinoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ brinoptions _null_ _null_ _null_ )); -DESCR("brin(internal)"); DATA(insert OID = 3952 ( brin_summarize_new_values PGNSP PGUID 12 1 0 0 0 f f f f f f v s 1 0 23 "2205" _null_ _null_ _null_ _null_ _null_ brin_summarize_new_values _null_ _null_ _null_ )); DESCR("brin: standalone scan new table pages"); @@ -694,35 +637,6 @@ DESCR("convert name to char(n)"); DATA(insert OID = 409 ( name PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 19 "1042" _null_ _null_ _null_ _null_ _null_ bpchar_name _null_ _null_ _null_ )); DESCR("convert char(n) to name"); -DATA(insert OID = 440 ( hashgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgettuple _null_ _null_ _null_ )); -DESCR("hash(internal)"); -DATA(insert OID = 637 ( hashgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgetbitmap _null_ _null_ _null_ )); -DESCR("hash(internal)"); -DATA(insert OID = 441 ( hashinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashinsert _null_ _null_ _null_ )); -DESCR("hash(internal)"); -DATA(insert OID = 443 ( hashbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbeginscan _null_ _null_ _null_ )); -DESCR("hash(internal)"); -DATA(insert OID = 444 ( hashrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashrescan _null_ _null_ _null_ )); -DESCR("hash(internal)"); -DATA(insert OID = 445 ( hashendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashendscan _null_ _null_ _null_ )); -DESCR("hash(internal)"); -DATA(insert OID = 446 ( hashmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashmarkpos _null_ _null_ _null_ )); -DESCR("hash(internal)"); -DATA(insert OID = 447 ( hashrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashrestrpos _null_ _null_ _null_ )); -DESCR("hash(internal)"); -DATA(insert OID = 448 ( hashbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbuild _null_ _null_ _null_ )); -DESCR("hash(internal)"); -DATA(insert OID = 327 ( hashbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashbuildempty _null_ _null_ _null_ )); -DESCR("hash(internal)"); -DATA(insert OID = 442 ( hashbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbulkdelete _null_ _null_ _null_ )); -DESCR("hash(internal)"); -DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashvacuumcleanup _null_ _null_ _null_ )); -DESCR("hash(internal)"); -DATA(insert OID = 438 ( hashcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashcostestimate _null_ _null_ _null_ )); -DESCR("hash(internal)"); -DATA(insert OID = 2786 ( hashoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ hashoptions _null_ _null_ _null_ )); -DESCR("hash(internal)"); - DATA(insert OID = 449 ( hashint2 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "21" _null_ _null_ _null_ _null_ _null_ hashint2 _null_ _null_ _null_ )); DESCR("hash"); DATA(insert OID = 450 ( hashint4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ hashint4 _null_ _null_ _null_ )); @@ -978,37 +892,6 @@ DESCR("larger of two"); DATA(insert OID = 771 ( int2smaller PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2smaller _null_ _null_ _null_ )); DESCR("smaller of two"); -DATA(insert OID = 774 ( gistgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgettuple _null_ _null_ _null_ )); -DESCR("gist(internal)"); -DATA(insert OID = 638 ( gistgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgetbitmap _null_ _null_ _null_ )); -DESCR("gist(internal)"); -DATA(insert OID = 775 ( gistinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistinsert _null_ _null_ _null_ )); -DESCR("gist(internal)"); -DATA(insert OID = 777 ( gistbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbeginscan _null_ _null_ _null_ )); -DESCR("gist(internal)"); -DATA(insert OID = 778 ( gistrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistrescan _null_ _null_ _null_ )); -DESCR("gist(internal)"); -DATA(insert OID = 779 ( gistendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistendscan _null_ _null_ _null_ )); -DESCR("gist(internal)"); -DATA(insert OID = 780 ( gistmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistmarkpos _null_ _null_ _null_ )); -DESCR("gist(internal)"); -DATA(insert OID = 781 ( gistrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistrestrpos _null_ _null_ _null_ )); -DESCR("gist(internal)"); -DATA(insert OID = 782 ( gistbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbuild _null_ _null_ _null_ )); -DESCR("gist(internal)"); -DATA(insert OID = 326 ( gistbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistbuildempty _null_ _null_ _null_ )); -DESCR("gist(internal)"); -DATA(insert OID = 776 ( gistbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbulkdelete _null_ _null_ _null_ )); -DESCR("gist(internal)"); -DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistvacuumcleanup _null_ _null_ _null_ )); -DESCR("gist(internal)"); -DATA(insert OID = 3280 ( gistcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ gistcanreturn _null_ _null_ _null_ )); -DESCR("gist(internal)"); -DATA(insert OID = 772 ( gistcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistcostestimate _null_ _null_ _null_ )); -DESCR("gist(internal)"); -DATA(insert OID = 2787 ( gistoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ gistoptions _null_ _null_ _null_ )); -DESCR("gist(internal)"); - DATA(insert OID = 784 ( tintervaleq PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervaleq _null_ _null_ _null_ )); DATA(insert OID = 785 ( tintervalne PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervalne _null_ _null_ _null_ )); DATA(insert OID = 786 ( tintervallt PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervallt _null_ _null_ _null_ )); @@ -3740,6 +3623,10 @@ DATA(insert OID = 3311 ( tsm_handler_in PGNSP PGUID 12 1 0 0 0 f f f f f f i s DESCR("I/O"); DATA(insert OID = 3312 ( tsm_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "3310" _null_ _null_ _null_ _null_ _null_ tsm_handler_out _null_ _null_ _null_ )); DESCR("I/O"); +DATA(insert OID = 326 ( index_am_handler_in PGNSP PGUID 12 1 0 0 0 f f f f f f i s 1 0 325 "2275" _null_ _null_ _null_ _null_ _null_ index_am_handler_in _null_ _null_ _null_ )); +DESCR("I/O"); +DATA(insert OID = 327 ( index_am_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "325" _null_ _null_ _null_ _null_ _null_ index_am_handler_out _null_ _null_ _null_ )); +DESCR("I/O"); /* tablesample method handlers */ DATA(insert OID = 3313 ( bernoulli PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 3310 "2281" _null_ _null_ _null_ _null_ _null_ tsm_bernoulli_handler _null_ _null_ _null_ )); @@ -4196,34 +4083,6 @@ DESCR("GiST support"); DATA(insert OID = 3288 ( gist_bbox_distance PGNSP PGUID 12 1 0 0 0 f f f f t f i s 4 0 701 "2281 600 23 26" _null_ _null_ _null_ _null_ _null_ gist_bbox_distance _null_ _null_ _null_ )); DESCR("GiST support"); -/* GIN */ -DATA(insert OID = 2731 ( gingetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gingetbitmap _null_ _null_ _null_ )); -DESCR("gin(internal)"); -DATA(insert OID = 2732 ( gininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gininsert _null_ _null_ _null_ )); -DESCR("gin(internal)"); -DATA(insert OID = 2733 ( ginbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbeginscan _null_ _null_ _null_ )); -DESCR("gin(internal)"); -DATA(insert OID = 2734 ( ginrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginrescan _null_ _null_ _null_ )); -DESCR("gin(internal)"); -DATA(insert OID = 2735 ( ginendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginendscan _null_ _null_ _null_ )); -DESCR("gin(internal)"); -DATA(insert OID = 2736 ( ginmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginmarkpos _null_ _null_ _null_ )); -DESCR("gin(internal)"); -DATA(insert OID = 2737 ( ginrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginrestrpos _null_ _null_ _null_ )); -DESCR("gin(internal)"); -DATA(insert OID = 2738 ( ginbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbuild _null_ _null_ _null_ )); -DESCR("gin(internal)"); -DATA(insert OID = 325 ( ginbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginbuildempty _null_ _null_ _null_ )); -DESCR("gin(internal)"); -DATA(insert OID = 2739 ( ginbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbulkdelete _null_ _null_ _null_ )); -DESCR("gin(internal)"); -DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ ginvacuumcleanup _null_ _null_ _null_ )); -DESCR("gin(internal)"); -DATA(insert OID = 2741 ( gincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gincostestimate _null_ _null_ _null_ )); -DESCR("gin(internal)"); -DATA(insert OID = 2788 ( ginoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ ginoptions _null_ _null_ _null_ )); -DESCR("gin(internal)"); - /* GIN array support */ DATA(insert OID = 2743 ( ginarrayextract PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 2281 "2277 2281 2281" _null_ _null_ _null_ _null_ _null_ ginarrayextract _null_ _null_ _null_ )); DESCR("GIN array support"); @@ -5119,38 +4978,6 @@ DESCR("construct timestamp with time zone"); DATA(insert OID = 3464 ( make_interval PGNSP PGUID 12 1 0 0 0 f f f f t f i s 7 0 1186 "23 23 23 23 23 23 701" _null_ _null_ "{years,months,weeks,days,hours,mins,secs}" _null_ _null_ make_interval _null_ _null_ _null_ )); DESCR("construct interval"); -/* spgist support functions */ -DATA(insert OID = 4001 ( spggettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggettuple _null_ _null_ _null_ )); -DESCR("spgist(internal)"); -DATA(insert OID = 4002 ( spggetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggetbitmap _null_ _null_ _null_ )); -DESCR("spgist(internal)"); -DATA(insert OID = 4003 ( spginsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spginsert _null_ _null_ _null_ )); -DESCR("spgist(internal)"); -DATA(insert OID = 4004 ( spgbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbeginscan _null_ _null_ _null_ )); -DESCR("spgist(internal)"); -DATA(insert OID = 4005 ( spgrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgrescan _null_ _null_ _null_ )); -DESCR("spgist(internal)"); -DATA(insert OID = 4006 ( spgendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgendscan _null_ _null_ _null_ )); -DESCR("spgist(internal)"); -DATA(insert OID = 4007 ( spgmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgmarkpos _null_ _null_ _null_ )); -DESCR("spgist(internal)"); -DATA(insert OID = 4008 ( spgrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgrestrpos _null_ _null_ _null_ )); -DESCR("spgist(internal)"); -DATA(insert OID = 4009 ( spgbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbuild _null_ _null_ _null_ )); -DESCR("spgist(internal)"); -DATA(insert OID = 4010 ( spgbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgbuildempty _null_ _null_ _null_ )); -DESCR("spgist(internal)"); -DATA(insert OID = 4011 ( spgbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbulkdelete _null_ _null_ _null_ )); -DESCR("spgist(internal)"); -DATA(insert OID = 4012 ( spgvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ spgvacuumcleanup _null_ _null_ _null_ )); -DESCR("spgist(internal)"); -DATA(insert OID = 4032 ( spgcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ spgcanreturn _null_ _null_ _null_ )); -DESCR("spgist(internal)"); -DATA(insert OID = 4013 ( spgcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgcostestimate _null_ _null_ _null_ )); -DESCR("spgist(internal)"); -DATA(insert OID = 4014 ( spgoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ spgoptions _null_ _null_ _null_ )); -DESCR("spgist(internal)"); - /* spgist opclasses */ DATA(insert OID = 4018 ( spg_quad_config PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_quad_config _null_ _null_ _null_ )); DESCR("SP-GiST support for quad tree over point"); @@ -5333,6 +5160,25 @@ DESCR("get an individual replication origin's replication progress"); DATA(insert OID = 6014 ( pg_show_replication_origin_status PGNSP PGUID 12 1 100 0 0 f f f f f t v r 0 0 2249 "" "{26,25,3220,3220}" "{o,o,o,o}" "{local_id, external_id, remote_lsn, local_lsn}" _null_ _null_ pg_show_replication_origin_status _null_ _null_ _null_ )); DESCR("get progress for all replication origins"); +/* Access methods handlers */ +DATA(insert OID = 330 ( bthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ bthandler _null_ _null_ _null_ )); +DESCR("btree handler"); +DATA(insert OID = 331 ( hashhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ hashhandler _null_ _null_ _null_ )); +DESCR("hash handler"); +DATA(insert OID = 332 ( gisthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ gisthandler _null_ _null_ _null_ )); +DESCR("gist handler"); +DATA(insert OID = 333 ( ginhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ ginhandler _null_ _null_ _null_ )); +DESCR("gin handler"); +DATA(insert OID = 334 ( spghandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ spghandler _null_ _null_ _null_ )); +DESCR("spgist handler"); +DATA(insert OID = 335 ( brinhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ brinhandler _null_ _null_ _null_ )); +DESCR("brin handler"); + +DATA(insert OID = 336 ( amvalidate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 16 "26" _null_ _null_ _null_ _null_ _null_ amvalidate _null_ _null_ _null_ )); +DESCR("ask access method to validate opclass"); + + + /* * Symbolic values for provolatile column: these indicate whether the result * of a function is dependent *only* on the values of its explicit arguments, diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 7dc95c8..59b04ac 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -696,6 +696,8 @@ DATA(insert OID = 3115 ( fdw_handler PGNSP PGUID 4 t p P f t \054 0 0 0 fdw_han #define FDW_HANDLEROID 3115 DATA(insert OID = 3310 ( tsm_handler PGNSP PGUID 4 t p P f t \054 0 0 0 tsm_handler_in tsm_handler_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ )); #define TSM_HANDLEROID 3310 +DATA(insert OID = 325 ( index_am_handler PGNSP PGUID 4 t p P f t \054 0 0 0 index_am_handler_in index_am_handler_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ )); +#define INDEX_AM_HANDLEROID 325 DATA(insert OID = 3831 ( anyrange PGNSP PGUID -1 f p P f t \054 0 0 0 anyrange_in anyrange_out - - - - - d x f 0 -1 0 0 _null_ _null_ _null_ )); #define ANYRANGEOID 3831 diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index adae296..d8b9649 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -95,6 +95,7 @@ extern Oid get_am_oid(const char *amname, bool missing_ok); extern char *get_am_name(Oid amOid); extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok); extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok); +extern Datum amvalidate(PG_FUNCTION_ARGS); /* commands/tsearchcmds.c */ extern ObjectAddress DefineTSParser(List *names, List *parameters); diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 4ae2f3e..be4a1e2 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -14,7 +14,7 @@ #ifndef EXECNODES_H #define EXECNODES_H -#include "access/genam.h" +#include "access/amapi.h" #include "access/heapam.h" #include "executor/instrument.h" #include "lib/pairingheap.h" @@ -55,7 +55,7 @@ * they're conventionally set to false otherwise. * ---------------- */ -typedef struct IndexInfo +struct IndexInfo { NodeTag type; int ii_NumIndexAttrs; @@ -74,7 +74,7 @@ typedef struct IndexInfo bool ii_ReadyForInserts; bool ii_Concurrent; bool ii_BrokenHotChain; -} IndexInfo; +}; /* ---------------- * ExprContext_CB diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 274480e..9a5ff45 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -452,7 +452,8 @@ typedef enum NodeTag T_TIDBitmap, /* in nodes/tidbitmap.h */ T_InlineCodeBlock, /* in nodes/parsenodes.h */ T_FdwRoutine, /* in foreign/fdwapi.h */ - T_TsmRoutine /* in access/tsmapi.h */ + T_TsmRoutine, /* in access/tsmapi.h */ + T_IndexAmRoutine /* in access/amapi.h */ } NodeTag; /* diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 79bed33..7427900 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -19,6 +19,7 @@ #include "nodes/params.h" #include "nodes/parsenodes.h" #include "storage/block.h" +#include "utils/relcache.h" /* @@ -546,8 +547,7 @@ typedef struct IndexOptInfo bool *canreturn; /* which index cols can be returned in an * index-only scan? */ Oid relam; /* OID of the access method (in pg_am) */ - - RegProcedure amcostestimate; /* OID of the access method's cost fcn */ + IndexAmRoutine *amroutine; /* routine of access method */ List *indexprs; /* expressions for non-simple index columns */ List *indpred; /* predicate if a partial index, else NIL */ @@ -558,12 +558,12 @@ typedef struct IndexOptInfo bool unique; /* true if a unique index */ bool immediate; /* is uniqueness enforced immediately? */ bool hypothetical; /* true if index doesn't really exist */ - bool amcanorderbyop; /* does AM support order by operator result? */ + bool amcanorderbyop; /* does AM support order by operator result? */ bool amoptionalkey; /* can query omit key for the first column? */ bool amsearcharray; /* can AM handle ScalarArrayOpExpr quals? */ bool amsearchnulls; /* can AM search for NULL/NOT NULL entries? */ bool amhasgettuple; /* does AM have amgettuple interface? */ - bool amhasgetbitmap; /* does AM have amgetbitmap interface? */ + bool amhasgetbitmap; /* does AM have amgetbitmap interface? */ } IndexOptInfo; @@ -817,7 +817,7 @@ typedef struct Path * itself represent the costs of an IndexScan or IndexOnlyScan plan type. *---------- */ -typedef struct IndexPath +struct IndexPath { Path path; IndexOptInfo *indexinfo; @@ -829,7 +829,7 @@ typedef struct IndexPath ScanDirection indexscandir; Cost indextotalcost; Selectivity indexselectivity; -} IndexPath; +}; /* * BitmapHeapPath represents one or more indexscans that generate TID bitmaps diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index fc1679e..8e59b8c 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -568,6 +568,8 @@ extern Datum fdw_handler_in(PG_FUNCTION_ARGS); extern Datum fdw_handler_out(PG_FUNCTION_ARGS); extern Datum tsm_handler_in(PG_FUNCTION_ARGS); extern Datum tsm_handler_out(PG_FUNCTION_ARGS); +extern Datum index_am_handler_in(PG_FUNCTION_ARGS); +extern Datum index_am_handler_out(PG_FUNCTION_ARGS); extern Datum internal_in(PG_FUNCTION_ARGS); extern Datum internal_out(PG_FUNCTION_ARGS); extern Datum opaque_in(PG_FUNCTION_ARGS); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 8a55a09..483b840 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -129,6 +129,7 @@ typedef struct RelationData /* use "struct" here to avoid needing to include htup.h: */ struct HeapTupleData *rd_indextuple; /* all of pg_index tuple */ Form_pg_am rd_am; /* pg_am tuple for index's AM */ + IndexAmRoutine *amroutine; /* * index access support info (used only for an index relation) diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h index 6953281..7cad109 100644 --- a/src/include/utils/relcache.h +++ b/src/include/utils/relcache.h @@ -19,6 +19,9 @@ typedef struct RelationData *Relation; +typedef struct IndexPath IndexPath; +typedef struct IndexInfo IndexInfo; + /* ---------------- * RelationPtr is used in the executor to support index scans @@ -28,6 +31,14 @@ typedef struct RelationData *Relation; */ typedef Relation *RelationPtr; +typedef struct IndexAmRoutine IndexAmRoutine; + +/* + * Routines to retreive IndexAmRoutine + */ +extern IndexAmRoutine *GetIndexAmRoutine(Oid amoid); +extern void InitIndexAmRoutine(Relation relation); + /* * Routines to open (lookup) and close a relcache entry */ diff --git a/src/include/utils/selfuncs.h b/src/include/utils/selfuncs.h index a7433d9..3745d1c 100644 --- a/src/include/utils/selfuncs.h +++ b/src/include/utils/selfuncs.h @@ -191,12 +191,36 @@ extern double estimate_num_groups(PlannerInfo *root, List *groupExprs, extern Selectivity estimate_hash_bucketsize(PlannerInfo *root, Node *hashkey, double nbuckets); -extern Datum brincostestimate(PG_FUNCTION_ARGS); -extern Datum btcostestimate(PG_FUNCTION_ARGS); -extern Datum hashcostestimate(PG_FUNCTION_ARGS); -extern Datum gistcostestimate(PG_FUNCTION_ARGS); -extern Datum spgcostestimate(PG_FUNCTION_ARGS); -extern Datum gincostestimate(PG_FUNCTION_ARGS); +extern void brincostestimate(PlannerInfo *root, IndexPath *path, + double loop_count, Cost *indexStartupCost, + Cost *indexTotalCost, + Selectivity *indexSelectivity, + double *indexCorrelation); +extern void btcostestimate(PlannerInfo *root, IndexPath *path, + double loop_count, Cost *indexStartupCost, + Cost *indexTotalCost, + Selectivity *indexSelectivity, + double *indexCorrelation); +extern void hashcostestimate(PlannerInfo *root, IndexPath *path, + double loop_count, Cost *indexStartupCost, + Cost *indexTotalCost, + Selectivity *indexSelectivity, + double *indexCorrelation); +extern void gistcostestimate(PlannerInfo *root, IndexPath *path, + double loop_count, Cost *indexStartupCost, + Cost *indexTotalCost, + Selectivity *indexSelectivity, + double *indexCorrelation); +extern void spgcostestimate(PlannerInfo *root, IndexPath *path, + double loop_count, Cost *indexStartupCost, + Cost *indexTotalCost, + Selectivity *indexSelectivity, + double *indexCorrelation); +extern void gincostestimate(PlannerInfo *root, IndexPath *path, + double loop_count, Cost *indexStartupCost, + Cost *indexTotalCost, + Selectivity *indexSelectivity, + double *indexCorrelation); /* Functions in array_selfuncs.c */ diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 28422ea..c403b80 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -2111,8 +2111,11 @@ create type alter1.ctype as (f1 int, f2 text); create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2'; create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype); +create function alter1.hash(alter1.ctype) returns int4 language sql +as 'select hashint4($1.f1) # hashtext($1.f2)'; create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as - operator 1 alter1.=(alter1.ctype, alter1.ctype); + operator 1 alter1.=(alter1.ctype, alter1.ctype), + function 1 alter1.hash(alter1.ctype); create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8; create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype); create text search configuration alter1.cfg(parser = alter1.prs); @@ -2128,6 +2131,7 @@ alter operator class alter1.ctype_hash_ops using hash set schema alter2; alter operator family alter1.ctype_hash_ops using hash set schema alter2; alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2; alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2; +alter function alter1.hash(alter1.ctype) set schema alter2; alter type alter1.ctype set schema alter2; alter conversion alter1.ascii_to_utf8 set schema alter2; alter text search parser alter1.prs set schema alter2; @@ -2164,7 +2168,7 @@ select alter2.plus1(41); -- clean up drop schema alter2 cascade; -NOTICE: drop cascades to 13 other objects +NOTICE: drop cascades to 14 other objects DETAIL: drop cascades to table alter2.t1 drop cascades to view alter2.v1 drop cascades to function alter2.plus1(integer) @@ -2173,6 +2177,7 @@ drop cascades to operator family alter2.ctype_hash_ops for access method hash drop cascades to type alter2.ctype drop cascades to function alter2.same(alter2.ctype,alter2.ctype) drop cascades to operator alter2.=(alter2.ctype,alter2.ctype) +drop cascades to function alter2.hash(alter2.ctype) drop cascades to conversion ascii_to_utf8 drop cascades to text search parser prs drop cascades to text search configuration cfg diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out index d85bc83..d1a322d 100644 --- a/src/test/regress/expected/oidjoins.out +++ b/src/test/regress/expected/oidjoins.out @@ -73,134 +73,6 @@ WHERE aggmtranstype != 0 AND ------+--------------- (0 rows) -SELECT ctid, amkeytype -FROM pg_catalog.pg_am fk -WHERE amkeytype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype); - ctid | amkeytype -------+----------- -(0 rows) - -SELECT ctid, aminsert -FROM pg_catalog.pg_am fk -WHERE aminsert != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert); - ctid | aminsert -------+---------- -(0 rows) - -SELECT ctid, ambeginscan -FROM pg_catalog.pg_am fk -WHERE ambeginscan != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan); - ctid | ambeginscan -------+------------- -(0 rows) - -SELECT ctid, amgettuple -FROM pg_catalog.pg_am fk -WHERE amgettuple != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple); - ctid | amgettuple -------+------------ -(0 rows) - -SELECT ctid, amgetbitmap -FROM pg_catalog.pg_am fk -WHERE amgetbitmap != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap); - ctid | amgetbitmap -------+------------- -(0 rows) - -SELECT ctid, amrescan -FROM pg_catalog.pg_am fk -WHERE amrescan != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan); - ctid | amrescan -------+---------- -(0 rows) - -SELECT ctid, amendscan -FROM pg_catalog.pg_am fk -WHERE amendscan != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan); - ctid | amendscan -------+----------- -(0 rows) - -SELECT ctid, ammarkpos -FROM pg_catalog.pg_am fk -WHERE ammarkpos != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos); - ctid | ammarkpos -------+----------- -(0 rows) - -SELECT ctid, amrestrpos -FROM pg_catalog.pg_am fk -WHERE amrestrpos != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos); - ctid | amrestrpos -------+------------ -(0 rows) - -SELECT ctid, ambuild -FROM pg_catalog.pg_am fk -WHERE ambuild != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild); - ctid | ambuild -------+--------- -(0 rows) - -SELECT ctid, ambuildempty -FROM pg_catalog.pg_am fk -WHERE ambuildempty != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty); - ctid | ambuildempty -------+-------------- -(0 rows) - -SELECT ctid, ambulkdelete -FROM pg_catalog.pg_am fk -WHERE ambulkdelete != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete); - ctid | ambulkdelete -------+-------------- -(0 rows) - -SELECT ctid, amvacuumcleanup -FROM pg_catalog.pg_am fk -WHERE amvacuumcleanup != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup); - ctid | amvacuumcleanup -------+----------------- -(0 rows) - -SELECT ctid, amcanreturn -FROM pg_catalog.pg_am fk -WHERE amcanreturn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn); - ctid | amcanreturn -------+------------- -(0 rows) - -SELECT ctid, amcostestimate -FROM pg_catalog.pg_am fk -WHERE amcostestimate != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate); - ctid | amcostestimate -------+---------------- -(0 rows) - -SELECT ctid, amoptions -FROM pg_catalog.pg_am fk -WHERE amoptions != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions); - ctid | amoptions -------+----------- -(0 rows) - SELECT ctid, amopfamily FROM pg_catalog.pg_amop fk WHERE amopfamily != 0 AND diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index df29fe5..708d84c 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -1479,6 +1479,12 @@ WHERE p1.oid != p2.oid AND -----+----- (0 rows) +-- Ask access methods to validate opclasses +SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid); + oid +----- +(0 rows) + -- **************** pg_amop **************** -- Look for illegal values in pg_amop fields SELECT p1.amopfamily, p1.amopstrategy @@ -1524,49 +1530,6 @@ WHERE p1.amopsortfamily <> 0 AND NOT EXISTS ------------+-------------- (0 rows) --- check for ordering operators not supported by parent AM -SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname -FROM pg_amop AS p1, pg_am AS p2 -WHERE p1.amopmethod = p2.oid AND - p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop; - amopfamily | amopopr | oid | amname -------------+---------+-----+-------- -(0 rows) - --- Cross-check amopstrategy index against parent AM -SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname -FROM pg_amop AS p1, pg_am AS p2 -WHERE p1.amopmethod = p2.oid AND - p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0; - amopfamily | amopopr | oid | amname -------------+---------+-----+-------- -(0 rows) - --- Detect missing pg_amop entries: should have as many strategy operators --- as AM expects for each datatype combination supported by the opfamily. --- We can't check this for AMs with variable strategy sets. -SELECT p1.amname, p2.amoplefttype, p2.amoprighttype -FROM pg_am AS p1, pg_amop AS p2 -WHERE p2.amopmethod = p1.oid AND - p1.amstrategies <> 0 AND - p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3 - WHERE p3.amopfamily = p2.amopfamily AND - p3.amoplefttype = p2.amoplefttype AND - p3.amoprighttype = p2.amoprighttype AND - p3.amoppurpose = 's'); - amname | amoplefttype | amoprighttype ---------+--------------+--------------- -(0 rows) - --- Currently, none of the AMs with fixed strategy sets support ordering ops. -SELECT p1.amname, p2.amopfamily, p2.amopstrategy -FROM pg_am AS p1, pg_amop AS p2 -WHERE p2.amopmethod = p1.oid AND - p1.amstrategies <> 0 AND p2.amoppurpose <> 's'; - amname | amopfamily | amopstrategy ---------+------------+-------------- -(0 rows) - -- Check that amopopr points at a reasonable-looking operator, ie a binary -- operator. If it's a search operator it had better yield boolean, -- otherwise an input type of its sort opfamily. @@ -1849,15 +1812,6 @@ WHERE p1.amprocfamily = 0 OR p1.amproclefttype = 0 OR p1.amprocrighttype = 0 --------------+----------- (0 rows) --- Cross-check amprocnum index against parent AM -SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname -FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3 -WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND - p1.amprocnum > p2.amsupport; - amprocfamily | amprocnum | oid | amname ---------------+-----------+-----+-------- -(0 rows) - -- Detect missing pg_amproc entries: should have as many support functions -- as AM expects for each datatype combination supported by the opfamily. SELECT * FROM ( diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 3ef55d9..0c784e1 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -1448,8 +1448,12 @@ as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2 create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype); +create function alter1.hash(alter1.ctype) returns int4 language sql +as 'select hashint4($1.f1) # hashtext($1.f2)'; + create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as - operator 1 alter1.=(alter1.ctype, alter1.ctype); + operator 1 alter1.=(alter1.ctype, alter1.ctype), + function 1 alter1.hash(alter1.ctype); create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8; @@ -1469,6 +1473,7 @@ alter operator class alter1.ctype_hash_ops using hash set schema alter2; alter operator family alter1.ctype_hash_ops using hash set schema alter2; alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2; alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2; +alter function alter1.hash(alter1.ctype) set schema alter2; alter type alter1.ctype set schema alter2; alter conversion alter1.ascii_to_utf8 set schema alter2; alter text search parser alter1.prs set schema alter2; diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql index 2fa628d..ca419fd 100644 --- a/src/test/regress/sql/oidjoins.sql +++ b/src/test/regress/sql/oidjoins.sql @@ -37,70 +37,6 @@ SELECT ctid, aggmtranstype FROM pg_catalog.pg_aggregate fk WHERE aggmtranstype != 0 AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype); -SELECT ctid, amkeytype -FROM pg_catalog.pg_am fk -WHERE amkeytype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype); -SELECT ctid, aminsert -FROM pg_catalog.pg_am fk -WHERE aminsert != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert); -SELECT ctid, ambeginscan -FROM pg_catalog.pg_am fk -WHERE ambeginscan != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan); -SELECT ctid, amgettuple -FROM pg_catalog.pg_am fk -WHERE amgettuple != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple); -SELECT ctid, amgetbitmap -FROM pg_catalog.pg_am fk -WHERE amgetbitmap != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap); -SELECT ctid, amrescan -FROM pg_catalog.pg_am fk -WHERE amrescan != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan); -SELECT ctid, amendscan -FROM pg_catalog.pg_am fk -WHERE amendscan != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan); -SELECT ctid, ammarkpos -FROM pg_catalog.pg_am fk -WHERE ammarkpos != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos); -SELECT ctid, amrestrpos -FROM pg_catalog.pg_am fk -WHERE amrestrpos != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos); -SELECT ctid, ambuild -FROM pg_catalog.pg_am fk -WHERE ambuild != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild); -SELECT ctid, ambuildempty -FROM pg_catalog.pg_am fk -WHERE ambuildempty != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty); -SELECT ctid, ambulkdelete -FROM pg_catalog.pg_am fk -WHERE ambulkdelete != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete); -SELECT ctid, amvacuumcleanup -FROM pg_catalog.pg_am fk -WHERE amvacuumcleanup != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup); -SELECT ctid, amcanreturn -FROM pg_catalog.pg_am fk -WHERE amcanreturn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn); -SELECT ctid, amcostestimate -FROM pg_catalog.pg_am fk -WHERE amcostestimate != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate); -SELECT ctid, amoptions -FROM pg_catalog.pg_am fk -WHERE amoptions != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions); SELECT ctid, amopfamily FROM pg_catalog.pg_amop fk WHERE amopfamily != 0 AND diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index c9bdd77..0e0506e 100644 --- a/src/test/regress/sql/opr_sanity.sql +++ b/src/test/regress/sql/opr_sanity.sql @@ -960,6 +960,10 @@ WHERE p1.oid != p2.oid AND p1.opcmethod = p2.opcmethod AND p1.opcintype = p2.opcintype AND p1.opcdefault AND p2.opcdefault; +-- Ask access methods to validate opclasses + +SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid); + -- **************** pg_amop **************** -- Look for illegal values in pg_amop fields @@ -995,41 +999,6 @@ WHERE p1.amopsortfamily <> 0 AND NOT EXISTS (SELECT 1 from pg_opfamily op WHERE op.oid = p1.amopsortfamily AND op.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')); --- check for ordering operators not supported by parent AM - -SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname -FROM pg_amop AS p1, pg_am AS p2 -WHERE p1.amopmethod = p2.oid AND - p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop; - --- Cross-check amopstrategy index against parent AM - -SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname -FROM pg_amop AS p1, pg_am AS p2 -WHERE p1.amopmethod = p2.oid AND - p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0; - --- Detect missing pg_amop entries: should have as many strategy operators --- as AM expects for each datatype combination supported by the opfamily. --- We can't check this for AMs with variable strategy sets. - -SELECT p1.amname, p2.amoplefttype, p2.amoprighttype -FROM pg_am AS p1, pg_amop AS p2 -WHERE p2.amopmethod = p1.oid AND - p1.amstrategies <> 0 AND - p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3 - WHERE p3.amopfamily = p2.amopfamily AND - p3.amoplefttype = p2.amoplefttype AND - p3.amoprighttype = p2.amoprighttype AND - p3.amoppurpose = 's'); - --- Currently, none of the AMs with fixed strategy sets support ordering ops. - -SELECT p1.amname, p2.amopfamily, p2.amopstrategy -FROM pg_am AS p1, pg_amop AS p2 -WHERE p2.amopmethod = p1.oid AND - p1.amstrategies <> 0 AND p2.amoppurpose <> 's'; - -- Check that amopopr points at a reasonable-looking operator, ie a binary -- operator. If it's a search operator it had better yield boolean, -- otherwise an input type of its sort opfamily. @@ -1176,13 +1145,6 @@ FROM pg_amproc as p1 WHERE p1.amprocfamily = 0 OR p1.amproclefttype = 0 OR p1.amprocrighttype = 0 OR p1.amprocnum < 1 OR p1.amproc = 0; --- Cross-check amprocnum index against parent AM - -SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname -FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3 -WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND - p1.amprocnum > p2.amsupport; - -- Detect missing pg_amproc entries: should have as many support functions -- as AM expects for each datatype combination supported by the opfamily.