diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c new file mode 100644 index 25d2a09..88b4f6f *** a/src/backend/access/brin/brin.c --- b/src/backend/access/brin/brin.c *************** *** 35,40 **** --- 35,83 ---- /* + * 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; + + PG_RETURN_POINTER(amroutine); + } + + /* * We use a BrinBuildState during initial construction of a BRIN index. * The running state is kept in a BrinMemTuple. */ *************** static void brin_vacuum_scan(Relation id *** 80,94 **** * 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) { - 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; --- 123,133 ---- * If the range is not currently summarized (i.e. the revmap returns NULL for * it), there's nothing to do. */ ! bool ! brininsert(Relation idxRel, Datum *values, bool *nulls, ! ItemPointer heaptid, Relation heapRel, ! IndexUniqueCheck checkUnique) { BlockNumber pagesPerRange; BrinDesc *bdesc = NULL; BrinRevmap *revmap; *************** brininsert(PG_FUNCTION_ARGS) *** 226,232 **** MemoryContextDelete(tupcxt); } ! return BoolGetDatum(false); } /* --- 265,271 ---- MemoryContextDelete(tupcxt); } ! return false; } /* *************** brininsert(PG_FUNCTION_ARGS) *** 236,247 **** * 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) { - Relation r = (Relation) PG_GETARG_POINTER(0); - int nkeys = PG_GETARG_INT32(1); - int norderbys = PG_GETARG_INT32(2); IndexScanDesc scan; BrinOpaque *opaque; --- 275,283 ---- * 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. */ ! IndexScanDesc ! brinbeginscan(Relation r, int nkeys, int norderbys) { IndexScanDesc scan; BrinOpaque *opaque; *************** brinbeginscan(PG_FUNCTION_ARGS) *** 252,258 **** opaque->bo_bdesc = brin_build_desc(r); scan->opaque = opaque; ! PG_RETURN_POINTER(scan); } /* --- 288,294 ---- opaque->bo_bdesc = brin_build_desc(r); scan->opaque = opaque; ! return scan; } /* *************** brinbeginscan(PG_FUNCTION_ARGS) *** 267,277 **** * unsummarized. Pages in those ranges need to be returned regardless of scan * keys. */ ! Datum ! bringetbitmap(PG_FUNCTION_ARGS) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1); Relation idxRel = scan->indexRelation; Buffer buf = InvalidBuffer; BrinDesc *bdesc; --- 303,311 ---- * unsummarized. Pages in those ranges need to be returned regardless of scan * keys. */ ! int64 ! bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) { Relation idxRel = scan->indexRelation; Buffer buf = InvalidBuffer; BrinDesc *bdesc; *************** bringetbitmap(PG_FUNCTION_ARGS) *** 451,470 **** * returns, but we don't have a precise idea of the number of heap tuples * involved. */ ! PG_RETURN_INT64(totalpages * 10); } /* * Re-initialize state for a BRIN index scan */ ! Datum ! brinrescan(PG_FUNCTION_ARGS) { - 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 --- 485,500 ---- * returns, but we don't have a precise idea of the number of heap tuples * involved. */ ! return totalpages * 10; } /* * Re-initialize state for a BRIN index scan */ ! void ! brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, ! ScanKey orderbys, int norderbys) { /* * Other index AMs preprocess the scan keys at this point, or sometime * early during the scan; this lets them optimize by removing redundant *************** brinrescan(PG_FUNCTION_ARGS) *** 476,513 **** 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) { - 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) { elog(ERROR, "BRIN does not support mark/restore"); - PG_RETURN_VOID(); } ! Datum ! brinrestrpos(PG_FUNCTION_ARGS) { elog(ERROR, "BRIN does not support mark/restore"); - PG_RETURN_VOID(); } /* --- 506,536 ---- if (scankey && scan->numberOfKeys > 0) memmove(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData)); } /* * Close down a BRIN index scan */ ! void ! brinendscan(IndexScanDesc scan) { BrinOpaque *opaque = (BrinOpaque *) scan->opaque; brinRevmapTerminate(opaque->bo_rmAccess); brin_free_desc(opaque->bo_bdesc); pfree(opaque); } ! void ! brinmarkpos(IndexScanDesc scan) { elog(ERROR, "BRIN does not support mark/restore"); } ! void ! brinrestrpos(IndexScanDesc scan) { elog(ERROR, "BRIN does not support mark/restore"); } /* *************** brinbuildCallback(Relation index, *** 579,590 **** /* * brinbuild() -- build a new BRIN index. */ ! Datum ! brinbuild(PG_FUNCTION_ARGS) { - 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; --- 602,610 ---- /* * brinbuild() -- build a new BRIN index. */ ! IndexBuildResult * ! brinbuild(Relation heap, Relation index, IndexInfo *indexInfo) { IndexBuildResult *result; double reltuples; double idxtuples; *************** brinbuild(PG_FUNCTION_ARGS) *** 663,675 **** result->heap_tuples = reltuples; result->index_tuples = idxtuples; ! PG_RETURN_POINTER(result); } ! Datum ! brinbuildempty(PG_FUNCTION_ARGS) { - Relation index = (Relation) PG_GETARG_POINTER(0); Buffer metabuf; /* An empty BRIN index has a metapage only. */ --- 683,694 ---- result->heap_tuples = reltuples; result->index_tuples = idxtuples; ! return result; } ! void ! brinbuildempty(Relation index) { Buffer metabuf; /* An empty BRIN index has a metapage only. */ *************** brinbuildempty(PG_FUNCTION_ARGS) *** 686,693 **** END_CRIT_SECTION(); UnlockReleaseBuffer(metabuf); - - PG_RETURN_VOID(); } /* --- 705,710 ---- *************** brinbuildempty(PG_FUNCTION_ARGS) *** 699,733 **** * 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) { - /* 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); } /* * This routine is in charge of "vacuuming" a BRIN index: we just summarize * ranges that are currently unsummarized. */ ! Datum ! brinvacuumcleanup(PG_FUNCTION_ARGS) { - 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); if (!stats) stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult)); --- 716,744 ---- * 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. */ ! IndexBulkDeleteResult * ! brinbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, ! IndexBulkDeleteCallback callback, void *callback_state) { /* allocate stats if first time through, else re-use existing struct */ if (stats == NULL) stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult)); ! return stats; } /* * This routine is in charge of "vacuuming" a BRIN index: we just summarize * ranges that are currently unsummarized. */ ! IndexBulkDeleteResult * ! brinvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) { Relation heapRel; /* No-op in ANALYZE ONLY mode */ if (info->analyze_only) ! return stats; if (!stats) stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult)); *************** brinvacuumcleanup(PG_FUNCTION_ARGS) *** 744,760 **** heap_close(heapRel, AccessShareLock); ! PG_RETURN_POINTER(stats); } /* * reloptions processor for BRIN indexes */ ! Datum ! brinoptions(PG_FUNCTION_ARGS) { - Datum reloptions = PG_GETARG_DATUM(0); - bool validate = PG_GETARG_BOOL(1); relopt_value *options; BrinOptions *rdopts; int numoptions; --- 755,769 ---- heap_close(heapRel, AccessShareLock); ! return stats; } /* * reloptions processor for BRIN indexes */ ! bytea * ! brinoptions(Datum reloptions, bool validate) { relopt_value *options; BrinOptions *rdopts; int numoptions; *************** brinoptions(PG_FUNCTION_ARGS) *** 767,773 **** /* if none set, we're done */ if (numoptions == 0) ! PG_RETURN_NULL(); rdopts = allocateReloptStruct(sizeof(BrinOptions), options, numoptions); --- 776,782 ---- /* if none set, we're done */ if (numoptions == 0) ! return NULL; rdopts = allocateReloptStruct(sizeof(BrinOptions), options, numoptions); *************** brinoptions(PG_FUNCTION_ARGS) *** 776,782 **** pfree(options); ! PG_RETURN_BYTEA_P(rdopts); } /* --- 785,791 ---- pfree(options); ! return (bytea *)rdopts; } /* diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c new file mode 100644 index 7479d40..e3eed88 *** a/src/backend/access/common/reloptions.c --- b/src/backend/access/common/reloptions.c *************** untransformRelOptions(Datum options) *** 878,884 **** * in the case of the tuple corresponding to an index, or InvalidOid otherwise. */ bytea * ! extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, Oid amoptions) { bytea *options; bool isnull; --- 878,884 ---- * in the case of the tuple corresponding to an index, or InvalidOid otherwise. */ bytea * ! extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, amoptions_function amoptions) { bytea *options; bool isnull; *************** heap_reloptions(char relkind, Datum relo *** 1366,1399 **** * validate error flag */ bytea * ! index_reloptions(RegProcedure amoptions, Datum reloptions, bool validate) { ! FmgrInfo flinfo; ! FunctionCallInfoData fcinfo; ! Datum result; ! ! Assert(RegProcedureIsValid(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); } /* --- 1366,1380 ---- * validate error flag */ bytea * ! index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate) { ! Assert(amoptions); /* Assume function is strict */ if (!PointerIsValid(DatumGetPointer(reloptions))) return NULL; ! return amoptions(reloptions, validate); } /* diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c new file mode 100644 index 54b2db8..29b22d6 *** a/src/backend/access/gin/ginget.c --- b/src/backend/access/gin/ginget.c *************** scanPendingInsert(IndexScanDesc scan, TI *** 1772,1782 **** #define GinIsVoidRes(s) ( ((GinScanOpaque) scan->opaque)->isVoidRes ) ! Datum ! gingetbitmap(PG_FUNCTION_ARGS) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1); GinScanOpaque so = (GinScanOpaque) scan->opaque; int64 ntids; ItemPointerData iptr; --- 1772,1780 ---- #define GinIsVoidRes(s) ( ((GinScanOpaque) scan->opaque)->isVoidRes ) ! int64 ! gingetbitmap(IndexScanDesc scan, TIDBitmap *tbm) { GinScanOpaque so = (GinScanOpaque) scan->opaque; int64 ntids; ItemPointerData iptr; *************** gingetbitmap(PG_FUNCTION_ARGS) *** 1827,1831 **** ntids++; } ! PG_RETURN_INT64(ntids); } --- 1825,1829 ---- ntids++; } ! return ntids; } diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c new file mode 100644 index fc44f02..131d749 *** a/src/backend/access/gin/gininsert.c --- b/src/backend/access/gin/gininsert.c *************** ginBuildCallback(Relation index, HeapTup *** 306,317 **** MemoryContextSwitchTo(oldCtx); } ! Datum ! ginbuild(PG_FUNCTION_ARGS) { - 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; --- 306,314 ---- MemoryContextSwitchTo(oldCtx); } ! IndexBuildResult * ! ginbuild(Relation heap, Relation index, IndexInfo *indexInfo) { IndexBuildResult *result; double reltuples; GinBuildState buildstate; *************** ginbuild(PG_FUNCTION_ARGS) *** 429,444 **** result->heap_tuples = reltuples; result->index_tuples = buildstate.indtuples; ! PG_RETURN_POINTER(result); } /* * ginbuildempty() -- build an empty gin index in the initialization fork */ ! Datum ! ginbuildempty(PG_FUNCTION_ARGS) { - Relation index = (Relation) PG_GETARG_POINTER(0); Buffer RootBuffer, MetaBuffer; --- 426,440 ---- result->heap_tuples = reltuples; result->index_tuples = buildstate.indtuples; ! return result; } /* * ginbuildempty() -- build an empty gin index in the initialization fork */ ! void ! ginbuildempty(Relation index) { Buffer RootBuffer, MetaBuffer; *************** ginbuildempty(PG_FUNCTION_ARGS) *** 463,470 **** /* Unlock and release the buffers. */ UnlockReleaseBuffer(MetaBuffer); UnlockReleaseBuffer(RootBuffer); - - PG_RETURN_VOID(); } /* --- 459,464 ---- *************** ginHeapTupleInsert(GinState *ginstate, O *** 489,506 **** item, 1, NULL); } ! Datum ! gininsert(PG_FUNCTION_ARGS) { - 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; --- 483,493 ---- item, 1, NULL); } ! bool ! gininsert(Relation index, Datum *values, bool *isnull, ! ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique) { GinState ginstate; MemoryContext oldCtx; MemoryContext insertCtx; *************** gininsert(PG_FUNCTION_ARGS) *** 541,545 **** MemoryContextSwitchTo(oldCtx); MemoryContextDelete(insertCtx); ! PG_RETURN_BOOL(false); } --- 528,532 ---- MemoryContextSwitchTo(oldCtx); MemoryContextDelete(insertCtx); ! return false; } diff --git a/src/backend/access/gin/ginscan.c b/src/backend/access/gin/ginscan.c new file mode 100644 index ac3a92b..d97a9db *** a/src/backend/access/gin/ginscan.c --- b/src/backend/access/gin/ginscan.c *************** *** 21,32 **** #include "utils/rel.h" ! Datum ! ginbeginscan(PG_FUNCTION_ARGS) { - Relation rel = (Relation) PG_GETARG_POINTER(0); - int nkeys = PG_GETARG_INT32(1); - int norderbys = PG_GETARG_INT32(2); IndexScanDesc scan; GinScanOpaque so; --- 21,29 ---- #include "utils/rel.h" ! IndexScanDesc ! ginbeginscan(Relation rel, int nkeys, int norderbys) { IndexScanDesc scan; GinScanOpaque so; *************** ginbeginscan(PG_FUNCTION_ARGS) *** 53,59 **** scan->opaque = so; ! PG_RETURN_POINTER(scan); } /* --- 50,56 ---- scan->opaque = so; ! return scan; } /* *************** ginNewScanKey(IndexScanDesc scan) *** 417,429 **** pgstat_count_index_scan(scan->indexRelation); } ! Datum ! ginrescan(PG_FUNCTION_ARGS) { - 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); --- 414,423 ---- pgstat_count_index_scan(scan->indexRelation); } ! void ! ginrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, ! ScanKey orderbys, int norderbys) { GinScanOpaque so = (GinScanOpaque) scan->opaque; ginFreeScanKeys(so); *************** ginrescan(PG_FUNCTION_ARGS) *** 433,447 **** memmove(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData)); } - - PG_RETURN_VOID(); } ! Datum ! ginendscan(PG_FUNCTION_ARGS) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); GinScanOpaque so = (GinScanOpaque) scan->opaque; ginFreeScanKeys(so); --- 427,438 ---- memmove(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData)); } } ! void ! ginendscan(IndexScanDesc scan) { GinScanOpaque so = (GinScanOpaque) scan->opaque; ginFreeScanKeys(so); *************** ginendscan(PG_FUNCTION_ARGS) *** 450,469 **** MemoryContextDelete(so->keyCtx); pfree(so); - - PG_RETURN_VOID(); } ! Datum ! ginmarkpos(PG_FUNCTION_ARGS) { elog(ERROR, "GIN does not support mark/restore"); - PG_RETURN_VOID(); } ! Datum ! ginrestrpos(PG_FUNCTION_ARGS) { elog(ERROR, "GIN does not support mark/restore"); - PG_RETURN_VOID(); } --- 441,456 ---- MemoryContextDelete(so->keyCtx); pfree(so); } ! void ! ginmarkpos(IndexScanDesc scan) { elog(ERROR, "GIN does not support mark/restore"); } ! void ! ginrestrpos(IndexScanDesc scan) { elog(ERROR, "GIN does not support mark/restore"); } diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c new file mode 100644 index cb4e32f..04f25f4 *** a/src/backend/access/gin/ginutil.c --- b/src/backend/access/gin/ginutil.c *************** *** 22,28 **** --- 22,72 ---- #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; + PG_RETURN_POINTER(amroutine); + } /* * initGinState: fill in an empty GinState struct to describe the index *************** ginExtractEntries(GinState *ginstate, Of *** 516,526 **** return entries; } ! Datum ! ginoptions(PG_FUNCTION_ARGS) { - Datum reloptions = PG_GETARG_DATUM(0); - bool validate = PG_GETARG_BOOL(1); relopt_value *options; GinOptions *rdopts; int numoptions; --- 560,568 ---- return entries; } ! bytea * ! ginoptions(Datum reloptions, bool validate) { relopt_value *options; GinOptions *rdopts; int numoptions; *************** ginoptions(PG_FUNCTION_ARGS) *** 535,541 **** /* if none set, we're done */ if (numoptions == 0) ! PG_RETURN_NULL(); rdopts = allocateReloptStruct(sizeof(GinOptions), options, numoptions); --- 577,583 ---- /* if none set, we're done */ if (numoptions == 0) ! return NULL; rdopts = allocateReloptStruct(sizeof(GinOptions), options, numoptions); *************** ginoptions(PG_FUNCTION_ARGS) *** 544,550 **** pfree(options); ! PG_RETURN_BYTEA_P(rdopts); } /* --- 586,592 ---- pfree(options); ! return (bytea *)rdopts; } /* diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c new file mode 100644 index 1315762..224dcc0 *** a/src/backend/access/gin/ginvacuum.c --- b/src/backend/access/gin/ginvacuum.c *************** ginVacuumEntryPage(GinVacuumState *gvs, *** 513,525 **** return (tmppage == origpage) ? NULL : tmppage; } ! Datum ! ginbulkdelete(PG_FUNCTION_ARGS) { - 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; --- 513,522 ---- return (tmppage == origpage) ? NULL : tmppage; } ! IndexBulkDeleteResult * ! ginbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, ! IndexBulkDeleteCallback callback, void *callback_state) { Relation index = info->index; BlockNumber blkno = GIN_ROOT_BLKNO; GinVacuumState gvs; *************** ginbulkdelete(PG_FUNCTION_ARGS) *** 634,647 **** MemoryContextDelete(gvs.tmpCxt); ! PG_RETURN_POINTER(gvs.result); } ! Datum ! ginvacuumcleanup(PG_FUNCTION_ARGS) { - IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0); - IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1); Relation index = info->index; bool needLock; BlockNumber npages, --- 631,642 ---- MemoryContextDelete(gvs.tmpCxt); ! return gvs.result; } ! IndexBulkDeleteResult * ! ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) { Relation index = info->index; bool needLock; BlockNumber npages, *************** ginvacuumcleanup(PG_FUNCTION_ARGS) *** 661,667 **** initGinState(&ginstate, index); ginInsertCleanup(&ginstate, true, stats); } ! PG_RETURN_POINTER(stats); } /* --- 656,662 ---- initGinState(&ginstate, index); ginInsertCleanup(&ginstate, true, stats); } ! return stats; } /* *************** ginvacuumcleanup(PG_FUNCTION_ARGS) *** 746,750 **** if (needLock) UnlockRelationForExtension(index, ExclusiveLock); ! PG_RETURN_POINTER(stats); } --- 741,745 ---- if (needLock) UnlockRelationForExtension(index, ExclusiveLock); ! return stats; } diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c new file mode 100644 index 0e49959..396a672 *** a/src/backend/access/gist/gist.c --- b/src/backend/access/gist/gist.c *************** *** 16,21 **** --- 16,22 ---- #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,29 **** --- 25,31 ---- #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); *************** static bool gistinserttuples(GISTInsertS *** 37,42 **** --- 39,86 ---- static void gistfinishsplit(GISTInsertState *state, GISTInsertStack *stack, GISTSTATE *giststate, List *splitinfo, bool releasebuf); + /* + * SP-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; + + PG_RETURN_POINTER(amroutine); + } #define ROTATEDIST(d) do { \ SplitedPageLayout *tmp=(SplitedPageLayout*)palloc(sizeof(SplitedPageLayout)); \ *************** createTempGistContext(void) *** 69,78 **** /* * gistbuildempty() -- build an empty gist index in the initialization fork */ ! Datum ! gistbuildempty(PG_FUNCTION_ARGS) { - Relation index = (Relation) PG_GETARG_POINTER(0); Buffer buffer; /* Initialize the root page */ --- 113,121 ---- /* * gistbuildempty() -- build an empty gist index in the initialization fork */ ! void ! gistbuildempty(Relation index) { Buffer buffer; /* Initialize the root page */ *************** gistbuildempty(PG_FUNCTION_ARGS) *** 88,95 **** /* Unlock and release the buffer */ UnlockReleaseBuffer(buffer); - - PG_RETURN_VOID(); } /* --- 131,136 ---- *************** gistbuildempty(PG_FUNCTION_ARGS) *** 98,115 **** * 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) { - 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; --- 139,149 ---- * 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. */ ! bool ! gistinsert(Relation r, Datum *values, bool *isnull, ! ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique) { IndexTuple itup; GISTSTATE *giststate; MemoryContext oldCxt; *************** gistinsert(PG_FUNCTION_ARGS) *** 135,141 **** MemoryContextSwitchTo(oldCxt); freeGISTstate(giststate); ! PG_RETURN_BOOL(false); } --- 169,175 ---- MemoryContextSwitchTo(oldCxt); freeGISTstate(giststate); ! return false; } diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c new file mode 100644 index ff888e2..08a029c *** a/src/backend/access/gist/gistbuild.c --- b/src/backend/access/gist/gistbuild.c *************** static BlockNumber gistGetParent(GISTBui *** 109,120 **** * but switches to more efficient buffering build algorithm after a certain * number of tuples (unless buffering mode is disabled). */ ! Datum ! gistbuild(PG_FUNCTION_ARGS) { - 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; --- 109,117 ---- * but switches to more efficient buffering build algorithm after a certain * number of tuples (unless buffering mode is disabled). */ ! IndexBuildResult * ! gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) { IndexBuildResult *result; double reltuples; GISTBuildState buildstate; *************** gistbuild(PG_FUNCTION_ARGS) *** 232,238 **** result->heap_tuples = reltuples; result->index_tuples = (double) buildstate.indtuples; ! PG_RETURN_POINTER(result); } /* --- 229,235 ---- result->heap_tuples = reltuples; result->index_tuples = (double) buildstate.indtuples; ! return result; } /* diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c new file mode 100644 index 20f695c..36d11fe *** a/src/backend/access/gist/gistget.c --- b/src/backend/access/gist/gistget.c *************** getNextNearest(IndexScanDesc scan) *** 530,540 **** /* * gistgettuple() -- Get the next tuple in the scan */ ! Datum ! gistgettuple(PG_FUNCTION_ARGS) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1); GISTScanOpaque so = (GISTScanOpaque) scan->opaque; if (dir != ForwardScanDirection) --- 530,538 ---- /* * gistgettuple() -- Get the next tuple in the scan */ ! bool ! gistgettuple(IndexScanDesc scan, ScanDirection dir) { GISTScanOpaque so = (GISTScanOpaque) scan->opaque; if (dir != ForwardScanDirection) *************** gistgettuple(PG_FUNCTION_ARGS) *** 563,569 **** if (scan->numberOfOrderBys > 0) { /* Must fetch tuples in strict distance order */ ! PG_RETURN_BOOL(getNextNearest(scan)); } else { --- 561,567 ---- if (scan->numberOfOrderBys > 0) { /* Must fetch tuples in strict distance order */ ! return getNextNearest(scan); } else { *************** gistgettuple(PG_FUNCTION_ARGS) *** 583,589 **** so->curPageData++; ! PG_RETURN_BOOL(true); } /* find and process the next index page */ --- 581,587 ---- so->curPageData++; ! return true; } /* find and process the next index page */ *************** gistgettuple(PG_FUNCTION_ARGS) *** 592,598 **** GISTSearchItem *item = getNextGISTSearchItem(so); if (!item) ! PG_RETURN_BOOL(false); CHECK_FOR_INTERRUPTS(); --- 590,596 ---- GISTSearchItem *item = getNextGISTSearchItem(so); if (!item) ! return false; CHECK_FOR_INTERRUPTS(); *************** gistgettuple(PG_FUNCTION_ARGS) *** 613,629 **** /* * gistgetbitmap() -- Get a bitmap of all heap tuple locations */ ! Datum ! gistgetbitmap(PG_FUNCTION_ARGS) { - 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); pgstat_count_index_scan(scan->indexRelation); --- 611,625 ---- /* * gistgetbitmap() -- Get a bitmap of all heap tuple locations */ ! int64 ! gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm) { GISTScanOpaque so = (GISTScanOpaque) scan->opaque; int64 ntids = 0; GISTSearchItem fakeItem; if (!so->qual_ok) ! return 0; pgstat_count_index_scan(scan->indexRelation); *************** gistgetbitmap(PG_FUNCTION_ARGS) *** 654,660 **** pfree(item); } ! PG_RETURN_INT64(ntids); } /* --- 650,656 ---- pfree(item); } ! return ntids; } /* *************** gistgetbitmap(PG_FUNCTION_ARGS) *** 662,675 **** * * Opclasses that implement a fetch function support index-only scans. */ ! Datum ! gistcanreturn(PG_FUNCTION_ARGS) { - 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); else ! PG_RETURN_BOOL(false); } --- 658,668 ---- * * Opclasses that implement a fetch function support index-only scans. */ ! bool ! gistcanreturn(Relation index, int attno) { if (OidIsValid(index_getprocid(index, attno, GIST_FETCH_PROC))) ! return true; else ! return false; } diff --git a/src/backend/access/gist/gistscan.c b/src/backend/access/gist/gistscan.c new file mode 100644 index ad39294..e0b5394 *** a/src/backend/access/gist/gistscan.c --- b/src/backend/access/gist/gistscan.c *************** pairingheap_GISTSearchItem_cmp(const pai *** 54,65 **** * Index AM API functions for scanning GiST indexes */ ! Datum ! gistbeginscan(PG_FUNCTION_ARGS) { - 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; --- 54,62 ---- * Index AM API functions for scanning GiST indexes */ ! IndexScanDesc ! gistbeginscan(Relation r, int nkeys, int norderbys) { IndexScanDesc scan; GISTSTATE *giststate; GISTScanOpaque so; *************** gistbeginscan(PG_FUNCTION_ARGS) *** 102,116 **** MemoryContextSwitchTo(oldCxt); ! PG_RETURN_POINTER(scan); } ! Datum ! gistrescan(PG_FUNCTION_ARGS) { - 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; --- 99,111 ---- MemoryContextSwitchTo(oldCxt); ! return scan; } ! void ! gistrescan(IndexScanDesc scan, ScanKey key, int nkeys, ! ScanKey orderbys, int norderbys) { /* nkeys and norderbys arguments are ignored */ GISTScanOpaque so = (GISTScanOpaque) scan->opaque; *************** gistrescan(PG_FUNCTION_ARGS) *** 309,336 **** if (!first_time) pfree(fn_extras); } - - PG_RETURN_VOID(); } ! Datum ! gistmarkpos(PG_FUNCTION_ARGS) { elog(ERROR, "GiST does not support mark/restore"); - PG_RETURN_VOID(); } ! Datum ! gistrestrpos(PG_FUNCTION_ARGS) { elog(ERROR, "GiST does not support mark/restore"); - PG_RETURN_VOID(); } ! Datum ! gistendscan(PG_FUNCTION_ARGS) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); GISTScanOpaque so = (GISTScanOpaque) scan->opaque; /* --- 304,326 ---- if (!first_time) pfree(fn_extras); } } ! void ! gistmarkpos(IndexScanDesc scan) { elog(ERROR, "GiST does not support mark/restore"); } ! void ! gistrestrpos(IndexScanDesc scan) { elog(ERROR, "GiST does not support mark/restore"); } ! void ! gistendscan(IndexScanDesc scan) { GISTScanOpaque so = (GISTScanOpaque) scan->opaque; /* *************** gistendscan(PG_FUNCTION_ARGS) *** 338,343 **** * as well as the queueCxt if there is a separate context for it. */ freeGISTstate(so->giststate); - - PG_RETURN_VOID(); } --- 328,331 ---- diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c new file mode 100644 index 7d596a3..45f6246 *** a/src/backend/access/gist/gistutil.c --- b/src/backend/access/gist/gistutil.c *************** gistNewBuffer(Relation r) *** 808,818 **** return buffer; } ! Datum ! gistoptions(PG_FUNCTION_ARGS) { - Datum reloptions = PG_GETARG_DATUM(0); - bool validate = PG_GETARG_BOOL(1); relopt_value *options; GiSTOptions *rdopts; int numoptions; --- 808,816 ---- return buffer; } ! bytea * ! gistoptions(Datum reloptions, bool validate) { relopt_value *options; GiSTOptions *rdopts; int numoptions; *************** gistoptions(PG_FUNCTION_ARGS) *** 826,832 **** /* if none set, we're done */ if (numoptions == 0) ! PG_RETURN_NULL(); rdopts = allocateReloptStruct(sizeof(GiSTOptions), options, numoptions); --- 824,830 ---- /* if none set, we're done */ if (numoptions == 0) ! return NULL; rdopts = allocateReloptStruct(sizeof(GiSTOptions), options, numoptions); *************** gistoptions(PG_FUNCTION_ARGS) *** 835,841 **** pfree(options); ! PG_RETURN_BYTEA_P(rdopts); } --- 833,839 ---- pfree(options); ! return (bytea *)rdopts; } diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c new file mode 100644 index 2337dbd..fb6947b *** a/src/backend/access/gist/gistvacuum.c --- b/src/backend/access/gist/gistvacuum.c *************** *** 25,35 **** /* * VACUUM cleanup: update FSM */ ! Datum ! gistvacuumcleanup(PG_FUNCTION_ARGS) { - IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0); - IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1); Relation rel = info->index; BlockNumber npages, blkno; --- 25,33 ---- /* * VACUUM cleanup: update FSM */ ! IndexBulkDeleteResult * ! gistvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) { Relation rel = info->index; BlockNumber npages, blkno; *************** gistvacuumcleanup(PG_FUNCTION_ARGS) *** 38,44 **** /* No-op in ANALYZE ONLY mode */ if (info->analyze_only) ! PG_RETURN_POINTER(stats); /* Set up all-zero stats if gistbulkdelete wasn't called */ if (stats == NULL) --- 36,42 ---- /* No-op in ANALYZE ONLY mode */ if (info->analyze_only) ! return stats; /* Set up all-zero stats if gistbulkdelete wasn't called */ if (stats == NULL) *************** gistvacuumcleanup(PG_FUNCTION_ARGS) *** 98,104 **** if (needLock) UnlockRelationForExtension(rel, ExclusiveLock); ! PG_RETURN_POINTER(stats); } typedef struct GistBDItem --- 96,102 ---- if (needLock) UnlockRelationForExtension(rel, ExclusiveLock); ! return stats; } typedef struct GistBDItem *************** pushStackIfSplited(Page page, GistBDItem *** 137,149 **** * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ ! Datum ! gistbulkdelete(PG_FUNCTION_ARGS) { - 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; --- 135,144 ---- * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ ! IndexBulkDeleteResult * ! gistbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, ! IndexBulkDeleteCallback callback, void *callback_state) { Relation rel = info->index; GistBDItem *stack, *ptr; *************** gistbulkdelete(PG_FUNCTION_ARGS) *** 279,283 **** vacuum_delay_point(); } ! PG_RETURN_POINTER(stats); } --- 274,278 ---- vacuum_delay_point(); } ! return stats; } diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c new file mode 100644 index 24b06a5..8f1b201 *** a/src/backend/access/hash/hash.c --- b/src/backend/access/hash/hash.c *************** *** 18,23 **** --- 18,24 ---- #include "postgres.h" + #include "access/amapi.h" #include "access/hash.h" #include "access/relscan.h" #include "catalog/index.h" *************** *** 26,31 **** --- 27,33 ---- #include "optimizer/plancat.h" #include "storage/bufmgr.h" #include "utils/rel.h" + #include "utils/selfuncs.h" /* Working state for hashbuild and its callback */ *************** static void hashbuildCallback(Relation i *** 42,57 **** bool tupleIsAlive, void *state); /* * hashbuild() -- build a new hash index. */ ! Datum ! hashbuild(PG_FUNCTION_ARGS) { - 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; --- 44,98 ---- 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; + + PG_RETURN_POINTER(amroutine); + } /* * hashbuild() -- build a new hash index. */ ! IndexBuildResult * ! hashbuild(Relation heap, Relation index, IndexInfo *indexInfo) { IndexBuildResult *result; BlockNumber relpages; double reltuples; *************** hashbuild(PG_FUNCTION_ARGS) *** 112,131 **** result->heap_tuples = reltuples; result->index_tuples = buildstate.indtuples; ! PG_RETURN_POINTER(result); } /* * hashbuildempty() -- build an empty hash index in the initialization fork */ ! Datum ! hashbuildempty(PG_FUNCTION_ARGS) { - Relation index = (Relation) PG_GETARG_POINTER(0); - _hash_metapinit(index, 0, INIT_FORKNUM); - - PG_RETURN_VOID(); } /* --- 153,168 ---- result->heap_tuples = reltuples; result->index_tuples = buildstate.indtuples; ! return result; } /* * hashbuildempty() -- build an empty hash index in the initialization fork */ ! void ! hashbuildempty(Relation index) { _hash_metapinit(index, 0, INIT_FORKNUM); } /* *************** hashbuildCallback(Relation index, *** 167,184 **** * 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) { - 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; /* --- 204,214 ---- * 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. */ ! bool ! hashinsert(Relation rel, Datum *values, bool *isnull, ! ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique) { IndexTuple itup; /* *************** hashinsert(PG_FUNCTION_ARGS) *** 191,197 **** * chosen in 1986, not of the way nulls are handled here. */ if (isnull[0]) ! PG_RETURN_BOOL(false); /* generate an index tuple */ itup = _hash_form_tuple(rel, values, isnull); --- 221,227 ---- * chosen in 1986, not of the way nulls are handled here. */ if (isnull[0]) ! return false; /* generate an index tuple */ itup = _hash_form_tuple(rel, values, isnull); *************** hashinsert(PG_FUNCTION_ARGS) *** 201,218 **** pfree(itup); ! PG_RETURN_BOOL(false); } /* * hashgettuple() -- Get the next tuple in the scan. */ ! Datum ! hashgettuple(PG_FUNCTION_ARGS) { - 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; --- 231,246 ---- pfree(itup); ! return false; } /* * hashgettuple() -- Get the next tuple in the scan. */ ! bool ! hashgettuple(IndexScanDesc scan, ScanDirection dir) { HashScanOpaque so = (HashScanOpaque) scan->opaque; Relation rel = scan->indexRelation; Buffer buf; *************** hashgettuple(PG_FUNCTION_ARGS) *** 314,331 **** /* Return current heap TID on success */ scan->xs_ctup.t_self = so->hashso_heappos; ! PG_RETURN_BOOL(res); } /* * hashgetbitmap() -- get all tuples at once */ ! Datum ! hashgetbitmap(PG_FUNCTION_ARGS) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1); HashScanOpaque so = (HashScanOpaque) scan->opaque; bool res; int64 ntids = 0; --- 342,357 ---- /* Return current heap TID on success */ scan->xs_ctup.t_self = so->hashso_heappos; ! return res; } /* * hashgetbitmap() -- get all tuples at once */ ! int64 ! hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm) { HashScanOpaque so = (HashScanOpaque) scan->opaque; bool res; int64 ntids = 0; *************** hashgetbitmap(PG_FUNCTION_ARGS) *** 362,380 **** res = _hash_next(scan, ForwardScanDirection); } ! PG_RETURN_INT64(ntids); } /* * hashbeginscan() -- start a scan on a hash index */ ! Datum ! hashbeginscan(PG_FUNCTION_ARGS) { - Relation rel = (Relation) PG_GETARG_POINTER(0); - int nkeys = PG_GETARG_INT32(1); - int norderbys = PG_GETARG_INT32(2); IndexScanDesc scan; HashScanOpaque so; --- 388,403 ---- res = _hash_next(scan, ForwardScanDirection); } ! return ntids; } /* * hashbeginscan() -- start a scan on a hash index */ ! IndexScanDesc ! hashbeginscan(Relation rel, int nkeys, int norderbys) { IndexScanDesc scan; HashScanOpaque so; *************** hashbeginscan(PG_FUNCTION_ARGS) *** 396,414 **** /* register scan in case we change pages it's using */ _hash_regscan(scan); ! PG_RETURN_POINTER(scan); } /* * hashrescan() -- rescan an index relation */ ! Datum ! hashrescan(PG_FUNCTION_ARGS) { - 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; --- 419,434 ---- /* register scan in case we change pages it's using */ _hash_regscan(scan); ! return scan; } /* * hashrescan() -- rescan an index relation */ ! void ! hashrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, ! ScanKey orderbys, int norderbys) { HashScanOpaque so = (HashScanOpaque) scan->opaque; Relation rel = scan->indexRelation; *************** hashrescan(PG_FUNCTION_ARGS) *** 434,450 **** scan->numberOfKeys * sizeof(ScanKeyData)); so->hashso_bucket_valid = false; } - - PG_RETURN_VOID(); } /* * hashendscan() -- close down a scan */ ! Datum ! hashendscan(PG_FUNCTION_ARGS) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); HashScanOpaque so = (HashScanOpaque) scan->opaque; Relation rel = scan->indexRelation; --- 454,467 ---- scan->numberOfKeys * sizeof(ScanKeyData)); so->hashso_bucket_valid = false; } } /* * hashendscan() -- close down a scan */ ! void ! hashendscan(IndexScanDesc scan) { HashScanOpaque so = (HashScanOpaque) scan->opaque; Relation rel = scan->indexRelation; *************** hashendscan(PG_FUNCTION_ARGS) *** 463,490 **** pfree(so); scan->opaque = NULL; - - PG_RETURN_VOID(); } /* * hashmarkpos() -- save current scan position */ ! Datum ! hashmarkpos(PG_FUNCTION_ARGS) { elog(ERROR, "hash does not support mark/restore"); - PG_RETURN_VOID(); } /* * hashrestrpos() -- restore scan to last saved position */ ! Datum ! hashrestrpos(PG_FUNCTION_ARGS) { elog(ERROR, "hash does not support mark/restore"); - PG_RETURN_VOID(); } /* --- 480,503 ---- pfree(so); scan->opaque = NULL; } /* * hashmarkpos() -- save current scan position */ ! void ! hashmarkpos(IndexScanDesc scan) { elog(ERROR, "hash does not support mark/restore"); } /* * hashrestrpos() -- restore scan to last saved position */ ! void ! hashrestrpos(IndexScanDesc scan) { elog(ERROR, "hash does not support mark/restore"); } /* *************** hashrestrpos(PG_FUNCTION_ARGS) *** 494,506 **** * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ ! Datum ! hashbulkdelete(PG_FUNCTION_ARGS) { - 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; --- 507,516 ---- * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ ! IndexBulkDeleteResult * ! hashbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, ! IndexBulkDeleteCallback callback, void *callback_state) { Relation rel = info->index; double tuples_removed; double num_index_tuples; *************** loop_top: *** 670,676 **** stats->tuples_removed += tuples_removed; /* hashvacuumcleanup will fill in num_pages */ ! PG_RETURN_POINTER(stats); } /* --- 680,686 ---- stats->tuples_removed += tuples_removed; /* hashvacuumcleanup will fill in num_pages */ ! return stats; } /* *************** loop_top: *** 678,701 **** * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ ! Datum ! hashvacuumcleanup(PG_FUNCTION_ARGS) { - 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); /* update statistics */ num_pages = RelationGetNumberOfBlocks(rel); stats->num_pages = num_pages; ! PG_RETURN_POINTER(stats); } --- 688,709 ---- * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ ! IndexBulkDeleteResult * ! hashvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) { 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) ! return NULL; /* update statistics */ num_pages = RelationGetNumberOfBlocks(rel); stats->num_pages = num_pages; ! return stats; } diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c new file mode 100644 index 3d66216..85236e2 *** a/src/backend/access/hash/hashutil.c --- b/src/backend/access/hash/hashutil.c *************** _hash_checkpage(Relation rel, Buffer buf *** 217,234 **** } } ! Datum ! hashoptions(PG_FUNCTION_ARGS) { - 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(); } /* --- 217,232 ---- } } ! bytea * ! hashoptions(Datum reloptions, bool validate) { bytea *result; result = default_reloptions(reloptions, validate, RELOPT_KIND_HASH); if (result) ! return result; ! return NULL; } /* diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c new file mode 100644 index 2b27e73..ebf9313 *** a/src/backend/access/index/indexam.c --- b/src/backend/access/index/indexam.c *************** *** 65,70 **** --- 65,71 ---- #include "postgres.h" + #include "access/amapi.h" #include "access/relscan.h" #include "access/transam.h" #include "access/xlog.h" *************** *** 92,140 **** * ---------------------------------------------------------------- */ #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) ! #define GET_SCAN_PROCEDURE(pname) \ ! 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) static IndexScanDesc index_beginscan_internal(Relation indexRelation, int nkeys, int norderbys, Snapshot snapshot); --- 93,124 ---- * ---------------------------------------------------------------- */ #define RELATION_CHECKS \ ! do { \ ! Assert(RelationIsValid(indexRelation)); \ ! Assert(indexRelation->amroutine); \ ! Assert(!ReindexIsProcessingIndex(RelationGetRelid(indexRelation))); \ ! } while (0) #define SCAN_CHECKS \ do { \ ! 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); *************** index_insert(Relation indexRelation, *** 210,235 **** Relation heapRelation, IndexUniqueCheck checkUnique) { - FmgrInfo *procedure; - RELATION_CHECKS; ! GET_REL_PROCEDURE(aminsert); ! if (!(indexRelation->rd_am->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))); } /* --- 194,210 ---- Relation heapRelation, IndexUniqueCheck checkUnique) { RELATION_CHECKS; ! CHECK_PROCEDURE(aminsert); ! if (!(indexRelation->amroutine->ampredlocks)) CheckForSerializableConflictIn(indexRelation, (HeapTuple) NULL, InvalidBuffer); ! return indexRelation->amroutine->aminsert(indexRelation, values, isnull, ! heap_t_ctid, heapRelation, ! checkUnique); } /* *************** index_beginscan_internal(Relation indexR *** 289,300 **** int nkeys, int norderbys, Snapshot snapshot) { IndexScanDesc scan; - FmgrInfo *procedure; RELATION_CHECKS; ! GET_REL_PROCEDURE(ambeginscan); ! if (!(indexRelation->rd_am->ampredlocks)) PredicateLockRelation(indexRelation, snapshot); /* --- 264,274 ---- int nkeys, int norderbys, Snapshot snapshot) { IndexScanDesc scan; RELATION_CHECKS; ! CHECK_PROCEDURE(ambeginscan); ! if (!(indexRelation->amroutine->ampredlocks)) PredicateLockRelation(indexRelation, snapshot); /* *************** index_beginscan_internal(Relation indexR *** 305,315 **** /* * Tell the AM to open a scan. */ ! scan = (IndexScanDesc) ! DatumGetPointer(FunctionCall3(procedure, ! PointerGetDatum(indexRelation), ! Int32GetDatum(nkeys), ! Int32GetDatum(norderbys))); return scan; } --- 279,286 ---- /* * Tell the AM to open a scan. */ ! scan = indexRelation->amroutine->ambeginscan(indexRelation, nkeys, ! norderbys); return scan; } *************** index_rescan(IndexScanDesc scan, *** 331,340 **** ScanKey keys, int nkeys, ScanKey orderbys, int norderbys) { - FmgrInfo *procedure; - SCAN_CHECKS; ! GET_SCAN_PROCEDURE(amrescan); Assert(nkeys == scan->numberOfKeys); Assert(norderbys == scan->numberOfOrderBys); --- 302,309 ---- ScanKey keys, int nkeys, ScanKey orderbys, int norderbys) { SCAN_CHECKS; ! CHECK_SCAN_PROCEDURE(amrescan); Assert(nkeys == scan->numberOfKeys); Assert(norderbys == scan->numberOfOrderBys); *************** index_rescan(IndexScanDesc scan, *** 350,361 **** scan->kill_prior_tuple = false; /* for safety */ ! FunctionCall5(procedure, ! PointerGetDatum(scan), ! PointerGetDatum(keys), ! Int32GetDatum(nkeys), ! PointerGetDatum(orderbys), ! Int32GetDatum(norderbys)); } /* ---------------- --- 319,326 ---- scan->kill_prior_tuple = false; /* for safety */ ! scan->indexRelation->amroutine->amrescan(scan, keys, nkeys, ! orderbys, norderbys); } /* ---------------- *************** index_rescan(IndexScanDesc scan, *** 365,374 **** void index_endscan(IndexScanDesc scan) { - FmgrInfo *procedure; - SCAN_CHECKS; ! GET_SCAN_PROCEDURE(amendscan); /* Release any held pin on a heap page */ if (BufferIsValid(scan->xs_cbuf)) --- 330,337 ---- void index_endscan(IndexScanDesc scan) { SCAN_CHECKS; ! CHECK_SCAN_PROCEDURE(amendscan); /* Release any held pin on a heap page */ if (BufferIsValid(scan->xs_cbuf)) *************** index_endscan(IndexScanDesc scan) *** 378,384 **** } /* End the AM's scan */ ! FunctionCall1(procedure, PointerGetDatum(scan)); /* Release index refcount acquired by index_beginscan */ RelationDecrementReferenceCount(scan->indexRelation); --- 341,347 ---- } /* End the AM's scan */ ! scan->indexRelation->amroutine->amendscan(scan); /* Release index refcount acquired by index_beginscan */ RelationDecrementReferenceCount(scan->indexRelation); *************** index_endscan(IndexScanDesc scan) *** 394,405 **** void index_markpos(IndexScanDesc scan) { - FmgrInfo *procedure; - SCAN_CHECKS; ! GET_SCAN_PROCEDURE(ammarkpos); ! FunctionCall1(procedure, PointerGetDatum(scan)); } /* ---------------- --- 357,366 ---- void index_markpos(IndexScanDesc scan) { SCAN_CHECKS; ! CHECK_SCAN_PROCEDURE(ammarkpos); ! scan->indexRelation->amroutine->ammarkpos(scan); } /* ---------------- *************** index_markpos(IndexScanDesc scan) *** 421,438 **** void index_restrpos(IndexScanDesc scan) { - FmgrInfo *procedure; - Assert(IsMVCCSnapshot(scan->xs_snapshot)); SCAN_CHECKS; ! GET_SCAN_PROCEDURE(amrestrpos); scan->xs_continue_hot = false; scan->kill_prior_tuple = false; /* for safety */ ! FunctionCall1(procedure, PointerGetDatum(scan)); } /* ---------------- --- 382,397 ---- void index_restrpos(IndexScanDesc scan) { Assert(IsMVCCSnapshot(scan->xs_snapshot)); SCAN_CHECKS; ! CHECK_SCAN_PROCEDURE(amrestrpos); scan->xs_continue_hot = false; scan->kill_prior_tuple = false; /* for safety */ ! scan->indexRelation->amroutine->amrestrpos(scan); } /* ---------------- *************** index_restrpos(IndexScanDesc scan) *** 445,455 **** ItemPointer index_getnext_tid(IndexScanDesc scan, ScanDirection direction) { - FmgrInfo *procedure; bool found; SCAN_CHECKS; ! GET_SCAN_PROCEDURE(amgettuple); Assert(TransactionIdIsValid(RecentGlobalXmin)); --- 404,413 ---- ItemPointer index_getnext_tid(IndexScanDesc scan, ScanDirection direction) { bool found; SCAN_CHECKS; ! CHECK_SCAN_PROCEDURE(amgettuple); Assert(TransactionIdIsValid(RecentGlobalXmin)); *************** index_getnext_tid(IndexScanDesc scan, Sc *** 459,467 **** * 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))); /* Reset kill flag immediately for safety */ scan->kill_prior_tuple = false; --- 417,423 ---- * scan->xs_recheck and possibly scan->xs_itup, though we pay no attention * to those fields here. */ ! found = scan->indexRelation->amroutine->amgettuple(scan, direction); /* Reset kill flag immediately for safety */ scan->kill_prior_tuple = false; *************** index_getnext(IndexScanDesc scan, ScanDi *** 635,646 **** int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap) { - FmgrInfo *procedure; int64 ntids; Datum d; SCAN_CHECKS; ! GET_SCAN_PROCEDURE(amgetbitmap); /* just make sure this is false... */ scan->kill_prior_tuple = false; --- 591,601 ---- int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap) { int64 ntids; Datum d; SCAN_CHECKS; ! CHECK_SCAN_PROCEDURE(amgetbitmap); /* just make sure this is false... */ scan->kill_prior_tuple = false; *************** index_getbitmap(IndexScanDesc scan, TIDB *** 648,656 **** /* * have the am's getbitmap proc do all the work. */ ! d = FunctionCall2(procedure, ! PointerGetDatum(scan), ! PointerGetDatum(bitmap)); ntids = DatumGetInt64(d); --- 603,609 ---- /* * have the am's getbitmap proc do all the work. */ ! d = scan->indexRelation->amroutine->amgetbitmap(scan, bitmap); ntids = DatumGetInt64(d); *************** index_bulk_delete(IndexVacuumInfo *info, *** 680,699 **** void *callback_state) { Relation indexRelation = info->index; - FmgrInfo procedure; - IndexBulkDeleteResult *result; RELATION_CHECKS; ! GET_UNCACHED_REL_PROCEDURE(ambulkdelete); ! ! result = (IndexBulkDeleteResult *) ! DatumGetPointer(FunctionCall4(&procedure, ! PointerGetDatum(info), ! PointerGetDatum(stats), ! PointerGetDatum((Pointer) callback), ! PointerGetDatum(callback_state))); ! return result; } /* ---------------- --- 633,644 ---- void *callback_state) { Relation indexRelation = info->index; RELATION_CHECKS; ! CHECK_PROCEDURE(ambulkdelete); ! return indexRelation->amroutine->ambulkdelete(info, stats, ! callback, callback_state); } /* ---------------- *************** index_vacuum_cleanup(IndexVacuumInfo *in *** 707,724 **** 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))); ! return result; } /* ---------------- --- 652,662 ---- IndexBulkDeleteResult *stats) { Relation indexRelation = info->index; RELATION_CHECKS; ! CHECK_PROCEDURE(amvacuumcleanup); ! return indexRelation->amroutine->amvacuumcleanup(info, stats); } /* ---------------- *************** index_vacuum_cleanup(IndexVacuumInfo *in *** 731,749 **** 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)) return false; ! GET_REL_PROCEDURE(amcanreturn); ! ! return DatumGetBool(FunctionCall2(procedure, ! PointerGetDatum(indexRelation), ! Int32GetDatum(attno))); } /* ---------------- --- 669,681 ---- bool index_can_return(Relation indexRelation, int attno) { RELATION_CHECKS; /* amcanreturn is optional; assume FALSE if not provided by AM */ ! if (!indexRelation->amroutine->amcanreturn) return false; ! return indexRelation->amroutine->amcanreturn(indexRelation, attno); } /* ---------------- *************** index_getprocid(Relation irel, *** 781,787 **** int nproc; int procindex; ! nproc = irel->rd_am->amsupport; Assert(procnum > 0 && procnum <= (uint16) nproc); --- 713,719 ---- int nproc; int procindex; ! nproc = irel->amroutine->amsupport; Assert(procnum > 0 && procnum <= (uint16) nproc); *************** index_getprocinfo(Relation irel, *** 815,821 **** int nproc; int procindex; ! nproc = irel->rd_am->amsupport; Assert(procnum > 0 && procnum <= (uint16) nproc); --- 747,753 ---- int nproc; int procindex; ! 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 new file mode 100644 index cf4a6dc..1ba1f7f *** a/src/backend/access/nbtree/nbtree.c --- b/src/backend/access/nbtree/nbtree.c *************** static void btvacuumpage(BTVacState *vst *** 76,89 **** /* ! * btbuild() -- build a new btree index. */ Datum ! btbuild(PG_FUNCTION_ARGS) { - 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; --- 76,129 ---- /* ! * Btree handler function: return IndexAmRoutine with access method parameters ! * and callbacks. */ Datum ! 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; ! ! PG_RETURN_POINTER(amroutine); ! } ! ! /* ! * btbuild() -- build a new btree index. ! */ ! IndexBuildResult * ! btbuild(Relation heap, Relation index, IndexInfo *indexInfo) { IndexBuildResult *result; double reltuples; BTBuildState buildstate; *************** btbuild(PG_FUNCTION_ARGS) *** 155,161 **** result->heap_tuples = reltuples; result->index_tuples = buildstate.indtuples; ! PG_RETURN_POINTER(result); } /* --- 195,201 ---- result->heap_tuples = reltuples; result->index_tuples = buildstate.indtuples; ! return result; } /* *************** btbuildCallback(Relation index, *** 190,200 **** /* * btbuildempty() -- build an empty btree index in the initialization fork */ ! Datum ! btbuildempty(PG_FUNCTION_ARGS) { ! Relation index = (Relation) PG_GETARG_POINTER(0); ! Page metapage; /* Construct metapage. */ metapage = (Page) palloc(BLCKSZ); --- 230,239 ---- /* * btbuildempty() -- build an empty btree index in the initialization fork */ ! void ! btbuildempty(Relation index) { ! Page metapage; /* Construct metapage. */ metapage = (Page) palloc(BLCKSZ); *************** btbuildempty(PG_FUNCTION_ARGS) *** 214,221 **** * checkpoint may have moved the redo pointer past our xlog record. */ smgrimmedsync(index->rd_smgr, INIT_FORKNUM); - - PG_RETURN_VOID(); } /* --- 253,258 ---- *************** btbuildempty(PG_FUNCTION_ARGS) *** 224,238 **** * Descend the tree recursively, find the appropriate location for our * new tuple, and put it there. */ ! Datum ! btinsert(PG_FUNCTION_ARGS) { - 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; --- 261,271 ---- * Descend the tree recursively, find the appropriate location for our * new tuple, and put it there. */ ! bool ! btinsert(Relation rel, Datum *values, bool *isnull, ! ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique) { bool result; IndexTuple itup; *************** btinsert(PG_FUNCTION_ARGS) *** 244,260 **** pfree(itup); ! PG_RETURN_BOOL(result); } /* * btgettuple() -- Get the next tuple in the scan. */ ! Datum ! btgettuple(PG_FUNCTION_ARGS) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1); BTScanOpaque so = (BTScanOpaque) scan->opaque; bool res; --- 277,291 ---- pfree(itup); ! return result; } /* * btgettuple() -- Get the next tuple in the scan. */ ! bool ! btgettuple(IndexScanDesc scan, ScanDirection dir) { BTScanOpaque so = (BTScanOpaque) scan->opaque; bool res; *************** btgettuple(PG_FUNCTION_ARGS) *** 270,276 **** { /* punt if we have any unsatisfiable array keys */ if (so->numArrayKeys < 0) ! PG_RETURN_BOOL(false); _bt_start_array_keys(scan, dir); } --- 301,307 ---- { /* punt if we have any unsatisfiable array keys */ if (so->numArrayKeys < 0) ! return false; _bt_start_array_keys(scan, dir); } *************** btgettuple(PG_FUNCTION_ARGS) *** 320,336 **** /* ... otherwise see if we have more array keys to deal with */ } while (so->numArrayKeys && _bt_advance_array_keys(scan, dir)); ! PG_RETURN_BOOL(res); } /* * btgetbitmap() -- gets all matching tuples, and adds them to a bitmap */ ! Datum ! btgetbitmap(PG_FUNCTION_ARGS) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1); BTScanOpaque so = (BTScanOpaque) scan->opaque; int64 ntids = 0; ItemPointer heapTid; --- 351,365 ---- /* ... otherwise see if we have more array keys to deal with */ } while (so->numArrayKeys && _bt_advance_array_keys(scan, dir)); ! return res; } /* * btgetbitmap() -- gets all matching tuples, and adds them to a bitmap */ ! int64 ! btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm) { BTScanOpaque so = (BTScanOpaque) scan->opaque; int64 ntids = 0; ItemPointer heapTid; *************** btgetbitmap(PG_FUNCTION_ARGS) *** 342,348 **** { /* punt if we have any unsatisfiable array keys */ if (so->numArrayKeys < 0) ! PG_RETURN_INT64(ntids); _bt_start_array_keys(scan, ForwardScanDirection); } --- 371,377 ---- { /* punt if we have any unsatisfiable array keys */ if (so->numArrayKeys < 0) ! return ntids; _bt_start_array_keys(scan, ForwardScanDirection); } *************** btgetbitmap(PG_FUNCTION_ARGS) *** 380,397 **** /* Now see if we have more array keys to deal with */ } while (so->numArrayKeys && _bt_advance_array_keys(scan, ForwardScanDirection)); ! PG_RETURN_INT64(ntids); } /* * btbeginscan() -- start a scan on a btree index */ ! Datum ! btbeginscan(PG_FUNCTION_ARGS) { - Relation rel = (Relation) PG_GETARG_POINTER(0); - int nkeys = PG_GETARG_INT32(1); - int norderbys = PG_GETARG_INT32(2); IndexScanDesc scan; BTScanOpaque so; --- 409,423 ---- /* Now see if we have more array keys to deal with */ } while (so->numArrayKeys && _bt_advance_array_keys(scan, ForwardScanDirection)); ! return ntids; } /* * btbeginscan() -- start a scan on a btree index */ ! IndexScanDesc ! btbeginscan(Relation rel, int nkeys, int norderbys) { IndexScanDesc scan; BTScanOpaque so; *************** btbeginscan(PG_FUNCTION_ARGS) *** 429,447 **** scan->opaque = so; ! PG_RETURN_POINTER(scan); } /* * btrescan() -- rescan an index relation */ ! Datum ! btrescan(PG_FUNCTION_ARGS) { - 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 */ --- 455,470 ---- scan->opaque = so; ! return scan; } /* * btrescan() -- rescan an index relation */ ! void ! btrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, ! ScanKey orderbys, int norderbys) { BTScanOpaque so = (BTScanOpaque) scan->opaque; /* we aren't holding any read locks, but gotta drop the pins */ *************** btrescan(PG_FUNCTION_ARGS) *** 492,508 **** /* 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) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); BTScanOpaque so = (BTScanOpaque) scan->opaque; /* we aren't holding any read locks, but gotta drop the pins */ --- 515,528 ---- /* If any keys are SK_SEARCHARRAY type, set up array-key info */ _bt_preprocess_array_keys(scan); } /* * btendscan() -- close down a scan */ ! void ! btendscan(IndexScanDesc scan) { BTScanOpaque so = (BTScanOpaque) scan->opaque; /* we aren't holding any read locks, but gotta drop the pins */ *************** btendscan(PG_FUNCTION_ARGS) *** 531,547 **** 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) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); BTScanOpaque so = (BTScanOpaque) scan->opaque; /* There may be an old mark with a pin (but no lock). */ --- 551,564 ---- pfree(so->currTuples); /* so->markTuples should not be pfree'd, see btrescan */ pfree(so); } /* * btmarkpos() -- save current scan position */ ! void ! btmarkpos(IndexScanDesc scan) { BTScanOpaque so = (BTScanOpaque) scan->opaque; /* There may be an old mark with a pin (but no lock). */ *************** btmarkpos(PG_FUNCTION_ARGS) *** 564,580 **** /* 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) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); BTScanOpaque so = (BTScanOpaque) scan->opaque; /* Restore the marked positions of any array keys */ --- 581,594 ---- /* Also record the current positions of any array keys */ if (so->numArrayKeys) _bt_mark_array_keys(scan); } /* * btrestrpos() -- restore scan to last saved position */ ! void ! btrestrpos(IndexScanDesc scan) { BTScanOpaque so = (BTScanOpaque) scan->opaque; /* Restore the marked positions of any array keys */ *************** btrestrpos(PG_FUNCTION_ARGS) *** 642,649 **** else BTScanPosInvalidate(so->currPos); } - - PG_RETURN_VOID(); } /* --- 656,661 ---- *************** btrestrpos(PG_FUNCTION_ARGS) *** 653,665 **** * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ ! Datum ! btbulkdelete(PG_FUNCTION_ARGS) { - 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; --- 665,674 ---- * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ ! IndexBulkDeleteResult * ! btbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, ! IndexBulkDeleteCallback callback, void *callback_state) { Relation rel = info->index; BTCycleId cycleid; *************** btbulkdelete(PG_FUNCTION_ARGS) *** 678,684 **** PG_END_ENSURE_ERROR_CLEANUP(_bt_end_vacuum_callback, PointerGetDatum(rel)); _bt_end_vacuum(rel); ! PG_RETURN_POINTER(stats); } /* --- 687,693 ---- PG_END_ENSURE_ERROR_CLEANUP(_bt_end_vacuum_callback, PointerGetDatum(rel)); _bt_end_vacuum(rel); ! return stats; } /* *************** btbulkdelete(PG_FUNCTION_ARGS) *** 686,700 **** * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ ! Datum ! btvacuumcleanup(PG_FUNCTION_ARGS) { - 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); /* * If btbulkdelete was called, we need not do anything, just return the --- 695,706 ---- * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ ! IndexBulkDeleteResult * ! btvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) { /* No-op in ANALYZE ONLY mode */ if (info->analyze_only) ! return stats; /* * If btbulkdelete was called, we need not do anything, just return the *************** btvacuumcleanup(PG_FUNCTION_ARGS) *** 726,732 **** stats->num_index_tuples = info->num_heap_tuples; } ! PG_RETURN_POINTER(stats); } /* --- 732,738 ---- stats->num_index_tuples = info->num_heap_tuples; } ! return stats; } /* *************** restart: *** 1127,1134 **** * * btrees always do, so this is trivial. */ ! Datum ! btcanreturn(PG_FUNCTION_ARGS) { PG_RETURN_BOOL(true); } --- 1133,1140 ---- * * btrees always do, so this is trivial. */ ! 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 new file mode 100644 index 91331ba..2fec62d *** a/src/backend/access/nbtree/nbtutils.c --- b/src/backend/access/nbtree/nbtutils.c *************** BTreeShmemInit(void) *** 2058,2072 **** Assert(found); } ! Datum ! btoptions(PG_FUNCTION_ARGS) { - 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(); } --- 2058,2070 ---- Assert(found); } ! bytea * ! btoptions(Datum reloptions, bool validate) { bytea *result; result = default_reloptions(reloptions, validate, RELOPT_KIND_BTREE); if (result) ! return result; ! return NULL; } diff --git a/src/backend/access/spgist/spginsert.c b/src/backend/access/spgist/spginsert.c new file mode 100644 index bceee8d..c95ae3d *** a/src/backend/access/spgist/spginsert.c --- b/src/backend/access/spgist/spginsert.c *************** spgistBuildCallback(Relation index, Heap *** 65,76 **** /* * Build an SP-GiST index. */ ! Datum ! spgbuild(PG_FUNCTION_ARGS) { - 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; --- 65,73 ---- /* * Build an SP-GiST index. */ ! IndexBuildResult * ! spgbuild(Relation heap, Relation index, IndexInfo *indexInfo) { IndexBuildResult *result; double reltuples; SpGistBuildState buildstate; *************** spgbuild(PG_FUNCTION_ARGS) *** 151,166 **** result = (IndexBuildResult *) palloc0(sizeof(IndexBuildResult)); result->heap_tuples = result->index_tuples = reltuples; ! PG_RETURN_POINTER(result); } /* * Build an empty SPGiST index in the initialization fork */ ! Datum ! spgbuildempty(PG_FUNCTION_ARGS) { - Relation index = (Relation) PG_GETARG_POINTER(0); Page page; /* Construct metapage. */ --- 148,162 ---- result = (IndexBuildResult *) palloc0(sizeof(IndexBuildResult)); result->heap_tuples = result->index_tuples = reltuples; ! return result; } /* * Build an empty SPGiST index in the initialization fork */ ! void ! spgbuildempty(Relation index) { Page page; /* Construct metapage. */ *************** spgbuildempty(PG_FUNCTION_ARGS) *** 201,225 **** * 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) { - 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; --- 197,212 ---- * checkpoint may have moved the redo pointer past our xlog record. */ smgrimmedsync(index->rd_smgr, INIT_FORKNUM); } /* * Insert one new tuple into an SPGiST index. */ ! bool ! spginsert(Relation index, Datum *values, bool *isnull, ! ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique) { SpGistState spgstate; MemoryContext oldCtx; MemoryContext insertCtx; *************** spginsert(PG_FUNCTION_ARGS) *** 251,255 **** MemoryContextDelete(insertCtx); /* return false since we've not done any unique check */ ! PG_RETURN_BOOL(false); } --- 238,242 ---- MemoryContextDelete(insertCtx); /* return false since we've not done any unique check */ ! return false; } diff --git a/src/backend/access/spgist/spgscan.c b/src/backend/access/spgist/spgscan.c new file mode 100644 index 8a0d909..1e73690 *** a/src/backend/access/spgist/spgscan.c --- b/src/backend/access/spgist/spgscan.c *************** spgPrepareScanKeys(IndexScanDesc scan) *** 173,185 **** } } ! Datum ! spgbeginscan(PG_FUNCTION_ARGS) { - Relation rel = (Relation) PG_GETARG_POINTER(0); - int keysz = PG_GETARG_INT32(1); - - /* ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2); */ IndexScanDesc scan; SpGistScanOpaque so; --- 173,181 ---- } } ! IndexScanDesc ! spgbeginscan(Relation rel, int keysz, int orderbysz) { IndexScanDesc scan; SpGistScanOpaque so; *************** spgbeginscan(PG_FUNCTION_ARGS) *** 202,216 **** scan->opaque = so; ! PG_RETURN_POINTER(scan); } ! Datum ! spgrescan(PG_FUNCTION_ARGS) { - 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) --- 198,212 ---- scan->opaque = so; ! return scan; } ! ! void ! spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, ! ScanKey orderbys, int norderbys) { SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque; /* copy scankeys into local storage */ if (scankey && scan->numberOfKeys > 0) *************** spgrescan(PG_FUNCTION_ARGS) *** 224,256 **** /* set up starting stack entries */ resetSpGistScanOpaque(so); - - PG_RETURN_VOID(); } ! Datum ! spgendscan(PG_FUNCTION_ARGS) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque; MemoryContextDelete(so->tempCxt); - - PG_RETURN_VOID(); } ! Datum ! spgmarkpos(PG_FUNCTION_ARGS) { elog(ERROR, "SPGiST does not support mark/restore"); - PG_RETURN_VOID(); } ! Datum ! spgrestrpos(PG_FUNCTION_ARGS) { elog(ERROR, "SPGiST does not support mark/restore"); - PG_RETURN_VOID(); } /* --- 220,245 ---- /* set up starting stack entries */ resetSpGistScanOpaque(so); } ! void ! spgendscan(IndexScanDesc scan) { SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque; MemoryContextDelete(so->tempCxt); } ! void ! spgmarkpos(IndexScanDesc scan) { elog(ERROR, "SPGiST does not support mark/restore"); } ! void ! spgrestrpos(IndexScanDesc scan) { elog(ERROR, "SPGiST does not support mark/restore"); } /* *************** storeBitmap(SpGistScanOpaque so, ItemPoi *** 571,581 **** so->ntids++; } ! Datum ! spggetbitmap(PG_FUNCTION_ARGS) { - 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 */ --- 560,568 ---- so->ntids++; } ! int64 ! spggetbitmap(IndexScanDesc scan, TIDBitmap *tbm) { SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque; /* Copy want_itup to *so so we don't need to pass it around separately */ *************** spggetbitmap(PG_FUNCTION_ARGS) *** 586,592 **** spgWalk(scan->indexRelation, so, true, storeBitmap); ! PG_RETURN_INT64(so->ntids); } /* storeRes subroutine for gettuple case */ --- 573,579 ---- spgWalk(scan->indexRelation, so, true, storeBitmap); ! return so->ntids; } /* storeRes subroutine for gettuple case */ *************** storeGettuple(SpGistScanOpaque so, ItemP *** 610,620 **** so->nPtrs++; } ! Datum ! spggettuple(PG_FUNCTION_ARGS) { - IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); - ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1); SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque; if (dir != ForwardScanDirection) --- 597,605 ---- so->nPtrs++; } ! bool ! spggettuple(IndexScanDesc scan, ScanDirection dir) { SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque; if (dir != ForwardScanDirection) *************** spggettuple(PG_FUNCTION_ARGS) *** 632,638 **** scan->xs_recheck = so->recheck[so->iPtr]; scan->xs_itup = so->indexTups[so->iPtr]; so->iPtr++; ! PG_RETURN_BOOL(true); } if (so->want_itup) --- 617,623 ---- scan->xs_recheck = so->recheck[so->iPtr]; scan->xs_itup = so->indexTups[so->iPtr]; so->iPtr++; ! return true; } if (so->want_itup) *************** spggettuple(PG_FUNCTION_ARGS) *** 651,669 **** break; /* must have completed scan */ } ! PG_RETURN_BOOL(false); } ! Datum ! spgcanreturn(PG_FUNCTION_ARGS) { - 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); } --- 636,651 ---- break; /* must have completed scan */ } ! return false; } ! bool ! spgcanreturn(Relation index, int attno) { SpGistCache *cache; /* We can do it if the opclass config function says so */ cache = spgGetCache(index); ! return cache->config.canReturnData; } diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c new file mode 100644 index f38287c..3023fd7 *** a/src/backend/access/spgist/spgutils.c --- b/src/backend/access/spgist/spgutils.c *************** *** 24,30 **** --- 24,74 ---- #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; + PG_RETURN_POINTER(amroutine); + } /* Fill in a SpGistTypeDesc struct with info about the specified data type */ static void *************** SpGistInitMetapage(Page page) *** 489,506 **** /* * reloptions processing for SPGiST */ ! Datum ! spgoptions(PG_FUNCTION_ARGS) { - 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(); } /* --- 533,548 ---- /* * reloptions processing for SPGiST */ ! bytea * ! spgoptions(Datum reloptions, bool validate) { bytea *result; result = default_reloptions(reloptions, validate, RELOPT_KIND_SPGIST); if (result) ! return (bytea *)result; ! return NULL; } /* diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c new file mode 100644 index 06c0b0a..c3856a1 *** a/src/backend/access/spgist/spgvacuum.c --- b/src/backend/access/spgist/spgvacuum.c *************** spgvacuumscan(spgBulkDeleteState *bds) *** 881,893 **** * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ ! Datum ! spgbulkdelete(PG_FUNCTION_ARGS) { - 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 */ --- 881,890 ---- * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ ! IndexBulkDeleteResult * ! spgbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, ! IndexBulkDeleteCallback callback, void *callback_state) { spgBulkDeleteState bds; /* allocate stats if first time through, else re-use existing struct */ *************** spgbulkdelete(PG_FUNCTION_ARGS) *** 900,906 **** spgvacuumscan(&bds); ! PG_RETURN_POINTER(stats); } /* Dummy callback to delete no tuples during spgvacuumcleanup */ --- 897,903 ---- spgvacuumscan(&bds); ! return stats; } /* Dummy callback to delete no tuples during spgvacuumcleanup */ *************** dummy_callback(ItemPointer itemptr, void *** 915,931 **** * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ ! Datum ! spgvacuumcleanup(PG_FUNCTION_ARGS) { - 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); /* * We don't need to scan the index if there was a preceding bulkdelete --- 912,926 ---- * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ ! IndexBulkDeleteResult * ! spgvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) { Relation index = info->index; spgBulkDeleteState bds; /* No-op in ANALYZE ONLY mode */ if (info->analyze_only) ! return stats; /* * We don't need to scan the index if there was a preceding bulkdelete *************** spgvacuumcleanup(PG_FUNCTION_ARGS) *** 959,963 **** stats->num_index_tuples = info->num_heap_tuples; } ! PG_RETURN_POINTER(stats); } --- 954,958 ---- stats->num_index_tuples = info->num_heap_tuples; } ! return stats; } diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c new file mode 100644 index e59b163..8ace03d *** a/src/backend/catalog/index.c --- b/src/backend/catalog/index.c *************** *** 23,28 **** --- 23,29 ---- #include + #include "access/amapi.h" #include "access/multixact.h" #include "access/relscan.h" #include "access/sysattr.h" *************** ConstructTupleDescriptor(Relation heapRe *** 277,296 **** 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; 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); /* ... and to the table's tuple descriptor */ heapTupDesc = RelationGetDescr(heapRelation); --- 278,291 ---- int numatts = indexInfo->ii_NumIndexAttrs; ListCell *colnames_item = list_head(indexColNames); ListCell *indexpr_item = list_head(indexInfo->ii_Expressions); ! 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 */ ! amroutine = GetIndexAmRoutine(accessMethodObjectId); /* ... and to the table's tuple descriptor */ heapTupDesc = RelationGetDescr(heapRelation); *************** ConstructTupleDescriptor(Relation heapRe *** 437,443 **** if (OidIsValid(opclassTup->opckeytype)) keyType = opclassTup->opckeytype; else ! keyType = amform->amkeytype; ReleaseSysCache(tuple); if (OidIsValid(keyType) && keyType != to->atttypid) --- 432,438 ---- if (OidIsValid(opclassTup->opckeytype)) keyType = opclassTup->opckeytype; else ! keyType = amroutine->amkeytype; ReleaseSysCache(tuple); if (OidIsValid(keyType) && keyType != to->atttypid) *************** ConstructTupleDescriptor(Relation heapRe *** 459,466 **** } } - ReleaseSysCache(amtuple); - return indexTupDesc; } --- 454,459 ---- *************** index_build(Relation heapRelation, *** 1988,1994 **** bool isprimary, bool isreindex) { - RegProcedure procedure; IndexBuildResult *stats; Oid save_userid; int save_sec_context; --- 1981,1986 ---- *************** index_build(Relation heapRelation, *** 1998,2007 **** * sanity checks */ Assert(RelationIsValid(indexRelation)); ! Assert(PointerIsValid(indexRelation->rd_am)); ! ! procedure = indexRelation->rd_am->ambuild; ! Assert(RegProcedureIsValid(procedure)); ereport(DEBUG1, (errmsg("building index \"%s\" on table \"%s\"", --- 1990,1997 ---- * sanity checks */ Assert(RelationIsValid(indexRelation)); ! Assert(PointerIsValid(indexRelation->amroutine)); ! Assert(PointerIsValid(indexRelation->amroutine->ambuild)); ereport(DEBUG1, (errmsg("building index \"%s\" on table \"%s\"", *************** index_build(Relation heapRelation, *** 2021,2031 **** /* * Call the access method's build procedure */ ! stats = (IndexBuildResult *) ! DatumGetPointer(OidFunctionCall3(procedure, ! PointerGetDatum(heapRelation), ! PointerGetDatum(indexRelation), ! PointerGetDatum(indexInfo))); Assert(PointerIsValid(stats)); /* --- 2011,2018 ---- /* * Call the access method's build procedure */ ! stats = indexRelation->amroutine->ambuild(heapRelation, indexRelation, ! indexInfo); Assert(PointerIsValid(stats)); /* *************** index_build(Relation heapRelation, *** 2038,2048 **** 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)); } /* --- 2025,2033 ---- if (indexRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED && !smgrexists(indexRelation->rd_smgr, INIT_FORKNUM)) { RelationOpenSmgr(indexRelation); smgrcreate(indexRelation->rd_smgr, INIT_FORKNUM, false); ! indexRelation->amroutine->ambuildempty(indexRelation); } /* diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c new file mode 100644 index 7ab4874..7a7fd95 *** a/src/backend/commands/cluster.c --- b/src/backend/commands/cluster.c *************** *** 17,22 **** --- 17,23 ---- */ #include "postgres.h" + #include "access/amapi.h" #include "access/multixact.h" #include "access/relscan.h" #include "access/rewriteheap.h" *************** check_index_is_clusterable(Relation OldH *** 433,439 **** RelationGetRelationName(OldHeap)))); /* Index AM must allow clustering */ ! if (!OldIndex->rd_am->amclusterable) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot cluster on index \"%s\" because access method does not support clustering", --- 434,440 ---- RelationGetRelationName(OldHeap)))); /* Index AM must allow clustering */ ! 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 new file mode 100644 index b450bcf..9951993 *** a/src/backend/commands/indexcmds.c --- b/src/backend/commands/indexcmds.c *************** *** 15,20 **** --- 15,21 ---- #include "postgres.h" + #include "access/amapi.h" #include "access/htup_details.h" #include "access/reloptions.h" #include "access/xact.h" *************** CheckIndexCompatible(Oid oldId, *** 125,130 **** --- 126,132 ---- HeapTuple tuple; Form_pg_index indexForm; Form_pg_am accessMethodForm; + IndexAmRoutine *amRoutine; bool amcanorder; int16 *coloptions; IndexInfo *indexInfo; *************** CheckIndexCompatible(Oid oldId, *** 160,166 **** accessMethodName))); accessMethodId = HeapTupleGetOid(tuple); accessMethodForm = (Form_pg_am) GETSTRUCT(tuple); ! amcanorder = accessMethodForm->amcanorder; ReleaseSysCache(tuple); /* --- 162,170 ---- accessMethodName))); accessMethodId = HeapTupleGetOid(tuple); accessMethodForm = (Form_pg_am) GETSTRUCT(tuple); ! amRoutine = (IndexAmRoutine *)DatumGetPointer( ! OidFunctionCall0(accessMethodForm->amhandler)); ! amcanorder = amRoutine->amcanorder; ReleaseSysCache(tuple); /* *************** DefineIndex(Oid relationId, *** 315,322 **** Relation indexRelation; HeapTuple tuple; Form_pg_am accessMethodForm; bool amcanorder; ! RegProcedure amoptions; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; --- 319,327 ---- Relation indexRelation; HeapTuple tuple; Form_pg_am accessMethodForm; + IndexAmRoutine *amRoutine; bool amcanorder; ! amoptions_function amoptions; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; *************** DefineIndex(Oid relationId, *** 489,518 **** } accessMethodId = HeapTupleGetOid(tuple); accessMethodForm = (Form_pg_am) GETSTRUCT(tuple); 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) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("access method \"%s\" does not support unique indexes", accessMethodName))); ! if (numberOfAttributes > 1 && !accessMethodForm->amcanmulticol) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("access method \"%s\" does not support multicolumn indexes", accessMethodName))); ! if (stmt->excludeOpNames && !OidIsValid(accessMethodForm->amgettuple)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("access method \"%s\" does not support exclusion constraints", accessMethodName))); ! amcanorder = accessMethodForm->amcanorder; ! amoptions = accessMethodForm->amoptions; ReleaseSysCache(tuple); --- 494,525 ---- } 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 && !amRoutine->amcanunique) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("access method \"%s\" does not support unique indexes", accessMethodName))); ! 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(amRoutine->amgettuple)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("access method \"%s\" does not support exclusion constraints", accessMethodName))); ! amcanorder = amRoutine->amcanorder; ! amoptions = amRoutine->amoptions; ReleaseSysCache(tuple); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c new file mode 100644 index 126b119..c4cc9b4 *** a/src/backend/commands/tablecmds.c --- b/src/backend/commands/tablecmds.c *************** ATExecSetRelOptions(Relation rel, List * *** 9363,9369 **** (void) view_reloptions(newOptions, true); break; case RELKIND_INDEX: ! (void) index_reloptions(rel->rd_am->amoptions, newOptions, true); break; default: ereport(ERROR, --- 9363,9369 ---- (void) view_reloptions(newOptions, true); break; case RELKIND_INDEX: ! (void) index_reloptions(rel->amroutine->amoptions, newOptions, true); break; default: ereport(ERROR, *************** ATExecReplicaIdentity(Relation rel, Repl *** 10954,10960 **** 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) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot use non-unique index \"%s\" as replica identity", --- 10954,10960 ---- RelationGetRelationName(indexRel), RelationGetRelationName(rel)))); /* The AM must support uniqueness, and the index must in fact be unique. */ ! 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 new file mode 100644 index 93e1e9a..13fc2e2 *** a/src/backend/executor/execAmi.c --- b/src/backend/executor/execAmi.c *************** *** 12,17 **** --- 12,18 ---- */ #include "postgres.h" + #include "access/amapi.h" #include "access/htup_details.h" #include "executor/execdebug.h" #include "executor/nodeAgg.h" *************** IndexSupportsBackwardScan(Oid indexid) *** 528,533 **** --- 529,535 ---- 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)); *************** IndexSupportsBackwardScan(Oid indexid) *** 541,549 **** elog(ERROR, "cache lookup failed for access method %u", idxrelrec->relam); amrec = (Form_pg_am) GETSTRUCT(ht_am); ! result = amrec->amcanbackward; ReleaseSysCache(ht_idxrel); ReleaseSysCache(ht_am); --- 543,553 ---- 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 = amroutine->amcanbackward; + pfree(amroutine); ReleaseSysCache(ht_idxrel); ReleaseSysCache(ht_am); diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c new file mode 100644 index c0f14db..2de0579 *** a/src/backend/executor/nodeIndexscan.c --- b/src/backend/executor/nodeIndexscan.c *************** ExecIndexBuildScanKeys(PlanState *planst *** 1436,1442 **** Assert(rightop != NULL); ! if (index->rd_am->amsearcharray) { /* Index AM will handle this like a simple operator */ flags |= SK_SEARCHARRAY; --- 1436,1442 ---- Assert(rightop != NULL); ! 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 new file mode 100644 index 7069f60..60fc0fb *** a/src/backend/optimizer/path/costsize.c --- b/src/backend/optimizer/path/costsize.c *************** cost_index(IndexPath *path, PlannerInfo *** 368,381 **** * 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)); /* * Save amcostestimate's results for possible use in bitmap scan planning. --- 368,375 ---- * the fraction of main-table tuples we will have to retrieve) and its * correlation to the main-table tuple order. */ ! 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 new file mode 100644 index 9442e5f..d3d5d43 *** a/src/backend/optimizer/util/plancat.c --- b/src/backend/optimizer/util/plancat.c *************** get_relation_info(PlannerInfo *root, Oid *** 223,235 **** } 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); /* * Fetch the ordering information for the index, if any. --- 223,235 ---- } info->relam = indexRelation->rd_rel->relam; ! 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. *************** get_relation_info(PlannerInfo *root, Oid *** 240,246 **** * If it's a btree index, we can use its opfamily OIDs * directly as the sort ordering opfamily OIDs. */ ! Assert(indexRelation->rd_am->amcanorder); info->sortopfamily = info->opfamily; info->reverse_sort = (bool *) palloc(sizeof(bool) * ncolumns); --- 240,246 ---- * If it's a btree index, we can use its opfamily OIDs * directly as the sort ordering opfamily OIDs. */ ! Assert(indexRelation->amroutine->amcanorder); info->sortopfamily = info->opfamily; info->reverse_sort = (bool *) palloc(sizeof(bool) * ncolumns); *************** get_relation_info(PlannerInfo *root, Oid *** 254,260 **** info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0; } } ! else if (indexRelation->rd_am->amcanorder) { /* * Otherwise, identify the corresponding btree opfamilies by --- 254,260 ---- info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0; } } ! 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 new file mode 100644 index 16d40c7..0031511 *** a/src/backend/parser/parse_utilcmd.c --- b/src/backend/parser/parse_utilcmd.c *************** *** 26,31 **** --- 26,32 ---- #include "postgres.h" + #include "access/amapi.h" #include "access/htup_details.h" #include "access/reloptions.h" #include "catalog/dependency.h" *************** generateClonedIndexStmt(CreateStmtContex *** 1258,1264 **** iparam->nulls_ordering = SORTBY_NULLS_DEFAULT; /* Adjust options if necessary */ ! if (amrec->amcanorder) { /* * If it supports sort ordering, copy DESC and NULLS opts. Don't --- 1259,1265 ---- iparam->nulls_ordering = SORTBY_NULLS_DEFAULT; /* Adjust options if necessary */ ! 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 new file mode 100644 index 94e748e..63d6f0d *** a/src/backend/postmaster/autovacuum.c --- b/src/backend/postmaster/autovacuum.c *************** extract_autovac_opts(HeapTuple tup, Tupl *** 2420,2426 **** ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW || ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE); ! relopts = extractRelOptions(tup, pg_class_desc, InvalidOid); if (relopts == NULL) return NULL; --- 2420,2426 ---- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW || ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE); ! 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 new file mode 100644 index 5b809aa..bdd451d *** a/src/backend/utils/adt/pseudotypes.c --- b/src/backend/utils/adt/pseudotypes.c *************** tsm_handler_out(PG_FUNCTION_ARGS) *** 401,406 **** --- 401,433 ---- /* + * 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 new file mode 100644 index 51391f6..7d9577a *** a/src/backend/utils/adt/ruleutils.c --- b/src/backend/utils/adt/ruleutils.c *************** *** 19,24 **** --- 19,25 ---- #include #include + #include "access/amapi.h" #include "access/htup_details.h" #include "access/sysattr.h" #include "catalog/dependency.h" *************** pg_get_indexdef_worker(Oid indexrelid, i *** 1167,1172 **** --- 1168,1174 ---- if (!attrsOnly && (!colno || colno == keyno + 1)) { Oid indcoll; + IndexAmRoutine *amroutine; /* Add collation, if not default for column */ indcoll = indcollation->values[keyno]; *************** pg_get_indexdef_worker(Oid indexrelid, i *** 1177,1184 **** /* Add the operator class name, if not default */ get_opclass_name(indclass->values[keyno], keycoltype, &buf); /* Add options if relevant */ ! if (amrec->amcanorder) { /* if it supports sort ordering, report DESC and NULLS opts */ if (opt & INDOPTION_DESC) --- 1179,1189 ---- /* 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 (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 new file mode 100644 index 72bc502..081d21e *** a/src/backend/utils/adt/selfuncs.c --- b/src/backend/utils/adt/selfuncs.c *************** add_predicate_to_quals(IndexOptInfo *ind *** 6398,6413 **** } ! Datum ! btcostestimate(PG_FUNCTION_ARGS) { - 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; --- 6398,6408 ---- } ! void ! btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, ! Cost *indexStartupCost, Cost *indexTotalCost, ! Selectivity *indexSelectivity, double *indexCorrelation) { IndexOptInfo *index = path->indexinfo; List *qinfos; GenericCosts costs; *************** btcostestimate(PG_FUNCTION_ARGS) *** 6696,6715 **** *indexTotalCost = costs.indexTotalCost; *indexSelectivity = costs.indexSelectivity; *indexCorrelation = costs.indexCorrelation; - - PG_RETURN_VOID(); } ! Datum ! hashcostestimate(PG_FUNCTION_ARGS) { - 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; --- 6691,6703 ---- *indexTotalCost = costs.indexTotalCost; *indexSelectivity = costs.indexSelectivity; *indexCorrelation = costs.indexCorrelation; } ! void ! hashcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, ! Cost *indexStartupCost, Cost *indexTotalCost, ! Selectivity *indexSelectivity, double *indexCorrelation) { List *qinfos; GenericCosts costs; *************** hashcostestimate(PG_FUNCTION_ARGS) *** 6749,6768 **** *indexTotalCost = costs.indexTotalCost; *indexSelectivity = costs.indexSelectivity; *indexCorrelation = costs.indexCorrelation; - - PG_RETURN_VOID(); } ! Datum ! gistcostestimate(PG_FUNCTION_ARGS) { - 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; --- 6737,6749 ---- *indexTotalCost = costs.indexTotalCost; *indexSelectivity = costs.indexSelectivity; *indexCorrelation = costs.indexCorrelation; } ! void ! gistcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, ! Cost *indexStartupCost, Cost *indexTotalCost, ! Selectivity *indexSelectivity, double *indexCorrelation) { IndexOptInfo *index = path->indexinfo; List *qinfos; GenericCosts costs; *************** gistcostestimate(PG_FUNCTION_ARGS) *** 6815,6834 **** *indexTotalCost = costs.indexTotalCost; *indexSelectivity = costs.indexSelectivity; *indexCorrelation = costs.indexCorrelation; - - PG_RETURN_VOID(); } ! Datum ! spgcostestimate(PG_FUNCTION_ARGS) { - 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; --- 6796,6808 ---- *indexTotalCost = costs.indexTotalCost; *indexSelectivity = costs.indexSelectivity; *indexCorrelation = costs.indexCorrelation; } ! void ! spgcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, ! Cost *indexStartupCost, Cost *indexTotalCost, ! Selectivity *indexSelectivity, double *indexCorrelation) { IndexOptInfo *index = path->indexinfo; List *qinfos; GenericCosts costs; *************** spgcostestimate(PG_FUNCTION_ARGS) *** 6881,6888 **** *indexTotalCost = costs.indexTotalCost; *indexSelectivity = costs.indexSelectivity; *indexCorrelation = costs.indexCorrelation; - - PG_RETURN_VOID(); } --- 6855,6860 ---- *************** gincost_scalararrayopexpr(PlannerInfo *r *** 7177,7192 **** /* * GIN has search behavior completely different from other index types */ ! Datum ! gincostestimate(PG_FUNCTION_ARGS) { - 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; --- 7149,7159 ---- /* * GIN has search behavior completely different from other index types */ ! void ! gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count, ! Cost *indexStartupCost, Cost *indexTotalCost, ! Selectivity *indexSelectivity, double *indexCorrelation) { IndexOptInfo *index = path->indexinfo; List *indexQuals = path->indexquals; List *indexOrderBys = path->indexorderbys; *************** gincostestimate(PG_FUNCTION_ARGS) *** 7337,7343 **** *indexStartupCost = 0; *indexTotalCost = 0; *indexSelectivity = 0; ! PG_RETURN_VOID(); } if (counts.haveFullScan || indexQuals == NIL) --- 7304,7310 ---- *indexStartupCost = 0; *indexTotalCost = 0; *indexSelectivity = 0; ! return; } if (counts.haveFullScan || indexQuals == NIL) *************** gincostestimate(PG_FUNCTION_ARGS) *** 7459,7481 **** *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) { - 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; --- 7426,7441 ---- *indexStartupCost += qual_arg_cost; *indexTotalCost += qual_arg_cost; *indexTotalCost += (numTuples * *indexSelectivity) * (cpu_index_tuple_cost + qual_op_cost); } /* * BRIN has search behavior completely different from other index types */ ! void ! brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count, ! Cost *indexStartupCost, Cost *indexTotalCost, ! Selectivity *indexSelectivity, double *indexCorrelation) { IndexOptInfo *index = path->indexinfo; List *indexQuals = path->indexquals; List *indexOrderBys = path->indexorderbys; *************** brincostestimate(PG_FUNCTION_ARGS) *** 7528,7533 **** *indexTotalCost += (numTuples * *indexSelectivity) * (cpu_index_tuple_cost + qual_op_cost); /* XXX what about pages_per_range? */ - - PG_RETURN_VOID(); } --- 7488,7491 ---- diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c new file mode 100644 index 44e9509..5642bfa *** a/src/backend/utils/cache/relcache.c --- b/src/backend/utils/cache/relcache.c *************** static void RelationParseRelOptions(Rela *** 258,263 **** --- 258,264 ---- static void RelationBuildTupleDesc(Relation relation); static Relation RelationBuildDesc(Oid targetRelId, bool insertIt); static void RelationInitPhysicalAddr(Relation relation); + static void ValidateAmRoutine(IndexAmRoutine *amroutine, Form_pg_am aform); static void load_critical_index(Oid indexoid, Oid heapoid); static TupleDesc GetPgClassDescriptor(void); static TupleDesc GetPgIndexDescriptor(void); *************** RelationParseRelOptions(Relation relatio *** 445,451 **** options = extractRelOptions(tuple, GetPgClassDescriptor(), relation->rd_rel->relkind == RELKIND_INDEX ? ! relation->rd_am->amoptions : InvalidOid); /* * Copy parsed data into CacheMemoryContext. To guard against the --- 446,452 ---- options = extractRelOptions(tuple, GetPgClassDescriptor(), relation->rd_rel->relkind == RELKIND_INDEX ? ! relation->amroutine->amoptions : NULL); /* * Copy parsed data into CacheMemoryContext. To guard against the *************** RelationInitPhysicalAddr(Relation relati *** 1162,1174 **** } /* * 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; --- 1163,1233 ---- } /* + * Validate IndexAmRoutine is consistent with pg_am tuple. + */ + static void + ValidateAmRoutine(IndexAmRoutine *amroutine, Form_pg_am aform) + { + if (amroutine->amstrategies != aform->amstrategies + || amroutine->amsupport != aform->amsupport + || amroutine->amcanorderbyop != aform->amcanorderbyop + || amroutine->amstorage != aform->amstorage + || amroutine->amkeytype != aform->amkeytype) + elog(ERROR, "IndexAmRoutine doesn't match content of pg_am tuple"); + } + + /* + * 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)); + ValidateAmRoutine(result, (Form_pg_am)GETSTRUCT(tuple)); + + 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; + + ValidateAmRoutine(relation->amroutine, relation->rd_am); + } + + /* * Initialize index-access-method support data for an index relation */ void RelationInitIndexAccessInfo(Relation relation) { HeapTuple tuple; Datum indcollDatum; Datum indclassDatum; Datum indoptionDatum; *************** RelationInitIndexAccessInfo(Relation rel *** 1180,1185 **** --- 1239,1245 ---- MemoryContext oldcontext; int natts; uint16 amsupport; + Form_pg_am aform; /* * Make a copy of the pg_index entry for the index. Since pg_index *************** RelationInitIndexAccessInfo(Relation rel *** 1204,1219 **** if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for access method %u", relation->rd_rel->relam); ! aform = (Form_pg_am) MemoryContextAlloc(CacheMemoryContext, sizeof *aform); memcpy(aform, GETSTRUCT(tuple), sizeof *aform); ReleaseSysCache(tuple); relation->rd_am = aform; 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; /* * Make the private context to hold index access info. The reason we need --- 1264,1281 ---- if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for access method %u", relation->rd_rel->relam); ! 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 = relation->amroutine->amsupport; /* * Make the private context to hold index access info. The reason we need *************** load_relcache_init_file(bool shared) *** 4716,4722 **** Oid *opfamily; Oid *opcintype; RegProcedure *support; - int nsupport; int16 *indoption; Oid *indcollation; --- 4778,4783 ---- *************** load_relcache_init_file(bool shared) *** 4744,4749 **** --- 4805,4811 ---- if (fread(am, 1, len, fp) != len) goto read_failed; rel->rd_am = am; + rel->amroutine = NULL; /* * prepare index info context --- parameters should match *************** load_relcache_init_file(bool shared) *** 4808,4816 **** /* 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)); } else { --- 4870,4879 ---- /* set up zeroed fmgr-info vectors */ rel->rd_aminfo = (RelationAmInfo *) MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo)); rel->rd_supportinfo = (FmgrInfo *) ! MemoryContextAllocZero(indexcxt, relform->relnatts * am->amsupport * sizeof(FmgrInfo)); ! ! InitIndexAmRoutine(rel); } else { diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h new file mode 100644 index ...400aeee *** a/src/include/access/amapi.h --- b/src/include/access/amapi.h *************** *** 0 **** --- 1,163 ---- + /*------------------------------------------------------------------------- + * + * 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 "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); + + + 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; + }; + + #endif /* AMAPI_H */ diff --git a/src/include/access/brin.h b/src/include/access/brin.h new file mode 100644 index e72fb2d..15f52a1 *** a/src/include/access/brin.h --- b/src/include/access/brin.h *************** *** 10,15 **** --- 10,16 ---- #ifndef BRIN_H #define BRIN_H + #include "access/amapi.h" #include "fmgr.h" #include "nodes/execnodes.h" #include "utils/relcache.h" *************** *** 18,36 **** /* * 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); /* * Storage type for BRIN's reloptions --- 19,50 ---- /* * prototypes for functions in brin.c (external entry points for BRIN) */ ! extern Datum brinhandler(PG_FUNCTION_ARGS); ! 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/genam.h b/src/include/access/genam.h new file mode 100644 index d9d05a0..2f4ad91 *** a/src/include/access/genam.h --- b/src/include/access/genam.h *************** typedef enum IndexUniqueCheck *** 111,117 **** UNIQUE_CHECK_EXISTING /* Check if existing tuple is unique */ } IndexUniqueCheck; - /* * generalized index_ interface routines (in indexam.c) */ --- 111,116 ---- diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h new file mode 100644 index 5095fc1..9b23f65 *** a/src/include/access/gin_private.h --- b/src/include/access/gin_private.h *************** *** 10,16 **** #ifndef GIN_PRIVATE_H #define GIN_PRIVATE_H ! #include "access/genam.h" #include "access/gin.h" #include "access/itup.h" #include "fmgr.h" --- 10,16 ---- #ifndef GIN_PRIVATE_H #define GIN_PRIVATE_H ! #include "access/amapi.h" #include "access/gin.h" #include "access/itup.h" #include "fmgr.h" *************** typedef struct ginxlogDeleteListPages *** 593,599 **** /* ginutil.c */ ! extern Datum ginoptions(PG_FUNCTION_ARGS); extern void initGinState(GinState *state, Relation index); extern Buffer GinNewBuffer(Relation index); extern void GinInitBuffer(Buffer b, uint32 f); --- 593,600 ---- /* ginutil.c */ ! extern Datum ginhandler(PG_FUNCTION_ARGS); ! 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); *************** extern Datum gintuple_get_key(GinState * *** 614,622 **** GinNullCategory *category); /* gininsert.c */ ! extern Datum ginbuild(PG_FUNCTION_ARGS); ! extern Datum ginbuildempty(PG_FUNCTION_ARGS); ! extern Datum gininsert(PG_FUNCTION_ARGS); extern void ginEntryInsert(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, --- 615,626 ---- GinNullCategory *category); /* gininsert.c */ ! 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, *************** typedef struct GinScanOpaqueData *** 867,889 **** 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 void ginNewScanKey(IndexScanDesc scan); extern void ginFreeScanKeys(GinScanOpaque so); /* ginget.c */ ! extern Datum gingetbitmap(PG_FUNCTION_ARGS); /* ginlogic.c */ extern void ginInitConsistentFunction(GinState *ginstate, GinScanKey key); /* ginvacuum.c */ ! extern Datum ginbulkdelete(PG_FUNCTION_ARGS); ! extern Datum ginvacuumcleanup(PG_FUNCTION_ARGS); extern ItemPointer ginVacuumItemPointers(GinVacuumState *gvs, ItemPointerData *items, int nitem, int *nremaining); --- 871,898 ---- typedef GinScanOpaqueData *GinScanOpaque; ! 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 int64 gingetbitmap(IndexScanDesc scan, TIDBitmap *tbm); /* ginlogic.c */ extern void ginInitConsistentFunction(GinState *ginstate, GinScanKey key); /* ginvacuum.c */ ! 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 new file mode 100644 index 4f1a5c3..0e05f7b *** a/src/include/access/gist_private.h --- b/src/include/access/gist_private.h *************** *** 14,19 **** --- 14,20 ---- #ifndef GIST_PRIVATE_H #define GIST_PRIVATE_H + #include "access/amapi.h" #include "access/gist.h" #include "access/itup.h" #include "access/xlogreader.h" *************** typedef struct GiSTOptions *** 417,425 **** } GiSTOptions; /* gist.c */ ! extern Datum gistbuildempty(PG_FUNCTION_ARGS); ! extern Datum gistinsert(PG_FUNCTION_ARGS); ! extern Datum gistcanreturn(PG_FUNCTION_ARGS); extern MemoryContext createTempGistContext(void); extern GISTSTATE *initGISTstate(Relation index); extern void freeGISTstate(GISTSTATE *giststate); --- 418,429 ---- } GiSTOptions; /* gist.c */ ! extern Datum gisthandler(PG_FUNCTION_ARGS); ! 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); *************** extern XLogRecPtr gistXLogSplit(RelFileN *** 465,472 **** Buffer leftchild, bool markfollowright); /* gistget.c */ ! extern Datum gistgettuple(PG_FUNCTION_ARGS); ! extern Datum gistgetbitmap(PG_FUNCTION_ARGS); /* gistutil.c */ --- 469,476 ---- Buffer leftchild, bool markfollowright); /* gistget.c */ ! extern bool gistgettuple(IndexScanDesc scan, ScanDirection dir); ! extern int64 gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm); /* gistutil.c */ *************** extern Datum gistgetbitmap(PG_FUNCTION_A *** 476,482 **** #define GIST_MIN_FILLFACTOR 10 #define GIST_DEFAULT_FILLFACTOR 90 ! extern Datum gistoptions(PG_FUNCTION_ARGS); 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); --- 480,486 ---- #define GIST_MIN_FILLFACTOR 10 #define GIST_DEFAULT_FILLFACTOR 90 ! 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); *************** extern void gistMakeUnionKey(GISTSTATE * *** 525,532 **** extern XLogRecPtr gistGetFakeLSN(Relation rel); /* gistvacuum.c */ ! extern Datum gistbulkdelete(PG_FUNCTION_ARGS); ! extern Datum gistvacuumcleanup(PG_FUNCTION_ARGS); /* gistsplit.c */ extern void gistSplitByKey(Relation r, Page page, IndexTuple *itup, --- 529,540 ---- extern XLogRecPtr gistGetFakeLSN(Relation rel); /* gistvacuum.c */ ! 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, *************** extern void gistSplitByKey(Relation r, P *** 535,541 **** int attno); /* gistbuild.c */ ! extern Datum gistbuild(PG_FUNCTION_ARGS); extern void gistValidateBufferingOption(char *value); /* gistbuildbuffers.c */ --- 543,550 ---- int attno); /* gistbuild.c */ ! 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 new file mode 100644 index 15cb3d1..0e6afe9 *** a/src/include/access/gistscan.h --- b/src/include/access/gistscan.h *************** *** 16,25 **** #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); #endif /* GISTSCAN_H */ --- 16,26 ---- #include "fmgr.h" ! 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 new file mode 100644 index 97cb859..50600b5 *** a/src/include/access/hash.h --- b/src/include/access/hash.h *************** *** 17,23 **** #ifndef HASH_H #define HASH_H ! #include "access/genam.h" #include "access/itup.h" #include "access/sdir.h" #include "access/xlogreader.h" --- 17,23 ---- #ifndef HASH_H #define HASH_H ! #include "access/amapi.h" #include "access/itup.h" #include "access/sdir.h" #include "access/xlogreader.h" *************** typedef HashMetaPageData *HashMetaPage; *** 243,261 **** /* 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); /* * Datatype-specific hash functions in hashfunc.c. --- 243,270 ---- /* public routines */ ! extern Datum hashhandler(PG_FUNCTION_ARGS); ! 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 new file mode 100644 index 9e48efd..cc381c0 *** a/src/include/access/nbtree.h --- b/src/include/access/nbtree.h *************** *** 14,26 **** #ifndef NBTREE_H #define NBTREE_H ! #include "access/genam.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" /* There's room for a 16-bit vacuum cycle ID in BTPageOpaqueData */ typedef uint16 BTCycleId; --- 14,27 ---- #ifndef NBTREE_H #define NBTREE_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; *************** typedef BTScanOpaqueData *BTScanOpaque; *** 652,671 **** /* * 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); /* * prototypes for functions in nbtinsert.c --- 653,682 ---- /* * prototypes for functions in nbtree.c (external entry points for btree) */ ! extern Datum bthandler(PG_FUNCTION_ARGS); ! 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 new file mode 100644 index 2a3cbcd..7de02d2 *** a/src/include/access/reloptions.h --- b/src/include/access/reloptions.h *************** *** 19,24 **** --- 19,25 ---- #ifndef RELOPTIONS_H #define RELOPTIONS_H + #include "access/amapi.h" #include "access/htup.h" #include "access/tupdesc.h" #include "nodes/pg_list.h" *************** extern Datum transformRelOptions(Datum o *** 258,264 **** bool ignoreOids, bool isReset); extern List *untransformRelOptions(Datum options); extern bytea *extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, ! Oid amoptions); extern relopt_value *parseRelOptions(Datum options, bool validate, relopt_kind kind, int *numrelopts); extern void *allocateReloptStruct(Size base, relopt_value *options, --- 259,265 ---- bool ignoreOids, bool isReset); extern List *untransformRelOptions(Datum options); extern bytea *extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, ! amoptions_function amoptions); extern relopt_value *parseRelOptions(Datum options, bool validate, relopt_kind kind, int *numrelopts); extern void *allocateReloptStruct(Size base, relopt_value *options, *************** extern bytea *default_reloptions(Datum r *** 272,278 **** 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, bool validate); extern bytea *attribute_reloptions(Datum reloptions, bool validate); extern bytea *tablespace_reloptions(Datum reloptions, bool validate); --- 273,279 ---- 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(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 new file mode 100644 index 0cb8fd9..9c79de8 *** a/src/include/access/spgist.h --- b/src/include/access/spgist.h *************** *** 14,20 **** #ifndef SPGIST_H #define SPGIST_H ! #include "access/skey.h" #include "access/xlogreader.h" #include "fmgr.h" #include "lib/stringinfo.h" --- 14,20 ---- #ifndef SPGIST_H #define SPGIST_H ! #include "access/amapi.h" #include "access/xlogreader.h" #include "fmgr.h" #include "lib/stringinfo.h" *************** typedef struct spgLeafConsistentOut *** 174,200 **** } spgLeafConsistentOut; /* spginsert.c */ ! extern Datum spgbuild(PG_FUNCTION_ARGS); ! extern Datum spgbuildempty(PG_FUNCTION_ARGS); ! extern Datum spginsert(PG_FUNCTION_ARGS); /* 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); /* spgutils.c */ ! extern Datum spgoptions(PG_FUNCTION_ARGS); /* spgvacuum.c */ ! extern Datum spgbulkdelete(PG_FUNCTION_ARGS); ! extern Datum spgvacuumcleanup(PG_FUNCTION_ARGS); /* spgxlog.c */ extern void spg_redo(XLogReaderState *record); --- 174,211 ---- } spgLeafConsistentOut; + /* spgutils.c */ + extern Datum spghandler(PG_FUNCTION_ARGS); + /* spginsert.c */ ! 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 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 bytea *spgoptions(Datum reloptions, bool validate); /* spgvacuum.c */ ! 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/pg_am.h b/src/include/catalog/pg_am.h new file mode 100644 index 8a28b8e..8a6d9cd *** a/src/include/catalog/pg_am.h --- b/src/include/catalog/pg_am.h *************** *** 34,72 **** 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 */ } FormData_pg_am; /* ---------------- --- 34,49 ---- CATALOG(pg_am,2601) { NameData amname; /* access method name */ + regproc amhandler; /* handler function */ 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 amcanorderbyop; /* does AM support order by operator result? */ bool amstorage; /* can storage type differ from column type? */ Oid amkeytype; /* type of data in index, or InvalidOid */ } FormData_pg_am; /* ---------------- *************** typedef FormData_pg_am *Form_pg_am; *** 80,138 **** * compiler constants for pg_am * ---------------- */ ! #define Natts_pg_am 30 #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 /* ---------------- * 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 )); 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 )); 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 )); 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 )); 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 )); 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 )); DESCR("block range index (BRIN) access method"); #define BRIN_AM_OID 3580 --- 57,92 ---- * compiler constants for pg_am * ---------------- */ ! #define Natts_pg_am 7 #define Anum_pg_am_amname 1 ! #define Anum_pg_am_amhandler 2 ! #define Anum_pg_am_amstrategies 3 ! #define Anum_pg_am_amsupport 4 #define Anum_pg_am_amcanorderbyop 5 ! #define Anum_pg_am_amstorage 6 ! #define Anum_pg_am_amkeytype 7 /* ---------------- * initial contents of pg_am * ---------------- */ ! DATA(insert OID = 403 ( btree bthandler 5 2 f f 0 )); DESCR("b-tree index access method"); #define BTREE_AM_OID 403 ! DATA(insert OID = 405 ( hash hashhandler 1 1 f f 23 )); DESCR("hash index access method"); #define HASH_AM_OID 405 ! DATA(insert OID = 783 ( gist gisthandler 0 9 t t 0 )); DESCR("GiST index access method"); #define GIST_AM_OID 783 ! DATA(insert OID = 2742 ( gin ginhandler 0 6 f t 0 )); DESCR("GIN index access method"); #define GIN_AM_OID 2742 ! DATA(insert OID = 4000 ( spgist spghandler 0 5 f f 0 )); DESCR("SP-GiST index access method"); #define SPGIST_AM_OID 4000 ! DATA(insert OID = 3580 ( brin brinhandler 0 15 f t 0 )); 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 new file mode 100644 index ddf7c67..e84b5ca *** a/src/include/catalog/pg_proc.h --- b/src/include/catalog/pg_proc.h *************** DESCR("convert int4 to float4"); *** 545,607 **** DATA(insert OID = 319 ( int4 PGNSP PGUID 12 1 0 0 0 f f f f t f i 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1 0 23 "2205" _null_ _null_ _null_ _null_ _null_ brin_summarize_new_values _null_ _null_ _null_ )); DESCR("brin: standalone scan new table pages"); --- 545,550 ---- *************** DESCR("convert name to char(n)"); *** 692,726 **** DATA(insert OID = 409 ( name PGNSP PGUID 12 1 0 0 0 f f f f t f i 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ hashint4 _null_ _null_ _null_ )); --- 635,640 ---- *************** DESCR("larger of two"); *** 976,1012 **** DATA(insert OID = 771 ( int2smaller PGNSP PGUID 12 1 0 0 0 f f f f t f i 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervallt _null_ _null_ _null_ )); --- 890,895 ---- *************** DATA(insert OID = 3311 ( tsm_handler_in *** 3738,3743 **** --- 3621,3630 ---- DESCR("I/O"); DATA(insert OID = 3312 ( tsm_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i 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 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 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 1 0 3310 "2281" _null_ _null_ _null_ _null_ _null_ tsm_bernoulli_handler _null_ _null_ _null_ )); *************** DESCR("GiST support"); *** 4194,4227 **** DATA(insert OID = 3288 ( gist_bbox_distance PGNSP PGUID 12 1 0 0 0 f f f f t f i 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 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 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 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 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 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 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 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 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 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 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 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 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 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 3 0 2281 "2277 2281 2281" _null_ _null_ _null_ _null_ _null_ ginarrayextract _null_ _null_ _null_ )); DESCR("GIN array support"); --- 4081,4086 ---- *************** DESCR("construct timestamp with time zon *** 5117,5154 **** DATA(insert OID = 3464 ( make_interval PGNSP PGUID 12 1 0 0 0 f f f f t f i 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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"); --- 4976,4981 ---- *************** DESCR("get an individual replication ori *** 5331,5336 **** --- 5158,5178 ---- DATA(insert OID = 6014 ( pg_show_replication_origin_status PGNSP PGUID 12 1 100 0 0 f f f f f t v 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 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 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 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 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 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 0 0 325 "" _null_ _null_ _null_ _null_ _null_ brinhandler _null_ _null_ _null_ )); + DESCR("brin handler"); + + /* * 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 new file mode 100644 index 7dc95c8..59b04ac *** a/src/include/catalog/pg_type.h --- b/src/include/catalog/pg_type.h *************** DATA(insert OID = 3115 ( fdw_handler PGN *** 696,701 **** --- 696,703 ---- #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/nodes/execnodes.h b/src/include/nodes/execnodes.h new file mode 100644 index 5796de8..6856932 *** a/src/include/nodes/execnodes.h --- b/src/include/nodes/execnodes.h *************** *** 14,20 **** #ifndef EXECNODES_H #define EXECNODES_H ! #include "access/genam.h" #include "access/heapam.h" #include "executor/instrument.h" #include "lib/pairingheap.h" --- 14,20 ---- #ifndef EXECNODES_H #define EXECNODES_H ! #include "access/amapi.h" #include "access/heapam.h" #include "executor/instrument.h" #include "lib/pairingheap.h" *************** *** 55,61 **** * they're conventionally set to false otherwise. * ---------------- */ ! typedef struct IndexInfo { NodeTag type; int ii_NumIndexAttrs; --- 55,61 ---- * they're conventionally set to false otherwise. * ---------------- */ ! struct IndexInfo { NodeTag type; int ii_NumIndexAttrs; *************** typedef struct IndexInfo *** 74,80 **** bool ii_ReadyForInserts; bool ii_Concurrent; bool ii_BrokenHotChain; ! } IndexInfo; /* ---------------- * ExprContext_CB --- 74,80 ---- bool ii_ReadyForInserts; bool ii_Concurrent; bool ii_BrokenHotChain; ! }; /* ---------------- * ExprContext_CB diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h new file mode 100644 index 748e434..c88fd19 *** a/src/include/nodes/nodes.h --- b/src/include/nodes/nodes.h *************** typedef enum NodeTag *** 453,459 **** T_TIDBitmap, /* in nodes/tidbitmap.h */ T_InlineCodeBlock, /* in nodes/parsenodes.h */ T_FdwRoutine, /* in foreign/fdwapi.h */ ! T_TsmRoutine /* in access/tsmapi.h */ } NodeTag; /* --- 453,460 ---- 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_IndexAmRoutine /* in access/amapi.h */ } NodeTag; /* diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h new file mode 100644 index 5dc23d9..4644298 *** a/src/include/nodes/relation.h --- b/src/include/nodes/relation.h *************** *** 19,24 **** --- 19,25 ---- #include "nodes/params.h" #include "nodes/parsenodes.h" #include "storage/block.h" + #include "utils/relcache.h" /* *************** typedef struct IndexOptInfo *** 542,549 **** 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 */ List *indexprs; /* expressions for non-simple index columns */ List *indpred; /* predicate if a partial index, else NIL */ --- 543,549 ---- bool *canreturn; /* which index cols can be returned in an * index-only scan? */ Oid relam; /* OID of the access method (in pg_am) */ ! IndexAmRoutine *amroutine; /* routine of access method */ List *indexprs; /* expressions for non-simple index columns */ List *indpred; /* predicate if a partial index, else NIL */ *************** typedef struct IndexOptInfo *** 554,565 **** 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 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? */ } IndexOptInfo; --- 554,565 ---- 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 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? */ } IndexOptInfo; *************** typedef struct Path *** 813,819 **** * itself represent the costs of an IndexScan or IndexOnlyScan plan type. *---------- */ ! typedef struct IndexPath { Path path; IndexOptInfo *indexinfo; --- 813,819 ---- * itself represent the costs of an IndexScan or IndexOnlyScan plan type. *---------- */ ! struct IndexPath { Path path; IndexOptInfo *indexinfo; *************** typedef struct IndexPath *** 825,831 **** ScanDirection indexscandir; Cost indextotalcost; Selectivity indexselectivity; ! } IndexPath; /* * BitmapHeapPath represents one or more indexscans that generate TID bitmaps --- 825,831 ---- ScanDirection indexscandir; Cost indextotalcost; Selectivity indexselectivity; ! }; /* * BitmapHeapPath represents one or more indexscans that generate TID bitmaps diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h new file mode 100644 index fc1679e..8e59b8c *** a/src/include/utils/builtins.h --- b/src/include/utils/builtins.h *************** extern Datum fdw_handler_in(PG_FUNCTION_ *** 568,573 **** --- 568,575 ---- 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 new file mode 100644 index 8a55a09..483b840 *** a/src/include/utils/rel.h --- b/src/include/utils/rel.h *************** typedef struct RelationData *** 129,134 **** --- 129,135 ---- /* 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 new file mode 100644 index 6953281..7cad109 *** a/src/include/utils/relcache.h --- b/src/include/utils/relcache.h *************** *** 19,24 **** --- 19,27 ---- typedef struct RelationData *Relation; + typedef struct IndexPath IndexPath; + typedef struct IndexInfo IndexInfo; + /* ---------------- * RelationPtr is used in the executor to support index scans *************** typedef struct RelationData *Relation; *** 28,33 **** --- 31,44 ---- */ 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 new file mode 100644 index b3d8017..9ed804c *** a/src/include/utils/selfuncs.h --- b/src/include/utils/selfuncs.h *************** extern double estimate_num_groups(Planne *** 190,201 **** 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); /* Functions in array_selfuncs.c */ --- 190,225 ---- extern Selectivity estimate_hash_bucketsize(PlannerInfo *root, Node *hashkey, double nbuckets); ! 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/oidjoins.out b/src/test/regress/expected/oidjoins.out new file mode 100644 index d85bc83..efdb809 *** a/src/test/regress/expected/oidjoins.out --- b/src/test/regress/expected/oidjoins.out *************** WHERE amkeytype != 0 AND *** 81,206 **** ------+----------- (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 --- 81,86 ---- diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql new file mode 100644 index 2fa628d..f002e17 *** a/src/test/regress/sql/oidjoins.sql --- b/src/test/regress/sql/oidjoins.sql *************** SELECT ctid, amkeytype *** 41,106 **** 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 --- 41,46 ----