WIP: Rework access method interface
Hacker,
some time before I proposed patches implementing CREATE ACCESS METHOD.
/messages/by-id/CAPpHfdsXwZmojm6Dx+TJnpYk27kT4o7Ri6X_4OSWcByu1Rm+VA@mail.gmail.com
As I get from comments to my patches and also from Tom's comment about AM
interface in tablesampling thread – AM interface needs reworking. And
AFAICS AM interface rework is essential to have CREATE ACCESS METHOD
command.
/messages/by-id/5438.1436740611@sss.pgh.pa.us
This is why I'd like to show a WIP patch implementing AM interface rework.
Patch is quite dirty yet, but I think it illustrated the idea quite clear.
AM now have single parameter – handler function. This handler returns
pointer to AmRoutine which have the same data as pg_am had before. Thus,
API is organized very like FDW.
However, this patch appears to take more work than I expected. It have to
do many changes spread among many files. Also, it appears not so easy to
hide amsupport into AmRoutine, because it's needed for relcache. As a
temporary solution it's duplicated in RelationData.
What do you think about this approach of AM interface rework?
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Attachments:
aminterface-1.patchapplication/octet-stream; name=aminterface-1.patchDownload
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
new file mode 100644
index fc9f964..84360c0
*** a/src/backend/access/brin/brin.c
--- b/src/backend/access/brin/brin.c
***************
*** 34,39 ****
--- 34,78 ----
#include "utils/snapmgr.h"
+ Datum
+ brinhandler(PG_FUNCTION_ARGS)
+ {
+ AmRoutine *amroutine = makeNode(AmRoutine);
+
+ 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 union_tuples(BrinDesc *bdesc
*** 79,93 ****
* 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;
--- 118,128 ----
* 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)
*** 225,231 ****
MemoryContextDelete(tupcxt);
}
! return BoolGetDatum(false);
}
/*
--- 260,266 ----
MemoryContextDelete(tupcxt);
}
! return false;
}
/*
*************** brininsert(PG_FUNCTION_ARGS)
*** 235,246 ****
* 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;
--- 270,278 ----
* 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)
*** 251,257 ****
opaque->bo_bdesc = brin_build_desc(r);
scan->opaque = opaque;
! PG_RETURN_POINTER(scan);
}
/*
--- 283,289 ----
opaque->bo_bdesc = brin_build_desc(r);
scan->opaque = opaque;
! return scan;
}
/*
*************** brinbeginscan(PG_FUNCTION_ARGS)
*** 266,276 ****
* 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;
--- 298,306 ----
* 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)
*** 450,469 ****
* 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
--- 480,495 ----
* 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)
*** 475,512 ****
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();
}
/*
--- 501,531 ----
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,
*** 578,589 ****
/*
* 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;
--- 597,605 ----
/*
* brinbuild() -- build a new BRIN index.
*/
! IndexBuildResult *
! brinbuild(Relation heap, Relation index, IndexInfo *indexInfo)
{
IndexBuildResult *result;
double reltuples;
double idxtuples;
*************** brinbuild(PG_FUNCTION_ARGS)
*** 662,674 ****
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. */
--- 678,689 ----
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)
*** 685,692 ****
END_CRIT_SECTION();
UnlockReleaseBuffer(metabuf);
-
- PG_RETURN_VOID();
}
/*
--- 700,705 ----
*************** brinbuildempty(PG_FUNCTION_ARGS)
*** 698,732 ****
* 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));
--- 711,739 ----
* 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)
*** 741,757 ****
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;
--- 748,762 ----
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)
*** 764,770 ****
/* if none set, we're done */
if (numoptions == 0)
! PG_RETURN_NULL();
rdopts = allocateReloptStruct(sizeof(BrinOptions), options, numoptions);
--- 769,775 ----
/* if none set, we're done */
if (numoptions == 0)
! return NULL;
rdopts = allocateReloptStruct(sizeof(BrinOptions), options, numoptions);
*************** brinoptions(PG_FUNCTION_ARGS)
*** 773,779 ****
pfree(options);
! PG_RETURN_BYTEA_P(rdopts);
}
/*
--- 778,784 ----
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 180f529..0543ef7
*** a/src/backend/access/common/reloptions.c
--- b/src/backend/access/common/reloptions.c
*************** untransformRelOptions(Datum options)
*** 832,838 ****
* 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;
--- 832,838 ----
* 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
*** 1320,1353 ****
* 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);
}
/*
--- 1320,1334 ----
* 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..346e973
*** a/src/backend/access/gin/ginutil.c
--- b/src/backend/access/gin/ginutil.c
***************
*** 22,28 ****
--- 22,68 ----
#include "miscadmin.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
+ #include "utils/selfuncs.h"
+
+
+ Datum
+ ginhandler(PG_FUNCTION_ARGS)
+ {
+ AmRoutine *amroutine = makeNode(AmRoutine);
+
+ 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;
--- 556,564 ----
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);
--- 573,579 ----
/* 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);
}
/*
--- 582,588 ----
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..75143a9
*** 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,82 ----
static void gistfinishsplit(GISTInsertState *state, GISTInsertStack *stack,
GISTSTATE *giststate, List *splitinfo, bool releasebuf);
+ Datum
+ gisthandler(PG_FUNCTION_ARGS)
+ {
+ AmRoutine *amroutine = makeNode(AmRoutine);
+
+ 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 */
--- 109,117 ----
/*
* 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();
}
/*
--- 127,132 ----
*************** 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;
--- 135,145 ----
* 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);
}
--- 165,171 ----
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..b5afc3b
*** 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,94 ----
bool tupleIsAlive,
void *state);
+ Datum
+ hashhandler(PG_FUNCTION_ARGS)
+ {
+ AmRoutine *amroutine = makeNode(AmRoutine);
+
+ 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();
}
/*
--- 149,164 ----
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;
/*
--- 200,210 ----
* 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);
--- 217,223 ----
* 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;
--- 227,242 ----
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;
--- 338,353 ----
/* 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;
--- 384,399 ----
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;
--- 415,430 ----
/* 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;
--- 450,463 ----
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();
}
/*
--- 476,499 ----
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;
--- 503,512 ----
*
* 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);
}
/*
--- 676,682 ----
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);
}
--- 684,705 ----
*
* 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..b812977
*** 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,126 ----
* ----------------------------------------------------------------
*/
#define RELATION_CHECKS \
! do { \
! Assert(RelationIsValid(indexRelation)); \
! if (!indexRelation->amroutine) \
! InitAmRoutine(indexRelation); \
! Assert(!ReindexIsProcessingIndex(RelationGetRelid(indexRelation))); \
! } while (0)
#define SCAN_CHECKS \
do { \
! Assert(IndexScanIsValid(scan)); \
! Assert(RelationIsValid(scan->indexRelation)); \
! if (!scan->indexRelation->amroutine) \
! InitAmRoutine(scan->indexRelation); \
! } 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)));
}
/*
--- 196,213 ----
Relation heapRelation,
IndexUniqueCheck checkUnique)
{
RELATION_CHECKS;
! if (!(indexRelation->amroutine->ampredlocks))
CheckForSerializableConflictIn(indexRelation,
(HeapTuple) NULL,
InvalidBuffer);
! CHECK_PROCEDURE(aminsert);
!
! 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);
/*
--- 267,278 ----
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;
}
--- 283,290 ----
/*
* 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);
--- 306,314 ----
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));
}
/* ----------------
--- 324,331 ----
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))
--- 335,343 ----
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);
--- 347,353 ----
}
/* 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));
}
/* ----------------
--- 363,372 ----
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));
}
/* ----------------
--- 388,403 ----
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));
--- 410,419 ----
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;
--- 423,429 ----
* 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;
--- 597,607 ----
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);
--- 609,615 ----
/*
* 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;
}
/* ----------------
--- 639,650 ----
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;
}
/* ----------------
--- 658,668 ----
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)));
}
/* ----------------
--- 675,689 ----
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;
! CHECK_PROCEDURE(amcanreturn);
! 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);
--- 721,727 ----
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);
--- 755,761 ----
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..ddb4d2b
*** a/src/backend/access/nbtree/nbtree.c
--- b/src/backend/access/nbtree/nbtree.c
*************** static void btvacuumpage(BTVacState *vst
*** 75,89 ****
BlockNumber orig_blkno);
/*
* 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;
--- 75,125 ----
BlockNumber orig_blkno);
+ Datum
+ bthandler(PG_FUNCTION_ARGS)
+ {
+ AmRoutine *amroutine = makeNode(AmRoutine);
+
+ 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);
}
/*
--- 191,197 ----
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);
--- 226,235 ----
/*
* 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();
}
/*
--- 249,254 ----
*************** 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;
--- 257,267 ----
* 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;
--- 273,287 ----
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);
}
--- 297,303 ----
{
/* 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;
--- 347,361 ----
/* ... 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);
}
--- 367,373 ----
{
/* 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;
--- 405,419 ----
/* 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 */
--- 451,466 ----
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 */
--- 511,524 ----
/* 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). */
--- 547,560 ----
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 */
--- 577,590 ----
/* 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();
}
/*
--- 652,657 ----
*************** 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;
--- 661,670 ----
*
* 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);
}
/*
--- 683,689 ----
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
--- 691,702 ----
*
* 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);
}
/*
--- 728,734 ----
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);
}
--- 1129,1136 ----
*
* 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..87a9ce5
*** a/src/backend/access/spgist/spgutils.c
--- b/src/backend/access/spgist/spgutils.c
***************
*** 24,30 ****
--- 24,70 ----
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "utils/lsyscache.h"
+ #include "utils/selfuncs.h"
+
+
+ Datum
+ spghandler(PG_FUNCTION_ARGS)
+ {
+ AmRoutine *amroutine = makeNode(AmRoutine);
+
+ 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();
}
/*
--- 529,544 ----
/*
* 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..b3e5ff6
*** a/src/backend/catalog/index.c
--- b/src/backend/catalog/index.c
***************
*** 23,28 ****
--- 23,29 ----
#include <unistd.h>
+ #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);
! AmRoutine *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 = GetAmRoutine(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..27ab2b3
*** 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;
+ AmRoutine *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 = (AmRoutine *)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;
+ AmRoutine *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 = (AmRoutine *)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/opclasscmds.c b/src/backend/commands/opclasscmds.c
new file mode 100644
index 3375f10..a73c5b5
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 335,340 ****
--- 335,341 ----
Relation rel;
HeapTuple tup;
Form_pg_am pg_am;
+ AmRoutine *amroutine;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 362,373 ****
amoid = HeapTupleGetOid(tup);
pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
! amstorage = pg_am->amstorage;
/* XXX Should we make any privilege check against the AM? */
--- 363,375 ----
amoid = HeapTupleGetOid(tup);
pg_am = (Form_pg_am) GETSTRUCT(tup);
! amroutine = (AmRoutine *)DatumGetPointer(OidFunctionCall0(pg_am->amhandler));
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
! amstorage = amroutine->amstorage;
/* XXX Should we make any privilege check against the AM? */
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 777,782 ****
--- 779,785 ----
maxProcNumber; /* amsupport value */
HeapTuple tup;
Form_pg_am pg_am;
+ AmRoutine *amroutine;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 788,798 ****
amoid = HeapTupleGetOid(tup);
pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
/* XXX Should we make any privilege check against the AM? */
--- 791,802 ----
amoid = HeapTupleGetOid(tup);
pg_am = (Form_pg_am) GETSTRUCT(tup);
! amroutine = (AmRoutine *)DatumGetPointer(OidFunctionCall0(pg_am->amhandler));
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
/* XXX Should we make any privilege check against the AM? */
*************** assignOperTypes(OpFamilyMember *member,
*** 1101,1113 ****
*/
HeapTuple amtup;
Form_pg_am pg_am;
amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
if (amtup == NULL)
elog(ERROR, "cache lookup failed for access method %u", amoid);
pg_am = (Form_pg_am) GETSTRUCT(amtup);
! if (!pg_am->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
--- 1105,1119 ----
*/
HeapTuple amtup;
Form_pg_am pg_am;
+ AmRoutine *amroutine;
amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
if (amtup == NULL)
elog(ERROR, "cache lookup failed for access method %u", amoid);
pg_am = (Form_pg_am) GETSTRUCT(amtup);
+ amroutine = (AmRoutine *)DatumGetPointer(OidFunctionCall0(pg_am->amhandler));
! if (!amroutine->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
new file mode 100644
index 970abd4..07ea58c
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
*************** ATExecSetRelOptions(Relation rel, List *
*** 9367,9373 ****
(void) view_reloptions(newOptions, true);
break;
case RELKIND_INDEX:
! (void) index_reloptions(rel->rd_am->amoptions, newOptions, true);
break;
default:
ereport(ERROR,
--- 9367,9373 ----
(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
*** 10958,10964 ****
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",
--- 10958,10964 ----
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..5672faf
*** 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;
+ AmRoutine *amroutine;
/* Fetch the pg_class tuple of the index relation */
ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexid));
*************** IndexSupportsBackwardScan(Oid indexid)
*** 541,548 ****
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,551 ----
elog(ERROR, "cache lookup failed for access method %u",
idxrelrec->relam);
amrec = (Form_pg_am) GETSTRUCT(ht_am);
+ amroutine = (AmRoutine *)DatumGetPointer(OidFunctionCall0(amrec->amhandler));
! result = amroutine->amcanbackward;
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..788c747
*** 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->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..9569a55
*** 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->amcostestimate = indexRelation->amroutine->amcostestimate;
! 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/ruleutils.c b/src/backend/utils/adt/ruleutils.c
new file mode 100644
index 51391f6..af9dd45
*** a/src/backend/utils/adt/ruleutils.c
--- b/src/backend/utils/adt/ruleutils.c
***************
*** 19,24 ****
--- 19,25 ----
#include <unistd.h>
#include <fcntl.h>
+ #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;
+ AmRoutine *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 = (AmRoutine *)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 14b8c2f..2b2bddc
*** a/src/backend/utils/adt/selfuncs.c
--- b/src/backend/utils/adt/selfuncs.c
*************** add_predicate_to_quals(IndexOptInfo *ind
*** 6392,6407 ****
}
! 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;
--- 6392,6402 ----
}
! 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)
*** 6690,6709 ****
*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;
--- 6685,6697 ----
*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)
*** 6743,6762 ****
*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;
--- 6731,6743 ----
*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)
*** 6809,6828 ****
*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;
--- 6790,6802 ----
*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)
*** 6875,6882 ****
*indexTotalCost = costs.indexTotalCost;
*indexSelectivity = costs.indexSelectivity;
*indexCorrelation = costs.indexCorrelation;
-
- PG_RETURN_VOID();
}
--- 6849,6854 ----
*************** gincost_scalararrayopexpr(PlannerInfo *r
*** 7171,7186 ****
/*
* 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;
--- 7143,7153 ----
/*
* 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)
*** 7331,7337 ****
*indexStartupCost = 0;
*indexTotalCost = 0;
*indexSelectivity = 0;
! PG_RETURN_VOID();
}
if (counts.haveFullScan || indexQuals == NIL)
--- 7298,7304 ----
*indexStartupCost = 0;
*indexTotalCost = 0;
*indexSelectivity = 0;
! return;
}
if (counts.haveFullScan || indexQuals == NIL)
*************** gincostestimate(PG_FUNCTION_ARGS)
*** 7453,7475 ****
*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;
--- 7420,7435 ----
*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)
*** 7522,7527 ****
*indexTotalCost += (numTuples * *indexSelectivity) * (cpu_index_tuple_cost + qual_op_cost);
/* XXX what about pages_per_range? */
-
- PG_RETURN_VOID();
}
--- 7482,7485 ----
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
new file mode 100644
index 44e9509..abf1ca6
*** a/src/backend/utils/cache/relcache.c
--- b/src/backend/utils/cache/relcache.c
*************** RelationParseRelOptions(Relation relatio
*** 437,442 ****
--- 437,445 ----
return;
}
+ if (relation->rd_rel->relkind == RELKIND_INDEX && !relation->amroutine)
+ InitAmRoutine(relation);
+
/*
* Fetch reloptions from tuple; have to use a hardwired descriptor because
* we might not have any other for pg_class yet (consider executing this
*************** 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
--- 448,454 ----
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
*** 1161,1166 ****
--- 1164,1201 ----
}
}
+ AmRoutine *
+ GetAmRoutine(Oid amoid)
+ {
+ 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;
+ ReleaseSysCache(tuple);
+
+ if (!RegProcedureIsValid(amhandler))
+ elog(ERROR, "invalid %u regproc", amhandler);
+
+ return (AmRoutine *)DatumGetPointer(OidFunctionCall0(amhandler));
+ }
+
+ void
+ InitAmRoutine(Relation relation)
+ {
+ AmRoutine *amroutine;
+
+ amroutine = (AmRoutine *)MemoryContextAlloc(CacheMemoryContext,
+ sizeof(AmRoutine));
+ memcpy(amroutine, (AmRoutine *)DatumGetPointer(OidFunctionCall0(
+ relation->rd_am->amhandler)), sizeof(AmRoutine));
+ relation->amroutine = amroutine;
+ relation->nsupport = amroutine->amsupport;
+ }
+
/*
* Initialize index-access-method support data for an index relation
*/
*************** void
*** 1168,1174 ****
RelationInitIndexAccessInfo(Relation relation)
{
HeapTuple tuple;
- Form_pg_am aform;
Datum indcollDatum;
Datum indclassDatum;
Datum indoptionDatum;
--- 1203,1208 ----
*************** RelationInitIndexAccessInfo(Relation rel
*** 1180,1185 ****
--- 1214,1220 ----
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
--- 1239,1256 ----
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;
+ InitAmRoutine(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;
--- 4753,4758 ----
*************** load_relcache_init_file(bool shared)
*** 4744,4749 ****
--- 4780,4786 ----
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
{
--- 4845,4852 ----
/* set up zeroed fmgr-info vectors */
rel->rd_aminfo = (RelationAmInfo *)
MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
rel->rd_supportinfo = (FmgrInfo *)
! MemoryContextAllocZero(indexcxt, relform->relnatts * rel->nsupport * sizeof(FmgrInfo));
}
else
{
*************** write_relcache_init_file(bool shared)
*** 5079,5085 ****
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
--- 5115,5121 ----
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (rel->nsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h
new file mode 100644
index ...a071b4b
*** a/src/include/access/amapi.h
--- b/src/include/access/amapi.h
***************
*** 0 ****
--- 1,153 ----
+ /*-------------------------------------------------------------------------
+ *
+ * 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.
+ */
+
+ typedef bool
+ (*aminsert_function) (Relation indexRelation,
+ Datum *values,
+ bool *isnull,
+ ItemPointer heap_tid,
+ Relation heapRelation,
+ IndexUniqueCheck checkUnique);
+
+ typedef IndexScanDesc
+ (*ambeginscan_function) (Relation indexRelation,
+ int nkeys,
+ int norderbys);
+
+ typedef bool
+ (*amgettuple_function) (IndexScanDesc scan,
+ ScanDirection direction);
+
+ typedef int64
+ (*amgetbitmap_function) (IndexScanDesc scan,
+ TIDBitmap *tbm);
+
+ typedef void
+ (*amrescan_function) (IndexScanDesc scan,
+ ScanKey keys,
+ int nkeys,
+ ScanKey orderbys,
+ int norderbys);
+
+ typedef void
+ (*amendscan_function) (IndexScanDesc scan);
+
+ typedef void
+ (*ammarkpos_function) (IndexScanDesc scan);
+
+ typedef void
+ (*amrestrpos_function) (IndexScanDesc scan);
+
+ typedef IndexBuildResult *
+ (*ambuild_function) (Relation heapRelation,
+ Relation indexRelation,
+ IndexInfo *indexInfo);
+
+ typedef void
+ (*ambuildempty_function) (Relation indexRelation);
+
+ typedef IndexBulkDeleteResult *
+ (*ambulkdelete_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+
+ typedef IndexBulkDeleteResult *
+ (*amvacuumcleanup_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
+
+ typedef bool
+ (*amcanreturn_function) (Relation indexRelation, int attno);
+
+ typedef bytea *
+ (*amoptions_function) (Datum reloptions,
+ bool validate);
+
+
+ struct AmRoutine
+ {
+ 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;
+
+ /* "insert this tuple" function */
+ aminsert_function aminsert;
+ /* "prepare for index scan" function */
+ ambeginscan_function ambeginscan;
+ /* "next valid tuple" function, or NULL */
+ amgettuple_function amgettuple;
+ /* "fetch all valid tuples" function, or NULL */
+ amgetbitmap_function amgetbitmap;
+ /* "(re)start index scan" function */
+ amrescan_function amrescan;
+ /* "end index scan" function */
+ amendscan_function amendscan;
+ /* "mark current scan position" function */
+ ammarkpos_function ammarkpos;
+ /* "restore marked scan position" function */
+ amrestrpos_function amrestrpos;
+ /* "build new index" function */
+ ambuild_function ambuild;
+ /* "build empty index" function */
+ ambuildempty_function ambuildempty;
+ /* bulk-delete function */
+ ambulkdelete_function ambulkdelete;
+ /* post-VACUUM cleanup function */
+ amvacuumcleanup_function amvacuumcleanup;
+ /* can indexscan return IndexTuples? */
+ amcanreturn_function amcanreturn;
+ /* estimate cost of an indexscan */
+ amcostestimate_function amcostestimate;
+ /* parse AM-specific parameters */
+ 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..8155cb8
*** a/src/include/access/genam.h
--- b/src/include/access/genam.h
***************
*** 21,26 ****
--- 21,28 ----
#include "utils/relcache.h"
#include "utils/snapshot.h"
+ typedef struct IndexInfo IndexInfo;
+
/*
* Struct for statistics returned by ambuild
*/
*************** typedef enum IndexUniqueCheck
*** 111,117 ****
UNIQUE_CHECK_EXISTING /* Check if existing tuple is unique */
} IndexUniqueCheck;
-
/*
* generalized index_ interface routines (in indexam.c)
*/
--- 113,118 ----
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 e7b6bb5..5cb6fd4
*** 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
*** 256,262 ****
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,
--- 257,263 ----
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
*** 270,276 ****
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);
--- 271,277 ----
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..5174096
*** 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
*** 175,200 ****
/* 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);
--- 175,209 ----
/* spginsert.c */
! extern Datum spghandler(PG_FUNCTION_ARGS);
! extern IndexBuildResult *spgbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void spgbuildempty(Relation indexRelation);
! extern bool spginsert(Relation index, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
/* spgscan.c */
! extern 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..f19a873
*** 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,40 ----
CATALOG(pg_am,2601)
{
NameData amname; /* access method name */
! regproc amhandler; /* handler function */
} 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
--- 48,78 ----
* compiler constants for pg_am
* ----------------
*/
! #define Natts_pg_am 2
#define Anum_pg_am_amname 1
! #define Anum_pg_am_amhandler 2
/* ----------------
* initial contents of pg_am
* ----------------
*/
! DATA(insert OID = 403 ( btree bthandler ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
! DATA(insert OID = 405 ( hash hashhandler ));
DESCR("hash index access method");
#define HASH_AM_OID 405
! DATA(insert OID = 783 ( gist gisthandler ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
! DATA(insert OID = 2742 ( gin ginhandler ));
DESCR("GIN index access method");
#define GIN_AM_OID 2742
! DATA(insert OID = 4000 ( spgist spghandler ));
DESCR("SP-GiST index access method");
#define SPGIST_AM_OID 4000
! DATA(insert OID = 3580 ( brin brinhandler ));
DESCR("block range index (BRIN) access method");
#define BRIN_AM_OID 3580
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index c9fe0f8..1887239
*** 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 ----
*************** 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");
--- 4077,4082 ----
*************** 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");
--- 4972,4977 ----
*************** DESCR("get an individual replication ori
*** 5331,5336 ****
--- 5154,5174 ----
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 2281 "" _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 2281 "" _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 2281 "" _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 2281 "" _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 2281 "" _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 2281 "" _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/nodes/execnodes.h b/src/include/nodes/execnodes.h
new file mode 100644
index 5796de8..fc59b1e
*** a/src/include/nodes/execnodes.h
--- b/src/include/nodes/execnodes.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..3366942
*** 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_AmRoutine /* in access/amapi.h */
} NodeTag;
/*
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
new file mode 100644
index cb916ea..689c918
*** a/src/include/nodes/relation.h
--- b/src/include/nodes/relation.h
*************** typedef struct RelOptInfo
*** 484,489 ****
--- 484,500 ----
bool has_eclass_joins; /* T means joininfo is incomplete */
} RelOptInfo;
+ typedef struct IndexPath IndexPath;
+
+ typedef void
+ (*amcostestimate_function) (PlannerInfo *root,
+ IndexPath *path,
+ double loop_count,
+ Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+
/*
* IndexOptInfo
* Per-index information for planning/optimization
*************** typedef struct IndexOptInfo
*** 536,542 ****
* 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 */
--- 547,553 ----
* index-only scan? */
Oid relam; /* OID of the access method (in pg_am) */
! amcostestimate_function 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 */
*************** typedef struct Path
*** 806,812 ****
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! typedef struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
--- 817,823 ----
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
*************** typedef struct IndexPath
*** 818,824 ****
ScanDirection indexscandir;
Cost indextotalcost;
Selectivity indexselectivity;
! } IndexPath;
/*
* BitmapHeapPath represents one or more indexscans that generate TID bitmaps
--- 829,835 ----
ScanDirection indexscandir;
Cost indextotalcost;
Selectivity indexselectivity;
! };
/*
* BitmapHeapPath represents one or more indexscans that generate TID bitmaps
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
new file mode 100644
index 8a55a09..9991345
*** a/src/include/utils/rel.h
--- b/src/include/utils/rel.h
*************** typedef struct RelationData
*** 128,134 ****
Form_pg_index rd_index; /* pg_index tuple describing this index */
/* 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 */
/*
* index access support info (used only for an index relation)
--- 128,136 ----
Form_pg_index rd_index; /* pg_index tuple describing this index */
/* use "struct" here to avoid needing to include htup.h: */
struct HeapTupleData *rd_indextuple; /* all of pg_index tuple */
! Form_pg_am rd_am;
! int16 nsupport;
! AmRoutine *amroutine; /* pg_am tuple for index's AM */
/*
* 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..3f660f6
*** a/src/include/utils/relcache.h
--- b/src/include/utils/relcache.h
***************
*** 17,23 ****
#include "access/tupdesc.h"
#include "nodes/bitmapset.h"
-
typedef struct RelationData *Relation;
/* ----------------
--- 17,22 ----
*************** typedef struct RelationData *Relation;
*** 28,33 ****
--- 27,37 ----
*/
typedef Relation *RelationPtr;
+ typedef struct AmRoutine AmRoutine;
+
+ AmRoutine *GetAmRoutine(Oid amoid);
+ void InitAmRoutine(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 */
On 2015-08-09 23:56, Alexander Korotkov wrote:
Hacker,
some time before I proposed patches implementing CREATE ACCESS METHOD.
/messages/by-id/CAPpHfdsXwZmojm6Dx+TJnpYk27kT4o7Ri6X_4OSWcByu1Rm+VA@mail.gmail.com
As I get from comments to my patches and also from Tom's comment about
AM interface in tablesampling thread – AM interface needs reworking. And
AFAICS AM interface rework is essential to have CREATE ACCESS METHOD
command.
/messages/by-id/5438.1436740611@sss.pgh.pa.us
Cool, I was planning to take a stab at this myself when I have time, so
I am glad you posted this.
This is why I'd like to show a WIP patch implementing AM interface
rework. Patch is quite dirty yet, but I think it illustrated the idea
quite clear. AM now have single parameter – handler function. This
handler returns pointer to AmRoutine which have the same data as pg_am
had before. Thus, API is organized very like FDW.
I wonder if it would make sense to call it IndexAmRoutine instead in
case we add other AMs (like the sequence am, or maybe column store if
that's done as AM) in the future.
The patch should probably add the am_handler type which should be return
type of the am handler function (see fdw_handler and tsm_handler types).
I also think that the CHECK_PROCEDUREs should be in the place of the
original GET_REL_PROCEDUREs (just after relation check). If the
interface must exist we may as well check for it at the beginning and
not after we did some other work which is useless without the interface.
However, this patch appears to take more work than I expected. It have
to do many changes spread among many files.
Yeah you need to change the definition and I/O handling of every AM
function, but that's to be expected.
Also, it appears not so easy
to hide amsupport into AmRoutine, because it's needed for relcache. As a
temporary solution it's duplicated in RelationData.
I don't understand this, there is already AmRoutine in RelationData, why
the need for additional field for just amsupport?
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Aug 10, 2015 at 1:12 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
On 2015-08-09 23:56, Alexander Korotkov wrote:
Hacker,
some time before I proposed patches implementing CREATE ACCESS METHOD.
/messages/by-id/CAPpHfdsXwZmojm6Dx+TJnpYk27kT4o7Ri6X_4OSWcByu1Rm+VA@mail.gmail.com
As I get from comments to my patches and also from Tom's comment about
AM interface in tablesampling thread – AM interface needs reworking. And
AFAICS AM interface rework is essential to have CREATE ACCESS METHOD
command.
/messages/by-id/5438.1436740611@sss.pgh.pa.usCool, I was planning to take a stab at this myself when I have time, so I
am glad you posted this.This is why I'd like to show a WIP patch implementing AM interface
rework. Patch is quite dirty yet, but I think it illustrated the idea
quite clear. AM now have single parameter – handler function. This
handler returns pointer to AmRoutine which have the same data as pg_am
had before. Thus, API is organized very like FDW.I wonder if it would make sense to call it IndexAmRoutine instead in case
we add other AMs (like the sequence am, or maybe column store if that's
done as AM) in the future.
Good point!
The patch should probably add the am_handler type which should be return
type of the am handler function (see fdw_handler and tsm_handler types).
Sounds reasonable!
I also think that the CHECK_PROCEDUREs should be in the place of the
original GET_REL_PROCEDUREs (just after relation check). If the interface
must exist we may as well check for it at the beginning and not after we
did some other work which is useless without the interface.
Ok, good point too.
However, this patch appears to take more work than I expected. It have
to do many changes spread among many files.
Yeah you need to change the definition and I/O handling of every AM
function, but that's to be expected.
Yes, this is why I decided to get some feedback on this stage of work.
Also, it appears not so easy
to hide amsupport into AmRoutine, because it's needed for relcache. As a
temporary solution it's duplicated in RelationData.I don't understand this, there is already AmRoutine in RelationData, why
the need for additional field for just amsupport?
We need amsupport in load_relcache_init_file() which reads
"pg_internal.init". I'm not sure this is correct place to call am_handler.
It should work in the case of built-in AM. But if AM is defined in the
extension then we wouldn't be able to do catalog lookup for am_handler on
this stage of initialization.
Another point is that amsupport and amstrategies are used for regression
tests of opclasses and opfamilies. Thus, we probably can keep them in pg_am.
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Alexander Korotkov <a.korotkov@postgrespro.ru> writes:
On Mon, Aug 10, 2015 at 1:12 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
I don't understand this, there is already AmRoutine in RelationData, why
the need for additional field for just amsupport?
We need amsupport in load_relcache_init_file() which reads
"pg_internal.init". I'm not sure this is correct place to call am_handler.
It should work in the case of built-in AM. But if AM is defined in the
extension then we wouldn't be able to do catalog lookup for am_handler on
this stage of initialization.
This is an issue we'll have to face before there's much hope of having
index AMs as extensions: how would you locate any extension function
without catalog access? Storing raw function pointers in pg_internal.init
is not an answer in an ASLR world.
I think we can dodge the issue so far as pg_internal.init is concerned by
decreeing that system catalogs can only have indexes with built-in AMs.
Calling a built-in function doesn't require catalog access, so there
should be no problem with re-calling the handler function by OID during
load_relcache_init_file().
We could also have problems with WAL replay, though I think the consensus
there is that extension AMs have to use generic WAL records that don't
require any index-specific replay code.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Aug 10, 2015 at 5:48 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Alexander Korotkov <a.korotkov@postgrespro.ru> writes:
On Mon, Aug 10, 2015 at 1:12 PM, Petr Jelinek <petr@2ndquadrant.com>
wrote:
I don't understand this, there is already AmRoutine in RelationData, why
the need for additional field for just amsupport?We need amsupport in load_relcache_init_file() which reads
"pg_internal.init". I'm not sure this is correct place to callam_handler.
It should work in the case of built-in AM. But if AM is defined in the
extension then we wouldn't be able to do catalog lookup for am_handler on
this stage of initialization.This is an issue we'll have to face before there's much hope of having
index AMs as extensions: how would you locate any extension function
without catalog access? Storing raw function pointers in pg_internal.init
is not an answer in an ASLR world.I think we can dodge the issue so far as pg_internal.init is concerned by
decreeing that system catalogs can only have indexes with built-in AMs.
Calling a built-in function doesn't require catalog access, so there
should be no problem with re-calling the handler function by OID during
load_relcache_init_file().
That should work, thanks! Also we can have SQL-visible functions to get
amsupport and amstrategies and use them in the regression tests.
We could also have problems with WAL replay, though I think the consensus
there is that extension AMs have to use generic WAL records that don't
require any index-specific replay code.
Yes, I've already showed one version of generic WAL records. The main
objecting against them was it's hard insure that composed WAL-record is
correct.
Now I'm working on new version which would be much easier and safe to use.
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
On 2015-08-10 16:58, Alexander Korotkov wrote:
On Mon, Aug 10, 2015 at 5:48 PM, Tom Lane <tgl@sss.pgh.pa.us
<mailto:tgl@sss.pgh.pa.us>> wrote:Alexander Korotkov <a.korotkov@postgrespro.ru
<mailto:a.korotkov@postgrespro.ru>> writes:On Mon, Aug 10, 2015 at 1:12 PM, Petr Jelinek <petr@2ndquadrant.com <mailto:petr@2ndquadrant.com>> wrote:
I don't understand this, there is already AmRoutine in RelationData, why
the need for additional field for just amsupport?We need amsupport in load_relcache_init_file() which reads
"pg_internal.init". I'm not sure this is correct place to call am_handler.
It should work in the case of built-in AM. But if AM is defined in the
extension then we wouldn't be able to do catalog lookup for am_handler on
this stage of initialization.This is an issue we'll have to face before there's much hope of having
index AMs as extensions: how would you locate any extension function
without catalog access? Storing raw function pointers in
pg_internal.init
is not an answer in an ASLR world.I think we can dodge the issue so far as pg_internal.init is
concerned by
decreeing that system catalogs can only have indexes with built-in AMs.
Calling a built-in function doesn't require catalog access, so there
should be no problem with re-calling the handler function by OID during
load_relcache_init_file().That should work, thanks! Also we can have SQL-visible functions to get
amsupport and amstrategies and use them in the regression tests.
SQL-visible functions would be preferable to storing it in pg_am as
keeping the params in pg_am would limit the extensibility of pg_am itself.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Aug 10, 2015 at 6:36 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
On 2015-08-10 16:58, Alexander Korotkov wrote:
That should work, thanks! Also we can have SQL-visible functions to get
amsupport and amstrategies and use them in the regression tests.SQL-visible functions would be preferable to storing it in pg_am as
keeping the params in pg_am would limit the extensibility of pg_am itself.
I actually meant just two particular functions (not per AM) which both get
AM oid as argument. They should call amhandler and return amsupport and
amstrategies correspondingly.
These functions can be used in regression tests to check opclass and
opfamilies correctness.
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Petr Jelinek <petr@2ndquadrant.com> writes:
On 2015-08-10 16:58, Alexander Korotkov wrote:
That should work, thanks! Also we can have SQL-visible functions to get
amsupport and amstrategies and use them in the regression tests.
SQL-visible functions would be preferable to storing it in pg_am as
keeping the params in pg_am would limit the extensibility of pg_am itself.
I don't see any particularly good reason to remove amsupport and
amstrategies from pg_am. Those are closely tied to the other catalog
infrastructure for indexes (pg_amproc, pg_amop) which I don't think are
candidates for getting changed by this patch.
There are a couple of other pg_am columns, such as amstorage and
amcanorderbyop, which similarly bear on what's legal to appear in
related catalogs such as pg_opclass. I'd be sort of inclined to
leave those in the catalog as well. I do not see that exposing
a SQL function is better than exposing a catalog column; either
way, that property is SQL-visible.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Aug 10, 2015 at 6:47 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Petr Jelinek <petr@2ndquadrant.com> writes:
On 2015-08-10 16:58, Alexander Korotkov wrote:
That should work, thanks! Also we can have SQL-visible functions to get
amsupport and amstrategies and use them in the regression tests.SQL-visible functions would be preferable to storing it in pg_am as
keeping the params in pg_am would limit the extensibility of pg_amitself.
I don't see any particularly good reason to remove amsupport and
amstrategies from pg_am. Those are closely tied to the other catalog
infrastructure for indexes (pg_amproc, pg_amop) which I don't think are
candidates for getting changed by this patch.There are a couple of other pg_am columns, such as amstorage and
amcanorderbyop, which similarly bear on what's legal to appear in
related catalogs such as pg_opclass. I'd be sort of inclined to
leave those in the catalog as well. I do not see that exposing
a SQL function is better than exposing a catalog column; either
way, that property is SQL-visible.
That answers my question, thanks!
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
On 2015-08-10 17:47, Tom Lane wrote:
Petr Jelinek <petr@2ndquadrant.com> writes:
On 2015-08-10 16:58, Alexander Korotkov wrote:
That should work, thanks! Also we can have SQL-visible functions to get
amsupport and amstrategies and use them in the regression tests.SQL-visible functions would be preferable to storing it in pg_am as
keeping the params in pg_am would limit the extensibility of pg_am itself.I don't see any particularly good reason to remove amsupport and
amstrategies from pg_am. Those are closely tied to the other catalog
infrastructure for indexes (pg_amproc, pg_amop) which I don't think are
candidates for getting changed by this patch.
Ok, in that case it seems unlikely that we'll be able to use pg_am for
any other access methods besides indexes in the future.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Alexander Korotkov <a.korotkov@postgrespro.ru> writes:
On Mon, Aug 10, 2015 at 6:47 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
There are a couple of other pg_am columns, such as amstorage and
amcanorderbyop, which similarly bear on what's legal to appear in
related catalogs such as pg_opclass. I'd be sort of inclined to
leave those in the catalog as well. I do not see that exposing
a SQL function is better than exposing a catalog column; either
way, that property is SQL-visible.
That answers my question, thanks!
BTW, just to clarify: we can still have the desirable property that
CREATE INDEX ACCESS METHOD needs no parameters other than the AM handler
function name. The AM code would still expose all of its properties
through the struct returned by the handler. What is at issue here is
how information in that struct that needs to be available to SQL code
gets exposed. We can do that either by exposing SQL functions to get
it, or by having CREATE INDEX ACCESS METHOD call the handler and then
copy some fields into the new pg_am row. I'm suggesting that we should
do the latter for any fields that determine validity of pg_opclass,
pg_amop, etc entries associated with the AM type. The AM could not
reasonably change its mind about such properties (within a major
release at least) so there is no harm in making a long-lived copy
in pg_am. And we might as well not break SQL code unnecessarily
by removing fields that used to be there.
There may be some other AM properties that would be better to expose
through SQL functions because they could potentially change without
invalidating information stored in the other catalogs. I'm not sure
whether there is any such data that needs to be accessible at SQL
level, though.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Petr Jelinek <petr@2ndquadrant.com> writes:
On 2015-08-10 17:47, Tom Lane wrote:
I don't see any particularly good reason to remove amsupport and
amstrategies from pg_am. Those are closely tied to the other catalog
infrastructure for indexes (pg_amproc, pg_amop) which I don't think are
candidates for getting changed by this patch.
Ok, in that case it seems unlikely that we'll be able to use pg_am for
any other access methods besides indexes in the future.
I think that's likely for the best anyway; there are too many catalogs
that think a pg_am OID identifies an index AM. Better to create other
catalogs for other types of AMs.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Tom Lane wrote:
There are a couple of other pg_am columns, such as amstorage and
amcanorderbyop, which similarly bear on what's legal to appear in
related catalogs such as pg_opclass. I'd be sort of inclined to
leave those in the catalog as well. I do not see that exposing
a SQL function is better than exposing a catalog column; either
way, that property is SQL-visible.
If we do that, it doesn't seem reasonable to use the same catalog for
other things such as sequence AM, right? IMO it'd be better to keep the
catalog agnostic for exactly what each row is going to be an AM for.
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-08-10 18:08, Tom Lane wrote:
Alexander Korotkov <a.korotkov@postgrespro.ru> writes:
On Mon, Aug 10, 2015 at 6:47 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
There are a couple of other pg_am columns, such as amstorage and
amcanorderbyop, which similarly bear on what's legal to appear in
related catalogs such as pg_opclass. I'd be sort of inclined to
leave those in the catalog as well. I do not see that exposing
a SQL function is better than exposing a catalog column; either
way, that property is SQL-visible.That answers my question, thanks!
BTW, just to clarify: we can still have the desirable property that
CREATE INDEX ACCESS METHOD needs no parameters other than the AM handler
function name. The AM code would still expose all of its properties
through the struct returned by the handler. What is at issue here is
how information in that struct that needs to be available to SQL code
gets exposed. We can do that either by exposing SQL functions to get
it, or by having CREATE INDEX ACCESS METHOD call the handler and then
copy some fields into the new pg_am row. I'm suggesting that we should
do the latter for any fields that determine validity of pg_opclass,
pg_amop, etc entries associated with the AM type. The AM could not
reasonably change its mind about such properties (within a major
release at least) so there is no harm in making a long-lived copy
in pg_am. And we might as well not break SQL code unnecessarily
by removing fields that used to be there.
That's definitely the case for built-in AMs but 3rd party ones won't
necessarily follow PG release schedule/versioning and I can imagine
change of for example amcanorderbyop between AM releases as the AM
matures. This could probably be solved by some kind of invalidation
mechanism (even if it's some additional SQL).
However I am not sure if using catalog as some sort of cache for
function output is a good idea in general. IMHO it would be better to
just have those options as part of CREATE and ALTER DDL for INDEX ACCESS
METHODS if we store them in pg_am.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-08-10 18:16, Alvaro Herrera wrote:
Tom Lane wrote:
There are a couple of other pg_am columns, such as amstorage and
amcanorderbyop, which similarly bear on what's legal to appear in
related catalogs such as pg_opclass. I'd be sort of inclined to
leave those in the catalog as well. I do not see that exposing
a SQL function is better than exposing a catalog column; either
way, that property is SQL-visible.If we do that, it doesn't seem reasonable to use the same catalog for
other things such as sequence AM, right? IMO it'd be better to keep the
catalog agnostic for exactly what each row is going to be an AM for.
Yeah I said the same, the question is if we should have pg_am agnostic
or just assume that it's index AM and let other AM types create separate
catalogs. Tom seems to prefer the latter, I don't see problem with that,
except that I would really hate to add more am related columns to
pg_class. I would not mind having relam pointing to different AM catalog
for different relkinds but dunno if that's ok for others (it's not
really normalized design).
We could also keep pg_am agnostic and add pg_index_am for additional
info about index AMs, but that would make this patch more invasive.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Tom Lane wrote:
Petr Jelinek <petr@2ndquadrant.com> writes:
On 2015-08-10 17:47, Tom Lane wrote:
I don't see any particularly good reason to remove amsupport and
amstrategies from pg_am. Those are closely tied to the other catalog
infrastructure for indexes (pg_amproc, pg_amop) which I don't think are
candidates for getting changed by this patch.Ok, in that case it seems unlikely that we'll be able to use pg_am for
any other access methods besides indexes in the future.I think that's likely for the best anyway; there are too many catalogs
that think a pg_am OID identifies an index AM. Better to create other
catalogs for other types of AMs.
That means we won't be able to reuse pg_class.relam as a pointer to the
AM-of-the-other-kind either. I don't think this is the best course of
action. We have the sequence AM patch that already reuses
pg_class.relam to point to pg_seqam.oid, but you objected to that on
relational theory grounds, which seemed reasonable to me. The other
option is to create yet another pg_class column with an OID of some
other AM catalog, but this seems a waste.
FWIW the column store patch we're working on also wants to have its own
AM-like catalog. In our current code we have a separate catalog
pg_colstore_am, but are eagerly waiting for the discussion on this to
settle so that we can just use pg_am and pg_class.relam instead. (The
patch itself is not public yet since it's nowhere near usable, and this
detail is a pretty minor issue, but I thought reasonable to bring it up
here. We're also waiting on upper-planner "path-ification" since it
seems likely that some code will collide there, anyway.)
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
Tom Lane wrote:
I think that's likely for the best anyway; there are too many catalogs
that think a pg_am OID identifies an index AM. Better to create other
catalogs for other types of AMs.
That means we won't be able to reuse pg_class.relam as a pointer to the
AM-of-the-other-kind either.
Hm. So one way or the other we're going to end up violating relational
theory somewhere. OK, I yield: let's say that pg_am has amname, amkind,
amhandler, and nothing else. Then we will need SQL functions to expose
whatever information we think needs to be available to SQL code.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Aug 10, 2015 at 7:50 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
Tom Lane wrote:
I think that's likely for the best anyway; there are too many catalogs
that think a pg_am OID identifies an index AM. Better to create other
catalogs for other types of AMs.That means we won't be able to reuse pg_class.relam as a pointer to the
AM-of-the-other-kind either.Hm. So one way or the other we're going to end up violating relational
theory somewhere. OK, I yield: let's say that pg_am has amname, amkind,
amhandler, and nothing else. Then we will need SQL functions to expose
whatever information we think needs to be available to SQL code.
There is second revision of this patch. Changes are so:
* AmRoutine was renamed to IndexAmRoutine assuming there could be other
access methods in the future.
* amhandlers now return index_am_handler pseudotype.
* CHECK_PROCEDUREs are now is the place of original GET_REL_PROCEDUREs.
* amstrategies, amsupport, amcanorderbyop, amstorage, amkeytype are in
both pg_am and IndexAmRoutine. Consistence of amhandler answer and pg_am
tuple is checking.
* Some comments and refactoring.
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Attachments:
aminterface-2.pathapplication/octet-stream; name=aminterface-2.pathDownload
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 <unistd.h>
+ #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 <unistd.h>
#include <fcntl.h>
+ #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 ----
Alexander Korotkov <a.korotkov@postgrespro.ru> writes:
On Mon, Aug 10, 2015 at 7:50 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Hm. So one way or the other we're going to end up violating relational
theory somewhere. OK, I yield: let's say that pg_am has amname, amkind,
amhandler, and nothing else. Then we will need SQL functions to expose
whatever information we think needs to be available to SQL code.
There is second revision of this patch. Changes are so:
* AmRoutine was renamed to IndexAmRoutine assuming there could be other
access methods in the future.
* amhandlers now return index_am_handler pseudotype.
* CHECK_PROCEDUREs are now is the place of original GET_REL_PROCEDUREs.
* amstrategies, amsupport, amcanorderbyop, amstorage, amkeytype are in
both pg_am and IndexAmRoutine. Consistence of amhandler answer and pg_am
tuple is checking.
[ scratches head... ] I thought we'd just agreed we weren't going to keep
any of those pg_am columns? If we keep them, we'll have to define what
they mean for sequence AMs etc. ("Let them be NULL" would likely break
enough stuff that we might as well not have them.)
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Aug 24, 2015 at 5:15 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Alexander Korotkov <a.korotkov@postgrespro.ru> writes:
On Mon, Aug 10, 2015 at 7:50 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Hm. So one way or the other we're going to end up violating relational
theory somewhere. OK, I yield: let's say that pg_am has amname, amkind,
amhandler, and nothing else. Then we will need SQL functions to expose
whatever information we think needs to be available to SQL code.There is second revision of this patch. Changes are so:
* AmRoutine was renamed to IndexAmRoutine assuming there could be other
access methods in the future.
* amhandlers now return index_am_handler pseudotype.
* CHECK_PROCEDUREs are now is the place of original GET_REL_PROCEDUREs.
* amstrategies, amsupport, amcanorderbyop, amstorage, amkeytype are in
both pg_am and IndexAmRoutine. Consistence of amhandler answer and pg_am
tuple is checking.[ scratches head... ] I thought we'd just agreed we weren't going to keep
any of those pg_am columns? If we keep them, we'll have to define what
they mean for sequence AMs etc. ("Let them be NULL" would likely break
enough stuff that we might as well not have them.)
From the previous discussion I see following options:
1) Non-index access methods don't reuse pg_class.relam nor pg_am. Fully
relational compliant but complex catalog structure.
2) Non-index access methods reuse pg_class.relam but don't reuse pg_am.
This violates relational theory because single column reference multiple
tables.
3) Non-index access methods reuse both pg_class.relam and pg_am. This
violates relational theory because we store different objects in the same
table.
I'd say we already have precedent of #2. It's pg_depend which reference
objects of arbitrary types.
In the #3 we really shouldn't keep any specific to index am in pg_am.
But what we assume to be an access method in general? For instance, we have
foreign data wrappers which aren't access methods (but looks quite similar
from some degree).
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
On 8/24/15 9:49 AM, Alexander Korotkov wrote:
2) Non-index access methods reuse pg_class.relam but don't reuse pg_am.
This violates relational theory because single column reference multiple
tables.
3) Non-index access methods reuse both pg_class.relam and pg_am. This
violates relational theory because we store different objects in the
same table.I'd say we already have precedent of #2. It's pg_depend which reference
objects of arbitrary types.
In the #3 we really shouldn't keep any specific to index am in pg_am.
In userspace, table inheritance handles this nicely. Stick a "type"
field in the parent so you know what kind of entity each record is,
along with all your common fields. Everything else is in the children,
and code generally already knows which child table to hit or doesn't
care about specifics and hits only the parent. Perhaps something similar
could be made to work with a catalog table.
#2 seems like a twist on the same idea, except that there's fields in
pg_class that tell you what the child is instead of a real parent table.
Presumably we could still create a parent table even if the internals
were going through pg_class.
--
Jim Nasby, Data Architect, Blue Treble Consulting, Austin TX
Experts in Analytics, Data Architecture and PostgreSQL
Data in Trouble? Get it in Treble! http://BlueTreble.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Jim Nasby wrote:
On 8/24/15 9:49 AM, Alexander Korotkov wrote:
2) Non-index access methods reuse pg_class.relam but don't reuse pg_am.
This violates relational theory because single column reference multiple
tables.
3) Non-index access methods reuse both pg_class.relam and pg_am. This
violates relational theory because we store different objects in the
same table.I'd say we already have precedent of #2. It's pg_depend which reference
objects of arbitrary types.
In the #3 we really shouldn't keep any specific to index am in pg_am.
In my reading of the thread, we have a consensus for doing #3, and that
one gets my vote in any case.
In userspace, table inheritance handles this nicely. Stick a "type" field in
the parent so you know what kind of entity each record is, along with all
your common fields.
Yeah, this pattern is not hugely common but it's definitely used in some
places. In fact, I would think it is less of a violation of relational
theory than #2 -- because then relam is always a reference to pg_am,
instead of sometimes being a reference to some other catalog. What's
stored in pg_am is not pg_class' concern; and I think calling pg_am a
catalog for "access methods" (in a generic way, not only indexes) is
sound.
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
Jim Nasby wrote:
On 8/24/15 9:49 AM, Alexander Korotkov wrote:
3) Non-index access methods reuse both pg_class.relam and pg_am. This
violates relational theory because we store different objects in the
same table.
In my reading of the thread, we have a consensus for doing #3, and that
one gets my vote in any case.
That's what I thought as well.
In userspace, table inheritance handles this nicely. Stick a "type" field in
the parent so you know what kind of entity each record is, along with all
your common fields.
Yeah, this pattern is not hugely common but it's definitely used in some
places. In fact, I would think it is less of a violation of relational
theory than #2 -- because then relam is always a reference to pg_am,
instead of sometimes being a reference to some other catalog. What's
stored in pg_am is not pg_class' concern; and I think calling pg_am a
catalog for "access methods" (in a generic way, not only indexes) is
sound.
I'm good with this as long as all the things that get stored in pg_am
are things that pg_class.relam can legitimately reference. If somebody
proposed adding an "access method" kind that was not a relation access
method, I'd probably push back on whether that should be in pg_am or
someplace else.
The fact that the subsidiary tables like pg_opclass no longer have
perfectly clean foreign keys to pg_am is a bit annoying, but that's better
than having pg_class.relam linking to multiple tables. (Also, if we
really wanted to we could define the foreign key constraints as
multicolumn ones that also require a match on amkind. So it's not *that*
broken. We could easily add opr_sanity tests to verify proper matching.)
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 8/25/15 10:56 AM, Tom Lane wrote:
I'm good with this as long as all the things that get stored in pg_am
are things that pg_class.relam can legitimately reference. If somebody
proposed adding an "access method" kind that was not a relation access
method, I'd probably push back on whether that should be in pg_am or
someplace else.
Would fields in pg_am be overloaded then? From a SQL standpoint it'd be
much nicer to have child tables, though that could potentially be faked
with views.
The fact that the subsidiary tables like pg_opclass no longer have
perfectly clean foreign keys to pg_am is a bit annoying, but that's better
than having pg_class.relam linking to multiple tables. (Also, if we
really wanted to we could define the foreign key constraints as
multicolumn ones that also require a match on amkind. So it's not*that*
broken. We could easily add opr_sanity tests to verify proper matching.)
I have wished for something similar to CHECK constraints that operated
on data in a *related* table (something we already have a foreign key
to) for this purpose. In the past I've enforced it with triggers on both
sides but writing those gets old after a while.
--
Jim Nasby, Data Architect, Blue Treble Consulting, Austin TX
Experts in Analytics, Data Architecture and PostgreSQL
Data in Trouble? Get it in Treble! http://BlueTreble.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Jim Nasby wrote:
On 8/25/15 10:56 AM, Tom Lane wrote:
I'm good with this as long as all the things that get stored in pg_am
are things that pg_class.relam can legitimately reference. If somebody
proposed adding an "access method" kind that was not a relation access
method, I'd probably push back on whether that should be in pg_am or
someplace else.Would fields in pg_am be overloaded then? From a SQL standpoint it'd be much
nicer to have child tables, though that could potentially be faked with
views.
The whole point of this conversation is that we're getting rid of almost
all the columns in pg_am, leaving only an "amkind" column and a pointer
to a handler function.
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Jim Nasby <Jim.Nasby@bluetreble.com> writes:
On 8/25/15 10:56 AM, Tom Lane wrote:
I'm good with this as long as all the things that get stored in pg_am
are things that pg_class.relam can legitimately reference. If somebody
proposed adding an "access method" kind that was not a relation access
method, I'd probably push back on whether that should be in pg_am or
someplace else.
Would fields in pg_am be overloaded then?
No, because the proposal was to reduce pg_am to just amname, amkind
(which would be something like 'i' or 's'), and amhandler. Everything
specific to a particular type of access method would be shoved down to
the level of the C APIs.
From a SQL standpoint it'd be
much nicer to have child tables, though that could potentially be faked
with views.
I've looked into having actual child tables in the system catalogs, and
I'm afraid that the pain-to-reward ratio doesn't look very good.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Tue, Aug 25, 2015 at 7:20 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Jim Nasby <Jim.Nasby@bluetreble.com> writes:
On 8/25/15 10:56 AM, Tom Lane wrote:
I'm good with this as long as all the things that get stored in pg_am
are things that pg_class.relam can legitimately reference. If somebody
proposed adding an "access method" kind that was not a relation access
method, I'd probably push back on whether that should be in pg_am or
someplace else.Would fields in pg_am be overloaded then?
No, because the proposal was to reduce pg_am to just amname, amkind
(which would be something like 'i' or 's'), and amhandler. Everything
specific to a particular type of access method would be shoved down to
the level of the C APIs.
OK. So, as we mentioned before, if we need to expose something of am
parameters at SQL-level then we need to write special functions which would
call amhandler and expose it.
Did we come to the agreement on this solution?
From a SQL standpoint it'd be
much nicer to have child tables, though that could potentially be faked
with views.I've looked into having actual child tables in the system catalogs, and
I'm afraid that the pain-to-reward ratio doesn't look very good.
Agree. Teach syscache about inheritance would be overengeneering for this
problem.
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Alexander Korotkov <a.korotkov@postgrespro.ru> writes:
OK. So, as we mentioned before, if we need to expose something of am
parameters at SQL-level then we need to write special functions which would
call amhandler and expose it.
Did we come to the agreement on this solution?
I think we were agreed that we should write functions to expose whatever
needs to be visible at SQL level. I'm not sure that we had a consensus
on exactly which things need to be visible.
One thought here is that we might not want to just blindly duplicate
the existing pg_am behavior anyway. For example, the main use of the
amstrategies column was to allow validation of pg_amop.amopstrategy
entries --- but in 4 out of the 6 existing AMs, knowledge of the AM alone
isn't sufficient information to determine the valid set of strategy
numbers anyway. So inventing a "pg_amstrategies(am oid)" function seems
like it would be repeating a previous failure. Not quite sure what to
do instead, though. We could imagine something like "pg_amstrategies(am
oid, opclass oid)", but I don't see how to implement it without asking
opclasses to provide a validation function, which maybe is a change we
don't want to take on here.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Aug 26, 2015 at 6:50 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Alexander Korotkov <a.korotkov@postgrespro.ru> writes:
OK. So, as we mentioned before, if we need to expose something of am
parameters at SQL-level then we need to write special functions whichwould
call amhandler and expose it.
Did we come to the agreement on this solution?I think we were agreed that we should write functions to expose whatever
needs to be visible at SQL level. I'm not sure that we had a consensus
on exactly which things need to be visible.One thought here is that we might not want to just blindly duplicate
the existing pg_am behavior anyway. For example, the main use of the
amstrategies column was to allow validation of pg_amop.amopstrategy
entries --- but in 4 out of the 6 existing AMs, knowledge of the AM alone
isn't sufficient information to determine the valid set of strategy
numbers anyway. So inventing a "pg_amstrategies(am oid)" function seems
like it would be repeating a previous failure. Not quite sure what to
do instead, though. We could imagine something like "pg_amstrategies(am
oid, opclass oid)", but I don't see how to implement it without asking
opclasses to provide a validation function, which maybe is a change we
don't want to take on here.
Could we add another function to access method interface which would
validate opclass?
Am could validate this way not only strategies, but also supporting
functions. For instance, in GIN, we now require opclass to specify at least
one of consistent and triconsistent. ISTM I would be nice to let the access
method check such conditions. Also, we would be able to check opclass
correction on its creation. Now one can create opclass with missing support
functions which doesn't work.
In the SQL-level we can create function which validates opclass using this
new method. This function can be used in regression tests.
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
On Wed, Aug 26, 2015 at 7:20 PM, Alexander Korotkov <
a.korotkov@postgrespro.ru> wrote:
On Wed, Aug 26, 2015 at 6:50 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Alexander Korotkov <a.korotkov@postgrespro.ru> writes:
OK. So, as we mentioned before, if we need to expose something of am
parameters at SQL-level then we need to write special functions whichwould
call amhandler and expose it.
Did we come to the agreement on this solution?I think we were agreed that we should write functions to expose whatever
needs to be visible at SQL level. I'm not sure that we had a consensus
on exactly which things need to be visible.One thought here is that we might not want to just blindly duplicate
the existing pg_am behavior anyway. For example, the main use of the
amstrategies column was to allow validation of pg_amop.amopstrategy
entries --- but in 4 out of the 6 existing AMs, knowledge of the AM alone
isn't sufficient information to determine the valid set of strategy
numbers anyway. So inventing a "pg_amstrategies(am oid)" function seems
like it would be repeating a previous failure. Not quite sure what to
do instead, though. We could imagine something like "pg_amstrategies(am
oid, opclass oid)", but I don't see how to implement it without asking
opclasses to provide a validation function, which maybe is a change we
don't want to take on here.Could we add another function to access method interface which would
validate opclass?
Am could validate this way not only strategies, but also supporting
functions. For instance, in GIN, we now require opclass to specify at least
one of consistent and triconsistent. ISTM I would be nice to let the access
method check such conditions. Also, we would be able to check opclass
correction on its creation. Now one can create opclass with missing support
functions which doesn't work.
In the SQL-level we can create function which validates opclass using this
new method. This function can be used in regression tests.
Should I try to implement such new access method function, say 'amvalidate'?
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
On 2015-08-27 15:15, Alexander Korotkov wrote:
On Wed, Aug 26, 2015 at 7:20 PM, Alexander Korotkov
<a.korotkov@postgrespro.ru <mailto:a.korotkov@postgrespro.ru>> wrote:On Wed, Aug 26, 2015 at 6:50 PM, Tom Lane <tgl@sss.pgh.pa.us
<mailto:tgl@sss.pgh.pa.us>> wrote:One thought here is that we might not want to just blindly duplicate
the existing pg_am behavior anyway. For example, the main use
of the
amstrategies column was to allow validation of pg_amop.amopstrategy
entries --- but in 4 out of the 6 existing AMs, knowledge of the
AM alone
isn't sufficient information to determine the valid set of strategy
numbers anyway. So inventing a "pg_amstrategies(am oid)"
function seems
like it would be repeating a previous failure. Not quite sure
what to
do instead, though. We could imagine something like
"pg_amstrategies(am
oid, opclass oid)", but I don't see how to implement it without
asking
opclasses to provide a validation function, which maybe is a
change we
don't want to take on here.Could we add another function to access method interface which would
validate opclass?
Am could validate this way not only strategies, but also supporting
functions. For instance, in GIN, we now require opclass to specify
at least one of consistent and triconsistent. ISTM I would be nice
to let the access method check such conditions. Also, we would be
able to check opclass correction on its creation. Now one can create
opclass with missing support functions which doesn't work.
In the SQL-level we can create function which validates opclass
using this new method. This function can be used in regression tests.Should I try to implement such new access method function, say 'amvalidate'?
Makes sense to me to do that, should be probably optional though.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Aug 31, 2015 at 1:28 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
On 2015-08-27 15:15, Alexander Korotkov wrote:
On Wed, Aug 26, 2015 at 7:20 PM, Alexander Korotkov
<a.korotkov@postgrespro.ru <mailto:a.korotkov@postgrespro.ru>> wrote:
Could we add another function to access method interface which would
validate opclass?
Am could validate this way not only strategies, but also supporting
functions. For instance, in GIN, we now require opclass to specify
at least one of consistent and triconsistent. ISTM I would be nice
to let the access method check such conditions. Also, we would be
able to check opclass correction on its creation. Now one can create
opclass with missing support functions which doesn't work.
In the SQL-level we can create function which validates opclass
using this new method. This function can be used in regression tests.Should I try to implement such new access method function, say
'amvalidate'?Makes sense to me to do that, should be probably optional though.
Attached patch is implementing this. It doesn't pretend to be fully correct
implementation, but it should be enough for proof the concept.
In this patch access method exposes another function: amvalidate. It takes
data structure representing opclass and throws error if it finds it invalid.
This method is used on new opclass definition (alter operator family etc.
are not yet implemented but planned). Also, there is SQL function
validate_opclass(oid) which is used in regression tests.
Any thoughts?
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Attachments:
aminterface-3.patchapplication/octet-stream; name=aminterface-3.patchDownload
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
new file mode 100644
index 25d2a09..82aedc1
*** a/src/backend/access/brin/brin.c
--- b/src/backend/access/brin/brin.c
***************
*** 35,40 ****
--- 35,132 ----
/*
+ * BRIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ brinhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 15;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = brininsert;
+ amroutine->ambeginscan = brinbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = bringetbitmap;
+ amroutine->amrescan = brinrescan;
+ amroutine->amendscan = brinendscan;
+ amroutine->ammarkpos = brinmarkpos;
+ amroutine->amrestrpos = brinrestrpos;
+ amroutine->ambuild = brinbuild;
+ amroutine->ambuildempty = brinbuildempty;
+ amroutine->ambulkdelete = brinbulkdelete;
+ amroutine->amvacuumcleanup = brinvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = brincostestimate;
+ amroutine->amoptions = brinoptions;
+ amroutine->amvalidate = brinvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ brinvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[BRIN_NPROC] = {false};
+ int i;
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype
+ || proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > BRIN_NPROC)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid support number for BRIN: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u was defined more than once",
+ proc->number)));
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < BRIN_PROCNUM_UNION; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN doesn't support order by operators")));
+ }
+ }
+
+ /*
* We use a BrinBuildState during initial construction of a BRIN index.
* The running state is kept in a BrinMemTuple.
*/
*************** 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;
--- 172,182 ----
* 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);
}
/*
--- 314,320 ----
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;
--- 324,332 ----
* 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);
}
/*
--- 337,343 ----
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;
--- 352,360 ----
* 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
--- 534,549 ----
* 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();
}
/*
--- 555,585 ----
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;
--- 651,659 ----
/*
* 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. */
--- 732,743 ----
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();
}
/*
--- 754,759 ----
*************** 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));
--- 765,793 ----
* 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;
--- 804,818 ----
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);
--- 825,831 ----
/* 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);
}
/*
--- 834,840 ----
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 49e9185..92701b9
*** 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..443078d
*** a/src/backend/access/gin/ginutil.c
--- b/src/backend/access/gin/ginutil.c
***************
*** 22,28 ****
--- 22,132 ----
#include "miscadmin.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
+ #include "utils/selfuncs.h"
+
+
+ /*
+ * GIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ ginhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 6;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = gininsert;
+ amroutine->ambeginscan = ginbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = gingetbitmap;
+ amroutine->amrescan = ginrescan;
+ amroutine->amendscan = ginendscan;
+ amroutine->ammarkpos = ginmarkpos;
+ amroutine->amrestrpos = ginrestrpos;
+ amroutine->ambuild = ginbuild;
+ amroutine->ambuildempty = ginbuildempty;
+ amroutine->ambulkdelete = ginbulkdelete;
+ amroutine->amvacuumcleanup = ginvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = gincostestimate;
+ amroutine->amoptions = ginoptions;
+ amroutine->amvalidate = ginvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ ginvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[GINNProcs] = {false};
+ int i;
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+ if (proc->lefttype != opclass->intype
+ || proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > GINNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid support number for GIN: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u was defined more than once",
+ proc->number)));
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < GIN_EXTRACTQUERY_PROC; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u is required", i + 1)));
+ }
+
+ if (!procsPresent[GIN_CONSISTENT_PROC - 1]
+ && !procsPresent[GIN_TRICONSISTENT_PROC - 1])
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("At least one of consistent support (number %u) "
+ "and triconsistent cupport (number %u) is "
+ "is required",
+ GIN_CONSISTENT_PROC, GIN_TRICONSISTENT_PROC)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN doesn't support order by operators")));
+ }
+ }
/*
* initGinState: fill in an empty GinState struct to describe the index
*************** 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;
--- 620,628 ----
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);
--- 637,643 ----
/* 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);
}
/*
--- 646,652 ----
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..065048c
*** 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,137 ----
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;
+ amroutine->amvalidate = gistvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ gistvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[GISTNProcs] = {false};
+ int i;
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype
+ || proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > GISTNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid support number for GiST: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u was defined more than once",
+ proc->number)));
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < GIST_EQUAL_PROC; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily)
+ && !procsPresent[GIST_DISTANCE_PROC - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST distance support function %u is required "
+ "for order by operators", GIST_DISTANCE_PROC)));
+ }
+ }
#define ROTATEDIST(d) do { \
SplitedPageLayout *tmp=(SplitedPageLayout*)palloc(sizeof(SplitedPageLayout)); \
*************** 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 */
--- 164,172 ----
/*
* 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();
}
/*
--- 182,187 ----
*************** 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;
--- 190,200 ----
* 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);
}
--- 220,226 ----
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..286596b
*** 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,150 ----
bool tupleIsAlive,
void *state);
+ /*
+ * Hash handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ hashhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 1;
+ amroutine->amsupport = 1;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = true;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = false;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = INT4OID;
+
+ amroutine->aminsert = hashinsert;
+ amroutine->ambeginscan = hashbeginscan;
+ amroutine->amgettuple = hashgettuple;
+ amroutine->amgetbitmap = hashgetbitmap;
+ amroutine->amrescan = hashrescan;
+ amroutine->amendscan = hashendscan;
+ amroutine->ammarkpos = hashmarkpos;
+ amroutine->amrestrpos = hashrestrpos;
+ amroutine->ambuild = hashbuild;
+ amroutine->ambuildempty = hashbuildempty;
+ amroutine->ambulkdelete = hashbulkdelete;
+ amroutine->amvacuumcleanup = hashvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = hashcostestimate;
+ amroutine->amoptions = hashoptions;
+ amroutine->amvalidate = hashvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ hashvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->number != HASHPROC)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid support number for hash: %u",
+ proc->number)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+ bool leftFound = false, rightFound = false;
+ ListCell *ll;
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Hash doesn't support order by operators")));
+
+ if (opr->number < 1 || opr->number > HTMaxStrategyNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid strategy number for hash: %u",
+ opr->number)));
+
+ foreach(ll, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(ll);
+
+ if (proc->lefttype == opr->lefttype)
+ leftFound = true;
+ if (proc->lefttype == opr->righttype)
+ rightFound = true;
+ }
+
+ if (!leftFound || !rightFound)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("No hash procedure found for operator: %u",
+ opr->object)));
+ }
+ }
/*
* hashbuild() -- build a new hash index.
*/
! 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();
}
/*
--- 205,220 ----
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;
/*
--- 256,266 ----
* 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);
--- 273,279 ----
* 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;
--- 283,298 ----
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;
--- 394,409 ----
/* 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;
--- 440,455 ----
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;
--- 471,486 ----
/* 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;
--- 506,519 ----
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();
}
/*
--- 532,555 ----
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;
--- 559,568 ----
*
* 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);
}
/*
--- 732,738 ----
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);
}
--- 740,761 ----
*
* 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..fa933f6
*** 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,182 ----
/*
! * 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;
! amroutine->amvalidate = btvalidate;
!
! PG_RETURN_POINTER(amroutine);
! }
!
! void
! btvalidate(OpClassInfo *opclass)
! {
! ListCell *l;
!
! foreach(l, opclass->procedures)
! {
! OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
!
! if (proc->number != BTORDER_PROC
! && proc->number != BTSORTSUPPORT_PROC)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("Invalid support number for btree: %u",
! proc->number)));
! }
!
! foreach(l, opclass->operators)
! {
! OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
! bool found = false;
! ListCell *ll;
!
! if (OidIsValid(opr->sortfamily))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("Btree doesn't support order by operators")));
!
! if (opr->number < 1 || opr->number > BTMaxStrategyNumber)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("Invalid strategy number for btree: %u",
! opr->number)));
!
! foreach(ll, opclass->procedures)
! {
! OpFamilyMember *proc = (OpFamilyMember *) lfirst(ll);
!
! if (proc->number == BTORDER_PROC
! && proc->lefttype == opr->lefttype
! && proc->righttype == opr->righttype)
! found = true;
! }
!
! if (!found)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("No ordering procedure found for operator: %u",
! opr->object)));
! }
! }
!
! /*
! * btbuild() -- build a new btree index.
! */
! IndexBuildResult *
! btbuild(Relation heap, Relation index, IndexInfo *indexInfo)
{
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);
}
/*
--- 248,254 ----
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);
--- 283,292 ----
/*
* 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();
}
/*
--- 306,311 ----
*************** 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;
--- 314,324 ----
* 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;
--- 330,344 ----
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);
}
--- 354,360 ----
{
/* 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;
--- 404,418 ----
/* ... 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);
}
--- 424,430 ----
{
/* 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;
--- 462,476 ----
/* 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 */
--- 508,523 ----
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 */
--- 568,581 ----
/* 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). */
--- 604,617 ----
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 */
--- 634,647 ----
/* 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();
}
/*
--- 709,714 ----
*************** 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;
--- 718,727 ----
*
* 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);
}
/*
--- 740,746 ----
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
--- 748,759 ----
*
* 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);
}
/*
--- 785,791 ----
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);
}
--- 1186,1193 ----
*
* 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..644b836
*** a/src/backend/access/spgist/spgutils.c
--- b/src/backend/access/spgist/spgutils.c
***************
*** 24,30 ****
--- 24,123 ----
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "utils/lsyscache.h"
+ #include "utils/selfuncs.h"
+
+
+ /*
+ * SP-GiST handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ spghandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 5;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+ amroutine->aminsert = spginsert;
+ amroutine->ambeginscan = spgbeginscan;
+ amroutine->amgettuple = spggettuple;
+ amroutine->amgetbitmap = spggetbitmap;
+ amroutine->amrescan = spgrescan;
+ amroutine->amendscan = spgendscan;
+ amroutine->ammarkpos = spgmarkpos;
+ amroutine->amrestrpos = spgrestrpos;
+ amroutine->ambuild = spgbuild;
+ amroutine->ambuildempty = spgbuildempty;
+ amroutine->ambulkdelete = spgbulkdelete;
+ amroutine->amvacuumcleanup = spgvacuumcleanup;
+ amroutine->amcanreturn = spgcanreturn;
+ amroutine->amcostestimate = spgcostestimate;
+ amroutine->amoptions = spgoptions;
+ amroutine->amvalidate = spgvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ spgvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[SPGISTNProc] = {false};
+ int i;
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype
+ || proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > SPGISTNProc)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid support number for SP-GiST: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u was defined more than once",
+ proc->number)));
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < SPGISTNProc; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST doesn't support order by operators")));
+ }
+ }
/* Fill in a SpGistTypeDesc struct with info about the specified data type */
static void
*************** 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();
}
/*
--- 582,597 ----
/*
* 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 <unistd.h>
+ #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/opclasscmds.c b/src/backend/commands/opclasscmds.c
new file mode 100644
index 3375f10..fe4bd12
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
***************
*** 42,47 ****
--- 42,48 ----
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
+ #include "utils/catcache.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 334,346 ****
ListCell *l;
Relation rel;
HeapTuple tup;
- Form_pg_am pg_am;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
--- 335,348 ----
ListCell *l;
Relation rel;
HeapTuple tup;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
+ IndexAmRoutine *amroutine;
+ OpClassInfo opclassinfo;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 361,373 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
! amstorage = pg_am->amstorage;
/* XXX Should we make any privilege check against the AM? */
--- 363,377 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
!
! amroutine = GetIndexAmRoutine(amoid);
!
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
! amstorage = amroutine->amstorage;
/* XXX Should we make any privilege check against the AM? */
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 582,587 ****
--- 586,597 ----
stmt->amname)));
}
+ opclassinfo.intype = typeoid;
+ opclassinfo.keytype = storageoid;
+ opclassinfo.procedures = procedures;
+ opclassinfo.operators = operators;
+ amroutine->amvalidate(&opclassinfo);
+
rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
/*
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 718,723 ****
--- 728,817 ----
return myself;
}
+ /*
+ * Collect opfamily information for opclass validation.
+ */
+ static void
+ getOpFamilyInfo(OpClassInfo *opclassinfo, Oid opfamilyoid)
+ {
+ CatCList *catlist;
+ int i;
+
+ opclassinfo->operators = NIL;
+ opclassinfo->procedures = NIL;
+
+ /* Find operators */
+ catlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ for (i = 0; i < catlist->n_members; i++)
+ {
+ HeapTuple oprtup = &catlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+ OpFamilyMember *opmember = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
+
+ opmember->object = oprform->amopopr;
+ opmember->number = oprform->amopstrategy;
+ opmember->lefttype = oprform->amoplefttype;
+ opmember->righttype = oprform->amoprighttype;
+ opmember->sortfamily = oprform->amopsortfamily;
+
+ opclassinfo->operators = lappend(opclassinfo->operators, opmember);
+ }
+ ReleaseCatCacheList(catlist);
+
+ /* Find support functions */
+ catlist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+ for (i = 0; i < catlist->n_members; i++)
+ {
+ HeapTuple proctup = &catlist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+ OpFamilyMember *procmember = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
+
+ procmember->object = procform->amproc;
+ procmember->number = procform->amprocnum;
+ procmember->lefttype = procform->amproclefttype;
+ procmember->righttype = procform->amprocrighttype;
+
+ opclassinfo->procedures = lappend(opclassinfo->procedures, procmember);
+ }
+ ReleaseCatCacheList(catlist);
+ }
+
+ /*
+ * Ask access method to validate given opclass.
+ */
+ Datum
+ validate_opclass(PG_FUNCTION_ARGS)
+ {
+ OpClassInfo opclassinfo;
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opclassoid = PG_GETARG_OID(0),
+ opfamilyoid,
+ amoid;
+ IndexAmRoutine *amroutine;
+
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ opclassinfo.intype = classform->opcintype;
+ opclassinfo.keytype = classform->opckeytype;
+ opfamilyoid = classform->opcfamily;
+ amoid = classform->opcmethod;
+
+ ReleaseSysCache(classtup);
+
+ getOpFamilyInfo(&opclassinfo, opfamilyoid);
+
+ amroutine = GetIndexAmRoutine(amoid);
+
+ amroutine->amvalidate(&opclassinfo);
+
+ PG_RETURN_BOOL(true);
+ }
+
/*
* DefineOpFamily
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 776,782 ****
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! Form_pg_am pg_am;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
--- 870,876 ----
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! IndexAmRoutine *amroutine;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 787,802 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
/* XXX Should we make any privilege check against the AM? */
- ReleaseSysCache(tup);
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
--- 881,896 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! amroutine = GetIndexAmRoutine(amoid);
! ReleaseSysCache(tup);
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
/* XXX Should we make any privilege check against the AM? */
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
*************** assignOperTypes(OpFamilyMember *member,
*** 1099,1119 ****
* the family has been created but not yet populated with the required
* operators.)
*/
! HeapTuple amtup;
! Form_pg_am pg_am;
! amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
! if (amtup == NULL)
! elog(ERROR, "cache lookup failed for access method %u", amoid);
! pg_am = (Form_pg_am) GETSTRUCT(amtup);
! if (!pg_am->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! NameStr(pg_am->amname))));
!
! ReleaseSysCache(amtup);
}
else
{
--- 1193,1207 ----
* the family has been created but not yet populated with the required
* operators.)
*/
! IndexAmRoutine *amroutine;
! amroutine = GetIndexAmRoutine(amoid);
! if (!amroutine->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! get_am_name(amoid))));
}
else
{
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 <unistd.h>
#include <fcntl.h>
+ #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..8214afa
*** a/src/backend/utils/cache/relcache.c
--- b/src/backend/utils/cache/relcache.c
*************** 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
--- 445,451 ----
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;
--- 1162,1215 ----
}
/*
+ * 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));
+
+ ReleaseSysCache(tuple);
+
+ return result;
+ }
+
+ /*
+ * Initialize IndexAmRoutine for relation.
+ */
+ void
+ InitIndexAmRoutine(Relation relation)
+ {
+ IndexAmRoutine *result, *tmp;
+
+ result = (IndexAmRoutine *)MemoryContextAlloc(CacheMemoryContext,
+ sizeof(IndexAmRoutine));
+ tmp = (IndexAmRoutine *)DatumGetPointer(
+ OidFunctionCall0(relation->rd_am->amhandler));
+ memcpy(result, tmp, sizeof(IndexAmRoutine));
+ relation->amroutine = result;
+ }
+
+ /*
* Initialize index-access-method support data for an index relation
*/
void
RelationInitIndexAccessInfo(Relation relation)
{
HeapTuple tuple;
Datum indcollDatum;
Datum indclassDatum;
Datum indoptionDatum;
*************** RelationInitIndexAccessInfo(Relation rel
*** 1180,1185 ****
--- 1221,1227 ----
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
--- 1246,1263 ----
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;
--- 4760,4765 ----
*************** load_relcache_init_file(bool shared)
*** 4744,4749 ****
--- 4787,4793 ----
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)
*** 4805,4816 ****
rel->rd_indoption = indoption;
/* 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
{
--- 4849,4861 ----
rel->rd_indoption = indoption;
+ InitIndexAmRoutine(rel);
+
/* set up zeroed fmgr-info vectors */
rel->rd_aminfo = (RelationAmInfo *)
MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
rel->rd_supportinfo = (FmgrInfo *)
! MemoryContextAllocZero(indexcxt, relform->relnatts * rel->amroutine->amsupport * sizeof(FmgrInfo));
}
else
{
*************** write_relcache_init_file(bool shared)
*** 5079,5085 ****
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
--- 5124,5130 ----
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (rel->amroutine->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h
new file mode 100644
index ...1fba425
*** a/src/include/access/amapi.h
--- b/src/include/access/amapi.h
***************
*** 0 ****
--- 1,169 ----
+ /*-------------------------------------------------------------------------
+ *
+ * amapi.h
+ * API for access methods
+ *
+ * Copyright (c) 2015, PostgreSQL Global Development Group
+ *
+ * src/include/access/amapi.h
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef AMAPI_H
+ #define AMAPI_H
+
+ #include "access/genam.h"
+ #include "catalog/opfam_internal.h"
+ #include "nodes/relation.h"
+
+ /*
+ * Callback function signatures --- see indexam.sgml for more info.
+ */
+
+ /* "insert this tuple" function */
+ typedef bool
+ (*aminsert_function) (Relation indexRelation,
+ Datum *values,
+ bool *isnull,
+ ItemPointer heap_tid,
+ Relation heapRelation,
+ IndexUniqueCheck checkUnique);
+
+ /* "prepare for index scan" function */
+ typedef IndexScanDesc
+ (*ambeginscan_function) (Relation indexRelation,
+ int nkeys,
+ int norderbys);
+
+ /* "next valid tuple" function, or NULL */
+ typedef bool
+ (*amgettuple_function) (IndexScanDesc scan,
+ ScanDirection direction);
+
+ /* "fetch all valid tuples" function, or NULL */
+ typedef int64
+ (*amgetbitmap_function) (IndexScanDesc scan,
+ TIDBitmap *tbm);
+
+ /* "(re)start index scan" function */
+ typedef void
+ (*amrescan_function) (IndexScanDesc scan,
+ ScanKey keys,
+ int nkeys,
+ ScanKey orderbys,
+ int norderbys);
+
+ /* "end index scan" function */
+ typedef void
+ (*amendscan_function) (IndexScanDesc scan);
+
+ /* "mark current scan position" function */
+ typedef void
+ (*ammarkpos_function) (IndexScanDesc scan);
+
+ /* "restore marked scan position" function */
+ typedef void
+ (*amrestrpos_function) (IndexScanDesc scan);
+
+ /* "build new index" function */
+ typedef IndexBuildResult *
+ (*ambuild_function) (Relation heapRelation,
+ Relation indexRelation,
+ IndexInfo *indexInfo);
+
+ /* "build empty index" function */
+ typedef void
+ (*ambuildempty_function) (Relation indexRelation);
+
+ /* bulk-delete function */
+ typedef IndexBulkDeleteResult *
+ (*ambulkdelete_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+
+ /* post-VACUUM cleanup function */
+ typedef IndexBulkDeleteResult *
+ (*amvacuumcleanup_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
+
+ /* can indexscan return IndexTuples? */
+ typedef bool
+ (*amcanreturn_function) (Relation indexRelation, int attno);
+
+ /* estimate cost of an indexscan */
+ typedef void
+ (*amcostestimate_function) (PlannerInfo *root,
+ IndexPath *path,
+ double loop_count,
+ Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+
+ /* parse AM-specific parameters */
+ typedef bytea *
+ (*amoptions_function) (Datum reloptions,
+ bool validate);
+
+ /* validate oplass */
+ typedef void
+ (*amvalidate_function) (OpClassInfo *opclass);
+
+
+ struct IndexAmRoutine
+ {
+ NodeTag type;
+
+ /*
+ * Total number of strategies (operators) by which we can traverse/search
+ * this AM. Zero if AM does not have a fixed set of strategy assignments.
+ */
+ int16 amstrategies;
+ /* total number of support functions that this AM uses */
+ int16 amsupport;
+ /* does AM support order by column value? */
+ bool amcanorder;
+ /* does AM support order by operator result? */
+ bool amcanorderbyop;
+ /* does AM support backward scan? */
+ bool amcanbackward;
+ /* does AM support UNIQUE indexes? */
+ bool amcanunique;
+ /* does AM support multi-column indexes? */
+ bool amcanmulticol;
+ /* can query omit key for the first column? */
+ bool amoptionalkey;
+ /* can AM handle ScalarArrayOpExpr quals? */
+ bool amsearcharray;
+ /* can AM search for NULL/NOT NULL entries? */
+ bool amsearchnulls;
+ /* can storage type differ from column type? */
+ bool amstorage;
+ /* does AM support cluster command? */
+ bool amclusterable;
+ /* does AM handle predicate locks? */
+ bool ampredlocks;
+ /* type of data in index, or InvalidOid */
+ Oid amkeytype;
+
+ /* interface functions */
+ aminsert_function aminsert;
+ ambeginscan_function ambeginscan;
+ amgettuple_function amgettuple;
+ amgetbitmap_function amgetbitmap;
+ amrescan_function amrescan;
+ amendscan_function amendscan;
+ ammarkpos_function ammarkpos;
+ amrestrpos_function amrestrpos;
+ ambuild_function ambuild;
+ ambuildempty_function ambuildempty;
+ ambulkdelete_function ambulkdelete;
+ amvacuumcleanup_function amvacuumcleanup;
+ amcanreturn_function amcanreturn;
+ amcostestimate_function amcostestimate;
+ amoptions_function amoptions;
+ amvalidate_function amvalidate;
+ };
+
+ #endif /* AMAPI_H */
diff --git a/src/include/access/brin.h b/src/include/access/brin.h
new file mode 100644
index e72fb2d..5ae5722
*** 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,51 ----
/*
* prototypes for functions in brin.c (external entry points for BRIN)
*/
! extern Datum brinhandler(PG_FUNCTION_ARGS);
! extern void brinvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *brinbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void brinbuildempty(Relation index);
! extern bool brininsert(Relation idxRel, Datum *values, bool *nulls,
! ItemPointer heaptid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys);
! extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
! ScanKey orderbys, int norderbys);
! extern void brinendscan(IndexScanDesc scan);
! extern void brinmarkpos(IndexScanDesc scan);
! extern void brinrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *brinbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *brinvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern void brincostestimate(PlannerInfo *root, IndexPath *path,
! double loop_count, Cost *indexStartupCost,
! Cost *indexTotalCost,
! Selectivity *indexSelectivity,
! double *indexCorrelation);
! extern bytea *brinoptions(Datum reloptions, bool validate);
/*
* Storage type for BRIN's reloptions
diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h
new file mode 100644
index 6be199e..2f8fe17
*** a/src/include/access/brin_internal.h
--- b/src/include/access/brin_internal.h
*************** typedef struct BrinDesc
*** 72,77 ****
--- 72,78 ----
#define BRIN_PROCNUM_CONSISTENT 3
#define BRIN_PROCNUM_UNION 4
/* procedure numbers up to 10 are reserved for BRIN future expansion */
+ #define BRIN_NPROC 15
#undef BRIN_DEBUG
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
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 acbe36a..3348436
*** 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,601 ----
/* ginutil.c */
! extern Datum ginhandler(PG_FUNCTION_ARGS);
! extern void ginvalidate(OpClassInfo *opclass);
! extern bytea *ginoptions(Datum reloptions, bool validate);
extern void initGinState(GinState *state, Relation index);
extern Buffer GinNewBuffer(Relation index);
extern void GinInitBuffer(Buffer b, uint32 f);
*************** 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,
--- 616,627 ----
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);
--- 872,899 ----
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..1411a85
*** 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,430 ----
} GiSTOptions;
/* gist.c */
! extern Datum gisthandler(PG_FUNCTION_ARGS);
! extern void gistvalidate(OpClassInfo *opclass);
! extern void gistbuildempty(Relation index);
! extern bool gistinsert(Relation r, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern bool gistcanreturn(Relation index, int attno);
extern MemoryContext createTempGistContext(void);
extern GISTSTATE *initGISTstate(Relation index);
extern void freeGISTstate(GISTSTATE *giststate);
*************** 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 */
--- 470,477 ----
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);
--- 481,487 ----
#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,
--- 530,541 ----
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 */
--- 544,551 ----
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..9595c6b
*** 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,271 ----
/* public routines */
! extern Datum hashhandler(PG_FUNCTION_ARGS);
! extern void hashvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *hashbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void hashbuildempty(Relation index);
! extern bool hashinsert(Relation rel, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc hashbeginscan(Relation rel, int nkeys, int norderbys);
! extern bool hashgettuple(IndexScanDesc scan, ScanDirection dir);
! extern int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void hashrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
! ScanKey orderbys, int norderbys);
! extern void hashendscan(IndexScanDesc scan);
! extern void hashmarkpos(IndexScanDesc scan);
! extern void hashrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *hashbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *hashvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern bytea *hashoptions(Datum reloptions, bool validate);
/*
* Datatype-specific hash functions in hashfunc.c.
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
new file mode 100644
index 9e48efd..4fab0a3
*** 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,683 ----
/*
* prototypes for functions in nbtree.c (external entry points for btree)
*/
! extern Datum bthandler(PG_FUNCTION_ARGS);
! extern void btvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *btbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void btbuildempty(Relation index);
! extern bool btinsert(Relation rel, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc btbeginscan(Relation indexRelation,
! int nkeys, int norderbys);
! extern bool btgettuple(IndexScanDesc scan, ScanDirection dir);
! extern int64 btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void btrescan(IndexScanDesc scan, ScanKey keys, int nkeys,
! ScanKey orderbys, int norderbys);
! extern void btendscan(IndexScanDesc scan);
! extern void btmarkpos(IndexScanDesc scan);
! extern void btrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *btbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *btvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern bool btcanreturn(Relation index, int attno);
! extern bytea *btoptions(Datum reloptions, bool validate);
/*
* prototypes for functions in nbtinsert.c
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
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..ba2c1c1
*** 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,212 ----
} spgLeafConsistentOut;
+ /* spgutils.c */
+ extern Datum spghandler(PG_FUNCTION_ARGS);
+ extern void spgvalidate(OpClassInfo *opclass);
+
/* 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/opfam_internal.h b/src/include/catalog/opfam_internal.h
new file mode 100644
index 32195a7..5cc0208
*** a/src/include/catalog/opfam_internal.h
--- b/src/include/catalog/opfam_internal.h
*************** typedef struct
*** 25,28 ****
--- 25,40 ----
Oid sortfamily; /* ordering operator's sort opfamily, or 0 */
} OpFamilyMember;
+ /*
+ * Opclass data for validation by access method.
+ */
+ typedef struct
+ {
+ Oid intype; /* input datatype */
+ Oid keytype; /* key datatype */
+ List *procedures; /* list of OpFamilyMember */
+ List *operators; /* list of OpFamilyMember */
+ } OpClassInfo;
+
+
#endif /* OPFAM_INTERNAL_H */
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
new file mode 100644
index 8a28b8e..f19a873
*** 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,40 ----
CATALOG(pg_am,2601)
{
NameData amname; /* access method name */
! regproc amhandler; /* handler function */
} 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
--- 48,78 ----
* compiler constants for pg_am
* ----------------
*/
! #define Natts_pg_am 2
#define Anum_pg_am_amname 1
! #define Anum_pg_am_amhandler 2
/* ----------------
* initial contents of pg_am
* ----------------
*/
! DATA(insert OID = 403 ( btree bthandler ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
! DATA(insert OID = 405 ( hash hashhandler ));
DESCR("hash index access method");
#define HASH_AM_OID 405
! DATA(insert OID = 783 ( gist gisthandler ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
! DATA(insert OID = 2742 ( gin ginhandler ));
DESCR("GIN index access method");
#define GIN_AM_OID 2742
! DATA(insert OID = 4000 ( spgist spghandler ));
DESCR("SP-GiST index access method");
#define SPGIST_AM_OID 4000
! DATA(insert OID = 3580 ( brin brinhandler ));
DESCR("block range index (BRIN) access method");
#define BRIN_AM_OID 3580
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index ddf7c67..ad9a5cf
*** 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,5182 ----
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");
+
+ DATA(insert OID = 336 ( validate_opclass PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 16 "26" _null_ _null_ _null_ _null_ _null_ validate_opclass _null_ _null_ _null_ ));
+ DESCR("opclass validate function");
+
+
+
/*
* 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/commands/defrem.h b/src/include/commands/defrem.h
new file mode 100644
index adae296..3357d84
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
*************** extern Oid get_am_oid(const char *amname
*** 95,100 ****
--- 95,101 ----
extern char *get_am_name(Oid amOid);
extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+ extern Datum validate_opclass(PG_FUNCTION_ARGS);
/* commands/tsearchcmds.c */
extern ObjectAddress DefineTSParser(List *names, List *parameters);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
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/alter_table.out b/src/test/regress/expected/alter_table.out
new file mode 100644
index 28422ea..c403b80
*** a/src/test/regress/expected/alter_table.out
--- b/src/test/regress/expected/alter_table.out
*************** create type alter1.ctype as (f1 int, f2
*** 2111,2118 ****
create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql
as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
create text search configuration alter1.cfg(parser = alter1.prs);
--- 2111,2121 ----
create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql
as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
+ create function alter1.hash(alter1.ctype) returns int4 language sql
+ as 'select hashint4($1.f1) # hashtext($1.f2)';
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype),
! function 1 alter1.hash(alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
create text search configuration alter1.cfg(parser = alter1.prs);
*************** alter operator class alter1.ctype_hash_o
*** 2128,2133 ****
--- 2131,2137 ----
alter operator family alter1.ctype_hash_ops using hash set schema alter2;
alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
+ alter function alter1.hash(alter1.ctype) set schema alter2;
alter type alter1.ctype set schema alter2;
alter conversion alter1.ascii_to_utf8 set schema alter2;
alter text search parser alter1.prs set schema alter2;
*************** select alter2.plus1(41);
*** 2164,2170 ****
-- clean up
drop schema alter2 cascade;
! NOTICE: drop cascades to 13 other objects
DETAIL: drop cascades to table alter2.t1
drop cascades to view alter2.v1
drop cascades to function alter2.plus1(integer)
--- 2168,2174 ----
-- clean up
drop schema alter2 cascade;
! NOTICE: drop cascades to 14 other objects
DETAIL: drop cascades to table alter2.t1
drop cascades to view alter2.v1
drop cascades to function alter2.plus1(integer)
*************** drop cascades to operator family alter2.
*** 2173,2178 ****
--- 2177,2183 ----
drop cascades to type alter2.ctype
drop cascades to function alter2.same(alter2.ctype,alter2.ctype)
drop cascades to operator alter2.=(alter2.ctype,alter2.ctype)
+ drop cascades to function alter2.hash(alter2.ctype)
drop cascades to conversion ascii_to_utf8
drop cascades to text search parser prs
drop cascades to text search configuration cfg
diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out
new file mode 100644
index d85bc83..d1a322d
*** a/src/test/regress/expected/oidjoins.out
--- b/src/test/regress/expected/oidjoins.out
*************** WHERE aggmtranstype != 0 AND
*** 73,206 ****
------+---------------
(0 rows)
- SELECT ctid, amkeytype
- FROM pg_catalog.pg_am fk
- WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
- ctid | amkeytype
- ------+-----------
- (0 rows)
-
- SELECT ctid, aminsert
- FROM pg_catalog.pg_am fk
- WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
- ctid | aminsert
- ------+----------
- (0 rows)
-
- SELECT ctid, ambeginscan
- FROM pg_catalog.pg_am fk
- WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
- ctid | ambeginscan
- ------+-------------
- (0 rows)
-
- SELECT ctid, amgettuple
- FROM pg_catalog.pg_am fk
- WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- ctid | amgettuple
- ------+------------
- (0 rows)
-
- SELECT ctid, amgetbitmap
- FROM pg_catalog.pg_am fk
- WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
- ctid | amgetbitmap
- ------+-------------
- (0 rows)
-
- SELECT ctid, amrescan
- FROM pg_catalog.pg_am fk
- WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
- ctid | amrescan
- ------+----------
- (0 rows)
-
- SELECT ctid, amendscan
- FROM pg_catalog.pg_am fk
- WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
- ctid | amendscan
- ------+-----------
- (0 rows)
-
- SELECT ctid, ammarkpos
- FROM pg_catalog.pg_am fk
- WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
- ctid | ammarkpos
- ------+-----------
- (0 rows)
-
- SELECT ctid, amrestrpos
- FROM pg_catalog.pg_am fk
- WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
- ctid | amrestrpos
- ------+------------
- (0 rows)
-
- SELECT ctid, ambuild
- FROM pg_catalog.pg_am fk
- WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
- ctid | ambuild
- ------+---------
- (0 rows)
-
- SELECT ctid, ambuildempty
- FROM pg_catalog.pg_am fk
- WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
- ctid | ambuildempty
- ------+--------------
- (0 rows)
-
- SELECT ctid, ambulkdelete
- FROM pg_catalog.pg_am fk
- WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
- ctid | ambulkdelete
- ------+--------------
- (0 rows)
-
- SELECT ctid, amvacuumcleanup
- FROM pg_catalog.pg_am fk
- WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
- ctid | amvacuumcleanup
- ------+-----------------
- (0 rows)
-
- SELECT ctid, amcanreturn
- FROM pg_catalog.pg_am fk
- WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
- ctid | amcanreturn
- ------+-------------
- (0 rows)
-
- SELECT ctid, amcostestimate
- FROM pg_catalog.pg_am fk
- WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
- ctid | amcostestimate
- ------+----------------
- (0 rows)
-
- SELECT ctid, amoptions
- FROM pg_catalog.pg_am fk
- WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
- ctid | amoptions
- ------+-----------
- (0 rows)
-
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 73,78 ----
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
new file mode 100644
index df29fe5..f4634c2
*** a/src/test/regress/expected/opr_sanity.out
--- b/src/test/regress/expected/opr_sanity.out
*************** WHERE p1.oid != p2.oid AND
*** 1479,1484 ****
--- 1479,1490 ----
-----+-----
(0 rows)
+ -- Ask access methods to validate opclasses
+ SELECT oid FROM pg_opclass WHERE NOT validate_opclass(oid);
+ oid
+ -----
+ (0 rows)
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
SELECT p1.amopfamily, p1.amopstrategy
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 1524,1572 ****
------------+--------------
(0 rows)
- -- check for ordering operators not supported by parent AM
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
- amopfamily | amopopr | oid | amname
- ------------+---------+-----+--------
- (0 rows)
-
- -- Cross-check amopstrategy index against parent AM
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
- amopfamily | amopopr | oid | amname
- ------------+---------+-----+--------
- (0 rows)
-
- -- Detect missing pg_amop entries: should have as many strategy operators
- -- as AM expects for each datatype combination supported by the opfamily.
- -- We can't check this for AMs with variable strategy sets.
- SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
- amname | amoplefttype | amoprighttype
- --------+--------------+---------------
- (0 rows)
-
- -- Currently, none of the AMs with fixed strategy sets support ordering ops.
- SELECT p1.amname, p2.amopfamily, p2.amopstrategy
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
- amname | amopfamily | amopstrategy
- --------+------------+--------------
- (0 rows)
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
--- 1530,1535 ----
*************** WHERE p1.amprocfamily = 0 OR p1.amprocle
*** 1849,1863 ****
--------------+-----------
(0 rows)
- -- Cross-check amprocnum index against parent AM
- SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
- FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
- WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
- amprocfamily | amprocnum | oid | amname
- --------------+-----------+-----+--------
- (0 rows)
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
SELECT * FROM (
--- 1812,1817 ----
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
new file mode 100644
index 3ef55d9..0c784e1
*** a/src/test/regress/sql/alter_table.sql
--- b/src/test/regress/sql/alter_table.sql
*************** as 'select $1.f1 is not distinct from $2
*** 1448,1455 ****
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
--- 1448,1459 ----
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
+ create function alter1.hash(alter1.ctype) returns int4 language sql
+ as 'select hashint4($1.f1) # hashtext($1.f2)';
+
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype),
! function 1 alter1.hash(alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
*************** alter operator class alter1.ctype_hash_o
*** 1469,1474 ****
--- 1473,1479 ----
alter operator family alter1.ctype_hash_ops using hash set schema alter2;
alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
+ alter function alter1.hash(alter1.ctype) set schema alter2;
alter type alter1.ctype set schema alter2;
alter conversion alter1.ascii_to_utf8 set schema alter2;
alter text search parser alter1.prs set schema alter2;
diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql
new file mode 100644
index 2fa628d..ca419fd
*** a/src/test/regress/sql/oidjoins.sql
--- b/src/test/regress/sql/oidjoins.sql
*************** SELECT ctid, aggmtranstype
*** 37,106 ****
FROM pg_catalog.pg_aggregate fk
WHERE aggmtranstype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
- SELECT ctid, amkeytype
- FROM pg_catalog.pg_am fk
- WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
- SELECT ctid, aminsert
- FROM pg_catalog.pg_am fk
- WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
- SELECT ctid, ambeginscan
- FROM pg_catalog.pg_am fk
- WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
- SELECT ctid, amgettuple
- FROM pg_catalog.pg_am fk
- WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- SELECT ctid, amgetbitmap
- FROM pg_catalog.pg_am fk
- WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
- SELECT ctid, amrescan
- FROM pg_catalog.pg_am fk
- WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
- SELECT ctid, amendscan
- FROM pg_catalog.pg_am fk
- WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
- SELECT ctid, ammarkpos
- FROM pg_catalog.pg_am fk
- WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
- SELECT ctid, amrestrpos
- FROM pg_catalog.pg_am fk
- WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
- SELECT ctid, ambuild
- FROM pg_catalog.pg_am fk
- WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
- SELECT ctid, ambuildempty
- FROM pg_catalog.pg_am fk
- WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
- SELECT ctid, ambulkdelete
- FROM pg_catalog.pg_am fk
- WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
- SELECT ctid, amvacuumcleanup
- FROM pg_catalog.pg_am fk
- WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
- SELECT ctid, amcanreturn
- FROM pg_catalog.pg_am fk
- WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
- SELECT ctid, amcostestimate
- FROM pg_catalog.pg_am fk
- WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
- SELECT ctid, amoptions
- FROM pg_catalog.pg_am fk
- WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 37,42 ----
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
new file mode 100644
index c9bdd77..75145d9
*** a/src/test/regress/sql/opr_sanity.sql
--- b/src/test/regress/sql/opr_sanity.sql
*************** WHERE p1.oid != p2.oid AND
*** 960,965 ****
--- 960,969 ----
p1.opcmethod = p2.opcmethod AND p1.opcintype = p2.opcintype AND
p1.opcdefault AND p2.opcdefault;
+ -- Ask access methods to validate opclasses
+
+ SELECT oid FROM pg_opclass WHERE NOT validate_opclass(oid);
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 995,1035 ****
(SELECT 1 from pg_opfamily op WHERE op.oid = p1.amopsortfamily
AND op.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree'));
- -- check for ordering operators not supported by parent AM
-
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
-
- -- Cross-check amopstrategy index against parent AM
-
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
-
- -- Detect missing pg_amop entries: should have as many strategy operators
- -- as AM expects for each datatype combination supported by the opfamily.
- -- We can't check this for AMs with variable strategy sets.
-
- SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
-
- -- Currently, none of the AMs with fixed strategy sets support ordering ops.
-
- SELECT p1.amname, p2.amopfamily, p2.amopstrategy
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
--- 999,1004 ----
*************** FROM pg_amproc as p1
*** 1176,1188 ****
WHERE p1.amprocfamily = 0 OR p1.amproclefttype = 0 OR p1.amprocrighttype = 0
OR p1.amprocnum < 1 OR p1.amproc = 0;
- -- Cross-check amprocnum index against parent AM
-
- SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
- FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
- WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
--- 1145,1150 ----
On 2015-09-04 16:26, Alexander Korotkov wrote:
Attached patch is implementing this. It doesn't pretend to be fully
correct implementation, but it should be enough for proof the concept.
In this patch access method exposes another function: amvalidate. It
takes data structure representing opclass and throws error if it finds
it invalid.
This method is used on new opclass definition (alter operator family
etc. are not yet implemented but planned). Also, there is SQL function
validate_opclass(oid) which is used in regression tests.
Any thoughts?
This is starting to look good.
However I don't like the naming differences between validate_opclass and
amvalidate. If you expect that the current amvalidate will only be used
for opclass validation then it should be renamed accordingly.
Also GetIndexAmRoutine should check the return type of the amhandler.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Sep 7, 2015 at 9:17 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
On 2015-09-04 16:26, Alexander Korotkov wrote:
Attached patch is implementing this. It doesn't pretend to be fully
correct implementation, but it should be enough for proof the concept.
In this patch access method exposes another function: amvalidate. It
takes data structure representing opclass and throws error if it finds
it invalid.
This method is used on new opclass definition (alter operator family
etc. are not yet implemented but planned). Also, there is SQL function
validate_opclass(oid) which is used in regression tests.
Any thoughts?This is starting to look good
Thanks!
However I don't like the naming differences between validate_opclass and
amvalidate. If you expect that the current amvalidate will only be used for
opclass validation then it should be renamed accordingly.
I'm not yet sure if we need separate validation of opfamilies.
Also GetIndexAmRoutine should check the return type of the amhandler.
Will be fixed.
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
On 2015-09-07 20:56, Alexander Korotkov wrote:
On Mon, Sep 7, 2015 at 9:17 PM, Petr Jelinek <petr@2ndquadrant.com
However I don't like the naming differences between validate_opclass
and amvalidate. If you expect that the current amvalidate will only
be used for opclass validation then it should be renamed accordingly.I'm not yet sure if we need separate validation of opfamilies.
Well either the amvalidate or the validate_opclass should be renamed
IMHO, depending on which way the checking goes (one interface for
everything with generic name or multiple interfaces for multiple
validations).
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Sep 7, 2015 at 10:02 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
On 2015-09-07 20:56, Alexander Korotkov wrote:
On Mon, Sep 7, 2015 at 9:17 PM, Petr Jelinek <petr@2ndquadrant.com
However I don't like the naming differences between validate_opclass
and amvalidate. If you expect that the current amvalidate will only
be used for opclass validation then it should be renamed accordingly.I'm not yet sure if we need separate validation of opfamilies.
Well either the amvalidate or the validate_opclass should be renamed IMHO,
depending on which way the checking goes (one interface for everything with
generic name or multiple interfaces for multiple validations).
Yes, I agree with you about naming.
I'm not sure about separate validation of opfamilies independent of its
naming. I'd like to get any arguments/advises about it.
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
On Mon, Sep 7, 2015 at 9:17 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
On 2015-09-04 16:26, Alexander Korotkov wrote:
Attached patch is implementing this. It doesn't pretend to be fully
correct implementation, but it should be enough for proof the concept.
In this patch access method exposes another function: amvalidate. It
takes data structure representing opclass and throws error if it finds
it invalid.
This method is used on new opclass definition (alter operator family
etc. are not yet implemented but planned). Also, there is SQL function
validate_opclass(oid) which is used in regression tests.
Any thoughts?This is starting to look good.
However I don't like the naming differences between validate_opclass and
amvalidate. If you expect that the current amvalidate will only be used for
opclass validation then it should be renamed accordingly.
validate_opclass was renamed to amvalidate.
Also GetIndexAmRoutine should check the return type of the amhandler.
Fixed.
See the attached patch.
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Attachments:
aminterface-4.patchapplication/octet-stream; name=aminterface-4.patchDownload
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
new file mode 100644
index 99337b0..092849f
*** a/src/backend/access/brin/brin.c
--- b/src/backend/access/brin/brin.c
***************
*** 35,40 ****
--- 35,132 ----
/*
+ * BRIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ brinhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 15;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = brininsert;
+ amroutine->ambeginscan = brinbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = bringetbitmap;
+ amroutine->amrescan = brinrescan;
+ amroutine->amendscan = brinendscan;
+ amroutine->ammarkpos = brinmarkpos;
+ amroutine->amrestrpos = brinrestrpos;
+ amroutine->ambuild = brinbuild;
+ amroutine->ambuildempty = brinbuildempty;
+ amroutine->ambulkdelete = brinbulkdelete;
+ amroutine->amvacuumcleanup = brinvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = brincostestimate;
+ amroutine->amoptions = brinoptions;
+ amroutine->amvalidate = brinvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ brinvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[BRIN_NPROC] = {false};
+ int i;
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype
+ || proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > BRIN_NPROC)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid support number for BRIN: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u was defined more than once",
+ proc->number)));
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < BRIN_PROCNUM_UNION; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN doesn't support order by operators")));
+ }
+ }
+
+ /*
* We use a BrinBuildState during initial construction of a BRIN index.
* The running state is kept in a BrinMemTuple.
*/
*************** 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;
--- 172,182 ----
* 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);
}
/*
--- 314,320 ----
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;
--- 324,332 ----
* 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);
}
/*
--- 337,343 ----
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;
--- 352,360 ----
* 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
--- 534,549 ----
* 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();
}
/*
--- 555,585 ----
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;
--- 651,659 ----
/*
* 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. */
--- 732,743 ----
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();
}
/*
--- 754,759 ----
*************** 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));
--- 765,793 ----
* 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;
--- 804,818 ----
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);
--- 825,831 ----
/* 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);
}
/*
--- 834,840 ----
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 d817eba..978d2dc
*** a/src/backend/access/common/reloptions.c
--- b/src/backend/access/common/reloptions.c
*************** untransformRelOptions(Datum options)
*** 891,897 ****
* 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;
--- 891,897 ----
* 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
*** 1379,1412 ****
* 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);
}
/*
--- 1379,1393 ----
* 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 49e9185..92701b9
*** 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..443078d
*** a/src/backend/access/gin/ginutil.c
--- b/src/backend/access/gin/ginutil.c
***************
*** 22,28 ****
--- 22,132 ----
#include "miscadmin.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
+ #include "utils/selfuncs.h"
+
+
+ /*
+ * GIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ ginhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 6;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = gininsert;
+ amroutine->ambeginscan = ginbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = gingetbitmap;
+ amroutine->amrescan = ginrescan;
+ amroutine->amendscan = ginendscan;
+ amroutine->ammarkpos = ginmarkpos;
+ amroutine->amrestrpos = ginrestrpos;
+ amroutine->ambuild = ginbuild;
+ amroutine->ambuildempty = ginbuildempty;
+ amroutine->ambulkdelete = ginbulkdelete;
+ amroutine->amvacuumcleanup = ginvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = gincostestimate;
+ amroutine->amoptions = ginoptions;
+ amroutine->amvalidate = ginvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ ginvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[GINNProcs] = {false};
+ int i;
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+ if (proc->lefttype != opclass->intype
+ || proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > GINNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid support number for GIN: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u was defined more than once",
+ proc->number)));
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < GIN_EXTRACTQUERY_PROC; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u is required", i + 1)));
+ }
+
+ if (!procsPresent[GIN_CONSISTENT_PROC - 1]
+ && !procsPresent[GIN_TRICONSISTENT_PROC - 1])
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("At least one of consistent support (number %u) "
+ "and triconsistent cupport (number %u) is "
+ "is required",
+ GIN_CONSISTENT_PROC, GIN_TRICONSISTENT_PROC)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN doesn't support order by operators")));
+ }
+ }
/*
* initGinState: fill in an empty GinState struct to describe the index
*************** 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;
--- 620,628 ----
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);
--- 637,643 ----
/* 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);
}
/*
--- 646,652 ----
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 4edc5a7..fb8c43a
*** 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 void gistfinishsplit(GISTInsertSt
*** 38,43 ****
--- 40,138 ----
GISTSTATE *giststate, List *splitinfo, bool releasebuf);
static void gistvacuumpage(Relation rel, Page page, Buffer buffer);
+ /*
+ * 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;
+ amroutine->amvalidate = gistvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ gistvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[GISTNProcs] = {false};
+ int i;
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype
+ || proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > GISTNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid support number for GiST: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u was defined more than once",
+ proc->number)));
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < GIST_EQUAL_PROC; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily)
+ && !procsPresent[GIST_DISTANCE_PROC - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST distance support function %u is required "
+ "for order by operators", GIST_DISTANCE_PROC)));
+ }
+ }
#define ROTATEDIST(d) do { \
SplitedPageLayout *tmp=(SplitedPageLayout*)palloc(sizeof(SplitedPageLayout)); \
*************** createTempGistContext(void)
*** 70,79 ****
/*
* 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 */
--- 165,173 ----
/*
* gistbuildempty() -- build an empty gist index in the initialization fork
*/
! void
! gistbuildempty(Relation index)
{
Buffer buffer;
/* Initialize the root page */
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 89,96 ****
/* Unlock and release the buffer */
UnlockReleaseBuffer(buffer);
-
- PG_RETURN_VOID();
}
/*
--- 183,188 ----
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 99,116 ****
* 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;
--- 191,201 ----
* 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)
*** 136,142 ****
MemoryContextSwitchTo(oldCxt);
freeGISTstate(giststate);
! PG_RETURN_BOOL(false);
}
--- 221,227 ----
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 ce8e582..1adf92f
*** a/src/backend/access/gist/gistget.c
--- b/src/backend/access/gist/gistget.c
*************** getNextNearest(IndexScanDesc scan)
*** 618,628 ****
/*
* 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)
--- 618,626 ----
/*
* 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)
*** 651,657 ****
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! PG_RETURN_BOOL(getNextNearest(scan));
}
else
{
--- 649,655 ----
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! return getNextNearest(scan);
}
else
{
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 688,694 ****
so->curPageData++;
! PG_RETURN_BOOL(true);
}
/*
--- 686,692 ----
so->curPageData++;
! return true;
}
/*
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 726,732 ****
item = getNextGISTSearchItem(so);
if (!item)
! PG_RETURN_BOOL(false);
CHECK_FOR_INTERRUPTS();
--- 724,730 ----
item = getNextGISTSearchItem(so);
if (!item)
! return false;
CHECK_FOR_INTERRUPTS();
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 750,766 ****
/*
* 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);
--- 748,762 ----
/*
* 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)
*** 791,797 ****
pfree(item);
}
! PG_RETURN_INT64(ntids);
}
/*
--- 787,793 ----
pfree(item);
}
! return ntids;
}
/*
*************** gistgetbitmap(PG_FUNCTION_ARGS)
*** 799,812 ****
*
* 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);
}
--- 795,805 ----
*
* 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 a17c5bc..22f0c68
*** 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)
*** 107,121 ****
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;
--- 104,116 ----
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)
*** 314,341 ****
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;
/*
--- 309,331 ----
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)
*** 343,348 ****
* as well as the queueCxt if there is a separate context for it.
*/
freeGISTstate(so->giststate);
-
- PG_RETURN_VOID();
}
--- 333,336 ----
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..286596b
*** 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,150 ----
bool tupleIsAlive,
void *state);
+ /*
+ * Hash handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ hashhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 1;
+ amroutine->amsupport = 1;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = true;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = false;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = INT4OID;
+
+ amroutine->aminsert = hashinsert;
+ amroutine->ambeginscan = hashbeginscan;
+ amroutine->amgettuple = hashgettuple;
+ amroutine->amgetbitmap = hashgetbitmap;
+ amroutine->amrescan = hashrescan;
+ amroutine->amendscan = hashendscan;
+ amroutine->ammarkpos = hashmarkpos;
+ amroutine->amrestrpos = hashrestrpos;
+ amroutine->ambuild = hashbuild;
+ amroutine->ambuildempty = hashbuildempty;
+ amroutine->ambulkdelete = hashbulkdelete;
+ amroutine->amvacuumcleanup = hashvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = hashcostestimate;
+ amroutine->amoptions = hashoptions;
+ amroutine->amvalidate = hashvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ hashvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->number != HASHPROC)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid support number for hash: %u",
+ proc->number)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+ bool leftFound = false, rightFound = false;
+ ListCell *ll;
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Hash doesn't support order by operators")));
+
+ if (opr->number < 1 || opr->number > HTMaxStrategyNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid strategy number for hash: %u",
+ opr->number)));
+
+ foreach(ll, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(ll);
+
+ if (proc->lefttype == opr->lefttype)
+ leftFound = true;
+ if (proc->lefttype == opr->righttype)
+ rightFound = true;
+ }
+
+ if (!leftFound || !rightFound)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("No hash procedure found for operator: %u",
+ opr->object)));
+ }
+ }
/*
* hashbuild() -- build a new hash index.
*/
! 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();
}
/*
--- 205,220 ----
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;
/*
--- 256,266 ----
* 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);
--- 273,279 ----
* 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;
--- 283,298 ----
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;
--- 394,409 ----
/* 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;
--- 440,455 ----
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;
--- 471,486 ----
/* 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;
--- 506,519 ----
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();
}
/*
--- 532,555 ----
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;
--- 559,568 ----
*
* 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);
}
/*
--- 732,738 ----
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);
}
--- 740,761 ----
*
* 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..fa933f6
*** 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,182 ----
/*
! * 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;
! amroutine->amvalidate = btvalidate;
!
! PG_RETURN_POINTER(amroutine);
! }
!
! void
! btvalidate(OpClassInfo *opclass)
! {
! ListCell *l;
!
! foreach(l, opclass->procedures)
! {
! OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
!
! if (proc->number != BTORDER_PROC
! && proc->number != BTSORTSUPPORT_PROC)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("Invalid support number for btree: %u",
! proc->number)));
! }
!
! foreach(l, opclass->operators)
! {
! OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
! bool found = false;
! ListCell *ll;
!
! if (OidIsValid(opr->sortfamily))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("Btree doesn't support order by operators")));
!
! if (opr->number < 1 || opr->number > BTMaxStrategyNumber)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("Invalid strategy number for btree: %u",
! opr->number)));
!
! foreach(ll, opclass->procedures)
! {
! OpFamilyMember *proc = (OpFamilyMember *) lfirst(ll);
!
! if (proc->number == BTORDER_PROC
! && proc->lefttype == opr->lefttype
! && proc->righttype == opr->righttype)
! found = true;
! }
!
! if (!found)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("No ordering procedure found for operator: %u",
! opr->object)));
! }
! }
!
! /*
! * btbuild() -- build a new btree index.
! */
! IndexBuildResult *
! btbuild(Relation heap, Relation index, IndexInfo *indexInfo)
{
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);
}
/*
--- 248,254 ----
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);
--- 283,292 ----
/*
* 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();
}
/*
--- 306,311 ----
*************** 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;
--- 314,324 ----
* 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;
--- 330,344 ----
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);
}
--- 354,360 ----
{
/* 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;
--- 404,418 ----
/* ... 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);
}
--- 424,430 ----
{
/* 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;
--- 462,476 ----
/* 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 */
--- 508,523 ----
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 */
--- 568,581 ----
/* 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). */
--- 604,617 ----
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 */
--- 634,647 ----
/* 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();
}
/*
--- 709,714 ----
*************** 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;
--- 718,727 ----
*
* 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);
}
/*
--- 740,746 ----
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
--- 748,759 ----
*
* 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);
}
/*
--- 785,791 ----
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);
}
--- 1186,1193 ----
*
* 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..644b836
*** a/src/backend/access/spgist/spgutils.c
--- b/src/backend/access/spgist/spgutils.c
***************
*** 24,30 ****
--- 24,123 ----
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "utils/lsyscache.h"
+ #include "utils/selfuncs.h"
+
+
+ /*
+ * SP-GiST handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ spghandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 5;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+ amroutine->aminsert = spginsert;
+ amroutine->ambeginscan = spgbeginscan;
+ amroutine->amgettuple = spggettuple;
+ amroutine->amgetbitmap = spggetbitmap;
+ amroutine->amrescan = spgrescan;
+ amroutine->amendscan = spgendscan;
+ amroutine->ammarkpos = spgmarkpos;
+ amroutine->amrestrpos = spgrestrpos;
+ amroutine->ambuild = spgbuild;
+ amroutine->ambuildempty = spgbuildempty;
+ amroutine->ambulkdelete = spgbulkdelete;
+ amroutine->amvacuumcleanup = spgvacuumcleanup;
+ amroutine->amcanreturn = spgcanreturn;
+ amroutine->amcostestimate = spgcostestimate;
+ amroutine->amoptions = spgoptions;
+ amroutine->amvalidate = spgvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ spgvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[SPGISTNProc] = {false};
+ int i;
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype
+ || proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > SPGISTNProc)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid support number for SP-GiST: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u was defined more than once",
+ proc->number)));
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < SPGISTNProc; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST doesn't support order by operators")));
+ }
+ }
/* Fill in a SpGistTypeDesc struct with info about the specified data type */
static void
*************** 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();
}
/*
--- 582,597 ----
/*
* 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 <unistd.h>
+ #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/opclasscmds.c b/src/backend/commands/opclasscmds.c
new file mode 100644
index 3375f10..672a4a2
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
***************
*** 42,47 ****
--- 42,48 ----
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
+ #include "utils/catcache.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 334,346 ****
ListCell *l;
Relation rel;
HeapTuple tup;
- Form_pg_am pg_am;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
--- 335,348 ----
ListCell *l;
Relation rel;
HeapTuple tup;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
+ IndexAmRoutine *amroutine;
+ OpClassInfo opclassinfo;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 361,373 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
! amstorage = pg_am->amstorage;
/* XXX Should we make any privilege check against the AM? */
--- 363,377 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
!
! amroutine = GetIndexAmRoutine(amoid);
!
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
! amstorage = amroutine->amstorage;
/* XXX Should we make any privilege check against the AM? */
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 582,587 ****
--- 586,597 ----
stmt->amname)));
}
+ opclassinfo.intype = typeoid;
+ opclassinfo.keytype = storageoid;
+ opclassinfo.procedures = procedures;
+ opclassinfo.operators = operators;
+ amroutine->amvalidate(&opclassinfo);
+
rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
/*
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 718,723 ****
--- 728,817 ----
return myself;
}
+ /*
+ * Collect opfamily information for opclass validation.
+ */
+ static void
+ getOpFamilyInfo(OpClassInfo *opclassinfo, Oid opfamilyoid)
+ {
+ CatCList *catlist;
+ int i;
+
+ opclassinfo->operators = NIL;
+ opclassinfo->procedures = NIL;
+
+ /* Find operators */
+ catlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ for (i = 0; i < catlist->n_members; i++)
+ {
+ HeapTuple oprtup = &catlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+ OpFamilyMember *opmember = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
+
+ opmember->object = oprform->amopopr;
+ opmember->number = oprform->amopstrategy;
+ opmember->lefttype = oprform->amoplefttype;
+ opmember->righttype = oprform->amoprighttype;
+ opmember->sortfamily = oprform->amopsortfamily;
+
+ opclassinfo->operators = lappend(opclassinfo->operators, opmember);
+ }
+ ReleaseCatCacheList(catlist);
+
+ /* Find support functions */
+ catlist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+ for (i = 0; i < catlist->n_members; i++)
+ {
+ HeapTuple proctup = &catlist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+ OpFamilyMember *procmember = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
+
+ procmember->object = procform->amproc;
+ procmember->number = procform->amprocnum;
+ procmember->lefttype = procform->amproclefttype;
+ procmember->righttype = procform->amprocrighttype;
+
+ opclassinfo->procedures = lappend(opclassinfo->procedures, procmember);
+ }
+ ReleaseCatCacheList(catlist);
+ }
+
+ /*
+ * Ask access method to validate given opclass.
+ */
+ Datum
+ amvalidate(PG_FUNCTION_ARGS)
+ {
+ OpClassInfo opclassinfo;
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opclassoid = PG_GETARG_OID(0),
+ opfamilyoid,
+ amoid;
+ IndexAmRoutine *amroutine;
+
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ opclassinfo.intype = classform->opcintype;
+ opclassinfo.keytype = classform->opckeytype;
+ opfamilyoid = classform->opcfamily;
+ amoid = classform->opcmethod;
+
+ ReleaseSysCache(classtup);
+
+ getOpFamilyInfo(&opclassinfo, opfamilyoid);
+
+ amroutine = GetIndexAmRoutine(amoid);
+
+ amroutine->amvalidate(&opclassinfo);
+
+ PG_RETURN_BOOL(true);
+ }
+
/*
* DefineOpFamily
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 776,782 ****
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! Form_pg_am pg_am;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
--- 870,876 ----
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! IndexAmRoutine *amroutine;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 787,802 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
/* XXX Should we make any privilege check against the AM? */
- ReleaseSysCache(tup);
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
--- 881,896 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! amroutine = GetIndexAmRoutine(amoid);
! ReleaseSysCache(tup);
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
/* XXX Should we make any privilege check against the AM? */
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
*************** assignOperTypes(OpFamilyMember *member,
*** 1099,1119 ****
* the family has been created but not yet populated with the required
* operators.)
*/
! HeapTuple amtup;
! Form_pg_am pg_am;
! amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
! if (amtup == NULL)
! elog(ERROR, "cache lookup failed for access method %u", amoid);
! pg_am = (Form_pg_am) GETSTRUCT(amtup);
! if (!pg_am->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! NameStr(pg_am->amname))));
!
! ReleaseSysCache(amtup);
}
else
{
--- 1193,1207 ----
* the family has been created but not yet populated with the required
* operators.)
*/
! IndexAmRoutine *amroutine;
! amroutine = GetIndexAmRoutine(amoid);
! if (!amroutine->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! get_am_name(amoid))));
}
else
{
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 d107d76..6853899
*** 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 <unistd.h>
#include <fcntl.h>
+ #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 420ef3d..f5969d3
*** a/src/backend/utils/cache/relcache.c
--- b/src/backend/utils/cache/relcache.c
*************** 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
--- 445,451 ----
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;
--- 1162,1215 ----
}
/*
+ * 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));
+
+ ReleaseSysCache(tuple);
+
+ return result;
+ }
+
+ /*
+ * Initialize IndexAmRoutine for relation.
+ */
+ void
+ InitIndexAmRoutine(Relation relation)
+ {
+ IndexAmRoutine *result, *tmp;
+
+ result = (IndexAmRoutine *)MemoryContextAlloc(CacheMemoryContext,
+ sizeof(IndexAmRoutine));
+ tmp = (IndexAmRoutine *)DatumGetPointer(
+ OidFunctionCall0(relation->rd_am->amhandler));
+ memcpy(result, tmp, sizeof(IndexAmRoutine));
+ relation->amroutine = result;
+ }
+
+ /*
* Initialize index-access-method support data for an index relation
*/
void
RelationInitIndexAccessInfo(Relation relation)
{
HeapTuple tuple;
Datum indcollDatum;
Datum indclassDatum;
Datum indoptionDatum;
*************** RelationInitIndexAccessInfo(Relation rel
*** 1180,1185 ****
--- 1221,1227 ----
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
--- 1246,1263 ----
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)
*** 4745,4751 ****
Oid *opfamily;
Oid *opcintype;
RegProcedure *support;
- int nsupport;
int16 *indoption;
Oid *indcollation;
--- 4789,4794 ----
*************** load_relcache_init_file(bool shared)
*** 4773,4778 ****
--- 4816,4822 ----
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)
*** 4834,4845 ****
rel->rd_indoption = indoption;
/* 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
{
--- 4878,4890 ----
rel->rd_indoption = indoption;
+ InitIndexAmRoutine(rel);
+
/* set up zeroed fmgr-info vectors */
rel->rd_aminfo = (RelationAmInfo *)
MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
rel->rd_supportinfo = (FmgrInfo *)
! MemoryContextAllocZero(indexcxt, relform->relnatts * rel->amroutine->amsupport * sizeof(FmgrInfo));
}
else
{
*************** write_relcache_init_file(bool shared)
*** 5108,5114 ****
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
--- 5153,5159 ----
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (rel->amroutine->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h
new file mode 100644
index ...1fba425
*** a/src/include/access/amapi.h
--- b/src/include/access/amapi.h
***************
*** 0 ****
--- 1,169 ----
+ /*-------------------------------------------------------------------------
+ *
+ * amapi.h
+ * API for access methods
+ *
+ * Copyright (c) 2015, PostgreSQL Global Development Group
+ *
+ * src/include/access/amapi.h
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef AMAPI_H
+ #define AMAPI_H
+
+ #include "access/genam.h"
+ #include "catalog/opfam_internal.h"
+ #include "nodes/relation.h"
+
+ /*
+ * Callback function signatures --- see indexam.sgml for more info.
+ */
+
+ /* "insert this tuple" function */
+ typedef bool
+ (*aminsert_function) (Relation indexRelation,
+ Datum *values,
+ bool *isnull,
+ ItemPointer heap_tid,
+ Relation heapRelation,
+ IndexUniqueCheck checkUnique);
+
+ /* "prepare for index scan" function */
+ typedef IndexScanDesc
+ (*ambeginscan_function) (Relation indexRelation,
+ int nkeys,
+ int norderbys);
+
+ /* "next valid tuple" function, or NULL */
+ typedef bool
+ (*amgettuple_function) (IndexScanDesc scan,
+ ScanDirection direction);
+
+ /* "fetch all valid tuples" function, or NULL */
+ typedef int64
+ (*amgetbitmap_function) (IndexScanDesc scan,
+ TIDBitmap *tbm);
+
+ /* "(re)start index scan" function */
+ typedef void
+ (*amrescan_function) (IndexScanDesc scan,
+ ScanKey keys,
+ int nkeys,
+ ScanKey orderbys,
+ int norderbys);
+
+ /* "end index scan" function */
+ typedef void
+ (*amendscan_function) (IndexScanDesc scan);
+
+ /* "mark current scan position" function */
+ typedef void
+ (*ammarkpos_function) (IndexScanDesc scan);
+
+ /* "restore marked scan position" function */
+ typedef void
+ (*amrestrpos_function) (IndexScanDesc scan);
+
+ /* "build new index" function */
+ typedef IndexBuildResult *
+ (*ambuild_function) (Relation heapRelation,
+ Relation indexRelation,
+ IndexInfo *indexInfo);
+
+ /* "build empty index" function */
+ typedef void
+ (*ambuildempty_function) (Relation indexRelation);
+
+ /* bulk-delete function */
+ typedef IndexBulkDeleteResult *
+ (*ambulkdelete_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+
+ /* post-VACUUM cleanup function */
+ typedef IndexBulkDeleteResult *
+ (*amvacuumcleanup_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
+
+ /* can indexscan return IndexTuples? */
+ typedef bool
+ (*amcanreturn_function) (Relation indexRelation, int attno);
+
+ /* estimate cost of an indexscan */
+ typedef void
+ (*amcostestimate_function) (PlannerInfo *root,
+ IndexPath *path,
+ double loop_count,
+ Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+
+ /* parse AM-specific parameters */
+ typedef bytea *
+ (*amoptions_function) (Datum reloptions,
+ bool validate);
+
+ /* validate oplass */
+ typedef void
+ (*amvalidate_function) (OpClassInfo *opclass);
+
+
+ struct IndexAmRoutine
+ {
+ NodeTag type;
+
+ /*
+ * Total number of strategies (operators) by which we can traverse/search
+ * this AM. Zero if AM does not have a fixed set of strategy assignments.
+ */
+ int16 amstrategies;
+ /* total number of support functions that this AM uses */
+ int16 amsupport;
+ /* does AM support order by column value? */
+ bool amcanorder;
+ /* does AM support order by operator result? */
+ bool amcanorderbyop;
+ /* does AM support backward scan? */
+ bool amcanbackward;
+ /* does AM support UNIQUE indexes? */
+ bool amcanunique;
+ /* does AM support multi-column indexes? */
+ bool amcanmulticol;
+ /* can query omit key for the first column? */
+ bool amoptionalkey;
+ /* can AM handle ScalarArrayOpExpr quals? */
+ bool amsearcharray;
+ /* can AM search for NULL/NOT NULL entries? */
+ bool amsearchnulls;
+ /* can storage type differ from column type? */
+ bool amstorage;
+ /* does AM support cluster command? */
+ bool amclusterable;
+ /* does AM handle predicate locks? */
+ bool ampredlocks;
+ /* type of data in index, or InvalidOid */
+ Oid amkeytype;
+
+ /* interface functions */
+ aminsert_function aminsert;
+ ambeginscan_function ambeginscan;
+ amgettuple_function amgettuple;
+ amgetbitmap_function amgetbitmap;
+ amrescan_function amrescan;
+ amendscan_function amendscan;
+ ammarkpos_function ammarkpos;
+ amrestrpos_function amrestrpos;
+ ambuild_function ambuild;
+ ambuildempty_function ambuildempty;
+ ambulkdelete_function ambulkdelete;
+ amvacuumcleanup_function amvacuumcleanup;
+ amcanreturn_function amcanreturn;
+ amcostestimate_function amcostestimate;
+ amoptions_function amoptions;
+ amvalidate_function amvalidate;
+ };
+
+ #endif /* AMAPI_H */
diff --git a/src/include/access/brin.h b/src/include/access/brin.h
new file mode 100644
index e72fb2d..5ae5722
*** 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,51 ----
/*
* prototypes for functions in brin.c (external entry points for BRIN)
*/
! extern Datum brinhandler(PG_FUNCTION_ARGS);
! extern void brinvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *brinbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void brinbuildempty(Relation index);
! extern bool brininsert(Relation idxRel, Datum *values, bool *nulls,
! ItemPointer heaptid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys);
! extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
! ScanKey orderbys, int norderbys);
! extern void brinendscan(IndexScanDesc scan);
! extern void brinmarkpos(IndexScanDesc scan);
! extern void brinrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *brinbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *brinvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern void brincostestimate(PlannerInfo *root, IndexPath *path,
! double loop_count, Cost *indexStartupCost,
! Cost *indexTotalCost,
! Selectivity *indexSelectivity,
! double *indexCorrelation);
! extern bytea *brinoptions(Datum reloptions, bool validate);
/*
* Storage type for BRIN's reloptions
diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h
new file mode 100644
index 6be199e..2f8fe17
*** a/src/include/access/brin_internal.h
--- b/src/include/access/brin_internal.h
*************** typedef struct BrinDesc
*** 72,77 ****
--- 72,78 ----
#define BRIN_PROCNUM_CONSISTENT 3
#define BRIN_PROCNUM_UNION 4
/* procedure numbers up to 10 are reserved for BRIN future expansion */
+ #define BRIN_NPROC 15
#undef BRIN_DEBUG
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
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 acbe36a..3348436
*** 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,601 ----
/* ginutil.c */
! extern Datum ginhandler(PG_FUNCTION_ARGS);
! extern void ginvalidate(OpClassInfo *opclass);
! extern bytea *ginoptions(Datum reloptions, bool validate);
extern void initGinState(GinState *state, Relation index);
extern Buffer GinNewBuffer(Relation index);
extern void GinInitBuffer(Buffer b, uint32 f);
*************** 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,
--- 616,627 ----
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);
--- 872,899 ----
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 1a77982..35fb34a
*** 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
*** 426,434 ****
} 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);
--- 427,439 ----
} GiSTOptions;
/* gist.c */
! extern Datum gisthandler(PG_FUNCTION_ARGS);
! extern void gistvalidate(OpClassInfo *opclass);
! extern void gistbuildempty(Relation index);
! extern bool gistinsert(Relation r, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern bool gistcanreturn(Relation index, int attno);
extern MemoryContext createTempGistContext(void);
extern GISTSTATE *initGISTstate(Relation index);
extern void freeGISTstate(GISTSTATE *giststate);
*************** extern XLogRecPtr gistXLogSplit(RelFileN
*** 474,481 ****
Buffer leftchild, bool markfollowright);
/* gistget.c */
! extern Datum gistgettuple(PG_FUNCTION_ARGS);
! extern Datum gistgetbitmap(PG_FUNCTION_ARGS);
/* gistutil.c */
--- 479,486 ----
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
*** 485,491 ****
#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);
--- 490,496 ----
#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 *
*** 534,541 ****
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,
--- 539,550 ----
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
*** 544,550 ****
int attno);
/* gistbuild.c */
! extern Datum gistbuild(PG_FUNCTION_ARGS);
extern void gistValidateBufferingOption(char *value);
/* gistbuildbuffers.c */
--- 553,560 ----
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..9595c6b
*** 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,271 ----
/* public routines */
! extern Datum hashhandler(PG_FUNCTION_ARGS);
! extern void hashvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *hashbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void hashbuildempty(Relation index);
! extern bool hashinsert(Relation rel, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc hashbeginscan(Relation rel, int nkeys, int norderbys);
! extern bool hashgettuple(IndexScanDesc scan, ScanDirection dir);
! extern int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void hashrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
! ScanKey orderbys, int norderbys);
! extern void hashendscan(IndexScanDesc scan);
! extern void hashmarkpos(IndexScanDesc scan);
! extern void hashrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *hashbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *hashvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern bytea *hashoptions(Datum reloptions, bool validate);
/*
* Datatype-specific hash functions in hashfunc.c.
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
new file mode 100644
index 9e48efd..4fab0a3
*** 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,683 ----
/*
* prototypes for functions in nbtree.c (external entry points for btree)
*/
! extern Datum bthandler(PG_FUNCTION_ARGS);
! extern void btvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *btbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void btbuildempty(Relation index);
! extern bool btinsert(Relation rel, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc btbeginscan(Relation indexRelation,
! int nkeys, int norderbys);
! extern bool btgettuple(IndexScanDesc scan, ScanDirection dir);
! extern int64 btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void btrescan(IndexScanDesc scan, ScanKey keys, int nkeys,
! ScanKey orderbys, int norderbys);
! extern void btendscan(IndexScanDesc scan);
! extern void btmarkpos(IndexScanDesc scan);
! extern void btrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *btbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *btvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern bool btcanreturn(Relation index, int attno);
! extern bytea *btoptions(Datum reloptions, bool validate);
/*
* prototypes for functions in nbtinsert.c
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
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..ba2c1c1
*** 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,212 ----
} spgLeafConsistentOut;
+ /* spgutils.c */
+ extern Datum spghandler(PG_FUNCTION_ARGS);
+ extern void spgvalidate(OpClassInfo *opclass);
+
/* 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/opfam_internal.h b/src/include/catalog/opfam_internal.h
new file mode 100644
index 32195a7..5cc0208
*** a/src/include/catalog/opfam_internal.h
--- b/src/include/catalog/opfam_internal.h
*************** typedef struct
*** 25,28 ****
--- 25,40 ----
Oid sortfamily; /* ordering operator's sort opfamily, or 0 */
} OpFamilyMember;
+ /*
+ * Opclass data for validation by access method.
+ */
+ typedef struct
+ {
+ Oid intype; /* input datatype */
+ Oid keytype; /* key datatype */
+ List *procedures; /* list of OpFamilyMember */
+ List *operators; /* list of OpFamilyMember */
+ } OpClassInfo;
+
+
#endif /* OPFAM_INTERNAL_H */
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
new file mode 100644
index 8a28b8e..f19a873
*** 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,40 ----
CATALOG(pg_am,2601)
{
NameData amname; /* access method name */
! regproc amhandler; /* handler function */
} 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
--- 48,78 ----
* compiler constants for pg_am
* ----------------
*/
! #define Natts_pg_am 2
#define Anum_pg_am_amname 1
! #define Anum_pg_am_amhandler 2
/* ----------------
* initial contents of pg_am
* ----------------
*/
! DATA(insert OID = 403 ( btree bthandler ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
! DATA(insert OID = 405 ( hash hashhandler ));
DESCR("hash index access method");
#define HASH_AM_OID 405
! DATA(insert OID = 783 ( gist gisthandler ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
! DATA(insert OID = 2742 ( gin ginhandler ));
DESCR("GIN index access method");
#define GIN_AM_OID 2742
! DATA(insert OID = 4000 ( spgist spghandler ));
DESCR("SP-GiST index access method");
#define SPGIST_AM_OID 4000
! DATA(insert OID = 3580 ( brin brinhandler ));
DESCR("block range index (BRIN) access method");
#define BRIN_AM_OID 3580
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index ddf7c67..408ee44
*** 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,5182 ----
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");
+
+ DATA(insert OID = 336 ( amvalidate PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 16 "26" _null_ _null_ _null_ _null_ _null_ amvalidate _null_ _null_ _null_ ));
+ DESCR("ask access method to validate opclass");
+
+
+
/*
* Symbolic values for provolatile column: these indicate whether the result
* of a function is dependent *only* on the values of its explicit arguments,
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
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/commands/defrem.h b/src/include/commands/defrem.h
new file mode 100644
index adae296..3357d84
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
*************** extern Oid get_am_oid(const char *amname
*** 95,100 ****
--- 95,101 ----
extern char *get_am_name(Oid amOid);
extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+ extern Datum validate_opclass(PG_FUNCTION_ARGS);
/* commands/tsearchcmds.c */
extern ObjectAddress DefineTSParser(List *names, List *parameters);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
new file mode 100644
index 4ae2f3e..be4a1e2
*** 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/alter_table.out b/src/test/regress/expected/alter_table.out
new file mode 100644
index 28422ea..c403b80
*** a/src/test/regress/expected/alter_table.out
--- b/src/test/regress/expected/alter_table.out
*************** create type alter1.ctype as (f1 int, f2
*** 2111,2118 ****
create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql
as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
create text search configuration alter1.cfg(parser = alter1.prs);
--- 2111,2121 ----
create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql
as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
+ create function alter1.hash(alter1.ctype) returns int4 language sql
+ as 'select hashint4($1.f1) # hashtext($1.f2)';
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype),
! function 1 alter1.hash(alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
create text search configuration alter1.cfg(parser = alter1.prs);
*************** alter operator class alter1.ctype_hash_o
*** 2128,2133 ****
--- 2131,2137 ----
alter operator family alter1.ctype_hash_ops using hash set schema alter2;
alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
+ alter function alter1.hash(alter1.ctype) set schema alter2;
alter type alter1.ctype set schema alter2;
alter conversion alter1.ascii_to_utf8 set schema alter2;
alter text search parser alter1.prs set schema alter2;
*************** select alter2.plus1(41);
*** 2164,2170 ****
-- clean up
drop schema alter2 cascade;
! NOTICE: drop cascades to 13 other objects
DETAIL: drop cascades to table alter2.t1
drop cascades to view alter2.v1
drop cascades to function alter2.plus1(integer)
--- 2168,2174 ----
-- clean up
drop schema alter2 cascade;
! NOTICE: drop cascades to 14 other objects
DETAIL: drop cascades to table alter2.t1
drop cascades to view alter2.v1
drop cascades to function alter2.plus1(integer)
*************** drop cascades to operator family alter2.
*** 2173,2178 ****
--- 2177,2183 ----
drop cascades to type alter2.ctype
drop cascades to function alter2.same(alter2.ctype,alter2.ctype)
drop cascades to operator alter2.=(alter2.ctype,alter2.ctype)
+ drop cascades to function alter2.hash(alter2.ctype)
drop cascades to conversion ascii_to_utf8
drop cascades to text search parser prs
drop cascades to text search configuration cfg
diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out
new file mode 100644
index d85bc83..d1a322d
*** a/src/test/regress/expected/oidjoins.out
--- b/src/test/regress/expected/oidjoins.out
*************** WHERE aggmtranstype != 0 AND
*** 73,206 ****
------+---------------
(0 rows)
- SELECT ctid, amkeytype
- FROM pg_catalog.pg_am fk
- WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
- ctid | amkeytype
- ------+-----------
- (0 rows)
-
- SELECT ctid, aminsert
- FROM pg_catalog.pg_am fk
- WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
- ctid | aminsert
- ------+----------
- (0 rows)
-
- SELECT ctid, ambeginscan
- FROM pg_catalog.pg_am fk
- WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
- ctid | ambeginscan
- ------+-------------
- (0 rows)
-
- SELECT ctid, amgettuple
- FROM pg_catalog.pg_am fk
- WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- ctid | amgettuple
- ------+------------
- (0 rows)
-
- SELECT ctid, amgetbitmap
- FROM pg_catalog.pg_am fk
- WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
- ctid | amgetbitmap
- ------+-------------
- (0 rows)
-
- SELECT ctid, amrescan
- FROM pg_catalog.pg_am fk
- WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
- ctid | amrescan
- ------+----------
- (0 rows)
-
- SELECT ctid, amendscan
- FROM pg_catalog.pg_am fk
- WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
- ctid | amendscan
- ------+-----------
- (0 rows)
-
- SELECT ctid, ammarkpos
- FROM pg_catalog.pg_am fk
- WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
- ctid | ammarkpos
- ------+-----------
- (0 rows)
-
- SELECT ctid, amrestrpos
- FROM pg_catalog.pg_am fk
- WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
- ctid | amrestrpos
- ------+------------
- (0 rows)
-
- SELECT ctid, ambuild
- FROM pg_catalog.pg_am fk
- WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
- ctid | ambuild
- ------+---------
- (0 rows)
-
- SELECT ctid, ambuildempty
- FROM pg_catalog.pg_am fk
- WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
- ctid | ambuildempty
- ------+--------------
- (0 rows)
-
- SELECT ctid, ambulkdelete
- FROM pg_catalog.pg_am fk
- WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
- ctid | ambulkdelete
- ------+--------------
- (0 rows)
-
- SELECT ctid, amvacuumcleanup
- FROM pg_catalog.pg_am fk
- WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
- ctid | amvacuumcleanup
- ------+-----------------
- (0 rows)
-
- SELECT ctid, amcanreturn
- FROM pg_catalog.pg_am fk
- WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
- ctid | amcanreturn
- ------+-------------
- (0 rows)
-
- SELECT ctid, amcostestimate
- FROM pg_catalog.pg_am fk
- WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
- ctid | amcostestimate
- ------+----------------
- (0 rows)
-
- SELECT ctid, amoptions
- FROM pg_catalog.pg_am fk
- WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
- ctid | amoptions
- ------+-----------
- (0 rows)
-
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 73,78 ----
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
new file mode 100644
index df29fe5..708d84c
*** a/src/test/regress/expected/opr_sanity.out
--- b/src/test/regress/expected/opr_sanity.out
*************** WHERE p1.oid != p2.oid AND
*** 1479,1484 ****
--- 1479,1490 ----
-----+-----
(0 rows)
+ -- Ask access methods to validate opclasses
+ SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid);
+ oid
+ -----
+ (0 rows)
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
SELECT p1.amopfamily, p1.amopstrategy
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 1524,1572 ****
------------+--------------
(0 rows)
- -- check for ordering operators not supported by parent AM
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
- amopfamily | amopopr | oid | amname
- ------------+---------+-----+--------
- (0 rows)
-
- -- Cross-check amopstrategy index against parent AM
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
- amopfamily | amopopr | oid | amname
- ------------+---------+-----+--------
- (0 rows)
-
- -- Detect missing pg_amop entries: should have as many strategy operators
- -- as AM expects for each datatype combination supported by the opfamily.
- -- We can't check this for AMs with variable strategy sets.
- SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
- amname | amoplefttype | amoprighttype
- --------+--------------+---------------
- (0 rows)
-
- -- Currently, none of the AMs with fixed strategy sets support ordering ops.
- SELECT p1.amname, p2.amopfamily, p2.amopstrategy
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
- amname | amopfamily | amopstrategy
- --------+------------+--------------
- (0 rows)
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
--- 1530,1535 ----
*************** WHERE p1.amprocfamily = 0 OR p1.amprocle
*** 1849,1863 ****
--------------+-----------
(0 rows)
- -- Cross-check amprocnum index against parent AM
- SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
- FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
- WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
- amprocfamily | amprocnum | oid | amname
- --------------+-----------+-----+--------
- (0 rows)
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
SELECT * FROM (
--- 1812,1817 ----
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
new file mode 100644
index 3ef55d9..0c784e1
*** a/src/test/regress/sql/alter_table.sql
--- b/src/test/regress/sql/alter_table.sql
*************** as 'select $1.f1 is not distinct from $2
*** 1448,1455 ****
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
--- 1448,1459 ----
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
+ create function alter1.hash(alter1.ctype) returns int4 language sql
+ as 'select hashint4($1.f1) # hashtext($1.f2)';
+
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype),
! function 1 alter1.hash(alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
*************** alter operator class alter1.ctype_hash_o
*** 1469,1474 ****
--- 1473,1479 ----
alter operator family alter1.ctype_hash_ops using hash set schema alter2;
alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
+ alter function alter1.hash(alter1.ctype) set schema alter2;
alter type alter1.ctype set schema alter2;
alter conversion alter1.ascii_to_utf8 set schema alter2;
alter text search parser alter1.prs set schema alter2;
diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql
new file mode 100644
index 2fa628d..ca419fd
*** a/src/test/regress/sql/oidjoins.sql
--- b/src/test/regress/sql/oidjoins.sql
*************** SELECT ctid, aggmtranstype
*** 37,106 ****
FROM pg_catalog.pg_aggregate fk
WHERE aggmtranstype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
- SELECT ctid, amkeytype
- FROM pg_catalog.pg_am fk
- WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
- SELECT ctid, aminsert
- FROM pg_catalog.pg_am fk
- WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
- SELECT ctid, ambeginscan
- FROM pg_catalog.pg_am fk
- WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
- SELECT ctid, amgettuple
- FROM pg_catalog.pg_am fk
- WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- SELECT ctid, amgetbitmap
- FROM pg_catalog.pg_am fk
- WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
- SELECT ctid, amrescan
- FROM pg_catalog.pg_am fk
- WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
- SELECT ctid, amendscan
- FROM pg_catalog.pg_am fk
- WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
- SELECT ctid, ammarkpos
- FROM pg_catalog.pg_am fk
- WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
- SELECT ctid, amrestrpos
- FROM pg_catalog.pg_am fk
- WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
- SELECT ctid, ambuild
- FROM pg_catalog.pg_am fk
- WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
- SELECT ctid, ambuildempty
- FROM pg_catalog.pg_am fk
- WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
- SELECT ctid, ambulkdelete
- FROM pg_catalog.pg_am fk
- WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
- SELECT ctid, amvacuumcleanup
- FROM pg_catalog.pg_am fk
- WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
- SELECT ctid, amcanreturn
- FROM pg_catalog.pg_am fk
- WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
- SELECT ctid, amcostestimate
- FROM pg_catalog.pg_am fk
- WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
- SELECT ctid, amoptions
- FROM pg_catalog.pg_am fk
- WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 37,42 ----
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
new file mode 100644
index c9bdd77..0e0506e
*** a/src/test/regress/sql/opr_sanity.sql
--- b/src/test/regress/sql/opr_sanity.sql
*************** WHERE p1.oid != p2.oid AND
*** 960,965 ****
--- 960,969 ----
p1.opcmethod = p2.opcmethod AND p1.opcintype = p2.opcintype AND
p1.opcdefault AND p2.opcdefault;
+ -- Ask access methods to validate opclasses
+
+ SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid);
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 995,1035 ****
(SELECT 1 from pg_opfamily op WHERE op.oid = p1.amopsortfamily
AND op.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree'));
- -- check for ordering operators not supported by parent AM
-
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
-
- -- Cross-check amopstrategy index against parent AM
-
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
-
- -- Detect missing pg_amop entries: should have as many strategy operators
- -- as AM expects for each datatype combination supported by the opfamily.
- -- We can't check this for AMs with variable strategy sets.
-
- SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
-
- -- Currently, none of the AMs with fixed strategy sets support ordering ops.
-
- SELECT p1.amname, p2.amopfamily, p2.amopstrategy
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
--- 999,1004 ----
*************** FROM pg_amproc as p1
*** 1176,1188 ****
WHERE p1.amprocfamily = 0 OR p1.amproclefttype = 0 OR p1.amprocrighttype = 0
OR p1.amprocnum < 1 OR p1.amproc = 0;
- -- Cross-check amprocnum index against parent AM
-
- SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
- FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
- WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
--- 1145,1150 ----
On Fri, Sep 11, 2015 at 4:22 PM, Alexander Korotkov <
a.korotkov@postgrespro.ru> wrote:
On Mon, Sep 7, 2015 at 9:17 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
On 2015-09-04 16:26, Alexander Korotkov wrote:
Attached patch is implementing this. It doesn't pretend to be fully
correct implementation, but it should be enough for proof the concept.
In this patch access method exposes another function: amvalidate. It
takes data structure representing opclass and throws error if it finds
it invalid.
This method is used on new opclass definition (alter operator family
etc. are not yet implemented but planned). Also, there is SQL function
validate_opclass(oid) which is used in regression tests.
Any thoughts?This is starting to look good.
However I don't like the naming differences between validate_opclass and
amvalidate. If you expect that the current amvalidate will only be used for
opclass validation then it should be renamed accordingly.validate_opclass was renamed to amvalidate.
Also GetIndexAmRoutine should check the return type of the amhandler.
Fixed.
See the attached patch.
Whhat I don't understand from this thread if we should wait 2ndQuadrant
for their sequence and column AMs or just start to work on committing it ?
Alvaro, where are you ?
Show quoted text
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-09-14 14:34, Oleg Bartunov wrote:
Whhat I don't understand from this thread if we should wait 2ndQuadrant
for their sequence and column AMs or just start to work on committing it
? Alvaro, where are you ?
I don't see problems with this patch from the sequence am perspective.
The next AM type will need to add code for different AM types but that's
mostly it.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
validate_opclass was renamed to amvalidate.
It seems to me, that amvalidate method of AM should get as argument only Oid of
operator family. Layout and meaning of amproc/amop fields are differ for
different AM and there isn't an AM which implements all possible features.
Actually, I'm a bit confused with follow piece of code (ginvalidate, for instance):
foreach(l, opclass->procedures)
{
...
if (proc->lefttype != opclass->intype
|| proc->righttype != opclass->intype)
continue;
...
That is amproc could contain a row, which connected to some operator class but
this fact will be missed this check and may be, never used or used wrongly.
Despite these observations, I think that this work is needed.
--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Sep 16, 2015 at 8:44 PM, Teodor Sigaev <teodor@sigaev.ru> wrote:
validate_opclass was renamed to amvalidate.
It seems to me, that amvalidate method of AM should get as argument only
Oid of operator family. Layout and meaning of amproc/amop fields are differ
for different AM and there isn't an AM which implements all possible
features.Actually, I'm a bit confused with follow piece of code (ginvalidate, for
instance):
foreach(l, opclass->procedures)
{
...
if (proc->lefttype != opclass->intype
|| proc->righttype != opclass->intype)
continue;
...That is amproc could contain a row, which connected to some operator class
but this fact will be missed this check and may be, never used or used
wrongly.Despite these observations, I think that this work is needed.
After, further personal discussion with Teodor, we decided that amvalidate
is out of scope for this patch.
It's not evident what should we validate in amvalidate and which way. I
think if we need amvalidate it should be subject of separate patch.
The attached patch exposes index access method parameters to SQL using
following fucntions:
* get_am_param_oid(oid, text)
* get_am_param_int(oid, text)
* get_am_param_bool(oid, text)
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Attachments:
aminterface-5.patchapplication/octet-stream; name=aminterface-5.patchDownload
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
new file mode 100644
index 99337b0..0442bd4
*** 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 d817eba..978d2dc
*** a/src/backend/access/common/reloptions.c
--- b/src/backend/access/common/reloptions.c
*************** untransformRelOptions(Datum options)
*** 891,897 ****
* 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;
--- 891,897 ----
* 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
*** 1379,1412 ****
* 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);
}
/*
--- 1379,1393 ----
* 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 49e9185..92701b9
*** 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 53bccf6..6e15049
*** 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 void gistfinishsplit(GISTInsertSt
*** 38,43 ****
--- 40,87 ----
GISTSTATE *giststate, List *splitinfo, bool releasebuf);
static void gistvacuumpage(Relation rel, Page page, Buffer buffer);
+ /*
+ * 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)
*** 70,79 ****
/*
* 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 */
--- 114,122 ----
/*
* gistbuildempty() -- build an empty gist index in the initialization fork
*/
! void
! gistbuildempty(Relation index)
{
Buffer buffer;
/* Initialize the root page */
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 89,96 ****
/* Unlock and release the buffer */
UnlockReleaseBuffer(buffer);
-
- PG_RETURN_VOID();
}
/*
--- 132,137 ----
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 99,116 ****
* 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;
--- 140,150 ----
* 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)
*** 136,142 ****
MemoryContextSwitchTo(oldCxt);
freeGISTstate(giststate);
! PG_RETURN_BOOL(false);
}
--- 170,176 ----
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 ce8e582..1adf92f
*** a/src/backend/access/gist/gistget.c
--- b/src/backend/access/gist/gistget.c
*************** getNextNearest(IndexScanDesc scan)
*** 618,628 ****
/*
* 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)
--- 618,626 ----
/*
* 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)
*** 651,657 ****
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! PG_RETURN_BOOL(getNextNearest(scan));
}
else
{
--- 649,655 ----
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! return getNextNearest(scan);
}
else
{
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 688,694 ****
so->curPageData++;
! PG_RETURN_BOOL(true);
}
/*
--- 686,692 ----
so->curPageData++;
! return true;
}
/*
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 726,732 ****
item = getNextGISTSearchItem(so);
if (!item)
! PG_RETURN_BOOL(false);
CHECK_FOR_INTERRUPTS();
--- 724,730 ----
item = getNextGISTSearchItem(so);
if (!item)
! return false;
CHECK_FOR_INTERRUPTS();
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 750,766 ****
/*
* 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);
--- 748,762 ----
/*
* 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)
*** 791,797 ****
pfree(item);
}
! PG_RETURN_INT64(ntids);
}
/*
--- 787,793 ----
pfree(item);
}
! return ntids;
}
/*
*************** gistgetbitmap(PG_FUNCTION_ARGS)
*** 799,812 ****
*
* 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);
}
--- 795,805 ----
*
* 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 a17c5bc..22f0c68
*** 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)
*** 107,121 ****
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;
--- 104,116 ----
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)
*** 314,341 ****
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;
/*
--- 309,331 ----
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)
*** 343,348 ****
* as well as the queueCxt if there is a separate context for it.
*/
freeGISTstate(so->giststate);
-
- PG_RETURN_VOID();
}
--- 333,336 ----
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 a0b0eeb..e0ce620
*** 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)
*** 276,280 ****
vacuum_delay_point();
}
! PG_RETURN_POINTER(stats);
}
--- 271,275 ----
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/genam.c b/src/backend/access/index/genam.c
new file mode 100644
index aa5b28c..1ec5631
*** a/src/backend/access/index/genam.c
--- b/src/backend/access/index/genam.c
*************** systable_endscan_ordered(SysScanDesc sys
*** 613,615 ****
--- 613,713 ----
UnregisterSnapshot(sysscan->snapshot);
pfree(sysscan);
}
+
+ /*
+ * Get oid parameter of access method.
+ */
+ Datum
+ get_am_param_oid(PG_FUNCTION_ARGS)
+ {
+ Oid amoid = PG_GETARG_OID(0);
+ text *param = PG_GETARG_TEXT_PP(1);
+ char *param_name;
+ IndexAmRoutine *routine;
+
+ routine = GetIndexAmRoutine(amoid);
+ param_name = text_to_cstring(param);
+
+ if (!strcmp(param_name, "amkeytype"))
+ PG_RETURN_OID(routine->amkeytype);
+
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid index access method oid parameter: \"%s\"",
+ param_name)));
+
+ pg_unreachable();
+ }
+
+ /*
+ * Get integer parameter of access method.
+ */
+ Datum
+ get_am_param_int(PG_FUNCTION_ARGS)
+ {
+ Oid amoid = PG_GETARG_OID(0);
+ text *param = PG_GETARG_TEXT_PP(1);
+ char *param_name;
+ IndexAmRoutine *routine;
+
+ routine = GetIndexAmRoutine(amoid);
+ param_name = text_to_cstring(param);
+
+ if (!strcmp(param_name, "amstrategies"))
+ PG_RETURN_OID(routine->amstrategies);
+ else if (!strcmp(param_name, "amsupport"))
+ PG_RETURN_OID(routine->amsupport);
+
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid index access method integer parameter: \"%s\"",
+ param_name)));
+
+ pg_unreachable();
+ }
+
+
+ /*
+ * Get boolean parameter of access method.
+ */
+ Datum
+ get_am_param_bool(PG_FUNCTION_ARGS)
+ {
+ Oid amoid = PG_GETARG_OID(0);
+ text *param = PG_GETARG_TEXT_PP(1);
+ char *param_name;
+ IndexAmRoutine *routine;
+
+ routine = GetIndexAmRoutine(amoid);
+ param_name = text_to_cstring(param);
+
+ if (!strcmp(param_name, "amcanorder"))
+ PG_RETURN_OID(routine->amcanorder);
+ else if (!strcmp(param_name, "amcanorderbyop"))
+ PG_RETURN_OID(routine->amcanorderbyop);
+ else if (!strcmp(param_name, "amcanbackward"))
+ PG_RETURN_OID(routine->amcanbackward);
+ else if (!strcmp(param_name, "amcanunique"))
+ PG_RETURN_OID(routine->amcanunique);
+ else if (!strcmp(param_name, "amcanmulticol"))
+ PG_RETURN_OID(routine->amcanmulticol);
+ else if (!strcmp(param_name, "amoptionalkey"))
+ PG_RETURN_OID(routine->amoptionalkey);
+ else if (!strcmp(param_name, "amsearcharray"))
+ PG_RETURN_OID(routine->amsearcharray);
+ else if (!strcmp(param_name, "amsearchnulls"))
+ PG_RETURN_OID(routine->amsearchnulls);
+ else if (!strcmp(param_name, "amstorage"))
+ PG_RETURN_OID(routine->amstorage);
+ else if (!strcmp(param_name, "amclusterable"))
+ PG_RETURN_OID(routine->amclusterable);
+ else if (!strcmp(param_name, "ampredlocks"))
+ PG_RETURN_OID(routine->ampredlocks);
+
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid index access method boolean parameter: \"%s\"",
+ param_name)));
+
+ pg_unreachable();
+ }
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 <unistd.h>
+ #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/opclasscmds.c b/src/backend/commands/opclasscmds.c
new file mode 100644
index 3375f10..a8208b3
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 334,346 ****
ListCell *l;
Relation rel;
HeapTuple tup;
- Form_pg_am pg_am;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
--- 334,346 ----
ListCell *l;
Relation rel;
HeapTuple tup;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
+ IndexAmRoutine *amroutine;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 361,373 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
! amstorage = pg_am->amstorage;
/* XXX Should we make any privilege check against the AM? */
--- 361,373 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! amroutine = GetIndexAmRoutine(amoid);
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
! amstorage = amroutine->amstorage;
/* XXX Should we make any privilege check against the AM? */
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 776,782 ****
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! Form_pg_am pg_am;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
--- 776,782 ----
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! IndexAmRoutine *amroutine;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 787,798 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
/* XXX Should we make any privilege check against the AM? */
--- 787,798 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! amroutine = GetIndexAmRoutine(amoid);
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
/* XXX Should we make any privilege check against the AM? */
*************** assignOperTypes(OpFamilyMember *member,
*** 1099,1119 ****
* the family has been created but not yet populated with the required
* operators.)
*/
! HeapTuple amtup;
! Form_pg_am pg_am;
! amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
! if (amtup == NULL)
! elog(ERROR, "cache lookup failed for access method %u", amoid);
! pg_am = (Form_pg_am) GETSTRUCT(amtup);
! if (!pg_am->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! NameStr(pg_am->amname))));
!
! ReleaseSysCache(amtup);
}
else
{
--- 1099,1113 ----
* the family has been created but not yet populated with the required
* operators.)
*/
! IndexAmRoutine *amroutine;
! amroutine = GetIndexAmRoutine(amoid);
! if (!amroutine->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! get_am_name(amoid))));
}
else
{
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 d107d76..6853899
*** 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 <unistd.h>
#include <fcntl.h>
+ #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 9c3d096..9febc95
*** a/src/backend/utils/cache/relcache.c
--- b/src/backend/utils/cache/relcache.c
*************** 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
--- 445,451 ----
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
*** 1160,1172 ****
}
/*
* 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;
--- 1160,1217 ----
}
/*
+ * Get IndexAmRoutine structure from access method oid.
+ */
+ IndexAmRoutine *
+ GetIndexAmRoutine(Oid amoid)
+ {
+ IndexAmRoutine *result;
+ HeapTuple tuple;
+ regproc amhandler;
+
+ tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for access method %u",
+ amoid);
+ amhandler = ((Form_pg_am)GETSTRUCT(tuple))->amhandler;
+
+ if (!RegProcedureIsValid(amhandler))
+ elog(ERROR, "invalid %u regproc", amhandler);
+
+ result = (IndexAmRoutine *)DatumGetPointer(OidFunctionCall0(amhandler));
+
+ if (result == NULL || !IsA(result, IndexAmRoutine))
+ elog(ERROR, "index access method handler function %u did not return an IndexAmRoutine struct",
+ amhandler);
+
+ ReleaseSysCache(tuple);
+
+ return result;
+ }
+
+ /*
+ * Initialize IndexAmRoutine for relation.
+ */
+ void
+ InitIndexAmRoutine(Relation relation)
+ {
+ IndexAmRoutine *result, *tmp;
+
+ result = (IndexAmRoutine *)MemoryContextAlloc(CacheMemoryContext,
+ sizeof(IndexAmRoutine));
+ tmp = (IndexAmRoutine *)DatumGetPointer(
+ OidFunctionCall0(relation->rd_am->amhandler));
+ memcpy(result, tmp, sizeof(IndexAmRoutine));
+ relation->amroutine = result;
+ }
+
+ /*
* Initialize index-access-method support data for an index relation
*/
void
RelationInitIndexAccessInfo(Relation relation)
{
HeapTuple tuple;
Datum indcollDatum;
Datum indclassDatum;
Datum indoptionDatum;
*************** RelationInitIndexAccessInfo(Relation rel
*** 1178,1183 ****
--- 1223,1229 ----
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
*** 1202,1217 ****
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
--- 1248,1265 ----
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)
*** 4743,4749 ****
Oid *opfamily;
Oid *opcintype;
RegProcedure *support;
- int nsupport;
int16 *indoption;
Oid *indcollation;
--- 4791,4796 ----
*************** load_relcache_init_file(bool shared)
*** 4771,4776 ****
--- 4818,4824 ----
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)
*** 4832,4843 ****
rel->rd_indoption = indoption;
/* 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
{
--- 4880,4892 ----
rel->rd_indoption = indoption;
+ InitIndexAmRoutine(rel);
+
/* set up zeroed fmgr-info vectors */
rel->rd_aminfo = (RelationAmInfo *)
MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
rel->rd_supportinfo = (FmgrInfo *)
! MemoryContextAllocZero(indexcxt, relform->relnatts * rel->amroutine->amsupport * sizeof(FmgrInfo));
}
else
{
*************** write_relcache_init_file(bool shared)
*** 5106,5112 ****
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
--- 5155,5161 ----
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (rel->amroutine->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h
new file mode 100644
index ...4b6dda2
*** a/src/include/access/amapi.h
--- b/src/include/access/amapi.h
***************
*** 0 ****
--- 1,164 ----
+ /*-------------------------------------------------------------------------
+ *
+ * amapi.h
+ * API for access methods
+ *
+ * Copyright (c) 2015, PostgreSQL Global Development Group
+ *
+ * src/include/access/amapi.h
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef AMAPI_H
+ #define AMAPI_H
+
+ #include "access/genam.h"
+ #include "catalog/opfam_internal.h"
+ #include "nodes/relation.h"
+
+ /*
+ * Callback function signatures --- see indexam.sgml for more info.
+ */
+
+ /* "insert this tuple" function */
+ typedef bool
+ (*aminsert_function) (Relation indexRelation,
+ Datum *values,
+ bool *isnull,
+ ItemPointer heap_tid,
+ Relation heapRelation,
+ IndexUniqueCheck checkUnique);
+
+ /* "prepare for index scan" function */
+ typedef IndexScanDesc
+ (*ambeginscan_function) (Relation indexRelation,
+ int nkeys,
+ int norderbys);
+
+ /* "next valid tuple" function, or NULL */
+ typedef bool
+ (*amgettuple_function) (IndexScanDesc scan,
+ ScanDirection direction);
+
+ /* "fetch all valid tuples" function, or NULL */
+ typedef int64
+ (*amgetbitmap_function) (IndexScanDesc scan,
+ TIDBitmap *tbm);
+
+ /* "(re)start index scan" function */
+ typedef void
+ (*amrescan_function) (IndexScanDesc scan,
+ ScanKey keys,
+ int nkeys,
+ ScanKey orderbys,
+ int norderbys);
+
+ /* "end index scan" function */
+ typedef void
+ (*amendscan_function) (IndexScanDesc scan);
+
+ /* "mark current scan position" function */
+ typedef void
+ (*ammarkpos_function) (IndexScanDesc scan);
+
+ /* "restore marked scan position" function */
+ typedef void
+ (*amrestrpos_function) (IndexScanDesc scan);
+
+ /* "build new index" function */
+ typedef IndexBuildResult *
+ (*ambuild_function) (Relation heapRelation,
+ Relation indexRelation,
+ IndexInfo *indexInfo);
+
+ /* "build empty index" function */
+ typedef void
+ (*ambuildempty_function) (Relation indexRelation);
+
+ /* bulk-delete function */
+ typedef IndexBulkDeleteResult *
+ (*ambulkdelete_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+
+ /* post-VACUUM cleanup function */
+ typedef IndexBulkDeleteResult *
+ (*amvacuumcleanup_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
+
+ /* can indexscan return IndexTuples? */
+ typedef bool
+ (*amcanreturn_function) (Relation indexRelation, int attno);
+
+ /* estimate cost of an indexscan */
+ typedef void
+ (*amcostestimate_function) (PlannerInfo *root,
+ IndexPath *path,
+ double loop_count,
+ Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+
+ /* parse AM-specific parameters */
+ typedef bytea *
+ (*amoptions_function) (Datum reloptions,
+ bool validate);
+
+
+ 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..5ae5722
*** 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,51 ----
/*
* prototypes for functions in brin.c (external entry points for BRIN)
*/
! extern Datum brinhandler(PG_FUNCTION_ARGS);
! extern void brinvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *brinbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void brinbuildempty(Relation index);
! extern bool brininsert(Relation idxRel, Datum *values, bool *nulls,
! ItemPointer heaptid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys);
! extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
! ScanKey orderbys, int norderbys);
! extern void brinendscan(IndexScanDesc scan);
! extern void brinmarkpos(IndexScanDesc scan);
! extern void brinrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *brinbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *brinvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern void brincostestimate(PlannerInfo *root, IndexPath *path,
! double loop_count, Cost *indexStartupCost,
! Cost *indexTotalCost,
! Selectivity *indexSelectivity,
! double *indexCorrelation);
! extern bytea *brinoptions(Datum reloptions, bool validate);
/*
* Storage type for BRIN's reloptions
diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h
new file mode 100644
index 6be199e..2f8fe17
*** a/src/include/access/brin_internal.h
--- b/src/include/access/brin_internal.h
*************** typedef struct BrinDesc
*** 72,77 ****
--- 72,78 ----
#define BRIN_PROCNUM_CONSISTENT 3
#define BRIN_PROCNUM_UNION 4
/* procedure numbers up to 10 are reserved for BRIN future expansion */
+ #define BRIN_NPROC 15
#undef BRIN_DEBUG
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
new file mode 100644
index d9d05a0..15170b2
*** 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 ----
*************** extern HeapTuple systable_getnext_ordere
*** 190,193 ****
--- 189,199 ----
ScanDirection direction);
extern void systable_endscan_ordered(SysScanDesc sysscan);
+ /*
+ * get attributes of access methods (in genam.c)
+ */
+ extern Datum get_am_param_oid(PG_FUNCTION_ARGS);
+ extern Datum get_am_param_int(PG_FUNCTION_ARGS);
+ extern Datum get_am_param_bool(PG_FUNCTION_ARGS);
+
#endif /* GENAM_H */
diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h
new file mode 100644
index acbe36a..3348436
*** 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,601 ----
/* ginutil.c */
! extern Datum ginhandler(PG_FUNCTION_ARGS);
! extern void ginvalidate(OpClassInfo *opclass);
! extern bytea *ginoptions(Datum reloptions, bool validate);
extern void initGinState(GinState *state, Relation index);
extern Buffer GinNewBuffer(Relation index);
extern void GinInitBuffer(Buffer b, uint32 f);
*************** 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,
--- 616,627 ----
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);
--- 872,899 ----
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 1a77982..35fb34a
*** 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
*** 426,434 ****
} 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);
--- 427,439 ----
} GiSTOptions;
/* gist.c */
! extern Datum gisthandler(PG_FUNCTION_ARGS);
! extern void gistvalidate(OpClassInfo *opclass);
! extern void gistbuildempty(Relation index);
! extern bool gistinsert(Relation r, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern bool gistcanreturn(Relation index, int attno);
extern MemoryContext createTempGistContext(void);
extern GISTSTATE *initGISTstate(Relation index);
extern void freeGISTstate(GISTSTATE *giststate);
*************** extern XLogRecPtr gistXLogSplit(RelFileN
*** 474,481 ****
Buffer leftchild, bool markfollowright);
/* gistget.c */
! extern Datum gistgettuple(PG_FUNCTION_ARGS);
! extern Datum gistgetbitmap(PG_FUNCTION_ARGS);
/* gistutil.c */
--- 479,486 ----
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
*** 485,491 ****
#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);
--- 490,496 ----
#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 *
*** 534,541 ****
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,
--- 539,550 ----
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
*** 544,550 ****
int attno);
/* gistbuild.c */
! extern Datum gistbuild(PG_FUNCTION_ARGS);
extern void gistValidateBufferingOption(char *value);
/* gistbuildbuffers.c */
--- 553,560 ----
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..9595c6b
*** 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,271 ----
/* public routines */
! extern Datum hashhandler(PG_FUNCTION_ARGS);
! extern void hashvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *hashbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void hashbuildempty(Relation index);
! extern bool hashinsert(Relation rel, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc hashbeginscan(Relation rel, int nkeys, int norderbys);
! extern bool hashgettuple(IndexScanDesc scan, ScanDirection dir);
! extern int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void hashrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
! ScanKey orderbys, int norderbys);
! extern void hashendscan(IndexScanDesc scan);
! extern void hashmarkpos(IndexScanDesc scan);
! extern void hashrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *hashbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *hashvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern bytea *hashoptions(Datum reloptions, bool validate);
/*
* Datatype-specific hash functions in hashfunc.c.
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
new file mode 100644
index 9e48efd..4fab0a3
*** 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,683 ----
/*
* prototypes for functions in nbtree.c (external entry points for btree)
*/
! extern Datum bthandler(PG_FUNCTION_ARGS);
! extern void btvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *btbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void btbuildempty(Relation index);
! extern bool btinsert(Relation rel, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc btbeginscan(Relation indexRelation,
! int nkeys, int norderbys);
! extern bool btgettuple(IndexScanDesc scan, ScanDirection dir);
! extern int64 btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void btrescan(IndexScanDesc scan, ScanKey keys, int nkeys,
! ScanKey orderbys, int norderbys);
! extern void btendscan(IndexScanDesc scan);
! extern void btmarkpos(IndexScanDesc scan);
! extern void btrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *btbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *btvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern bool btcanreturn(Relation index, int attno);
! extern bytea *btoptions(Datum reloptions, bool validate);
/*
* prototypes for functions in nbtinsert.c
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
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..ba2c1c1
*** 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,212 ----
} spgLeafConsistentOut;
+ /* spgutils.c */
+ extern Datum spghandler(PG_FUNCTION_ARGS);
+ extern void spgvalidate(OpClassInfo *opclass);
+
/* 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/opfam_internal.h b/src/include/catalog/opfam_internal.h
new file mode 100644
index 32195a7..5cc0208
*** a/src/include/catalog/opfam_internal.h
--- b/src/include/catalog/opfam_internal.h
*************** typedef struct
*** 25,28 ****
--- 25,40 ----
Oid sortfamily; /* ordering operator's sort opfamily, or 0 */
} OpFamilyMember;
+ /*
+ * Opclass data for validation by access method.
+ */
+ typedef struct
+ {
+ Oid intype; /* input datatype */
+ Oid keytype; /* key datatype */
+ List *procedures; /* list of OpFamilyMember */
+ List *operators; /* list of OpFamilyMember */
+ } OpClassInfo;
+
+
#endif /* OPFAM_INTERNAL_H */
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
new file mode 100644
index 8a28b8e..f19a873
*** 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,40 ----
CATALOG(pg_am,2601)
{
NameData amname; /* access method name */
! regproc amhandler; /* handler function */
} 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
--- 48,78 ----
* compiler constants for pg_am
* ----------------
*/
! #define Natts_pg_am 2
#define Anum_pg_am_amname 1
! #define Anum_pg_am_amhandler 2
/* ----------------
* initial contents of pg_am
* ----------------
*/
! DATA(insert OID = 403 ( btree bthandler ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
! DATA(insert OID = 405 ( hash hashhandler ));
DESCR("hash index access method");
#define HASH_AM_OID 405
! DATA(insert OID = 783 ( gist gisthandler ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
! DATA(insert OID = 2742 ( gin ginhandler ));
DESCR("GIN index access method");
#define GIN_AM_OID 2742
! DATA(insert OID = 4000 ( spgist spghandler ));
DESCR("SP-GiST index access method");
#define SPGIST_AM_OID 4000
! DATA(insert OID = 3580 ( brin brinhandler ));
DESCR("block range index (BRIN) access method");
#define BRIN_AM_OID 3580
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index eb55b3a..9fe43d6
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DESCR("convert int4 to float4");
*** 547,609 ****
DATA(insert OID = 319 ( int4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "700" _null_ _null_ _null_ _null_ _null_ ftoi4 _null_ _null_ _null_ ));
DESCR("convert float4 to int4");
- DATA(insert OID = 330 ( btgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgettuple _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 636 ( btgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgetbitmap _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 331 ( btinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btinsert _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 333 ( btbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbeginscan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 334 ( btrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btrescan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 335 ( btendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btendscan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 336 ( btmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btmarkpos _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 337 ( btrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btrestrpos _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 338 ( btbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbuild _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 328 ( btbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btbuildempty _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 332 ( btbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbulkdelete _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ btvacuumcleanup _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 276 ( btcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ btcanreturn _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 1268 ( btcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btcostestimate _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 2785 ( btoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ btoptions _null_ _null_ _null_ ));
- DESCR("btree(internal)");
-
- DATA(insert OID = 3789 ( bringetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ bringetbitmap _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3790 ( brininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brininsert _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3791 ( brinbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbeginscan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3792 ( brinrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinrescan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3793 ( brinendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinendscan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3794 ( brinmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinmarkpos _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3795 ( brinrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinrestrpos _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3796 ( brinbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbuild _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3797 ( brinbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinbuildempty _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3798 ( brinbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbulkdelete _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3799 ( brinvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ brinvacuumcleanup _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3800 ( brincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brincostestimate _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3801 ( brinoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ brinoptions _null_ _null_ _null_ ));
- DESCR("brin(internal)");
DATA(insert OID = 3952 ( brin_summarize_new_values PGNSP PGUID 12 1 0 0 0 f f f f f f v s 1 0 23 "2205" _null_ _null_ _null_ _null_ _null_ brin_summarize_new_values _null_ _null_ _null_ ));
DESCR("brin: standalone scan new table pages");
--- 547,552 ----
*************** DESCR("convert name to char(n)");
*** 694,728 ****
DATA(insert OID = 409 ( name PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 19 "1042" _null_ _null_ _null_ _null_ _null_ bpchar_name _null_ _null_ _null_ ));
DESCR("convert char(n) to name");
- DATA(insert OID = 440 ( hashgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgettuple _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 637 ( hashgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgetbitmap _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 441 ( hashinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashinsert _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 443 ( hashbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbeginscan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 444 ( hashrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashrescan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 445 ( hashendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashendscan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 446 ( hashmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashmarkpos _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 447 ( hashrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashrestrpos _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 448 ( hashbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbuild _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 327 ( hashbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashbuildempty _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 442 ( hashbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbulkdelete _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashvacuumcleanup _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 438 ( hashcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashcostestimate _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 2786 ( hashoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ hashoptions _null_ _null_ _null_ ));
- DESCR("hash(internal)");
-
DATA(insert OID = 449 ( hashint2 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "21" _null_ _null_ _null_ _null_ _null_ hashint2 _null_ _null_ _null_ ));
DESCR("hash");
DATA(insert OID = 450 ( hashint4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ hashint4 _null_ _null_ _null_ ));
--- 637,642 ----
*************** DESCR("larger of two");
*** 978,1014 ****
DATA(insert OID = 771 ( int2smaller PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2smaller _null_ _null_ _null_ ));
DESCR("smaller of two");
- DATA(insert OID = 774 ( gistgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgettuple _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 638 ( gistgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgetbitmap _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 775 ( gistinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistinsert _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 777 ( gistbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbeginscan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 778 ( gistrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistrescan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 779 ( gistendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistendscan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 780 ( gistmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistmarkpos _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 781 ( gistrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistrestrpos _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 782 ( gistbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbuild _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 326 ( gistbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistbuildempty _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 776 ( gistbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbulkdelete _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistvacuumcleanup _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 3280 ( gistcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ gistcanreturn _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 772 ( gistcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistcostestimate _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 2787 ( gistoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ gistoptions _null_ _null_ _null_ ));
- DESCR("gist(internal)");
-
DATA(insert OID = 784 ( tintervaleq PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervaleq _null_ _null_ _null_ ));
DATA(insert OID = 785 ( tintervalne PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervalne _null_ _null_ _null_ ));
DATA(insert OID = 786 ( tintervallt PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervallt _null_ _null_ _null_ ));
--- 892,897 ----
*************** DATA(insert OID = 3311 ( tsm_handler_in
*** 3740,3745 ****
--- 3623,3632 ----
DESCR("I/O");
DATA(insert OID = 3312 ( tsm_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "3310" _null_ _null_ _null_ _null_ _null_ tsm_handler_out _null_ _null_ _null_ ));
DESCR("I/O");
+ DATA(insert OID = 326 ( index_am_handler_in PGNSP PGUID 12 1 0 0 0 f f f f f f i s 1 0 325 "2275" _null_ _null_ _null_ _null_ _null_ index_am_handler_in _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 327 ( index_am_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "325" _null_ _null_ _null_ _null_ _null_ index_am_handler_out _null_ _null_ _null_ ));
+ DESCR("I/O");
/* tablesample method handlers */
DATA(insert OID = 3313 ( bernoulli PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 3310 "2281" _null_ _null_ _null_ _null_ _null_ tsm_bernoulli_handler _null_ _null_ _null_ ));
*************** DESCR("GiST support");
*** 4196,4229 ****
DATA(insert OID = 3288 ( gist_bbox_distance PGNSP PGUID 12 1 0 0 0 f f f f t f i s 4 0 701 "2281 600 23 26" _null_ _null_ _null_ _null_ _null_ gist_bbox_distance _null_ _null_ _null_ ));
DESCR("GiST support");
- /* GIN */
- DATA(insert OID = 2731 ( gingetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gingetbitmap _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2732 ( gininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gininsert _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2733 ( ginbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbeginscan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2734 ( ginrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginrescan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2735 ( ginendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginendscan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2736 ( ginmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginmarkpos _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2737 ( ginrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginrestrpos _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2738 ( ginbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbuild _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 325 ( ginbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginbuildempty _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2739 ( ginbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbulkdelete _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ ginvacuumcleanup _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2741 ( gincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gincostestimate _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2788 ( ginoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ ginoptions _null_ _null_ _null_ ));
- DESCR("gin(internal)");
-
/* GIN array support */
DATA(insert OID = 2743 ( ginarrayextract PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 2281 "2277 2281 2281" _null_ _null_ _null_ _null_ _null_ ginarrayextract _null_ _null_ _null_ ));
DESCR("GIN array support");
--- 4083,4088 ----
*************** DESCR("construct timestamp with time zon
*** 5119,5156 ****
DATA(insert OID = 3464 ( make_interval PGNSP PGUID 12 1 0 0 0 f f f f t f i s 7 0 1186 "23 23 23 23 23 23 701" _null_ _null_ "{years,months,weeks,days,hours,mins,secs}" _null_ _null_ make_interval _null_ _null_ _null_ ));
DESCR("construct interval");
- /* spgist support functions */
- DATA(insert OID = 4001 ( spggettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggettuple _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4002 ( spggetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggetbitmap _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4003 ( spginsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spginsert _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4004 ( spgbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbeginscan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4005 ( spgrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgrescan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4006 ( spgendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgendscan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4007 ( spgmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgmarkpos _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4008 ( spgrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgrestrpos _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4009 ( spgbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbuild _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4010 ( spgbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgbuildempty _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4011 ( spgbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbulkdelete _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4012 ( spgvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ spgvacuumcleanup _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4032 ( spgcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ spgcanreturn _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4013 ( spgcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgcostestimate _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4014 ( spgoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ spgoptions _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
-
/* spgist opclasses */
DATA(insert OID = 4018 ( spg_quad_config PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_quad_config _null_ _null_ _null_ ));
DESCR("SP-GiST support for quad tree over point");
--- 4978,4983 ----
*************** DESCR("get an individual replication ori
*** 5333,5338 ****
--- 5160,5188 ----
DATA(insert OID = 6014 ( pg_show_replication_origin_status PGNSP PGUID 12 1 100 0 0 f f f f f t v r 0 0 2249 "" "{26,25,3220,3220}" "{o,o,o,o}" "{local_id, external_id, remote_lsn, local_lsn}" _null_ _null_ pg_show_replication_origin_status _null_ _null_ _null_ ));
DESCR("get progress for all replication origins");
+ /* access methods handlers */
+ DATA(insert OID = 330 ( bthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ bthandler _null_ _null_ _null_ ));
+ DESCR("btree handler");
+ DATA(insert OID = 331 ( hashhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ hashhandler _null_ _null_ _null_ ));
+ DESCR("hash handler");
+ DATA(insert OID = 332 ( gisthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ gisthandler _null_ _null_ _null_ ));
+ DESCR("gist handler");
+ DATA(insert OID = 333 ( ginhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ ginhandler _null_ _null_ _null_ ));
+ DESCR("gin handler");
+ DATA(insert OID = 334 ( spghandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ spghandler _null_ _null_ _null_ ));
+ DESCR("spgist handler");
+ DATA(insert OID = 335 ( brinhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ brinhandler _null_ _null_ _null_ ));
+ DESCR("brin handler");
+
+ /* functions to get access methods parameters */
+ DATA(insert OID = 336 ( get_am_param_oid PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 26 "26 25" _null_ _null_ _null_ _null_ _null_ get_am_param_oid _null_ _null_ _null_ ));
+ DESCR("get am parameter as oid");
+ DATA(insert OID = 337 ( get_am_param_int PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "26 25" _null_ _null_ _null_ _null_ _null_ get_am_param_int _null_ _null_ _null_ ));
+ DESCR("get am parameter as integer");
+ DATA(insert OID = 338 ( get_am_param_bool PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 16 "26 25" _null_ _null_ _null_ _null_ _null_ get_am_param_bool _null_ _null_ _null_ ));
+ DESCR("get am parameter as boolean");
+
+
/*
* 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/commands/defrem.h b/src/include/commands/defrem.h
new file mode 100644
index adae296..d8b9649
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
*************** extern Oid get_am_oid(const char *amname
*** 95,100 ****
--- 95,101 ----
extern char *get_am_name(Oid amOid);
extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+ extern Datum amvalidate(PG_FUNCTION_ARGS);
/* commands/tsearchcmds.c */
extern ObjectAddress DefineTSParser(List *names, List *parameters);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
new file mode 100644
index 4ae2f3e..be4a1e2
*** 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 274480e..9a5ff45
*** a/src/include/nodes/nodes.h
--- b/src/include/nodes/nodes.h
*************** typedef enum NodeTag
*** 452,458 ****
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;
/*
--- 452,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 */
! 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 79bed33..7427900
*** 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
*** 546,553 ****
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 */
--- 547,553 ----
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
*** 558,569 ****
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;
--- 558,569 ----
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
*** 817,823 ****
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! typedef struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
--- 817,823 ----
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
*************** typedef struct IndexPath
*** 829,835 ****
ScanDirection indexscandir;
Cost indextotalcost;
Selectivity indexselectivity;
! } IndexPath;
/*
* BitmapHeapPath represents one or more indexscans that generate TID bitmaps
--- 829,835 ----
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..c200068
*** a/src/test/regress/expected/oidjoins.out
--- b/src/test/regress/expected/oidjoins.out
*************** WHERE aggmtranstype != 0 AND
*** 73,204 ****
------+---------------
(0 rows)
! SELECT ctid, amkeytype
! FROM pg_catalog.pg_am fk
! WHERE amkeytype != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
! ctid | amkeytype
! ------+-----------
! (0 rows)
!
! SELECT ctid, aminsert
! FROM pg_catalog.pg_am fk
! WHERE aminsert != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
! ctid | aminsert
! ------+----------
! (0 rows)
!
! SELECT ctid, ambeginscan
! FROM pg_catalog.pg_am fk
! WHERE ambeginscan != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
! ctid | ambeginscan
! ------+-------------
! (0 rows)
!
! SELECT ctid, amgettuple
! FROM pg_catalog.pg_am fk
! WHERE amgettuple != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
! ctid | amgettuple
! ------+------------
! (0 rows)
!
! SELECT ctid, amgetbitmap
! FROM pg_catalog.pg_am fk
! WHERE amgetbitmap != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
! ctid | amgetbitmap
! ------+-------------
! (0 rows)
!
! SELECT ctid, amrescan
! FROM pg_catalog.pg_am fk
! WHERE amrescan != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
! ctid | amrescan
! ------+----------
! (0 rows)
!
! SELECT ctid, amendscan
! FROM pg_catalog.pg_am fk
! WHERE amendscan != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
! ctid | amendscan
! ------+-----------
! (0 rows)
!
! SELECT ctid, ammarkpos
! FROM pg_catalog.pg_am fk
! WHERE ammarkpos != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
! ctid | ammarkpos
! ------+-----------
! (0 rows)
!
! SELECT ctid, amrestrpos
! FROM pg_catalog.pg_am fk
! WHERE amrestrpos != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
! ctid | amrestrpos
! ------+------------
! (0 rows)
!
! SELECT ctid, ambuild
! FROM pg_catalog.pg_am fk
! WHERE ambuild != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
! ctid | ambuild
! ------+---------
! (0 rows)
!
! SELECT ctid, ambuildempty
! FROM pg_catalog.pg_am fk
! WHERE ambuildempty != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
! ctid | ambuildempty
! ------+--------------
! (0 rows)
!
! SELECT ctid, ambulkdelete
! FROM pg_catalog.pg_am fk
! WHERE ambulkdelete != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
! ctid | ambulkdelete
! ------+--------------
! (0 rows)
!
! SELECT ctid, amvacuumcleanup
! FROM pg_catalog.pg_am fk
! WHERE amvacuumcleanup != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
! ctid | amvacuumcleanup
! ------+-----------------
! (0 rows)
!
! SELECT ctid, amcanreturn
! FROM pg_catalog.pg_am fk
! WHERE amcanreturn != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
! ctid | amcanreturn
! ------+-------------
! (0 rows)
!
! SELECT ctid, amcostestimate
! FROM pg_catalog.pg_am fk
! WHERE amcostestimate != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
! ctid | amcostestimate
! ------+----------------
! (0 rows)
!
! SELECT ctid, amoptions
! FROM pg_catalog.pg_am fk
! WHERE amoptions != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
! ctid | amoptions
! ------+-----------
(0 rows)
SELECT ctid, amopfamily
--- 73,84 ----
------+---------------
(0 rows)
! SELECT ctid, proc
! FROM (SELECT ctid, get_am_param_oid(oid, 'amkeytype') proc FROM pg_catalog.pg_am) fk
! WHERE fk.proc != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.proc);
! ctid | proc
! ------+------
(0 rows)
SELECT ctid, amopfamily
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
new file mode 100644
index df29fe5..7b7bef6
*** a/src/test/regress/expected/opr_sanity.out
--- b/src/test/regress/expected/opr_sanity.out
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 1528,1534 ****
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
! p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
amopfamily | amopopr | oid | amname
------------+---------+-----+--------
(0 rows)
--- 1528,1534 ----
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
! p1.amoppurpose = 'o' AND NOT get_am_param_bool(p2.oid, 'amcanorderbyop');
amopfamily | amopopr | oid | amname
------------+---------+-----+--------
(0 rows)
*************** WHERE p1.amopmethod = p2.oid AND
*** 1537,1543 ****
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
! p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
amopfamily | amopopr | oid | amname
------------+---------+-----+--------
(0 rows)
--- 1537,1544 ----
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
! p1.amopstrategy > get_am_param_int(p2.oid, 'amstrategies') AND
! get_am_param_int(p2.oid, 'amstrategies') <> 0;
amopfamily | amopopr | oid | amname
------------+---------+-----+--------
(0 rows)
*************** WHERE p1.amopmethod = p2.oid AND
*** 1548,1555 ****
SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
! p1.amstrategies <> 0 AND
! p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
WHERE p3.amopfamily = p2.amopfamily AND
p3.amoplefttype = p2.amoplefttype AND
p3.amoprighttype = p2.amoprighttype AND
--- 1549,1557 ----
SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
! get_am_param_int(p1.oid, 'amstrategies') <> 0 AND
! get_am_param_int(p1.oid, 'amstrategies') !=
! (SELECT count(*) FROM pg_amop AS p3
WHERE p3.amopfamily = p2.amopfamily AND
p3.amoplefttype = p2.amoplefttype AND
p3.amoprighttype = p2.amoprighttype AND
*************** WHERE p2.amopmethod = p1.oid AND
*** 1562,1568 ****
SELECT p1.amname, p2.amopfamily, p2.amopstrategy
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
! p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
amname | amopfamily | amopstrategy
--------+------------+--------------
(0 rows)
--- 1564,1570 ----
SELECT p1.amname, p2.amopfamily, p2.amopstrategy
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
! get_am_param_int(p1.oid, 'amstrategies') <> 0 AND p2.amoppurpose <> 's';
amname | amopfamily | amopstrategy
--------+------------+--------------
(0 rows)
*************** WHERE p1.amprocfamily = 0 OR p1.amprocle
*** 1853,1859 ****
SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
! p1.amprocnum > p2.amsupport;
amprocfamily | amprocnum | oid | amname
--------------+-----------+-----+--------
(0 rows)
--- 1855,1861 ----
SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
! p1.amprocnum > get_am_param_int(p2.oid, 'amsupport');
amprocfamily | amprocnum | oid | amname
--------------+-----------+-----+--------
(0 rows)
diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql
new file mode 100644
index 2fa628d..8e62f76
*** a/src/test/regress/sql/oidjoins.sql
--- b/src/test/regress/sql/oidjoins.sql
*************** SELECT ctid, aggmtranstype
*** 37,106 ****
FROM pg_catalog.pg_aggregate fk
WHERE aggmtranstype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
! SELECT ctid, amkeytype
! FROM pg_catalog.pg_am fk
! WHERE amkeytype != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
! SELECT ctid, aminsert
! FROM pg_catalog.pg_am fk
! WHERE aminsert != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
! SELECT ctid, ambeginscan
! FROM pg_catalog.pg_am fk
! WHERE ambeginscan != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
! SELECT ctid, amgettuple
! FROM pg_catalog.pg_am fk
! WHERE amgettuple != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
! SELECT ctid, amgetbitmap
! FROM pg_catalog.pg_am fk
! WHERE amgetbitmap != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
! SELECT ctid, amrescan
! FROM pg_catalog.pg_am fk
! WHERE amrescan != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
! SELECT ctid, amendscan
! FROM pg_catalog.pg_am fk
! WHERE amendscan != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
! SELECT ctid, ammarkpos
! FROM pg_catalog.pg_am fk
! WHERE ammarkpos != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
! SELECT ctid, amrestrpos
! FROM pg_catalog.pg_am fk
! WHERE amrestrpos != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
! SELECT ctid, ambuild
! FROM pg_catalog.pg_am fk
! WHERE ambuild != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
! SELECT ctid, ambuildempty
! FROM pg_catalog.pg_am fk
! WHERE ambuildempty != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
! SELECT ctid, ambulkdelete
! FROM pg_catalog.pg_am fk
! WHERE ambulkdelete != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
! SELECT ctid, amvacuumcleanup
! FROM pg_catalog.pg_am fk
! WHERE amvacuumcleanup != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
! SELECT ctid, amcanreturn
! FROM pg_catalog.pg_am fk
! WHERE amcanreturn != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
! SELECT ctid, amcostestimate
! FROM pg_catalog.pg_am fk
! WHERE amcostestimate != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
! SELECT ctid, amoptions
! FROM pg_catalog.pg_am fk
! WHERE amoptions != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 37,46 ----
FROM pg_catalog.pg_aggregate fk
WHERE aggmtranstype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
! SELECT ctid, proc
! FROM (SELECT ctid, get_am_param_oid(oid, 'amkeytype') proc FROM pg_catalog.pg_am) fk
! WHERE fk.proc != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.proc);
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
new file mode 100644
index c9bdd77..90e10e0
*** a/src/test/regress/sql/opr_sanity.sql
--- b/src/test/regress/sql/opr_sanity.sql
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 1000,1013 ****
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
! p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
-- Cross-check amopstrategy index against parent AM
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
! p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
-- Detect missing pg_amop entries: should have as many strategy operators
-- as AM expects for each datatype combination supported by the opfamily.
--- 1000,1014 ----
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
! p1.amoppurpose = 'o' AND NOT get_am_param_bool(p2.oid, 'amcanorderbyop');
-- Cross-check amopstrategy index against parent AM
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
! p1.amopstrategy > get_am_param_int(p2.oid, 'amstrategies') AND
! get_am_param_int(p2.oid, 'amstrategies') <> 0;
-- Detect missing pg_amop entries: should have as many strategy operators
-- as AM expects for each datatype combination supported by the opfamily.
*************** WHERE p1.amopmethod = p2.oid AND
*** 1016,1023 ****
SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
! p1.amstrategies <> 0 AND
! p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
WHERE p3.amopfamily = p2.amopfamily AND
p3.amoplefttype = p2.amoplefttype AND
p3.amoprighttype = p2.amoprighttype AND
--- 1017,1025 ----
SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
! get_am_param_int(p1.oid, 'amstrategies') <> 0 AND
! get_am_param_int(p1.oid, 'amstrategies') !=
! (SELECT count(*) FROM pg_amop AS p3
WHERE p3.amopfamily = p2.amopfamily AND
p3.amoplefttype = p2.amoplefttype AND
p3.amoprighttype = p2.amoprighttype AND
*************** WHERE p2.amopmethod = p1.oid AND
*** 1028,1034 ****
SELECT p1.amname, p2.amopfamily, p2.amopstrategy
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
! p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
--- 1030,1036 ----
SELECT p1.amname, p2.amopfamily, p2.amopstrategy
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
! get_am_param_int(p1.oid, 'amstrategies') <> 0 AND p2.amoppurpose <> 's';
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
*************** WHERE p1.amprocfamily = 0 OR p1.amprocle
*** 1181,1187 ****
SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
! p1.amprocnum > p2.amsupport;
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
--- 1183,1189 ----
SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
! p1.amprocnum > get_am_param_int(p2.oid, 'amsupport');
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
On 2015-09-18 14:58, Alexander Korotkov wrote:
On Wed, Sep 16, 2015 at 8:44 PM, Teodor Sigaev <teodor@sigaev.ru
<mailto:teodor@sigaev.ru>> wrote:validate_opclass was renamed to amvalidate.
It seems to me, that amvalidate method of AM should get as argument
only Oid of operator family. Layout and meaning of amproc/amop
fields are differ for different AM and there isn't an AM which
implements all possible features.After, further personal discussion with Teodor, we decided that
amvalidate is out of scope for this patch.
It's not evident what should we validate in amvalidate and which way. I
think if we need amvalidate it should be subject of separate patch.
The attached patch exposes index access method parameters to SQL using
following fucntions:
* get_am_param_oid(oid, text)
* get_am_param_int(oid, text)
* get_am_param_bool(oid, text)
Hmm, we might want these functons in any case (although I think just one
function which would return all am params would be better).
But why is it not evident? We do the validations in regression tests,
even if we just copy those then it's enough for a start.
If you mean that it's not obvious what are all the possible things that
amvalidate should validate in the future, then yes, that will always be
the case though. I think better solution would be to provide more
granular validation interface in the C api (i.e. have amvalidateopclass
etc). We can still have just one SQL exposed function called amvalidate
which will call all those C interfaces that are supported by current
version (I agree that those interfaces like amvalidateopclass should
accept just Oid).
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sun, Sep 20, 2015 at 5:02 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
On 2015-09-18 14:58, Alexander Korotkov wrote:
On Wed, Sep 16, 2015 at 8:44 PM, Teodor Sigaev <teodor@sigaev.ru
<mailto:teodor@sigaev.ru>> wrote:validate_opclass was renamed to amvalidate.
It seems to me, that amvalidate method of AM should get as argument
only Oid of operator family. Layout and meaning of amproc/amop
fields are differ for different AM and there isn't an AM which
implements all possible features.After, further personal discussion with Teodor, we decided that
amvalidate is out of scope for this patch.
It's not evident what should we validate in amvalidate and which way. I
think if we need amvalidate it should be subject of separate patch.
The attached patch exposes index access method parameters to SQL using
following fucntions:
* get_am_param_oid(oid, text)
* get_am_param_int(oid, text)
* get_am_param_bool(oid, text)Hmm, we might want these functons in any case (although I think just one
function which would return all am params would be better).But why is it not evident? We do the validations in regression tests, even
if we just copy those then it's enough for a start
The reason is that those validations were used only in regression tests
yet. It wasn't used for user-defined operator classes. User might define
invalid opclass and then alter it to valid. Or user might upgrade opclass
in two steps where intermediate step is invalid. This is why I think
validating opclasses in CREATE/ALTER command is not evident since it
changes user visible behavior and compatibility.
Simultaneously, implementing new API function just for regression tests
doesn't seem to worth it for me.
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Petr Jelinek <petr@2ndquadrant.com> writes:
On 2015-09-18 14:58, Alexander Korotkov wrote:
After, further personal discussion with Teodor, we decided that
amvalidate is out of scope for this patch.
It's not evident what should we validate in amvalidate and which way. I
think if we need amvalidate it should be subject of separate patch.
But why is it not evident? We do the validations in regression tests,
even if we just copy those then it's enough for a start.
I think the main reason this question is in-scope for this patch is
precisely the problem of what do we do about the regression tests.
I'm not in favor of exposing some SQL-level functions whose sole purpose
is to support those regression test queries, because while those queries
are very useful for detecting errors in handmade opclasses, they're hacks,
and always have been. They don't work well (or at all, really) for
anything more than btree/hash cases. It'd be better to expose amvalidate
functions, even if we don't yet have full infrastructure for them.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-09-20 16:17, Alexander Korotkov wrote:
On Sun, Sep 20, 2015 at 5:02 PM, Petr Jelinek <petr@2ndquadrant.com
Hmm, we might want these functons in any case (although I think just
one function which would return all am params would be better).But why is it not evident? We do the validations in regression
tests, even if we just copy those then it's enough for a startThe reason is that those validations were used only in regression tests
yet. It wasn't used for user-defined operator classes. User might define
invalid opclass and then alter it to valid. Or user might upgrade
opclass in two steps where intermediate step is invalid. This is why I
think validating opclasses in CREATE/ALTER command is not evident since
it changes user visible behavior and compatibility.
Simultaneously, implementing new API function just for regression tests
doesn't seem to worth it for me.
I think it's ok to not do automatic validation during CREATE/ALTER just
yet. And I also think it's much worse to implement a SQL API which
exposes internals just for regression tests than having a C API just for
regression tests. The reason for moving AM to C API was to have less of
the internals exposed at SQL level afaik.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sun, Sep 20, 2015 at 5:18 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Petr Jelinek <petr@2ndquadrant.com> writes:
On 2015-09-18 14:58, Alexander Korotkov wrote:
After, further personal discussion with Teodor, we decided that
amvalidate is out of scope for this patch.
It's not evident what should we validate in amvalidate and which way. I
think if we need amvalidate it should be subject of separate patch.But why is it not evident? We do the validations in regression tests,
even if we just copy those then it's enough for a start.I think the main reason this question is in-scope for this patch is
precisely the problem of what do we do about the regression tests.I'm not in favor of exposing some SQL-level functions whose sole purpose
is to support those regression test queries, because while those queries
are very useful for detecting errors in handmade opclasses, they're hacks,
and always have been. They don't work well (or at all, really) for
anything more than btree/hash cases. It'd be better to expose amvalidate
functions, even if we don't yet have full infrastructure for them.
I'm OK about continuing work on amvalidate if we can build consuensus on
its design.
Could you give some feedback on amvalidate version of patch please?
/messages/by-id/CAPpHfds8ZyWenz9vW6tE5RZXboL1vU_wSW181vEq+mU+v1dsiw@mail.gmail.com
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
I'm OK about continuing work on amvalidate if we can build consuensus on its design.
Could you give some feedback on amvalidate version of patch please?
/messages/by-id/CAPpHfds8ZyWenz9vW6tE5RZXboL1vU_wSW181vEq+mU+v1dsiw@mail.gmail.com
In attach a bit modified patch based on 4-th version, and if there are no strong
objections, I will commit it. Waiting this patch stops Alexander's development
on CREATE ACCESS METHOD and he needs to move forward.
--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/
Attachments:
aminterface-6.patchtext/plain; charset=UTF-8; name=aminterface-6.patchDownload
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index 99337b0..40e4a48 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -35,6 +35,105 @@
/*
+ * BRIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+Datum
+brinhandler(PG_FUNCTION_ARGS)
+{
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 15;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = brininsert;
+ amroutine->ambeginscan = brinbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = bringetbitmap;
+ amroutine->amrescan = brinrescan;
+ amroutine->amendscan = brinendscan;
+ amroutine->ammarkpos = brinmarkpos;
+ amroutine->amrestrpos = brinrestrpos;
+ amroutine->ambuild = brinbuild;
+ amroutine->ambuildempty = brinbuildempty;
+ amroutine->ambulkdelete = brinbulkdelete;
+ amroutine->amvacuumcleanup = brinvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = brincostestimate;
+ amroutine->amoptions = brinoptions;
+ amroutine->amvalidate = brinvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+}
+
+void
+brinvalidate(OpClassInfo *opclass)
+{
+ ListCell *l;
+ bool procsPresent[BRIN_NPROC];
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype ||
+ proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > BRIN_NPROC)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid support number for BRIN: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u was defined more than once",
+ proc->number)));
+
+ procsPresent[proc->number - 1] = true;
+ }
+
+ /*
+ * Don't use BRIN_NPROC because some procnumbers
+ * are reserved for future use
+ */
+ for (i = 0; i < BRIN_PROCNUM_UNION; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN doesn't support order by operators")));
+ }
+}
+
+/*
* We use a BrinBuildState during initial construction of a BRIN index.
* The running state is kept in a BrinMemTuple.
*/
@@ -80,15 +179,11 @@ static void brin_vacuum_scan(Relation idxrel, BufferAccessStrategy strategy);
* If the range is not currently summarized (i.e. the revmap returns NULL for
* it), there's nothing to do.
*/
-Datum
-brininsert(PG_FUNCTION_ARGS)
+bool
+brininsert(Relation idxRel, Datum *values, bool *nulls,
+ ItemPointer heaptid, Relation heapRel,
+ IndexUniqueCheck checkUnique)
{
- Relation idxRel = (Relation) PG_GETARG_POINTER(0);
- Datum *values = (Datum *) PG_GETARG_POINTER(1);
- bool *nulls = (bool *) PG_GETARG_POINTER(2);
- ItemPointer heaptid = (ItemPointer) PG_GETARG_POINTER(3);
-
- /* we ignore the rest of our arguments */
BlockNumber pagesPerRange;
BrinDesc *bdesc = NULL;
BrinRevmap *revmap;
@@ -226,7 +321,7 @@ brininsert(PG_FUNCTION_ARGS)
MemoryContextDelete(tupcxt);
}
- return BoolGetDatum(false);
+ return false;
}
/*
@@ -236,12 +331,9 @@ brininsert(PG_FUNCTION_ARGS)
* index was built with. Note that since this cannot be changed while we're
* holding lock on index, it's not necessary to recompute it during brinrescan.
*/
-Datum
-brinbeginscan(PG_FUNCTION_ARGS)
+IndexScanDesc
+brinbeginscan(Relation r, int nkeys, int norderbys)
{
- Relation r = (Relation) PG_GETARG_POINTER(0);
- int nkeys = PG_GETARG_INT32(1);
- int norderbys = PG_GETARG_INT32(2);
IndexScanDesc scan;
BrinOpaque *opaque;
@@ -252,7 +344,7 @@ brinbeginscan(PG_FUNCTION_ARGS)
opaque->bo_bdesc = brin_build_desc(r);
scan->opaque = opaque;
- PG_RETURN_POINTER(scan);
+ return scan;
}
/*
@@ -267,11 +359,9 @@ brinbeginscan(PG_FUNCTION_ARGS)
* unsummarized. Pages in those ranges need to be returned regardless of scan
* keys.
*/
-Datum
-bringetbitmap(PG_FUNCTION_ARGS)
+int64
+bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
Relation idxRel = scan->indexRelation;
Buffer buf = InvalidBuffer;
BrinDesc *bdesc;
@@ -451,20 +541,16 @@ bringetbitmap(PG_FUNCTION_ARGS)
* returns, but we don't have a precise idea of the number of heap tuples
* involved.
*/
- PG_RETURN_INT64(totalpages * 10);
+ return totalpages * 10;
}
/*
* Re-initialize state for a BRIN index scan
*/
-Datum
-brinrescan(PG_FUNCTION_ARGS)
+void
+brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
+ ScanKey orderbys, int norderbys)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
-
- /* other arguments ignored */
-
/*
* Other index AMs preprocess the scan keys at this point, or sometime
* early during the scan; this lets them optimize by removing redundant
@@ -476,38 +562,31 @@ brinrescan(PG_FUNCTION_ARGS)
if (scankey && scan->numberOfKeys > 0)
memmove(scan->keyData, scankey,
scan->numberOfKeys * sizeof(ScanKeyData));
-
- PG_RETURN_VOID();
}
/*
* Close down a BRIN index scan
*/
-Datum
-brinendscan(PG_FUNCTION_ARGS)
+void
+brinendscan(IndexScanDesc scan)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
BrinOpaque *opaque = (BrinOpaque *) scan->opaque;
brinRevmapTerminate(opaque->bo_rmAccess);
brin_free_desc(opaque->bo_bdesc);
pfree(opaque);
-
- PG_RETURN_VOID();
}
-Datum
-brinmarkpos(PG_FUNCTION_ARGS)
+void
+brinmarkpos(IndexScanDesc scan)
{
elog(ERROR, "BRIN does not support mark/restore");
- PG_RETURN_VOID();
}
-Datum
-brinrestrpos(PG_FUNCTION_ARGS)
+void
+brinrestrpos(IndexScanDesc scan)
{
elog(ERROR, "BRIN does not support mark/restore");
- PG_RETURN_VOID();
}
/*
@@ -579,12 +658,9 @@ brinbuildCallback(Relation index,
/*
* brinbuild() -- build a new BRIN index.
*/
-Datum
-brinbuild(PG_FUNCTION_ARGS)
+IndexBuildResult *
+brinbuild(Relation heap, Relation index, IndexInfo *indexInfo)
{
- Relation heap = (Relation) PG_GETARG_POINTER(0);
- Relation index = (Relation) PG_GETARG_POINTER(1);
- IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
IndexBuildResult *result;
double reltuples;
double idxtuples;
@@ -663,13 +739,12 @@ brinbuild(PG_FUNCTION_ARGS)
result->heap_tuples = reltuples;
result->index_tuples = idxtuples;
- PG_RETURN_POINTER(result);
+ return result;
}
-Datum
-brinbuildempty(PG_FUNCTION_ARGS)
+void
+brinbuildempty(Relation index)
{
- Relation index = (Relation) PG_GETARG_POINTER(0);
Buffer metabuf;
/* An empty BRIN index has a metapage only. */
@@ -686,8 +761,6 @@ brinbuildempty(PG_FUNCTION_ARGS)
END_CRIT_SECTION();
UnlockReleaseBuffer(metabuf);
-
- PG_RETURN_VOID();
}
/*
@@ -699,35 +772,29 @@ brinbuildempty(PG_FUNCTION_ARGS)
* tuple is deleted), meaning the need to re-run summarization on the affected
* range. Would need to add an extra flag in brintuples for that.
*/
-Datum
-brinbulkdelete(PG_FUNCTION_ARGS)
+IndexBulkDeleteResult *
+brinbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback, void *callback_state)
{
- /* other arguments are not currently used */
- IndexBulkDeleteResult *stats =
- (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
-
/* allocate stats if first time through, else re-use existing struct */
if (stats == NULL)
stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
- PG_RETURN_POINTER(stats);
+ return stats;
}
/*
* This routine is in charge of "vacuuming" a BRIN index: we just summarize
* ranges that are currently unsummarized.
*/
-Datum
-brinvacuumcleanup(PG_FUNCTION_ARGS)
+IndexBulkDeleteResult *
+brinvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
{
- IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
- IndexBulkDeleteResult *stats =
- (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
Relation heapRel;
/* No-op in ANALYZE ONLY mode */
if (info->analyze_only)
- PG_RETURN_POINTER(stats);
+ return stats;
if (!stats)
stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
@@ -744,17 +811,15 @@ brinvacuumcleanup(PG_FUNCTION_ARGS)
heap_close(heapRel, AccessShareLock);
- PG_RETURN_POINTER(stats);
+ return stats;
}
/*
* reloptions processor for BRIN indexes
*/
-Datum
-brinoptions(PG_FUNCTION_ARGS)
+bytea *
+brinoptions(Datum reloptions, bool validate)
{
- Datum reloptions = PG_GETARG_DATUM(0);
- bool validate = PG_GETARG_BOOL(1);
relopt_value *options;
BrinOptions *rdopts;
int numoptions;
@@ -767,7 +832,7 @@ brinoptions(PG_FUNCTION_ARGS)
/* if none set, we're done */
if (numoptions == 0)
- PG_RETURN_NULL();
+ return NULL;
rdopts = allocateReloptStruct(sizeof(BrinOptions), options, numoptions);
@@ -776,7 +841,7 @@ brinoptions(PG_FUNCTION_ARGS)
pfree(options);
- PG_RETURN_BYTEA_P(rdopts);
+ return (bytea *)rdopts;
}
/*
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index d817eba..978d2dc 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -891,7 +891,7 @@ untransformRelOptions(Datum options)
* in the case of the tuple corresponding to an index, or InvalidOid otherwise.
*/
bytea *
-extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, Oid amoptions)
+extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, amoptions_function amoptions)
{
bytea *options;
bool isnull;
@@ -1379,34 +1379,15 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
* validate error flag
*/
bytea *
-index_reloptions(RegProcedure amoptions, Datum reloptions, bool validate)
+index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
{
- FmgrInfo flinfo;
- FunctionCallInfoData fcinfo;
- Datum result;
-
- Assert(RegProcedureIsValid(amoptions));
+ Assert(amoptions);
/* Assume function is strict */
if (!PointerIsValid(DatumGetPointer(reloptions)))
return NULL;
- /* Can't use OidFunctionCallN because we might get a NULL result */
- fmgr_info(amoptions, &flinfo);
-
- InitFunctionCallInfoData(fcinfo, &flinfo, 2, InvalidOid, NULL, NULL);
-
- fcinfo.arg[0] = reloptions;
- fcinfo.arg[1] = BoolGetDatum(validate);
- fcinfo.argnull[0] = false;
- fcinfo.argnull[1] = false;
-
- result = FunctionCallInvoke(&fcinfo);
-
- if (fcinfo.isnull || DatumGetPointer(result) == NULL)
- return NULL;
-
- return DatumGetByteaP(result);
+ return amoptions(reloptions, validate);
}
/*
diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c
index 54b2db8..29b22d6 100644
--- a/src/backend/access/gin/ginget.c
+++ b/src/backend/access/gin/ginget.c
@@ -1772,11 +1772,9 @@ scanPendingInsert(IndexScanDesc scan, TIDBitmap *tbm, int64 *ntids)
#define GinIsVoidRes(s) ( ((GinScanOpaque) scan->opaque)->isVoidRes )
-Datum
-gingetbitmap(PG_FUNCTION_ARGS)
+int64
+gingetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
GinScanOpaque so = (GinScanOpaque) scan->opaque;
int64 ntids;
ItemPointerData iptr;
@@ -1827,5 +1825,5 @@ gingetbitmap(PG_FUNCTION_ARGS)
ntids++;
}
- PG_RETURN_INT64(ntids);
+ return ntids;
}
diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c
index 49e9185..92701b9 100644
--- a/src/backend/access/gin/gininsert.c
+++ b/src/backend/access/gin/gininsert.c
@@ -306,12 +306,9 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
MemoryContextSwitchTo(oldCtx);
}
-Datum
-ginbuild(PG_FUNCTION_ARGS)
+IndexBuildResult *
+ginbuild(Relation heap, Relation index, IndexInfo *indexInfo)
{
- Relation heap = (Relation) PG_GETARG_POINTER(0);
- Relation index = (Relation) PG_GETARG_POINTER(1);
- IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
IndexBuildResult *result;
double reltuples;
GinBuildState buildstate;
@@ -429,16 +426,15 @@ ginbuild(PG_FUNCTION_ARGS)
result->heap_tuples = reltuples;
result->index_tuples = buildstate.indtuples;
- PG_RETURN_POINTER(result);
+ return result;
}
/*
* ginbuildempty() -- build an empty gin index in the initialization fork
*/
-Datum
-ginbuildempty(PG_FUNCTION_ARGS)
+void
+ginbuildempty(Relation index)
{
- Relation index = (Relation) PG_GETARG_POINTER(0);
Buffer RootBuffer,
MetaBuffer;
@@ -463,8 +459,6 @@ ginbuildempty(PG_FUNCTION_ARGS)
/* Unlock and release the buffers. */
UnlockReleaseBuffer(MetaBuffer);
UnlockReleaseBuffer(RootBuffer);
-
- PG_RETURN_VOID();
}
/*
@@ -489,18 +483,11 @@ ginHeapTupleInsert(GinState *ginstate, OffsetNumber attnum,
item, 1, NULL);
}
-Datum
-gininsert(PG_FUNCTION_ARGS)
+bool
+gininsert(Relation index, Datum *values, bool *isnull,
+ ItemPointer ht_ctid, Relation heapRel,
+ IndexUniqueCheck checkUnique)
{
- Relation index = (Relation) PG_GETARG_POINTER(0);
- Datum *values = (Datum *) PG_GETARG_POINTER(1);
- bool *isnull = (bool *) PG_GETARG_POINTER(2);
- ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
-
-#ifdef NOT_USED
- Relation heapRel = (Relation) PG_GETARG_POINTER(4);
- IndexUniqueCheck checkUnique = (IndexUniqueCheck) PG_GETARG_INT32(5);
-#endif
GinState ginstate;
MemoryContext oldCtx;
MemoryContext insertCtx;
@@ -541,5 +528,5 @@ gininsert(PG_FUNCTION_ARGS)
MemoryContextSwitchTo(oldCtx);
MemoryContextDelete(insertCtx);
- PG_RETURN_BOOL(false);
+ return false;
}
diff --git a/src/backend/access/gin/ginscan.c b/src/backend/access/gin/ginscan.c
index ac3a92b..d97a9db 100644
--- a/src/backend/access/gin/ginscan.c
+++ b/src/backend/access/gin/ginscan.c
@@ -21,12 +21,9 @@
#include "utils/rel.h"
-Datum
-ginbeginscan(PG_FUNCTION_ARGS)
+IndexScanDesc
+ginbeginscan(Relation rel, int nkeys, int norderbys)
{
- Relation rel = (Relation) PG_GETARG_POINTER(0);
- int nkeys = PG_GETARG_INT32(1);
- int norderbys = PG_GETARG_INT32(2);
IndexScanDesc scan;
GinScanOpaque so;
@@ -53,7 +50,7 @@ ginbeginscan(PG_FUNCTION_ARGS)
scan->opaque = so;
- PG_RETURN_POINTER(scan);
+ return scan;
}
/*
@@ -417,13 +414,10 @@ ginNewScanKey(IndexScanDesc scan)
pgstat_count_index_scan(scan->indexRelation);
}
-Datum
-ginrescan(PG_FUNCTION_ARGS)
+void
+ginrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
+ ScanKey orderbys, int norderbys)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
-
- /* remaining arguments are ignored */
GinScanOpaque so = (GinScanOpaque) scan->opaque;
ginFreeScanKeys(so);
@@ -433,15 +427,12 @@ ginrescan(PG_FUNCTION_ARGS)
memmove(scan->keyData, scankey,
scan->numberOfKeys * sizeof(ScanKeyData));
}
-
- PG_RETURN_VOID();
}
-Datum
-ginendscan(PG_FUNCTION_ARGS)
+void
+ginendscan(IndexScanDesc scan)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
GinScanOpaque so = (GinScanOpaque) scan->opaque;
ginFreeScanKeys(so);
@@ -450,20 +441,16 @@ ginendscan(PG_FUNCTION_ARGS)
MemoryContextDelete(so->keyCtx);
pfree(so);
-
- PG_RETURN_VOID();
}
-Datum
-ginmarkpos(PG_FUNCTION_ARGS)
+void
+ginmarkpos(IndexScanDesc scan)
{
elog(ERROR, "GIN does not support mark/restore");
- PG_RETURN_VOID();
}
-Datum
-ginrestrpos(PG_FUNCTION_ARGS)
+void
+ginrestrpos(IndexScanDesc scan)
{
elog(ERROR, "GIN does not support mark/restore");
- PG_RETURN_VOID();
}
diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c
index cb4e32f..91a194f 100644
--- a/src/backend/access/gin/ginutil.c
+++ b/src/backend/access/gin/ginutil.c
@@ -22,9 +22,121 @@
#include "miscadmin.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
+#include "utils/selfuncs.h"
/*
+ * GIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+Datum
+ginhandler(PG_FUNCTION_ARGS)
+{
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 6;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = gininsert;
+ amroutine->ambeginscan = ginbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = gingetbitmap;
+ amroutine->amrescan = ginrescan;
+ amroutine->amendscan = ginendscan;
+ amroutine->ammarkpos = ginmarkpos;
+ amroutine->amrestrpos = ginrestrpos;
+ amroutine->ambuild = ginbuild;
+ amroutine->ambuildempty = ginbuildempty;
+ amroutine->ambulkdelete = ginbulkdelete;
+ amroutine->amvacuumcleanup = ginvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = gincostestimate;
+ amroutine->amoptions = ginoptions;
+ amroutine->amvalidate = ginvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+}
+
+void
+ginvalidate(OpClassInfo *opclass)
+{
+ ListCell *l;
+ bool procsPresent[GINNProcs];
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype ||
+ proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > GINNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid support number for GIN: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u was defined more than once",
+ proc->number)));
+
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < GINNProcs; i++)
+ {
+ if (i+1 == GIN_COMPARE_PARTIAL_PROC)
+ continue; /* optional method */
+ if (i+1 == GIN_CONSISTENT_PROC || i+1 == GIN_TRICONSISTENT_PROC)
+ continue; /* don't need to have both, see check below loop */
+
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u is required", i + 1)));
+ }
+
+ if (!procsPresent[GIN_CONSISTENT_PROC - 1]
+ && !procsPresent[GIN_TRICONSISTENT_PROC - 1])
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("At least one of consistent support (number %u) "
+ "and triconsistent cupport (number %u) is "
+ "is required",
+ GIN_CONSISTENT_PROC, GIN_TRICONSISTENT_PROC)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN doesn't support order by operators")));
+ }
+}
+
+/*
* initGinState: fill in an empty GinState struct to describe the index
*
* Note: assorted subsidiary data is allocated in the CurrentMemoryContext.
@@ -516,11 +628,9 @@ ginExtractEntries(GinState *ginstate, OffsetNumber attnum,
return entries;
}
-Datum
-ginoptions(PG_FUNCTION_ARGS)
+bytea *
+ginoptions(Datum reloptions, bool validate)
{
- Datum reloptions = PG_GETARG_DATUM(0);
- bool validate = PG_GETARG_BOOL(1);
relopt_value *options;
GinOptions *rdopts;
int numoptions;
@@ -535,7 +645,7 @@ ginoptions(PG_FUNCTION_ARGS)
/* if none set, we're done */
if (numoptions == 0)
- PG_RETURN_NULL();
+ return NULL;
rdopts = allocateReloptStruct(sizeof(GinOptions), options, numoptions);
@@ -544,7 +654,7 @@ ginoptions(PG_FUNCTION_ARGS)
pfree(options);
- PG_RETURN_BYTEA_P(rdopts);
+ return (bytea *)rdopts;
}
/*
diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c
index 323cfb0..5b38607 100644
--- a/src/backend/access/gin/ginvacuum.c
+++ b/src/backend/access/gin/ginvacuum.c
@@ -513,13 +513,10 @@ ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint3
return (tmppage == origpage) ? NULL : tmppage;
}
-Datum
-ginbulkdelete(PG_FUNCTION_ARGS)
+IndexBulkDeleteResult *
+ginbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback, void *callback_state)
{
- IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
- IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
- IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
- void *callback_state = (void *) PG_GETARG_POINTER(3);
Relation index = info->index;
BlockNumber blkno = GIN_ROOT_BLKNO;
GinVacuumState gvs;
@@ -634,14 +631,12 @@ ginbulkdelete(PG_FUNCTION_ARGS)
MemoryContextDelete(gvs.tmpCxt);
- PG_RETURN_POINTER(gvs.result);
+ return gvs.result;
}
-Datum
-ginvacuumcleanup(PG_FUNCTION_ARGS)
+IndexBulkDeleteResult *
+ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
{
- IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
- IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
Relation index = info->index;
bool needLock;
BlockNumber npages,
@@ -661,7 +656,7 @@ ginvacuumcleanup(PG_FUNCTION_ARGS)
initGinState(&ginstate, index);
ginInsertCleanup(&ginstate, true, true, stats);
}
- PG_RETURN_POINTER(stats);
+ return stats;
}
/*
@@ -746,5 +741,5 @@ ginvacuumcleanup(PG_FUNCTION_ARGS)
if (needLock)
UnlockRelationForExtension(index, ExclusiveLock);
- PG_RETURN_POINTER(stats);
+ return stats;
}
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 53bccf6..817b8be 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -16,6 +16,7 @@
#include "access/genam.h"
#include "access/gist_private.h"
+#include "access/gistscan.h"
#include "access/xloginsert.h"
#include "catalog/index.h"
#include "catalog/pg_collation.h"
@@ -24,6 +25,7 @@
#include "storage/indexfsm.h"
#include "utils/memutils.h"
#include "utils/rel.h"
+#include "utils/selfuncs.h"
/* non-export function prototypes */
static void gistfixsplit(GISTInsertState *state, GISTSTATE *giststate);
@@ -38,6 +40,104 @@ static void gistfinishsplit(GISTInsertState *state, GISTInsertStack *stack,
GISTSTATE *giststate, List *splitinfo, bool releasebuf);
static void gistvacuumpage(Relation rel, Page page, Buffer buffer);
+/*
+ * GiST handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+Datum
+gisthandler(PG_FUNCTION_ARGS)
+{
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 9;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = true;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = true;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = gistinsert;
+ amroutine->ambeginscan = gistbeginscan;
+ amroutine->amgettuple = gistgettuple;
+ amroutine->amgetbitmap = gistgetbitmap;
+ amroutine->amrescan = gistrescan;
+ amroutine->amendscan = gistendscan;
+ amroutine->ammarkpos = gistmarkpos;
+ amroutine->amrestrpos = gistrestrpos;
+ amroutine->ambuild = gistbuild;
+ amroutine->ambuildempty = gistbuildempty;
+ amroutine->ambulkdelete = gistbulkdelete;
+ amroutine->amvacuumcleanup = gistvacuumcleanup;
+ amroutine->amcanreturn = gistcanreturn;
+ amroutine->amcostestimate = gistcostestimate;
+ amroutine->amoptions = gistoptions;
+ amroutine->amvalidate = gistvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+}
+
+void
+gistvalidate(OpClassInfo *opclass)
+{
+ ListCell *l;
+ bool procsPresent[GISTNProcs];
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype ||
+ proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > GISTNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid support number for GiST: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u was defined more than once",
+ proc->number)));
+
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < GISTNProcs; i++)
+ {
+ if (i+1 == GIST_DISTANCE_PROC || i+1 == GIST_FETCH_PROC)
+ continue; /* optional methods */
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily)
+ && !procsPresent[GIST_DISTANCE_PROC - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST distance support function %u is required "
+ "for order by operators", GIST_DISTANCE_PROC)));
+ }
+}
#define ROTATEDIST(d) do { \
SplitedPageLayout *tmp=(SplitedPageLayout*)palloc(sizeof(SplitedPageLayout)); \
@@ -70,10 +170,9 @@ createTempGistContext(void)
/*
* gistbuildempty() -- build an empty gist index in the initialization fork
*/
-Datum
-gistbuildempty(PG_FUNCTION_ARGS)
+void
+gistbuildempty(Relation index)
{
- Relation index = (Relation) PG_GETARG_POINTER(0);
Buffer buffer;
/* Initialize the root page */
@@ -89,8 +188,6 @@ gistbuildempty(PG_FUNCTION_ARGS)
/* Unlock and release the buffer */
UnlockReleaseBuffer(buffer);
-
- PG_RETURN_VOID();
}
/*
@@ -99,18 +196,11 @@ gistbuildempty(PG_FUNCTION_ARGS)
* This is the public interface routine for tuple insertion in GiSTs.
* It doesn't do any work; just locks the relation and passes the buck.
*/
-Datum
-gistinsert(PG_FUNCTION_ARGS)
+bool
+gistinsert(Relation r, Datum *values, bool *isnull,
+ ItemPointer ht_ctid, Relation heapRel,
+ IndexUniqueCheck checkUnique)
{
- Relation r = (Relation) PG_GETARG_POINTER(0);
- Datum *values = (Datum *) PG_GETARG_POINTER(1);
- bool *isnull = (bool *) PG_GETARG_POINTER(2);
- ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
-
-#ifdef NOT_USED
- Relation heapRel = (Relation) PG_GETARG_POINTER(4);
- IndexUniqueCheck checkUnique = (IndexUniqueCheck) PG_GETARG_INT32(5);
-#endif
IndexTuple itup;
GISTSTATE *giststate;
MemoryContext oldCxt;
@@ -136,7 +226,7 @@ gistinsert(PG_FUNCTION_ARGS)
MemoryContextSwitchTo(oldCxt);
freeGISTstate(giststate);
- PG_RETURN_BOOL(false);
+ return false;
}
diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c
index ff888e2..08a029c 100644
--- a/src/backend/access/gist/gistbuild.c
+++ b/src/backend/access/gist/gistbuild.c
@@ -109,12 +109,9 @@ static BlockNumber gistGetParent(GISTBuildState *buildstate, BlockNumber child);
* but switches to more efficient buffering build algorithm after a certain
* number of tuples (unless buffering mode is disabled).
*/
-Datum
-gistbuild(PG_FUNCTION_ARGS)
+IndexBuildResult *
+gistbuild(Relation heap, Relation index, IndexInfo *indexInfo)
{
- Relation heap = (Relation) PG_GETARG_POINTER(0);
- Relation index = (Relation) PG_GETARG_POINTER(1);
- IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
IndexBuildResult *result;
double reltuples;
GISTBuildState buildstate;
@@ -232,7 +229,7 @@ gistbuild(PG_FUNCTION_ARGS)
result->heap_tuples = reltuples;
result->index_tuples = (double) buildstate.indtuples;
- PG_RETURN_POINTER(result);
+ return result;
}
/*
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index ce8e582..1adf92f 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -618,11 +618,9 @@ getNextNearest(IndexScanDesc scan)
/*
* gistgettuple() -- Get the next tuple in the scan
*/
-Datum
-gistgettuple(PG_FUNCTION_ARGS)
+bool
+gistgettuple(IndexScanDesc scan, ScanDirection dir)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
if (dir != ForwardScanDirection)
@@ -651,7 +649,7 @@ gistgettuple(PG_FUNCTION_ARGS)
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
- PG_RETURN_BOOL(getNextNearest(scan));
+ return getNextNearest(scan);
}
else
{
@@ -688,7 +686,7 @@ gistgettuple(PG_FUNCTION_ARGS)
so->curPageData++;
- PG_RETURN_BOOL(true);
+ return true;
}
/*
@@ -726,7 +724,7 @@ gistgettuple(PG_FUNCTION_ARGS)
item = getNextGISTSearchItem(so);
if (!item)
- PG_RETURN_BOOL(false);
+ return false;
CHECK_FOR_INTERRUPTS();
@@ -750,17 +748,15 @@ gistgettuple(PG_FUNCTION_ARGS)
/*
* gistgetbitmap() -- Get a bitmap of all heap tuple locations
*/
-Datum
-gistgetbitmap(PG_FUNCTION_ARGS)
+int64
+gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
int64 ntids = 0;
GISTSearchItem fakeItem;
if (!so->qual_ok)
- PG_RETURN_INT64(0);
+ return 0;
pgstat_count_index_scan(scan->indexRelation);
@@ -791,7 +787,7 @@ gistgetbitmap(PG_FUNCTION_ARGS)
pfree(item);
}
- PG_RETURN_INT64(ntids);
+ return ntids;
}
/*
@@ -799,14 +795,11 @@ gistgetbitmap(PG_FUNCTION_ARGS)
*
* Opclasses that implement a fetch function support index-only scans.
*/
-Datum
-gistcanreturn(PG_FUNCTION_ARGS)
+bool
+gistcanreturn(Relation index, int attno)
{
- Relation index = (Relation) PG_GETARG_POINTER(0);
- int attno = PG_GETARG_INT32(1);
-
if (OidIsValid(index_getprocid(index, attno, GIST_FETCH_PROC)))
- PG_RETURN_BOOL(true);
+ return true;
else
- PG_RETURN_BOOL(false);
+ return false;
}
diff --git a/src/backend/access/gist/gistscan.c b/src/backend/access/gist/gistscan.c
index a17c5bc..22f0c68 100644
--- a/src/backend/access/gist/gistscan.c
+++ b/src/backend/access/gist/gistscan.c
@@ -54,12 +54,9 @@ pairingheap_GISTSearchItem_cmp(const pairingheap_node *a, const pairingheap_node
* Index AM API functions for scanning GiST indexes
*/
-Datum
-gistbeginscan(PG_FUNCTION_ARGS)
+IndexScanDesc
+gistbeginscan(Relation r, int nkeys, int norderbys)
{
- Relation r = (Relation) PG_GETARG_POINTER(0);
- int nkeys = PG_GETARG_INT32(1);
- int norderbys = PG_GETARG_INT32(2);
IndexScanDesc scan;
GISTSTATE *giststate;
GISTScanOpaque so;
@@ -107,15 +104,13 @@ gistbeginscan(PG_FUNCTION_ARGS)
MemoryContextSwitchTo(oldCxt);
- PG_RETURN_POINTER(scan);
+ return scan;
}
-Datum
-gistrescan(PG_FUNCTION_ARGS)
+void
+gistrescan(IndexScanDesc scan, ScanKey key, int nkeys,
+ ScanKey orderbys, int norderbys)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- ScanKey key = (ScanKey) PG_GETARG_POINTER(1);
- ScanKey orderbys = (ScanKey) PG_GETARG_POINTER(3);
/* nkeys and norderbys arguments are ignored */
GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
@@ -314,28 +309,23 @@ gistrescan(PG_FUNCTION_ARGS)
if (!first_time)
pfree(fn_extras);
}
-
- PG_RETURN_VOID();
}
-Datum
-gistmarkpos(PG_FUNCTION_ARGS)
+void
+gistmarkpos(IndexScanDesc scan)
{
elog(ERROR, "GiST does not support mark/restore");
- PG_RETURN_VOID();
}
-Datum
-gistrestrpos(PG_FUNCTION_ARGS)
+void
+gistrestrpos(IndexScanDesc scan)
{
elog(ERROR, "GiST does not support mark/restore");
- PG_RETURN_VOID();
}
-Datum
-gistendscan(PG_FUNCTION_ARGS)
+void
+gistendscan(IndexScanDesc scan)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
/*
@@ -343,6 +333,4 @@ gistendscan(PG_FUNCTION_ARGS)
* as well as the queueCxt if there is a separate context for it.
*/
freeGISTstate(so->giststate);
-
- PG_RETURN_VOID();
}
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 7d596a3..45f6246 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -808,11 +808,9 @@ gistNewBuffer(Relation r)
return buffer;
}
-Datum
-gistoptions(PG_FUNCTION_ARGS)
+bytea *
+gistoptions(Datum reloptions, bool validate)
{
- Datum reloptions = PG_GETARG_DATUM(0);
- bool validate = PG_GETARG_BOOL(1);
relopt_value *options;
GiSTOptions *rdopts;
int numoptions;
@@ -826,7 +824,7 @@ gistoptions(PG_FUNCTION_ARGS)
/* if none set, we're done */
if (numoptions == 0)
- PG_RETURN_NULL();
+ return NULL;
rdopts = allocateReloptStruct(sizeof(GiSTOptions), options, numoptions);
@@ -835,7 +833,7 @@ gistoptions(PG_FUNCTION_ARGS)
pfree(options);
- PG_RETURN_BYTEA_P(rdopts);
+ return (bytea *)rdopts;
}
diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c
index a0b0eeb..e0ce620 100644
--- a/src/backend/access/gist/gistvacuum.c
+++ b/src/backend/access/gist/gistvacuum.c
@@ -25,11 +25,9 @@
/*
* VACUUM cleanup: update FSM
*/
-Datum
-gistvacuumcleanup(PG_FUNCTION_ARGS)
+IndexBulkDeleteResult *
+gistvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
{
- IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
- IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
Relation rel = info->index;
BlockNumber npages,
blkno;
@@ -38,7 +36,7 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
/* No-op in ANALYZE ONLY mode */
if (info->analyze_only)
- PG_RETURN_POINTER(stats);
+ return stats;
/* Set up all-zero stats if gistbulkdelete wasn't called */
if (stats == NULL)
@@ -98,7 +96,7 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
if (needLock)
UnlockRelationForExtension(rel, ExclusiveLock);
- PG_RETURN_POINTER(stats);
+ return stats;
}
typedef struct GistBDItem
@@ -137,13 +135,10 @@ pushStackIfSplited(Page page, GistBDItem *stack)
*
* Result: a palloc'd struct containing statistical info for VACUUM displays.
*/
-Datum
-gistbulkdelete(PG_FUNCTION_ARGS)
+IndexBulkDeleteResult *
+gistbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback, void *callback_state)
{
- IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
- IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
- IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
- void *callback_state = (void *) PG_GETARG_POINTER(3);
Relation rel = info->index;
GistBDItem *stack,
*ptr;
@@ -276,5 +271,5 @@ gistbulkdelete(PG_FUNCTION_ARGS)
vacuum_delay_point();
}
- PG_RETURN_POINTER(stats);
+ return stats;
}
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index 24b06a5..286596b 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -18,6 +18,7 @@
#include "postgres.h"
+#include "access/amapi.h"
#include "access/hash.h"
#include "access/relscan.h"
#include "catalog/index.h"
@@ -26,6 +27,7 @@
#include "optimizer/plancat.h"
#include "storage/bufmgr.h"
#include "utils/rel.h"
+#include "utils/selfuncs.h"
/* Working state for hashbuild and its callback */
@@ -42,16 +44,107 @@ static void hashbuildCallback(Relation index,
bool tupleIsAlive,
void *state);
+/*
+ * Hash handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+Datum
+hashhandler(PG_FUNCTION_ARGS)
+{
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 1;
+ amroutine->amsupport = 1;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = true;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = false;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = INT4OID;
+
+ amroutine->aminsert = hashinsert;
+ amroutine->ambeginscan = hashbeginscan;
+ amroutine->amgettuple = hashgettuple;
+ amroutine->amgetbitmap = hashgetbitmap;
+ amroutine->amrescan = hashrescan;
+ amroutine->amendscan = hashendscan;
+ amroutine->ammarkpos = hashmarkpos;
+ amroutine->amrestrpos = hashrestrpos;
+ amroutine->ambuild = hashbuild;
+ amroutine->ambuildempty = hashbuildempty;
+ amroutine->ambulkdelete = hashbulkdelete;
+ amroutine->amvacuumcleanup = hashvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = hashcostestimate;
+ amroutine->amoptions = hashoptions;
+ amroutine->amvalidate = hashvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+}
+
+void
+hashvalidate(OpClassInfo *opclass)
+{
+ ListCell *l;
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->number != HASHPROC)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid support number for hash: %u",
+ proc->number)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+ bool leftFound = false, rightFound = false;
+ ListCell *ll;
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Hash doesn't support order by operators")));
+
+ if (opr->number < 1 || opr->number > HTMaxStrategyNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid strategy number for hash: %u",
+ opr->number)));
+
+ foreach(ll, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(ll);
+
+ if (proc->lefttype == opr->lefttype)
+ leftFound = true;
+ if (proc->lefttype == opr->righttype)
+ rightFound = true;
+ }
+
+ if (!leftFound || !rightFound)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("No hash procedure found for operator: %u",
+ opr->object)));
+ }
+}
/*
* hashbuild() -- build a new hash index.
*/
-Datum
-hashbuild(PG_FUNCTION_ARGS)
+IndexBuildResult *
+hashbuild(Relation heap, Relation index, IndexInfo *indexInfo)
{
- Relation heap = (Relation) PG_GETARG_POINTER(0);
- Relation index = (Relation) PG_GETARG_POINTER(1);
- IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
IndexBuildResult *result;
BlockNumber relpages;
double reltuples;
@@ -112,20 +205,16 @@ hashbuild(PG_FUNCTION_ARGS)
result->heap_tuples = reltuples;
result->index_tuples = buildstate.indtuples;
- PG_RETURN_POINTER(result);
+ return result;
}
/*
* hashbuildempty() -- build an empty hash index in the initialization fork
*/
-Datum
-hashbuildempty(PG_FUNCTION_ARGS)
+void
+hashbuildempty(Relation index)
{
- Relation index = (Relation) PG_GETARG_POINTER(0);
-
_hash_metapinit(index, 0, INIT_FORKNUM);
-
- PG_RETURN_VOID();
}
/*
@@ -167,18 +256,11 @@ hashbuildCallback(Relation index,
* Hash on the heap tuple's key, form an index tuple with hash code.
* Find the appropriate location for the new tuple, and put it there.
*/
-Datum
-hashinsert(PG_FUNCTION_ARGS)
+bool
+hashinsert(Relation rel, Datum *values, bool *isnull,
+ ItemPointer ht_ctid, Relation heapRel,
+ IndexUniqueCheck checkUnique)
{
- Relation rel = (Relation) PG_GETARG_POINTER(0);
- Datum *values = (Datum *) PG_GETARG_POINTER(1);
- bool *isnull = (bool *) PG_GETARG_POINTER(2);
- ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
-
-#ifdef NOT_USED
- Relation heapRel = (Relation) PG_GETARG_POINTER(4);
- IndexUniqueCheck checkUnique = (IndexUniqueCheck) PG_GETARG_INT32(5);
-#endif
IndexTuple itup;
/*
@@ -191,7 +273,7 @@ hashinsert(PG_FUNCTION_ARGS)
* chosen in 1986, not of the way nulls are handled here.
*/
if (isnull[0])
- PG_RETURN_BOOL(false);
+ return false;
/* generate an index tuple */
itup = _hash_form_tuple(rel, values, isnull);
@@ -201,18 +283,16 @@ hashinsert(PG_FUNCTION_ARGS)
pfree(itup);
- PG_RETURN_BOOL(false);
+ return false;
}
/*
* hashgettuple() -- Get the next tuple in the scan.
*/
-Datum
-hashgettuple(PG_FUNCTION_ARGS)
+bool
+hashgettuple(IndexScanDesc scan, ScanDirection dir)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
HashScanOpaque so = (HashScanOpaque) scan->opaque;
Relation rel = scan->indexRelation;
Buffer buf;
@@ -314,18 +394,16 @@ hashgettuple(PG_FUNCTION_ARGS)
/* Return current heap TID on success */
scan->xs_ctup.t_self = so->hashso_heappos;
- PG_RETURN_BOOL(res);
+ return res;
}
/*
* hashgetbitmap() -- get all tuples at once
*/
-Datum
-hashgetbitmap(PG_FUNCTION_ARGS)
+int64
+hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
HashScanOpaque so = (HashScanOpaque) scan->opaque;
bool res;
int64 ntids = 0;
@@ -362,19 +440,16 @@ hashgetbitmap(PG_FUNCTION_ARGS)
res = _hash_next(scan, ForwardScanDirection);
}
- PG_RETURN_INT64(ntids);
+ return ntids;
}
/*
* hashbeginscan() -- start a scan on a hash index
*/
-Datum
-hashbeginscan(PG_FUNCTION_ARGS)
+IndexScanDesc
+hashbeginscan(Relation rel, int nkeys, int norderbys)
{
- Relation rel = (Relation) PG_GETARG_POINTER(0);
- int nkeys = PG_GETARG_INT32(1);
- int norderbys = PG_GETARG_INT32(2);
IndexScanDesc scan;
HashScanOpaque so;
@@ -396,19 +471,16 @@ hashbeginscan(PG_FUNCTION_ARGS)
/* register scan in case we change pages it's using */
_hash_regscan(scan);
- PG_RETURN_POINTER(scan);
+ return scan;
}
/*
* hashrescan() -- rescan an index relation
*/
-Datum
-hashrescan(PG_FUNCTION_ARGS)
+void
+hashrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
+ ScanKey orderbys, int norderbys)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
-
- /* remaining arguments are ignored */
HashScanOpaque so = (HashScanOpaque) scan->opaque;
Relation rel = scan->indexRelation;
@@ -434,17 +506,14 @@ hashrescan(PG_FUNCTION_ARGS)
scan->numberOfKeys * sizeof(ScanKeyData));
so->hashso_bucket_valid = false;
}
-
- PG_RETURN_VOID();
}
/*
* hashendscan() -- close down a scan
*/
-Datum
-hashendscan(PG_FUNCTION_ARGS)
+void
+hashendscan(IndexScanDesc scan)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
HashScanOpaque so = (HashScanOpaque) scan->opaque;
Relation rel = scan->indexRelation;
@@ -463,28 +532,24 @@ hashendscan(PG_FUNCTION_ARGS)
pfree(so);
scan->opaque = NULL;
-
- PG_RETURN_VOID();
}
/*
* hashmarkpos() -- save current scan position
*/
-Datum
-hashmarkpos(PG_FUNCTION_ARGS)
+void
+hashmarkpos(IndexScanDesc scan)
{
elog(ERROR, "hash does not support mark/restore");
- PG_RETURN_VOID();
}
/*
* hashrestrpos() -- restore scan to last saved position
*/
-Datum
-hashrestrpos(PG_FUNCTION_ARGS)
+void
+hashrestrpos(IndexScanDesc scan)
{
elog(ERROR, "hash does not support mark/restore");
- PG_RETURN_VOID();
}
/*
@@ -494,13 +559,10 @@ hashrestrpos(PG_FUNCTION_ARGS)
*
* Result: a palloc'd struct containing statistical info for VACUUM displays.
*/
-Datum
-hashbulkdelete(PG_FUNCTION_ARGS)
+IndexBulkDeleteResult *
+hashbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback, void *callback_state)
{
- IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
- IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
- IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
- void *callback_state = (void *) PG_GETARG_POINTER(3);
Relation rel = info->index;
double tuples_removed;
double num_index_tuples;
@@ -670,7 +732,7 @@ loop_top:
stats->tuples_removed += tuples_removed;
/* hashvacuumcleanup will fill in num_pages */
- PG_RETURN_POINTER(stats);
+ return stats;
}
/*
@@ -678,24 +740,22 @@ loop_top:
*
* Result: a palloc'd struct containing statistical info for VACUUM displays.
*/
-Datum
-hashvacuumcleanup(PG_FUNCTION_ARGS)
+IndexBulkDeleteResult *
+hashvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
{
- IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
- IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
Relation rel = info->index;
BlockNumber num_pages;
/* If hashbulkdelete wasn't called, return NULL signifying no change */
/* Note: this covers the analyze_only case too */
if (stats == NULL)
- PG_RETURN_POINTER(NULL);
+ return NULL;
/* update statistics */
num_pages = RelationGetNumberOfBlocks(rel);
stats->num_pages = num_pages;
- PG_RETURN_POINTER(stats);
+ return stats;
}
diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c
index 3d66216..85236e2 100644
--- a/src/backend/access/hash/hashutil.c
+++ b/src/backend/access/hash/hashutil.c
@@ -217,18 +217,16 @@ _hash_checkpage(Relation rel, Buffer buf, int flags)
}
}
-Datum
-hashoptions(PG_FUNCTION_ARGS)
+bytea *
+hashoptions(Datum reloptions, bool validate)
{
- Datum reloptions = PG_GETARG_DATUM(0);
- bool validate = PG_GETARG_BOOL(1);
bytea *result;
result = default_reloptions(reloptions, validate, RELOPT_KIND_HASH);
if (result)
- PG_RETURN_BYTEA_P(result);
- PG_RETURN_NULL();
+ return result;
+ return NULL;
}
/*
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 2b27e73..ebf9313 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -65,6 +65,7 @@
#include "postgres.h"
+#include "access/amapi.h"
#include "access/relscan.h"
#include "access/transam.h"
#include "access/xlog.h"
@@ -92,49 +93,32 @@
* ----------------------------------------------------------------
*/
#define RELATION_CHECKS \
-( \
- AssertMacro(RelationIsValid(indexRelation)), \
- AssertMacro(PointerIsValid(indexRelation->rd_am)), \
- AssertMacro(!ReindexIsProcessingIndex(RelationGetRelid(indexRelation))) \
-)
-
-#define SCAN_CHECKS \
-( \
- AssertMacro(IndexScanIsValid(scan)), \
- AssertMacro(RelationIsValid(scan->indexRelation)), \
- AssertMacro(PointerIsValid(scan->indexRelation->rd_am)) \
-)
-
-#define GET_REL_PROCEDURE(pname) \
-do { \
- procedure = &indexRelation->rd_aminfo->pname; \
- if (!OidIsValid(procedure->fn_oid)) \
- { \
- RegProcedure procOid = indexRelation->rd_am->pname; \
- if (!RegProcedureIsValid(procOid)) \
- elog(ERROR, "invalid %s regproc", CppAsString(pname)); \
- fmgr_info_cxt(procOid, procedure, indexRelation->rd_indexcxt); \
- } \
-} while(0)
-
-#define GET_UNCACHED_REL_PROCEDURE(pname) \
do { \
- if (!RegProcedureIsValid(indexRelation->rd_am->pname)) \
- elog(ERROR, "invalid %s regproc", CppAsString(pname)); \
- fmgr_info(indexRelation->rd_am->pname, &procedure); \
-} while(0)
+ Assert(RelationIsValid(indexRelation)); \
+ Assert(indexRelation->amroutine); \
+ Assert(!ReindexIsProcessingIndex(RelationGetRelid(indexRelation))); \
+} while (0)
-#define GET_SCAN_PROCEDURE(pname) \
+#define SCAN_CHECKS \
do { \
- procedure = &scan->indexRelation->rd_aminfo->pname; \
- if (!OidIsValid(procedure->fn_oid)) \
- { \
- RegProcedure procOid = scan->indexRelation->rd_am->pname; \
- if (!RegProcedureIsValid(procOid)) \
- elog(ERROR, "invalid %s regproc", CppAsString(pname)); \
- fmgr_info_cxt(procOid, procedure, scan->indexRelation->rd_indexcxt); \
- } \
-} while(0)
+ Assert(IndexScanIsValid(scan)); \
+ Assert(RelationIsValid(scan->indexRelation)); \
+ Assert(scan->indexRelation->amroutine); \
+} while (0)
+
+#define CHECK_PROCEDURE(pname) \
+if (!indexRelation->amroutine->pname) \
+{ \
+ elog(ERROR, "%s is undefined for %s", \
+ CppAsString(pname), RelationGetRelationName(indexRelation)); \
+} \
+
+#define CHECK_SCAN_PROCEDURE(pname) \
+if (!scan->indexRelation->amroutine->pname) \
+{ \
+ elog(ERROR, "%s is undefined for %s", \
+ CppAsString(pname), RelationGetRelationName(scan->indexRelation)); \
+} \
static IndexScanDesc index_beginscan_internal(Relation indexRelation,
int nkeys, int norderbys, Snapshot snapshot);
@@ -210,26 +194,17 @@ index_insert(Relation indexRelation,
Relation heapRelation,
IndexUniqueCheck checkUnique)
{
- FmgrInfo *procedure;
-
RELATION_CHECKS;
- GET_REL_PROCEDURE(aminsert);
+ CHECK_PROCEDURE(aminsert);
- if (!(indexRelation->rd_am->ampredlocks))
+ if (!(indexRelation->amroutine->ampredlocks))
CheckForSerializableConflictIn(indexRelation,
(HeapTuple) NULL,
InvalidBuffer);
- /*
- * have the am's insert proc do all the work.
- */
- return DatumGetBool(FunctionCall6(procedure,
- PointerGetDatum(indexRelation),
- PointerGetDatum(values),
- PointerGetDatum(isnull),
- PointerGetDatum(heap_t_ctid),
- PointerGetDatum(heapRelation),
- Int32GetDatum((int32) checkUnique)));
+ return indexRelation->amroutine->aminsert(indexRelation, values, isnull,
+ heap_t_ctid, heapRelation,
+ checkUnique);
}
/*
@@ -289,12 +264,11 @@ index_beginscan_internal(Relation indexRelation,
int nkeys, int norderbys, Snapshot snapshot)
{
IndexScanDesc scan;
- FmgrInfo *procedure;
RELATION_CHECKS;
- GET_REL_PROCEDURE(ambeginscan);
+ CHECK_PROCEDURE(ambeginscan);
- if (!(indexRelation->rd_am->ampredlocks))
+ if (!(indexRelation->amroutine->ampredlocks))
PredicateLockRelation(indexRelation, snapshot);
/*
@@ -305,11 +279,8 @@ index_beginscan_internal(Relation indexRelation,
/*
* Tell the AM to open a scan.
*/
- scan = (IndexScanDesc)
- DatumGetPointer(FunctionCall3(procedure,
- PointerGetDatum(indexRelation),
- Int32GetDatum(nkeys),
- Int32GetDatum(norderbys)));
+ scan = indexRelation->amroutine->ambeginscan(indexRelation, nkeys,
+ norderbys);
return scan;
}
@@ -331,10 +302,8 @@ index_rescan(IndexScanDesc scan,
ScanKey keys, int nkeys,
ScanKey orderbys, int norderbys)
{
- FmgrInfo *procedure;
-
SCAN_CHECKS;
- GET_SCAN_PROCEDURE(amrescan);
+ CHECK_SCAN_PROCEDURE(amrescan);
Assert(nkeys == scan->numberOfKeys);
Assert(norderbys == scan->numberOfOrderBys);
@@ -350,12 +319,8 @@ index_rescan(IndexScanDesc scan,
scan->kill_prior_tuple = false; /* for safety */
- FunctionCall5(procedure,
- PointerGetDatum(scan),
- PointerGetDatum(keys),
- Int32GetDatum(nkeys),
- PointerGetDatum(orderbys),
- Int32GetDatum(norderbys));
+ scan->indexRelation->amroutine->amrescan(scan, keys, nkeys,
+ orderbys, norderbys);
}
/* ----------------
@@ -365,10 +330,8 @@ index_rescan(IndexScanDesc scan,
void
index_endscan(IndexScanDesc scan)
{
- FmgrInfo *procedure;
-
SCAN_CHECKS;
- GET_SCAN_PROCEDURE(amendscan);
+ CHECK_SCAN_PROCEDURE(amendscan);
/* Release any held pin on a heap page */
if (BufferIsValid(scan->xs_cbuf))
@@ -378,7 +341,7 @@ index_endscan(IndexScanDesc scan)
}
/* End the AM's scan */
- FunctionCall1(procedure, PointerGetDatum(scan));
+ scan->indexRelation->amroutine->amendscan(scan);
/* Release index refcount acquired by index_beginscan */
RelationDecrementReferenceCount(scan->indexRelation);
@@ -394,12 +357,10 @@ index_endscan(IndexScanDesc scan)
void
index_markpos(IndexScanDesc scan)
{
- FmgrInfo *procedure;
-
SCAN_CHECKS;
- GET_SCAN_PROCEDURE(ammarkpos);
+ CHECK_SCAN_PROCEDURE(ammarkpos);
- FunctionCall1(procedure, PointerGetDatum(scan));
+ scan->indexRelation->amroutine->ammarkpos(scan);
}
/* ----------------
@@ -421,18 +382,16 @@ index_markpos(IndexScanDesc scan)
void
index_restrpos(IndexScanDesc scan)
{
- FmgrInfo *procedure;
-
Assert(IsMVCCSnapshot(scan->xs_snapshot));
SCAN_CHECKS;
- GET_SCAN_PROCEDURE(amrestrpos);
+ CHECK_SCAN_PROCEDURE(amrestrpos);
scan->xs_continue_hot = false;
scan->kill_prior_tuple = false; /* for safety */
- FunctionCall1(procedure, PointerGetDatum(scan));
+ scan->indexRelation->amroutine->amrestrpos(scan);
}
/* ----------------
@@ -445,11 +404,10 @@ index_restrpos(IndexScanDesc scan)
ItemPointer
index_getnext_tid(IndexScanDesc scan, ScanDirection direction)
{
- FmgrInfo *procedure;
bool found;
SCAN_CHECKS;
- GET_SCAN_PROCEDURE(amgettuple);
+ CHECK_SCAN_PROCEDURE(amgettuple);
Assert(TransactionIdIsValid(RecentGlobalXmin));
@@ -459,9 +417,7 @@ index_getnext_tid(IndexScanDesc scan, ScanDirection direction)
* scan->xs_recheck and possibly scan->xs_itup, though we pay no attention
* to those fields here.
*/
- found = DatumGetBool(FunctionCall2(procedure,
- PointerGetDatum(scan),
- Int32GetDatum(direction)));
+ found = scan->indexRelation->amroutine->amgettuple(scan, direction);
/* Reset kill flag immediately for safety */
scan->kill_prior_tuple = false;
@@ -635,12 +591,11 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
int64
index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap)
{
- FmgrInfo *procedure;
int64 ntids;
Datum d;
SCAN_CHECKS;
- GET_SCAN_PROCEDURE(amgetbitmap);
+ CHECK_SCAN_PROCEDURE(amgetbitmap);
/* just make sure this is false... */
scan->kill_prior_tuple = false;
@@ -648,9 +603,7 @@ index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap)
/*
* have the am's getbitmap proc do all the work.
*/
- d = FunctionCall2(procedure,
- PointerGetDatum(scan),
- PointerGetDatum(bitmap));
+ d = scan->indexRelation->amroutine->amgetbitmap(scan, bitmap);
ntids = DatumGetInt64(d);
@@ -680,20 +633,12 @@ index_bulk_delete(IndexVacuumInfo *info,
void *callback_state)
{
Relation indexRelation = info->index;
- FmgrInfo procedure;
- IndexBulkDeleteResult *result;
RELATION_CHECKS;
- GET_UNCACHED_REL_PROCEDURE(ambulkdelete);
+ CHECK_PROCEDURE(ambulkdelete);
- result = (IndexBulkDeleteResult *)
- DatumGetPointer(FunctionCall4(&procedure,
- PointerGetDatum(info),
- PointerGetDatum(stats),
- PointerGetDatum((Pointer) callback),
- PointerGetDatum(callback_state)));
-
- return result;
+ return indexRelation->amroutine->ambulkdelete(info, stats,
+ callback, callback_state);
}
/* ----------------
@@ -707,18 +652,11 @@ index_vacuum_cleanup(IndexVacuumInfo *info,
IndexBulkDeleteResult *stats)
{
Relation indexRelation = info->index;
- FmgrInfo procedure;
- IndexBulkDeleteResult *result;
RELATION_CHECKS;
- GET_UNCACHED_REL_PROCEDURE(amvacuumcleanup);
-
- result = (IndexBulkDeleteResult *)
- DatumGetPointer(FunctionCall2(&procedure,
- PointerGetDatum(info),
- PointerGetDatum(stats)));
+ CHECK_PROCEDURE(amvacuumcleanup);
- return result;
+ return indexRelation->amroutine->amvacuumcleanup(info, stats);
}
/* ----------------
@@ -731,19 +669,13 @@ index_vacuum_cleanup(IndexVacuumInfo *info,
bool
index_can_return(Relation indexRelation, int attno)
{
- FmgrInfo *procedure;
-
RELATION_CHECKS;
/* amcanreturn is optional; assume FALSE if not provided by AM */
- if (!RegProcedureIsValid(indexRelation->rd_am->amcanreturn))
+ if (!indexRelation->amroutine->amcanreturn)
return false;
- GET_REL_PROCEDURE(amcanreturn);
-
- return DatumGetBool(FunctionCall2(procedure,
- PointerGetDatum(indexRelation),
- Int32GetDatum(attno)));
+ return indexRelation->amroutine->amcanreturn(indexRelation, attno);
}
/* ----------------
@@ -781,7 +713,7 @@ index_getprocid(Relation irel,
int nproc;
int procindex;
- nproc = irel->rd_am->amsupport;
+ nproc = irel->amroutine->amsupport;
Assert(procnum > 0 && procnum <= (uint16) nproc);
@@ -815,7 +747,7 @@ index_getprocinfo(Relation irel,
int nproc;
int procindex;
- nproc = irel->rd_am->amsupport;
+ nproc = irel->amroutine->amsupport;
Assert(procnum > 0 && procnum <= (uint16) nproc);
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index cf4a6dc..fa933f6 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -76,14 +76,107 @@ static void btvacuumpage(BTVacState *vstate, BlockNumber blkno,
/*
- * btbuild() -- build a new btree index.
+ * Btree handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
*/
Datum
-btbuild(PG_FUNCTION_ARGS)
+bthandler(PG_FUNCTION_ARGS)
+{
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 5;
+ amroutine->amsupport = 2;
+ amroutine->amcanorder = true;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = true;
+ amroutine->amcanunique = true;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = true;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = true;
+ amroutine->ampredlocks = true;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = btinsert;
+ amroutine->ambeginscan = btbeginscan;
+ amroutine->amgettuple = btgettuple;
+ amroutine->amgetbitmap = btgetbitmap;
+ amroutine->amrescan = btrescan;
+ amroutine->amendscan = btendscan;
+ amroutine->ammarkpos = btmarkpos;
+ amroutine->amrestrpos = btrestrpos;
+ amroutine->ambuild = btbuild;
+ amroutine->ambuildempty = btbuildempty;
+ amroutine->ambulkdelete = btbulkdelete;
+ amroutine->amvacuumcleanup = btvacuumcleanup;
+ amroutine->amcanreturn = btcanreturn;
+ amroutine->amcostestimate = btcostestimate;
+ amroutine->amoptions = btoptions;
+ amroutine->amvalidate = btvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+}
+
+void
+btvalidate(OpClassInfo *opclass)
+{
+ ListCell *l;
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->number != BTORDER_PROC
+ && proc->number != BTSORTSUPPORT_PROC)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid support number for btree: %u",
+ proc->number)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+ bool found = false;
+ ListCell *ll;
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Btree doesn't support order by operators")));
+
+ if (opr->number < 1 || opr->number > BTMaxStrategyNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid strategy number for btree: %u",
+ opr->number)));
+
+ foreach(ll, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(ll);
+
+ if (proc->number == BTORDER_PROC
+ && proc->lefttype == opr->lefttype
+ && proc->righttype == opr->righttype)
+ found = true;
+ }
+
+ if (!found)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("No ordering procedure found for operator: %u",
+ opr->object)));
+ }
+}
+
+/*
+ * btbuild() -- build a new btree index.
+ */
+IndexBuildResult *
+btbuild(Relation heap, Relation index, IndexInfo *indexInfo)
{
- Relation heap = (Relation) PG_GETARG_POINTER(0);
- Relation index = (Relation) PG_GETARG_POINTER(1);
- IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
IndexBuildResult *result;
double reltuples;
BTBuildState buildstate;
@@ -155,7 +248,7 @@ btbuild(PG_FUNCTION_ARGS)
result->heap_tuples = reltuples;
result->index_tuples = buildstate.indtuples;
- PG_RETURN_POINTER(result);
+ return result;
}
/*
@@ -190,11 +283,10 @@ btbuildCallback(Relation index,
/*
* btbuildempty() -- build an empty btree index in the initialization fork
*/
-Datum
-btbuildempty(PG_FUNCTION_ARGS)
+void
+btbuildempty(Relation index)
{
- Relation index = (Relation) PG_GETARG_POINTER(0);
- Page metapage;
+ Page metapage;
/* Construct metapage. */
metapage = (Page) palloc(BLCKSZ);
@@ -214,8 +306,6 @@ btbuildempty(PG_FUNCTION_ARGS)
* checkpoint may have moved the redo pointer past our xlog record.
*/
smgrimmedsync(index->rd_smgr, INIT_FORKNUM);
-
- PG_RETURN_VOID();
}
/*
@@ -224,15 +314,11 @@ btbuildempty(PG_FUNCTION_ARGS)
* Descend the tree recursively, find the appropriate location for our
* new tuple, and put it there.
*/
-Datum
-btinsert(PG_FUNCTION_ARGS)
+bool
+btinsert(Relation rel, Datum *values, bool *isnull,
+ ItemPointer ht_ctid, Relation heapRel,
+ IndexUniqueCheck checkUnique)
{
- Relation rel = (Relation) PG_GETARG_POINTER(0);
- Datum *values = (Datum *) PG_GETARG_POINTER(1);
- bool *isnull = (bool *) PG_GETARG_POINTER(2);
- ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
- Relation heapRel = (Relation) PG_GETARG_POINTER(4);
- IndexUniqueCheck checkUnique = (IndexUniqueCheck) PG_GETARG_INT32(5);
bool result;
IndexTuple itup;
@@ -244,17 +330,15 @@ btinsert(PG_FUNCTION_ARGS)
pfree(itup);
- PG_RETURN_BOOL(result);
+ return result;
}
/*
* btgettuple() -- Get the next tuple in the scan.
*/
-Datum
-btgettuple(PG_FUNCTION_ARGS)
+bool
+btgettuple(IndexScanDesc scan, ScanDirection dir)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
BTScanOpaque so = (BTScanOpaque) scan->opaque;
bool res;
@@ -270,7 +354,7 @@ btgettuple(PG_FUNCTION_ARGS)
{
/* punt if we have any unsatisfiable array keys */
if (so->numArrayKeys < 0)
- PG_RETURN_BOOL(false);
+ return false;
_bt_start_array_keys(scan, dir);
}
@@ -320,17 +404,15 @@ btgettuple(PG_FUNCTION_ARGS)
/* ... otherwise see if we have more array keys to deal with */
} while (so->numArrayKeys && _bt_advance_array_keys(scan, dir));
- PG_RETURN_BOOL(res);
+ return res;
}
/*
* btgetbitmap() -- gets all matching tuples, and adds them to a bitmap
*/
-Datum
-btgetbitmap(PG_FUNCTION_ARGS)
+int64
+btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
BTScanOpaque so = (BTScanOpaque) scan->opaque;
int64 ntids = 0;
ItemPointer heapTid;
@@ -342,7 +424,7 @@ btgetbitmap(PG_FUNCTION_ARGS)
{
/* punt if we have any unsatisfiable array keys */
if (so->numArrayKeys < 0)
- PG_RETURN_INT64(ntids);
+ return ntids;
_bt_start_array_keys(scan, ForwardScanDirection);
}
@@ -380,18 +462,15 @@ btgetbitmap(PG_FUNCTION_ARGS)
/* Now see if we have more array keys to deal with */
} while (so->numArrayKeys && _bt_advance_array_keys(scan, ForwardScanDirection));
- PG_RETURN_INT64(ntids);
+ return ntids;
}
/*
* btbeginscan() -- start a scan on a btree index
*/
-Datum
-btbeginscan(PG_FUNCTION_ARGS)
+IndexScanDesc
+btbeginscan(Relation rel, int nkeys, int norderbys)
{
- Relation rel = (Relation) PG_GETARG_POINTER(0);
- int nkeys = PG_GETARG_INT32(1);
- int norderbys = PG_GETARG_INT32(2);
IndexScanDesc scan;
BTScanOpaque so;
@@ -429,19 +508,16 @@ btbeginscan(PG_FUNCTION_ARGS)
scan->opaque = so;
- PG_RETURN_POINTER(scan);
+ return scan;
}
/*
* btrescan() -- rescan an index relation
*/
-Datum
-btrescan(PG_FUNCTION_ARGS)
+void
+btrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
+ ScanKey orderbys, int norderbys)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
-
- /* remaining arguments are ignored */
BTScanOpaque so = (BTScanOpaque) scan->opaque;
/* we aren't holding any read locks, but gotta drop the pins */
@@ -492,17 +568,14 @@ btrescan(PG_FUNCTION_ARGS)
/* If any keys are SK_SEARCHARRAY type, set up array-key info */
_bt_preprocess_array_keys(scan);
-
- PG_RETURN_VOID();
}
/*
* btendscan() -- close down a scan
*/
-Datum
-btendscan(PG_FUNCTION_ARGS)
+void
+btendscan(IndexScanDesc scan)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
BTScanOpaque so = (BTScanOpaque) scan->opaque;
/* we aren't holding any read locks, but gotta drop the pins */
@@ -531,17 +604,14 @@ btendscan(PG_FUNCTION_ARGS)
pfree(so->currTuples);
/* so->markTuples should not be pfree'd, see btrescan */
pfree(so);
-
- PG_RETURN_VOID();
}
/*
* btmarkpos() -- save current scan position
*/
-Datum
-btmarkpos(PG_FUNCTION_ARGS)
+void
+btmarkpos(IndexScanDesc scan)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
BTScanOpaque so = (BTScanOpaque) scan->opaque;
/* There may be an old mark with a pin (but no lock). */
@@ -564,17 +634,14 @@ btmarkpos(PG_FUNCTION_ARGS)
/* Also record the current positions of any array keys */
if (so->numArrayKeys)
_bt_mark_array_keys(scan);
-
- PG_RETURN_VOID();
}
/*
* btrestrpos() -- restore scan to last saved position
*/
-Datum
-btrestrpos(PG_FUNCTION_ARGS)
+void
+btrestrpos(IndexScanDesc scan)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
BTScanOpaque so = (BTScanOpaque) scan->opaque;
/* Restore the marked positions of any array keys */
@@ -642,8 +709,6 @@ btrestrpos(PG_FUNCTION_ARGS)
else
BTScanPosInvalidate(so->currPos);
}
-
- PG_RETURN_VOID();
}
/*
@@ -653,13 +718,10 @@ btrestrpos(PG_FUNCTION_ARGS)
*
* Result: a palloc'd struct containing statistical info for VACUUM displays.
*/
-Datum
-btbulkdelete(PG_FUNCTION_ARGS)
+IndexBulkDeleteResult *
+btbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback, void *callback_state)
{
- IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
- IndexBulkDeleteResult *volatile stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
- IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
- void *callback_state = (void *) PG_GETARG_POINTER(3);
Relation rel = info->index;
BTCycleId cycleid;
@@ -678,7 +740,7 @@ btbulkdelete(PG_FUNCTION_ARGS)
PG_END_ENSURE_ERROR_CLEANUP(_bt_end_vacuum_callback, PointerGetDatum(rel));
_bt_end_vacuum(rel);
- PG_RETURN_POINTER(stats);
+ return stats;
}
/*
@@ -686,15 +748,12 @@ btbulkdelete(PG_FUNCTION_ARGS)
*
* Result: a palloc'd struct containing statistical info for VACUUM displays.
*/
-Datum
-btvacuumcleanup(PG_FUNCTION_ARGS)
+IndexBulkDeleteResult *
+btvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
{
- IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
- IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
-
/* No-op in ANALYZE ONLY mode */
if (info->analyze_only)
- PG_RETURN_POINTER(stats);
+ return stats;
/*
* If btbulkdelete was called, we need not do anything, just return the
@@ -726,7 +785,7 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
stats->num_index_tuples = info->num_heap_tuples;
}
- PG_RETURN_POINTER(stats);
+ return stats;
}
/*
@@ -1127,8 +1186,8 @@ restart:
*
* btrees always do, so this is trivial.
*/
-Datum
-btcanreturn(PG_FUNCTION_ARGS)
+bool
+btcanreturn(Relation index, int attno)
{
PG_RETURN_BOOL(true);
}
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 91331ba..2fec62d 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -2058,15 +2058,13 @@ BTreeShmemInit(void)
Assert(found);
}
-Datum
-btoptions(PG_FUNCTION_ARGS)
+bytea *
+btoptions(Datum reloptions, bool validate)
{
- Datum reloptions = PG_GETARG_DATUM(0);
- bool validate = PG_GETARG_BOOL(1);
bytea *result;
result = default_reloptions(reloptions, validate, RELOPT_KIND_BTREE);
if (result)
- PG_RETURN_BYTEA_P(result);
- PG_RETURN_NULL();
+ return result;
+ return NULL;
}
diff --git a/src/backend/access/spgist/spginsert.c b/src/backend/access/spgist/spginsert.c
index bceee8d..c95ae3d 100644
--- a/src/backend/access/spgist/spginsert.c
+++ b/src/backend/access/spgist/spginsert.c
@@ -65,12 +65,9 @@ spgistBuildCallback(Relation index, HeapTuple htup, Datum *values,
/*
* Build an SP-GiST index.
*/
-Datum
-spgbuild(PG_FUNCTION_ARGS)
+IndexBuildResult *
+spgbuild(Relation heap, Relation index, IndexInfo *indexInfo)
{
- Relation heap = (Relation) PG_GETARG_POINTER(0);
- Relation index = (Relation) PG_GETARG_POINTER(1);
- IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
IndexBuildResult *result;
double reltuples;
SpGistBuildState buildstate;
@@ -151,16 +148,15 @@ spgbuild(PG_FUNCTION_ARGS)
result = (IndexBuildResult *) palloc0(sizeof(IndexBuildResult));
result->heap_tuples = result->index_tuples = reltuples;
- PG_RETURN_POINTER(result);
+ return result;
}
/*
* Build an empty SPGiST index in the initialization fork
*/
-Datum
-spgbuildempty(PG_FUNCTION_ARGS)
+void
+spgbuildempty(Relation index)
{
- Relation index = (Relation) PG_GETARG_POINTER(0);
Page page;
/* Construct metapage. */
@@ -201,25 +197,16 @@ spgbuildempty(PG_FUNCTION_ARGS)
* checkpoint may have moved the redo pointer past our xlog record.
*/
smgrimmedsync(index->rd_smgr, INIT_FORKNUM);
-
- PG_RETURN_VOID();
}
/*
* Insert one new tuple into an SPGiST index.
*/
-Datum
-spginsert(PG_FUNCTION_ARGS)
+bool
+spginsert(Relation index, Datum *values, bool *isnull,
+ ItemPointer ht_ctid, Relation heapRel,
+ IndexUniqueCheck checkUnique)
{
- Relation index = (Relation) PG_GETARG_POINTER(0);
- Datum *values = (Datum *) PG_GETARG_POINTER(1);
- bool *isnull = (bool *) PG_GETARG_POINTER(2);
- ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
-
-#ifdef NOT_USED
- Relation heapRel = (Relation) PG_GETARG_POINTER(4);
- IndexUniqueCheck checkUnique = (IndexUniqueCheck) PG_GETARG_INT32(5);
-#endif
SpGistState spgstate;
MemoryContext oldCtx;
MemoryContext insertCtx;
@@ -251,5 +238,5 @@ spginsert(PG_FUNCTION_ARGS)
MemoryContextDelete(insertCtx);
/* return false since we've not done any unique check */
- PG_RETURN_BOOL(false);
+ return false;
}
diff --git a/src/backend/access/spgist/spgscan.c b/src/backend/access/spgist/spgscan.c
index 8a0d909..1e73690 100644
--- a/src/backend/access/spgist/spgscan.c
+++ b/src/backend/access/spgist/spgscan.c
@@ -173,13 +173,9 @@ spgPrepareScanKeys(IndexScanDesc scan)
}
}
-Datum
-spgbeginscan(PG_FUNCTION_ARGS)
+IndexScanDesc
+spgbeginscan(Relation rel, int keysz, int orderbysz)
{
- Relation rel = (Relation) PG_GETARG_POINTER(0);
- int keysz = PG_GETARG_INT32(1);
-
- /* ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2); */
IndexScanDesc scan;
SpGistScanOpaque so;
@@ -202,15 +198,15 @@ spgbeginscan(PG_FUNCTION_ARGS)
scan->opaque = so;
- PG_RETURN_POINTER(scan);
+ return scan;
}
-Datum
-spgrescan(PG_FUNCTION_ARGS)
+
+void
+spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
+ ScanKey orderbys, int norderbys)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque;
- ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
/* copy scankeys into local storage */
if (scankey && scan->numberOfKeys > 0)
@@ -224,33 +220,26 @@ spgrescan(PG_FUNCTION_ARGS)
/* set up starting stack entries */
resetSpGistScanOpaque(so);
-
- PG_RETURN_VOID();
}
-Datum
-spgendscan(PG_FUNCTION_ARGS)
+void
+spgendscan(IndexScanDesc scan)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque;
MemoryContextDelete(so->tempCxt);
-
- PG_RETURN_VOID();
}
-Datum
-spgmarkpos(PG_FUNCTION_ARGS)
+void
+spgmarkpos(IndexScanDesc scan)
{
elog(ERROR, "SPGiST does not support mark/restore");
- PG_RETURN_VOID();
}
-Datum
-spgrestrpos(PG_FUNCTION_ARGS)
+void
+spgrestrpos(IndexScanDesc scan)
{
elog(ERROR, "SPGiST does not support mark/restore");
- PG_RETURN_VOID();
}
/*
@@ -571,11 +560,9 @@ storeBitmap(SpGistScanOpaque so, ItemPointer heapPtr,
so->ntids++;
}
-Datum
-spggetbitmap(PG_FUNCTION_ARGS)
+int64
+spggetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque;
/* Copy want_itup to *so so we don't need to pass it around separately */
@@ -586,7 +573,7 @@ spggetbitmap(PG_FUNCTION_ARGS)
spgWalk(scan->indexRelation, so, true, storeBitmap);
- PG_RETURN_INT64(so->ntids);
+ return so->ntids;
}
/* storeRes subroutine for gettuple case */
@@ -610,11 +597,9 @@ storeGettuple(SpGistScanOpaque so, ItemPointer heapPtr,
so->nPtrs++;
}
-Datum
-spggettuple(PG_FUNCTION_ARGS)
+bool
+spggettuple(IndexScanDesc scan, ScanDirection dir)
{
- IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque;
if (dir != ForwardScanDirection)
@@ -632,7 +617,7 @@ spggettuple(PG_FUNCTION_ARGS)
scan->xs_recheck = so->recheck[so->iPtr];
scan->xs_itup = so->indexTups[so->iPtr];
so->iPtr++;
- PG_RETURN_BOOL(true);
+ return true;
}
if (so->want_itup)
@@ -651,19 +636,16 @@ spggettuple(PG_FUNCTION_ARGS)
break; /* must have completed scan */
}
- PG_RETURN_BOOL(false);
+ return false;
}
-Datum
-spgcanreturn(PG_FUNCTION_ARGS)
+bool
+spgcanreturn(Relation index, int attno)
{
- Relation index = (Relation) PG_GETARG_POINTER(0);
-
- /* int i = PG_GETARG_INT32(1); */
SpGistCache *cache;
/* We can do it if the opclass config function says so */
cache = spgGetCache(index);
- PG_RETURN_BOOL(cache->config.canReturnData);
+ return cache->config.canReturnData;
}
diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c
index f38287c..3de4494 100644
--- a/src/backend/access/spgist/spgutils.c
+++ b/src/backend/access/spgist/spgutils.c
@@ -24,8 +24,104 @@
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "utils/lsyscache.h"
+#include "utils/selfuncs.h"
+/*
+ * SP-GiST handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+Datum
+spghandler(PG_FUNCTION_ARGS)
+{
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 5;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = spginsert;
+ amroutine->ambeginscan = spgbeginscan;
+ amroutine->amgettuple = spggettuple;
+ amroutine->amgetbitmap = spggetbitmap;
+ amroutine->amrescan = spgrescan;
+ amroutine->amendscan = spgendscan;
+ amroutine->ammarkpos = spgmarkpos;
+ amroutine->amrestrpos = spgrestrpos;
+ amroutine->ambuild = spgbuild;
+ amroutine->ambuildempty = spgbuildempty;
+ amroutine->ambulkdelete = spgbulkdelete;
+ amroutine->amvacuumcleanup = spgvacuumcleanup;
+ amroutine->amcanreturn = spgcanreturn;
+ amroutine->amcostestimate = spgcostestimate;
+ amroutine->amoptions = spgoptions;
+ amroutine->amvalidate = spgvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+}
+
+void
+spgvalidate(OpClassInfo *opclass)
+{
+ ListCell *l;
+ bool procsPresent[SPGISTNProc];
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype ||
+ proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > SPGISTNProc)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("Invalid support number for SP-GiST: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u was defined more than once",
+ proc->number)));
+
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < SPGISTNProc; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST doesn't support order by operators")));
+ }
+}
+
/* Fill in a SpGistTypeDesc struct with info about the specified data type */
static void
fillTypeDesc(SpGistTypeDesc *desc, Oid type)
@@ -489,18 +585,16 @@ SpGistInitMetapage(Page page)
/*
* reloptions processing for SPGiST
*/
-Datum
-spgoptions(PG_FUNCTION_ARGS)
+bytea *
+spgoptions(Datum reloptions, bool validate)
{
- Datum reloptions = PG_GETARG_DATUM(0);
- bool validate = PG_GETARG_BOOL(1);
bytea *result;
result = default_reloptions(reloptions, validate, RELOPT_KIND_SPGIST);
if (result)
- PG_RETURN_BYTEA_P(result);
- PG_RETURN_NULL();
+ return (bytea *)result;
+ return NULL;
}
/*
diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c
index 06c0b0a..c3856a1 100644
--- a/src/backend/access/spgist/spgvacuum.c
+++ b/src/backend/access/spgist/spgvacuum.c
@@ -881,13 +881,10 @@ spgvacuumscan(spgBulkDeleteState *bds)
*
* Result: a palloc'd struct containing statistical info for VACUUM displays.
*/
-Datum
-spgbulkdelete(PG_FUNCTION_ARGS)
+IndexBulkDeleteResult *
+spgbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback, void *callback_state)
{
- IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
- IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
- IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
- void *callback_state = (void *) PG_GETARG_POINTER(3);
spgBulkDeleteState bds;
/* allocate stats if first time through, else re-use existing struct */
@@ -900,7 +897,7 @@ spgbulkdelete(PG_FUNCTION_ARGS)
spgvacuumscan(&bds);
- PG_RETURN_POINTER(stats);
+ return stats;
}
/* Dummy callback to delete no tuples during spgvacuumcleanup */
@@ -915,17 +912,15 @@ dummy_callback(ItemPointer itemptr, void *state)
*
* Result: a palloc'd struct containing statistical info for VACUUM displays.
*/
-Datum
-spgvacuumcleanup(PG_FUNCTION_ARGS)
+IndexBulkDeleteResult *
+spgvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
{
- IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
- IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
Relation index = info->index;
spgBulkDeleteState bds;
/* No-op in ANALYZE ONLY mode */
if (info->analyze_only)
- PG_RETURN_POINTER(stats);
+ return stats;
/*
* We don't need to scan the index if there was a preceding bulkdelete
@@ -959,5 +954,5 @@ spgvacuumcleanup(PG_FUNCTION_ARGS)
stats->num_index_tuples = info->num_heap_tuples;
}
- PG_RETURN_POINTER(stats);
+ return stats;
}
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index e59b163..8ace03d 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -23,6 +23,7 @@
#include <unistd.h>
+#include "access/amapi.h"
#include "access/multixact.h"
#include "access/relscan.h"
#include "access/sysattr.h"
@@ -277,20 +278,14 @@ ConstructTupleDescriptor(Relation heapRelation,
int numatts = indexInfo->ii_NumIndexAttrs;
ListCell *colnames_item = list_head(indexColNames);
ListCell *indexpr_item = list_head(indexInfo->ii_Expressions);
- HeapTuple amtuple;
- Form_pg_am amform;
+ IndexAmRoutine *amroutine;
TupleDesc heapTupDesc;
TupleDesc indexTupDesc;
int natts; /* #atts in heap rel --- for error checks */
int i;
/* We need access to the index AM's pg_am tuple */
- amtuple = SearchSysCache1(AMOID,
- ObjectIdGetDatum(accessMethodObjectId));
- if (!HeapTupleIsValid(amtuple))
- elog(ERROR, "cache lookup failed for access method %u",
- accessMethodObjectId);
- amform = (Form_pg_am) GETSTRUCT(amtuple);
+ amroutine = GetIndexAmRoutine(accessMethodObjectId);
/* ... and to the table's tuple descriptor */
heapTupDesc = RelationGetDescr(heapRelation);
@@ -437,7 +432,7 @@ ConstructTupleDescriptor(Relation heapRelation,
if (OidIsValid(opclassTup->opckeytype))
keyType = opclassTup->opckeytype;
else
- keyType = amform->amkeytype;
+ keyType = amroutine->amkeytype;
ReleaseSysCache(tuple);
if (OidIsValid(keyType) && keyType != to->atttypid)
@@ -459,8 +454,6 @@ ConstructTupleDescriptor(Relation heapRelation,
}
}
- ReleaseSysCache(amtuple);
-
return indexTupDesc;
}
@@ -1988,7 +1981,6 @@ index_build(Relation heapRelation,
bool isprimary,
bool isreindex)
{
- RegProcedure procedure;
IndexBuildResult *stats;
Oid save_userid;
int save_sec_context;
@@ -1998,10 +1990,8 @@ index_build(Relation heapRelation,
* sanity checks
*/
Assert(RelationIsValid(indexRelation));
- Assert(PointerIsValid(indexRelation->rd_am));
-
- procedure = indexRelation->rd_am->ambuild;
- Assert(RegProcedureIsValid(procedure));
+ Assert(PointerIsValid(indexRelation->amroutine));
+ Assert(PointerIsValid(indexRelation->amroutine->ambuild));
ereport(DEBUG1,
(errmsg("building index \"%s\" on table \"%s\"",
@@ -2021,11 +2011,8 @@ index_build(Relation heapRelation,
/*
* Call the access method's build procedure
*/
- stats = (IndexBuildResult *)
- DatumGetPointer(OidFunctionCall3(procedure,
- PointerGetDatum(heapRelation),
- PointerGetDatum(indexRelation),
- PointerGetDatum(indexInfo)));
+ stats = indexRelation->amroutine->ambuild(heapRelation, indexRelation,
+ indexInfo);
Assert(PointerIsValid(stats));
/*
@@ -2038,11 +2025,9 @@ index_build(Relation heapRelation,
if (indexRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
!smgrexists(indexRelation->rd_smgr, INIT_FORKNUM))
{
- RegProcedure ambuildempty = indexRelation->rd_am->ambuildempty;
-
RelationOpenSmgr(indexRelation);
smgrcreate(indexRelation->rd_smgr, INIT_FORKNUM, false);
- OidFunctionCall1(ambuildempty, PointerGetDatum(indexRelation));
+ indexRelation->amroutine->ambuildempty(indexRelation);
}
/*
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 7ab4874..7a7fd95 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -17,6 +17,7 @@
*/
#include "postgres.h"
+#include "access/amapi.h"
#include "access/multixact.h"
#include "access/relscan.h"
#include "access/rewriteheap.h"
@@ -433,7 +434,7 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck, LOCKMOD
RelationGetRelationName(OldHeap))));
/* Index AM must allow clustering */
- if (!OldIndex->rd_am->amclusterable)
+ if (!OldIndex->amroutine->amclusterable)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot cluster on index \"%s\" because access method does not support clustering",
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b450bcf..9951993 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -15,6 +15,7 @@
#include "postgres.h"
+#include "access/amapi.h"
#include "access/htup_details.h"
#include "access/reloptions.h"
#include "access/xact.h"
@@ -125,6 +126,7 @@ CheckIndexCompatible(Oid oldId,
HeapTuple tuple;
Form_pg_index indexForm;
Form_pg_am accessMethodForm;
+ IndexAmRoutine *amRoutine;
bool amcanorder;
int16 *coloptions;
IndexInfo *indexInfo;
@@ -160,7 +162,9 @@ CheckIndexCompatible(Oid oldId,
accessMethodName)));
accessMethodId = HeapTupleGetOid(tuple);
accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
- amcanorder = accessMethodForm->amcanorder;
+ amRoutine = (IndexAmRoutine *)DatumGetPointer(
+ OidFunctionCall0(accessMethodForm->amhandler));
+ amcanorder = amRoutine->amcanorder;
ReleaseSysCache(tuple);
/*
@@ -315,8 +319,9 @@ DefineIndex(Oid relationId,
Relation indexRelation;
HeapTuple tuple;
Form_pg_am accessMethodForm;
+ IndexAmRoutine *amRoutine;
bool amcanorder;
- RegProcedure amoptions;
+ amoptions_function amoptions;
Datum reloptions;
int16 *coloptions;
IndexInfo *indexInfo;
@@ -489,30 +494,32 @@ DefineIndex(Oid relationId,
}
accessMethodId = HeapTupleGetOid(tuple);
accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
+ amRoutine = (IndexAmRoutine *)DatumGetPointer(
+ OidFunctionCall0(accessMethodForm->amhandler));
if (strcmp(accessMethodName, "hash") == 0 &&
RelationNeedsWAL(rel))
ereport(WARNING,
(errmsg("hash indexes are not WAL-logged and their use is discouraged")));
- if (stmt->unique && !accessMethodForm->amcanunique)
+ if (stmt->unique && !amRoutine->amcanunique)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("access method \"%s\" does not support unique indexes",
accessMethodName)));
- if (numberOfAttributes > 1 && !accessMethodForm->amcanmulticol)
+ if (numberOfAttributes > 1 && !amRoutine->amcanmulticol)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("access method \"%s\" does not support multicolumn indexes",
accessMethodName)));
- if (stmt->excludeOpNames && !OidIsValid(accessMethodForm->amgettuple))
+ if (stmt->excludeOpNames && !OidIsValid(amRoutine->amgettuple))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("access method \"%s\" does not support exclusion constraints",
accessMethodName)));
- amcanorder = accessMethodForm->amcanorder;
- amoptions = accessMethodForm->amoptions;
+ amcanorder = amRoutine->amcanorder;
+ amoptions = amRoutine->amoptions;
ReleaseSysCache(tuple);
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index 3375f10..672a4a2 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -42,6 +42,7 @@
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
+#include "utils/catcache.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
@@ -334,13 +335,14 @@ DefineOpClass(CreateOpClassStmt *stmt)
ListCell *l;
Relation rel;
HeapTuple tup;
- Form_pg_am pg_am;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
+ IndexAmRoutine *amroutine;
+ OpClassInfo opclassinfo;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
@@ -361,13 +363,15 @@ DefineOpClass(CreateOpClassStmt *stmt)
stmt->amname)));
amoid = HeapTupleGetOid(tup);
- pg_am = (Form_pg_am) GETSTRUCT(tup);
- maxOpNumber = pg_am->amstrategies;
+
+ amroutine = GetIndexAmRoutine(amoid);
+
+ maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
- maxProcNumber = pg_am->amsupport;
- amstorage = pg_am->amstorage;
+ maxProcNumber = amroutine->amsupport;
+ amstorage = amroutine->amstorage;
/* XXX Should we make any privilege check against the AM? */
@@ -582,6 +586,12 @@ DefineOpClass(CreateOpClassStmt *stmt)
stmt->amname)));
}
+ opclassinfo.intype = typeoid;
+ opclassinfo.keytype = storageoid;
+ opclassinfo.procedures = procedures;
+ opclassinfo.operators = operators;
+ amroutine->amvalidate(&opclassinfo);
+
rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
/*
@@ -718,6 +728,90 @@ DefineOpClass(CreateOpClassStmt *stmt)
return myself;
}
+/*
+ * Collect opfamily information for opclass validation.
+ */
+static void
+getOpFamilyInfo(OpClassInfo *opclassinfo, Oid opfamilyoid)
+{
+ CatCList *catlist;
+ int i;
+
+ opclassinfo->operators = NIL;
+ opclassinfo->procedures = NIL;
+
+ /* Find operators */
+ catlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ for (i = 0; i < catlist->n_members; i++)
+ {
+ HeapTuple oprtup = &catlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+ OpFamilyMember *opmember = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
+
+ opmember->object = oprform->amopopr;
+ opmember->number = oprform->amopstrategy;
+ opmember->lefttype = oprform->amoplefttype;
+ opmember->righttype = oprform->amoprighttype;
+ opmember->sortfamily = oprform->amopsortfamily;
+
+ opclassinfo->operators = lappend(opclassinfo->operators, opmember);
+ }
+ ReleaseCatCacheList(catlist);
+
+ /* Find support functions */
+ catlist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+ for (i = 0; i < catlist->n_members; i++)
+ {
+ HeapTuple proctup = &catlist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+ OpFamilyMember *procmember = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
+
+ procmember->object = procform->amproc;
+ procmember->number = procform->amprocnum;
+ procmember->lefttype = procform->amproclefttype;
+ procmember->righttype = procform->amprocrighttype;
+
+ opclassinfo->procedures = lappend(opclassinfo->procedures, procmember);
+ }
+ ReleaseCatCacheList(catlist);
+}
+
+/*
+ * Ask access method to validate given opclass.
+ */
+Datum
+amvalidate(PG_FUNCTION_ARGS)
+{
+ OpClassInfo opclassinfo;
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opclassoid = PG_GETARG_OID(0),
+ opfamilyoid,
+ amoid;
+ IndexAmRoutine *amroutine;
+
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ opclassinfo.intype = classform->opcintype;
+ opclassinfo.keytype = classform->opckeytype;
+ opfamilyoid = classform->opcfamily;
+ amoid = classform->opcmethod;
+
+ ReleaseSysCache(classtup);
+
+ getOpFamilyInfo(&opclassinfo, opfamilyoid);
+
+ amroutine = GetIndexAmRoutine(amoid);
+
+ amroutine->amvalidate(&opclassinfo);
+
+ PG_RETURN_BOOL(true);
+}
+
/*
* DefineOpFamily
@@ -776,7 +870,7 @@ AlterOpFamily(AlterOpFamilyStmt *stmt)
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
- Form_pg_am pg_am;
+ IndexAmRoutine *amroutine;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
@@ -787,16 +881,16 @@ AlterOpFamily(AlterOpFamilyStmt *stmt)
stmt->amname)));
amoid = HeapTupleGetOid(tup);
- pg_am = (Form_pg_am) GETSTRUCT(tup);
- maxOpNumber = pg_am->amstrategies;
+ amroutine = GetIndexAmRoutine(amoid);
+ ReleaseSysCache(tup);
+ maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
- maxProcNumber = pg_am->amsupport;
+ maxProcNumber = amroutine->amsupport;
/* XXX Should we make any privilege check against the AM? */
- ReleaseSysCache(tup);
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
@@ -1099,21 +1193,15 @@ assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
* the family has been created but not yet populated with the required
* operators.)
*/
- HeapTuple amtup;
- Form_pg_am pg_am;
+ IndexAmRoutine *amroutine;
- amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
- if (amtup == NULL)
- elog(ERROR, "cache lookup failed for access method %u", amoid);
- pg_am = (Form_pg_am) GETSTRUCT(amtup);
+ amroutine = GetIndexAmRoutine(amoid);
- if (!pg_am->amcanorderbyop)
+ if (!amroutine->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
- NameStr(pg_am->amname))));
-
- ReleaseSysCache(amtup);
+ get_am_name(amoid))));
}
else
{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 126b119..c4cc9b4 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -9363,7 +9363,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
(void) view_reloptions(newOptions, true);
break;
case RELKIND_INDEX:
- (void) index_reloptions(rel->rd_am->amoptions, newOptions, true);
+ (void) index_reloptions(rel->amroutine->amoptions, newOptions, true);
break;
default:
ereport(ERROR,
@@ -10954,7 +10954,7 @@ ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode
RelationGetRelationName(indexRel),
RelationGetRelationName(rel))));
/* The AM must support uniqueness, and the index must in fact be unique. */
- if (!indexRel->rd_am->amcanunique || !indexRel->rd_index->indisunique)
+ if (!indexRel->amroutine->amcanunique || !indexRel->rd_index->indisunique)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot use non-unique index \"%s\" as replica identity",
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index 93e1e9a..13fc2e2 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -12,6 +12,7 @@
*/
#include "postgres.h"
+#include "access/amapi.h"
#include "access/htup_details.h"
#include "executor/execdebug.h"
#include "executor/nodeAgg.h"
@@ -528,6 +529,7 @@ IndexSupportsBackwardScan(Oid indexid)
HeapTuple ht_am;
Form_pg_class idxrelrec;
Form_pg_am amrec;
+ IndexAmRoutine *amroutine;
/* Fetch the pg_class tuple of the index relation */
ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexid));
@@ -541,9 +543,11 @@ IndexSupportsBackwardScan(Oid indexid)
elog(ERROR, "cache lookup failed for access method %u",
idxrelrec->relam);
amrec = (Form_pg_am) GETSTRUCT(ht_am);
+ amroutine = (IndexAmRoutine *)DatumGetPointer(OidFunctionCall0(amrec->amhandler));
- result = amrec->amcanbackward;
+ result = amroutine->amcanbackward;
+ pfree(amroutine);
ReleaseSysCache(ht_idxrel);
ReleaseSysCache(ht_am);
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index c0f14db..2de0579 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -1436,7 +1436,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
Assert(rightop != NULL);
- if (index->rd_am->amsearcharray)
+ if (index->amroutine->amsearcharray)
{
/* Index AM will handle this like a simple operator */
flags |= SK_SEARCHARRAY;
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index d107d76..6853899 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -368,14 +368,8 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count)
* the fraction of main-table tuples we will have to retrieve) and its
* correlation to the main-table tuple order.
*/
- OidFunctionCall7(index->amcostestimate,
- PointerGetDatum(root),
- PointerGetDatum(path),
- Float8GetDatum(loop_count),
- PointerGetDatum(&indexStartupCost),
- PointerGetDatum(&indexTotalCost),
- PointerGetDatum(&indexSelectivity),
- PointerGetDatum(&indexCorrelation));
+ index->amroutine->amcostestimate(root, path, loop_count, &indexStartupCost,
+ &indexTotalCost, &indexSelectivity, &indexCorrelation);
/*
* Save amcostestimate's results for possible use in bitmap scan planning.
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 9442e5f..d3d5d43 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -223,13 +223,13 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
}
info->relam = indexRelation->rd_rel->relam;
- info->amcostestimate = indexRelation->rd_am->amcostestimate;
- info->amcanorderbyop = indexRelation->rd_am->amcanorderbyop;
- info->amoptionalkey = indexRelation->rd_am->amoptionalkey;
- info->amsearcharray = indexRelation->rd_am->amsearcharray;
- info->amsearchnulls = indexRelation->rd_am->amsearchnulls;
- info->amhasgettuple = OidIsValid(indexRelation->rd_am->amgettuple);
- info->amhasgetbitmap = OidIsValid(indexRelation->rd_am->amgetbitmap);
+ info->amroutine = indexRelation->amroutine;
+ info->amcanorderbyop = indexRelation->amroutine->amcanorderbyop;
+ info->amoptionalkey = indexRelation->amroutine->amoptionalkey;
+ info->amsearcharray = indexRelation->amroutine->amsearcharray;
+ info->amsearchnulls = indexRelation->amroutine->amsearchnulls;
+ info->amhasgettuple = OidIsValid(indexRelation->amroutine->amgettuple);
+ info->amhasgetbitmap = OidIsValid(indexRelation->amroutine->amgetbitmap);
/*
* Fetch the ordering information for the index, if any.
@@ -240,7 +240,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
* If it's a btree index, we can use its opfamily OIDs
* directly as the sort ordering opfamily OIDs.
*/
- Assert(indexRelation->rd_am->amcanorder);
+ Assert(indexRelation->amroutine->amcanorder);
info->sortopfamily = info->opfamily;
info->reverse_sort = (bool *) palloc(sizeof(bool) * ncolumns);
@@ -254,7 +254,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0;
}
}
- else if (indexRelation->rd_am->amcanorder)
+ else if (indexRelation->amroutine->amcanorder)
{
/*
* Otherwise, identify the corresponding btree opfamilies by
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 16d40c7..0031511 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -26,6 +26,7 @@
#include "postgres.h"
+#include "access/amapi.h"
#include "access/htup_details.h"
#include "access/reloptions.h"
#include "catalog/dependency.h"
@@ -1258,7 +1259,7 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
/* Adjust options if necessary */
- if (amrec->amcanorder)
+ if (source_idx->amroutine->amcanorder)
{
/*
* If it supports sort ordering, copy DESC and NULLS opts. Don't
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 94e748e..63d6f0d 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -2420,7 +2420,7 @@ extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
- relopts = extractRelOptions(tup, pg_class_desc, InvalidOid);
+ relopts = extractRelOptions(tup, pg_class_desc, NULL);
if (relopts == NULL)
return NULL;
diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c
index 5b809aa..bdd451d 100644
--- a/src/backend/utils/adt/pseudotypes.c
+++ b/src/backend/utils/adt/pseudotypes.c
@@ -401,6 +401,33 @@ tsm_handler_out(PG_FUNCTION_ARGS)
/*
+ * index_am_handler_in - input routine for pseudo-type INDEX_AM_HANDLER.
+ */
+Datum
+index_am_handler_in(PG_FUNCTION_ARGS)
+{
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot accept a value of type index_am_handler")));
+
+ PG_RETURN_VOID(); /* keep compiler quiet */
+}
+
+/*
+ * index_am_handler_out - output routine for pseudo-type INDEX_AM_HANDLER.
+ */
+Datum
+index_am_handler_out(PG_FUNCTION_ARGS)
+{
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot display a value of type index_am_handler")));
+
+ PG_RETURN_VOID(); /* keep compiler quiet */
+}
+
+
+/*
* internal_in - input routine for pseudo-type INTERNAL.
*/
Datum
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 51391f6..7d9577a 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -19,6 +19,7 @@
#include <unistd.h>
#include <fcntl.h>
+#include "access/amapi.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "catalog/dependency.h"
@@ -1167,6 +1168,7 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
if (!attrsOnly && (!colno || colno == keyno + 1))
{
Oid indcoll;
+ IndexAmRoutine *amroutine;
/* Add collation, if not default for column */
indcoll = indcollation->values[keyno];
@@ -1177,8 +1179,11 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
/* Add the operator class name, if not default */
get_opclass_name(indclass->values[keyno], keycoltype, &buf);
+ amroutine = (IndexAmRoutine *)DatumGetPointer(
+ OidFunctionCall0(amrec->amhandler));
+
/* Add options if relevant */
- if (amrec->amcanorder)
+ if (amroutine->amcanorder)
{
/* if it supports sort ordering, report DESC and NULLS opts */
if (opt & INDOPTION_DESC)
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 37fad86..9a83e10 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -6443,16 +6443,11 @@ add_predicate_to_quals(IndexOptInfo *index, List *indexQuals)
}
-Datum
-btcostestimate(PG_FUNCTION_ARGS)
+void
+btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
+ Cost *indexStartupCost, Cost *indexTotalCost,
+ Selectivity *indexSelectivity, double *indexCorrelation)
{
- PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
- IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1);
- double loop_count = PG_GETARG_FLOAT8(2);
- Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3);
- Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4);
- Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
- double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
IndexOptInfo *index = path->indexinfo;
List *qinfos;
GenericCosts costs;
@@ -6741,20 +6736,13 @@ btcostestimate(PG_FUNCTION_ARGS)
*indexTotalCost = costs.indexTotalCost;
*indexSelectivity = costs.indexSelectivity;
*indexCorrelation = costs.indexCorrelation;
-
- PG_RETURN_VOID();
}
-Datum
-hashcostestimate(PG_FUNCTION_ARGS)
+void
+hashcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
+ Cost *indexStartupCost, Cost *indexTotalCost,
+ Selectivity *indexSelectivity, double *indexCorrelation)
{
- PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
- IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1);
- double loop_count = PG_GETARG_FLOAT8(2);
- Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3);
- Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4);
- Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
- double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
List *qinfos;
GenericCosts costs;
@@ -6794,20 +6782,13 @@ hashcostestimate(PG_FUNCTION_ARGS)
*indexTotalCost = costs.indexTotalCost;
*indexSelectivity = costs.indexSelectivity;
*indexCorrelation = costs.indexCorrelation;
-
- PG_RETURN_VOID();
}
-Datum
-gistcostestimate(PG_FUNCTION_ARGS)
+void
+gistcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
+ Cost *indexStartupCost, Cost *indexTotalCost,
+ Selectivity *indexSelectivity, double *indexCorrelation)
{
- PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
- IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1);
- double loop_count = PG_GETARG_FLOAT8(2);
- Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3);
- Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4);
- Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
- double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
IndexOptInfo *index = path->indexinfo;
List *qinfos;
GenericCosts costs;
@@ -6860,20 +6841,13 @@ gistcostestimate(PG_FUNCTION_ARGS)
*indexTotalCost = costs.indexTotalCost;
*indexSelectivity = costs.indexSelectivity;
*indexCorrelation = costs.indexCorrelation;
-
- PG_RETURN_VOID();
}
-Datum
-spgcostestimate(PG_FUNCTION_ARGS)
+void
+spgcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
+ Cost *indexStartupCost, Cost *indexTotalCost,
+ Selectivity *indexSelectivity, double *indexCorrelation)
{
- PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
- IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1);
- double loop_count = PG_GETARG_FLOAT8(2);
- Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3);
- Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4);
- Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
- double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
IndexOptInfo *index = path->indexinfo;
List *qinfos;
GenericCosts costs;
@@ -6926,8 +6900,6 @@ spgcostestimate(PG_FUNCTION_ARGS)
*indexTotalCost = costs.indexTotalCost;
*indexSelectivity = costs.indexSelectivity;
*indexCorrelation = costs.indexCorrelation;
-
- PG_RETURN_VOID();
}
@@ -7222,16 +7194,11 @@ gincost_scalararrayopexpr(PlannerInfo *root,
/*
* GIN has search behavior completely different from other index types
*/
-Datum
-gincostestimate(PG_FUNCTION_ARGS)
+void
+gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
+ Cost *indexStartupCost, Cost *indexTotalCost,
+ Selectivity *indexSelectivity, double *indexCorrelation)
{
- PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
- IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1);
- double loop_count = PG_GETARG_FLOAT8(2);
- Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3);
- Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4);
- Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
- double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
IndexOptInfo *index = path->indexinfo;
List *indexQuals = path->indexquals;
List *indexOrderBys = path->indexorderbys;
@@ -7382,7 +7349,7 @@ gincostestimate(PG_FUNCTION_ARGS)
*indexStartupCost = 0;
*indexTotalCost = 0;
*indexSelectivity = 0;
- PG_RETURN_VOID();
+ return;
}
if (counts.haveFullScan || indexQuals == NIL)
@@ -7504,23 +7471,16 @@ gincostestimate(PG_FUNCTION_ARGS)
*indexStartupCost += qual_arg_cost;
*indexTotalCost += qual_arg_cost;
*indexTotalCost += (numTuples * *indexSelectivity) * (cpu_index_tuple_cost + qual_op_cost);
-
- PG_RETURN_VOID();
}
/*
* BRIN has search behavior completely different from other index types
*/
-Datum
-brincostestimate(PG_FUNCTION_ARGS)
+void
+brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
+ Cost *indexStartupCost, Cost *indexTotalCost,
+ Selectivity *indexSelectivity, double *indexCorrelation)
{
- PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
- IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1);
- double loop_count = PG_GETARG_FLOAT8(2);
- Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3);
- Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4);
- Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
- double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
IndexOptInfo *index = path->indexinfo;
List *indexQuals = path->indexquals;
List *indexOrderBys = path->indexorderbys;
@@ -7573,6 +7533,4 @@ brincostestimate(PG_FUNCTION_ARGS)
*indexTotalCost += (numTuples * *indexSelectivity) * (cpu_index_tuple_cost + qual_op_cost);
/* XXX what about pages_per_range? */
-
- PG_RETURN_VOID();
}
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 9c3d096..9febc95 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -445,7 +445,7 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple)
options = extractRelOptions(tuple,
GetPgClassDescriptor(),
relation->rd_rel->relkind == RELKIND_INDEX ?
- relation->rd_am->amoptions : InvalidOid);
+ relation->amroutine->amoptions : NULL);
/*
* Copy parsed data into CacheMemoryContext. To guard against the
@@ -1160,13 +1160,58 @@ RelationInitPhysicalAddr(Relation relation)
}
/*
+ * Get IndexAmRoutine structure from access method oid.
+ */
+IndexAmRoutine *
+GetIndexAmRoutine(Oid amoid)
+{
+ IndexAmRoutine *result;
+ HeapTuple tuple;
+ regproc amhandler;
+
+ tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for access method %u",
+ amoid);
+ amhandler = ((Form_pg_am)GETSTRUCT(tuple))->amhandler;
+
+ if (!RegProcedureIsValid(amhandler))
+ elog(ERROR, "invalid %u regproc", amhandler);
+
+ result = (IndexAmRoutine *)DatumGetPointer(OidFunctionCall0(amhandler));
+
+ if (result == NULL || !IsA(result, IndexAmRoutine))
+ elog(ERROR, "index access method handler function %u did not return an IndexAmRoutine struct",
+ amhandler);
+
+ ReleaseSysCache(tuple);
+
+ return result;
+}
+
+/*
+ * Initialize IndexAmRoutine for relation.
+ */
+void
+InitIndexAmRoutine(Relation relation)
+{
+ IndexAmRoutine *result, *tmp;
+
+ result = (IndexAmRoutine *)MemoryContextAlloc(CacheMemoryContext,
+ sizeof(IndexAmRoutine));
+ tmp = (IndexAmRoutine *)DatumGetPointer(
+ OidFunctionCall0(relation->rd_am->amhandler));
+ memcpy(result, tmp, sizeof(IndexAmRoutine));
+ relation->amroutine = result;
+}
+
+/*
* Initialize index-access-method support data for an index relation
*/
void
RelationInitIndexAccessInfo(Relation relation)
{
HeapTuple tuple;
- Form_pg_am aform;
Datum indcollDatum;
Datum indclassDatum;
Datum indoptionDatum;
@@ -1178,6 +1223,7 @@ RelationInitIndexAccessInfo(Relation relation)
MemoryContext oldcontext;
int natts;
uint16 amsupport;
+ Form_pg_am aform;
/*
* Make a copy of the pg_index entry for the index. Since pg_index
@@ -1202,16 +1248,18 @@ RelationInitIndexAccessInfo(Relation relation)
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for access method %u",
relation->rd_rel->relam);
- aform = (Form_pg_am) MemoryContextAlloc(CacheMemoryContext, sizeof *aform);
+ aform = (Form_pg_am)MemoryContextAlloc(CacheMemoryContext, sizeof *aform);
memcpy(aform, GETSTRUCT(tuple), sizeof *aform);
ReleaseSysCache(tuple);
relation->rd_am = aform;
+ InitIndexAmRoutine(relation);
+
natts = relation->rd_rel->relnatts;
if (natts != relation->rd_index->indnatts)
elog(ERROR, "relnatts disagrees with indnatts for index %u",
RelationGetRelid(relation));
- amsupport = aform->amsupport;
+ amsupport = relation->amroutine->amsupport;
/*
* Make the private context to hold index access info. The reason we need
@@ -4743,7 +4791,6 @@ load_relcache_init_file(bool shared)
Oid *opfamily;
Oid *opcintype;
RegProcedure *support;
- int nsupport;
int16 *indoption;
Oid *indcollation;
@@ -4771,6 +4818,7 @@ load_relcache_init_file(bool shared)
if (fread(am, 1, len, fp) != len)
goto read_failed;
rel->rd_am = am;
+ rel->amroutine = NULL;
/*
* prepare index info context --- parameters should match
@@ -4832,12 +4880,13 @@ load_relcache_init_file(bool shared)
rel->rd_indoption = indoption;
+ InitIndexAmRoutine(rel);
+
/* set up zeroed fmgr-info vectors */
rel->rd_aminfo = (RelationAmInfo *)
MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
- nsupport = relform->relnatts * am->amsupport;
rel->rd_supportinfo = (FmgrInfo *)
- MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
+ MemoryContextAllocZero(indexcxt, relform->relnatts * rel->amroutine->amsupport * sizeof(FmgrInfo));
}
else
{
@@ -5106,7 +5155,7 @@ write_relcache_init_file(bool shared)
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
- relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
+ relform->relnatts * (rel->amroutine->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h
new file mode 100644
index 0000000..2e0257a
--- /dev/null
+++ b/src/include/access/amapi.h
@@ -0,0 +1,169 @@
+/*-------------------------------------------------------------------------
+ *
+ * amapi.h
+ * API for access methods
+ *
+ * Copyright (c) 2015, PostgreSQL Global Development Group
+ *
+ * src/include/access/amapi.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef AMAPI_H
+#define AMAPI_H
+
+#include "access/genam.h"
+#include "catalog/opfam_internal.h"
+#include "nodes/relation.h"
+
+/*
+ * Callback function signatures --- see indexam.sgml for more info.
+ */
+
+/* "insert this tuple" function */
+typedef bool
+(*aminsert_function) (Relation indexRelation,
+ Datum *values,
+ bool *isnull,
+ ItemPointer heap_tid,
+ Relation heapRelation,
+ IndexUniqueCheck checkUnique);
+
+/* "prepare for index scan" function */
+typedef IndexScanDesc
+(*ambeginscan_function) (Relation indexRelation,
+ int nkeys,
+ int norderbys);
+
+/* "next valid tuple" function, or NULL */
+typedef bool
+(*amgettuple_function) (IndexScanDesc scan,
+ ScanDirection direction);
+
+/* "fetch all valid tuples" function, or NULL */
+typedef int64
+(*amgetbitmap_function) (IndexScanDesc scan,
+ TIDBitmap *tbm);
+
+/* "(re)start index scan" function */
+typedef void
+(*amrescan_function) (IndexScanDesc scan,
+ ScanKey keys,
+ int nkeys,
+ ScanKey orderbys,
+ int norderbys);
+
+/* "end index scan" function */
+typedef void
+(*amendscan_function) (IndexScanDesc scan);
+
+/* "mark current scan position" function */
+typedef void
+(*ammarkpos_function) (IndexScanDesc scan);
+
+/* "restore marked scan position" function */
+typedef void
+(*amrestrpos_function) (IndexScanDesc scan);
+
+/* "build new index" function */
+typedef IndexBuildResult *
+(*ambuild_function) (Relation heapRelation,
+ Relation indexRelation,
+ IndexInfo *indexInfo);
+
+/* "build empty index" function */
+typedef void
+(*ambuildempty_function) (Relation indexRelation);
+
+/* bulk-delete function */
+typedef IndexBulkDeleteResult *
+(*ambulkdelete_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+
+/* post-VACUUM cleanup function */
+typedef IndexBulkDeleteResult *
+(*amvacuumcleanup_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
+
+/* can indexscan return IndexTuples? */
+typedef bool
+(*amcanreturn_function) (Relation indexRelation, int attno);
+
+/* estimate cost of an indexscan */
+typedef void
+(*amcostestimate_function) (PlannerInfo *root,
+ IndexPath *path,
+ double loop_count,
+ Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+
+/* parse AM-specific parameters */
+typedef bytea *
+(*amoptions_function) (Datum reloptions,
+ bool validate);
+
+/* validate oplass */
+typedef void
+(*amvalidate_function) (OpClassInfo *opclass);
+
+
+struct IndexAmRoutine
+{
+ NodeTag type;
+
+ /*
+ * Total number of strategies (operators) by which we can traverse/search
+ * this AM. Zero if AM does not have a fixed set of strategy assignments.
+ */
+ int16 amstrategies;
+ /* total number of support functions that this AM uses */
+ int16 amsupport;
+ /* does AM support order by column value? */
+ bool amcanorder;
+ /* does AM support order by operator result? */
+ bool amcanorderbyop;
+ /* does AM support backward scan? */
+ bool amcanbackward;
+ /* does AM support UNIQUE indexes? */
+ bool amcanunique;
+ /* does AM support multi-column indexes? */
+ bool amcanmulticol;
+ /* can query omit key for the first column? */
+ bool amoptionalkey;
+ /* can AM handle ScalarArrayOpExpr quals? */
+ bool amsearcharray;
+ /* can AM search for NULL/NOT NULL entries? */
+ bool amsearchnulls;
+ /* can storage type differ from column type? */
+ bool amstorage;
+ /* does AM support cluster command? */
+ bool amclusterable;
+ /* does AM handle predicate locks? */
+ bool ampredlocks;
+ /* type of data in index, or InvalidOid */
+ Oid amkeytype;
+
+ /* interface functions */
+ aminsert_function aminsert;
+ ambeginscan_function ambeginscan;
+ amgettuple_function amgettuple;
+ amgetbitmap_function amgetbitmap;
+ amrescan_function amrescan;
+ amendscan_function amendscan;
+ ammarkpos_function ammarkpos;
+ amrestrpos_function amrestrpos;
+ ambuild_function ambuild;
+ ambuildempty_function ambuildempty;
+ ambulkdelete_function ambulkdelete;
+ amvacuumcleanup_function amvacuumcleanup;
+ amcanreturn_function amcanreturn;
+ amcostestimate_function amcostestimate;
+ amoptions_function amoptions;
+ amvalidate_function amvalidate;
+};
+
+#endif /* AMAPI_H */
diff --git a/src/include/access/brin.h b/src/include/access/brin.h
index e72fb2d..5ae5722 100644
--- a/src/include/access/brin.h
+++ b/src/include/access/brin.h
@@ -10,6 +10,7 @@
#ifndef BRIN_H
#define BRIN_H
+#include "access/amapi.h"
#include "fmgr.h"
#include "nodes/execnodes.h"
#include "utils/relcache.h"
@@ -18,19 +19,33 @@
/*
* prototypes for functions in brin.c (external entry points for BRIN)
*/
-extern Datum brinbuild(PG_FUNCTION_ARGS);
-extern Datum brinbuildempty(PG_FUNCTION_ARGS);
-extern Datum brininsert(PG_FUNCTION_ARGS);
-extern Datum brinbeginscan(PG_FUNCTION_ARGS);
-extern Datum bringetbitmap(PG_FUNCTION_ARGS);
-extern Datum brinrescan(PG_FUNCTION_ARGS);
-extern Datum brinendscan(PG_FUNCTION_ARGS);
-extern Datum brinmarkpos(PG_FUNCTION_ARGS);
-extern Datum brinrestrpos(PG_FUNCTION_ARGS);
-extern Datum brinbulkdelete(PG_FUNCTION_ARGS);
-extern Datum brinvacuumcleanup(PG_FUNCTION_ARGS);
-extern Datum brincostestimate(PG_FUNCTION_ARGS);
-extern Datum brinoptions(PG_FUNCTION_ARGS);
+extern Datum brinhandler(PG_FUNCTION_ARGS);
+extern void brinvalidate(OpClassInfo *opclass);
+extern IndexBuildResult *brinbuild(Relation heap, Relation index,
+ IndexInfo *indexInfo);
+extern void brinbuildempty(Relation index);
+extern bool brininsert(Relation idxRel, Datum *values, bool *nulls,
+ ItemPointer heaptid, Relation heapRel,
+ IndexUniqueCheck checkUnique);
+extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys);
+extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
+extern void brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
+ ScanKey orderbys, int norderbys);
+extern void brinendscan(IndexScanDesc scan);
+extern void brinmarkpos(IndexScanDesc scan);
+extern void brinrestrpos(IndexScanDesc scan);
+extern IndexBulkDeleteResult *brinbulkdelete(IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+extern IndexBulkDeleteResult *brinvacuumcleanup(IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
+extern void brincostestimate(PlannerInfo *root, IndexPath *path,
+ double loop_count, Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+extern bytea *brinoptions(Datum reloptions, bool validate);
/*
* Storage type for BRIN's reloptions
diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h
index 6be199e..2f8fe17 100644
--- a/src/include/access/brin_internal.h
+++ b/src/include/access/brin_internal.h
@@ -72,6 +72,7 @@ typedef struct BrinDesc
#define BRIN_PROCNUM_CONSISTENT 3
#define BRIN_PROCNUM_UNION 4
/* procedure numbers up to 10 are reserved for BRIN future expansion */
+#define BRIN_NPROC 15
#undef BRIN_DEBUG
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
index d9d05a0..2f4ad91 100644
--- a/src/include/access/genam.h
+++ b/src/include/access/genam.h
@@ -111,7 +111,6 @@ typedef enum IndexUniqueCheck
UNIQUE_CHECK_EXISTING /* Check if existing tuple is unique */
} IndexUniqueCheck;
-
/*
* generalized index_ interface routines (in indexam.c)
*/
diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h
index 5021887..a77d43f 100644
--- a/src/include/access/gin_private.h
+++ b/src/include/access/gin_private.h
@@ -10,7 +10,7 @@
#ifndef GIN_PRIVATE_H
#define GIN_PRIVATE_H
-#include "access/genam.h"
+#include "access/amapi.h"
#include "access/gin.h"
#include "access/itup.h"
#include "fmgr.h"
@@ -593,7 +593,9 @@ typedef struct ginxlogDeleteListPages
/* ginutil.c */
-extern Datum ginoptions(PG_FUNCTION_ARGS);
+extern Datum ginhandler(PG_FUNCTION_ARGS);
+extern void ginvalidate(OpClassInfo *opclass);
+extern bytea *ginoptions(Datum reloptions, bool validate);
extern void initGinState(GinState *state, Relation index);
extern Buffer GinNewBuffer(Relation index);
extern void GinInitBuffer(Buffer b, uint32 f);
@@ -614,9 +616,12 @@ extern Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple,
GinNullCategory *category);
/* gininsert.c */
-extern Datum ginbuild(PG_FUNCTION_ARGS);
-extern Datum ginbuildempty(PG_FUNCTION_ARGS);
-extern Datum gininsert(PG_FUNCTION_ARGS);
+extern IndexBuildResult *ginbuild(Relation heap, Relation index,
+ IndexInfo *indexInfo);
+extern void ginbuildempty(Relation index);
+extern bool gininsert(Relation index, Datum *values, bool *isnull,
+ ItemPointer ht_ctid, Relation heapRel,
+ IndexUniqueCheck checkUnique);
extern void ginEntryInsert(GinState *ginstate,
OffsetNumber attnum, Datum key, GinNullCategory category,
ItemPointerData *items, uint32 nitem,
@@ -867,23 +872,28 @@ typedef struct GinScanOpaqueData
typedef GinScanOpaqueData *GinScanOpaque;
-extern Datum ginbeginscan(PG_FUNCTION_ARGS);
-extern Datum ginendscan(PG_FUNCTION_ARGS);
-extern Datum ginrescan(PG_FUNCTION_ARGS);
-extern Datum ginmarkpos(PG_FUNCTION_ARGS);
-extern Datum ginrestrpos(PG_FUNCTION_ARGS);
+extern IndexScanDesc ginbeginscan(Relation rel, int nkeys, int norderbys);
+extern void ginendscan(IndexScanDesc scan);
+extern void ginrescan(IndexScanDesc scan, ScanKey key, int nkeys,
+ ScanKey orderbys, int norderbys);
+extern void ginmarkpos(IndexScanDesc scan);
+extern void ginrestrpos(IndexScanDesc scan);
extern void ginNewScanKey(IndexScanDesc scan);
extern void ginFreeScanKeys(GinScanOpaque so);
/* ginget.c */
-extern Datum gingetbitmap(PG_FUNCTION_ARGS);
+extern int64 gingetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
/* ginlogic.c */
extern void ginInitConsistentFunction(GinState *ginstate, GinScanKey key);
/* ginvacuum.c */
-extern Datum ginbulkdelete(PG_FUNCTION_ARGS);
-extern Datum ginvacuumcleanup(PG_FUNCTION_ARGS);
+extern IndexBulkDeleteResult *ginbulkdelete(IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+extern IndexBulkDeleteResult *ginvacuumcleanup(IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
extern ItemPointer ginVacuumItemPointers(GinVacuumState *gvs,
ItemPointerData *items, int nitem, int *nremaining);
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index 1a77982..35fb34a 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -14,6 +14,7 @@
#ifndef GIST_PRIVATE_H
#define GIST_PRIVATE_H
+#include "access/amapi.h"
#include "access/gist.h"
#include "access/itup.h"
#include "access/xlogreader.h"
@@ -426,9 +427,13 @@ typedef struct GiSTOptions
} GiSTOptions;
/* gist.c */
-extern Datum gistbuildempty(PG_FUNCTION_ARGS);
-extern Datum gistinsert(PG_FUNCTION_ARGS);
-extern Datum gistcanreturn(PG_FUNCTION_ARGS);
+extern Datum gisthandler(PG_FUNCTION_ARGS);
+extern void gistvalidate(OpClassInfo *opclass);
+extern void gistbuildempty(Relation index);
+extern bool gistinsert(Relation r, Datum *values, bool *isnull,
+ ItemPointer ht_ctid, Relation heapRel,
+ IndexUniqueCheck checkUnique);
+extern bool gistcanreturn(Relation index, int attno);
extern MemoryContext createTempGistContext(void);
extern GISTSTATE *initGISTstate(Relation index);
extern void freeGISTstate(GISTSTATE *giststate);
@@ -474,8 +479,8 @@ extern XLogRecPtr gistXLogSplit(RelFileNode node,
Buffer leftchild, bool markfollowright);
/* gistget.c */
-extern Datum gistgettuple(PG_FUNCTION_ARGS);
-extern Datum gistgetbitmap(PG_FUNCTION_ARGS);
+extern bool gistgettuple(IndexScanDesc scan, ScanDirection dir);
+extern int64 gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
/* gistutil.c */
@@ -485,7 +490,7 @@ extern Datum gistgetbitmap(PG_FUNCTION_ARGS);
#define GIST_MIN_FILLFACTOR 10
#define GIST_DEFAULT_FILLFACTOR 90
-extern Datum gistoptions(PG_FUNCTION_ARGS);
+extern bytea *gistoptions(Datum reloptions, bool validate);
extern bool gistfitpage(IndexTuple *itvec, int len);
extern bool gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace);
extern void gistcheckpage(Relation rel, Buffer buf);
@@ -534,8 +539,12 @@ extern void gistMakeUnionKey(GISTSTATE *giststate, int attno,
extern XLogRecPtr gistGetFakeLSN(Relation rel);
/* gistvacuum.c */
-extern Datum gistbulkdelete(PG_FUNCTION_ARGS);
-extern Datum gistvacuumcleanup(PG_FUNCTION_ARGS);
+extern IndexBulkDeleteResult *gistbulkdelete(IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+extern IndexBulkDeleteResult *gistvacuumcleanup(IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
/* gistsplit.c */
extern void gistSplitByKey(Relation r, Page page, IndexTuple *itup,
@@ -544,7 +553,8 @@ extern void gistSplitByKey(Relation r, Page page, IndexTuple *itup,
int attno);
/* gistbuild.c */
-extern Datum gistbuild(PG_FUNCTION_ARGS);
+extern IndexBuildResult *gistbuild(Relation heap, Relation index,
+ IndexInfo *indexInfo);
extern void gistValidateBufferingOption(char *value);
/* gistbuildbuffers.c */
diff --git a/src/include/access/gistscan.h b/src/include/access/gistscan.h
index 15cb3d1..0e6afe9 100644
--- a/src/include/access/gistscan.h
+++ b/src/include/access/gistscan.h
@@ -16,10 +16,11 @@
#include "fmgr.h"
-extern Datum gistbeginscan(PG_FUNCTION_ARGS);
-extern Datum gistrescan(PG_FUNCTION_ARGS);
-extern Datum gistmarkpos(PG_FUNCTION_ARGS);
-extern Datum gistrestrpos(PG_FUNCTION_ARGS);
-extern Datum gistendscan(PG_FUNCTION_ARGS);
+extern IndexScanDesc gistbeginscan(Relation r, int nkeys, int norderbys);
+extern void gistrescan(IndexScanDesc scan, ScanKey key, int nkeys,
+ ScanKey orderbys, int norderbys);
+extern void gistmarkpos(IndexScanDesc scan);
+extern void gistrestrpos(IndexScanDesc scan);
+extern void gistendscan(IndexScanDesc scan);
#endif /* GISTSCAN_H */
diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index 97cb859..9595c6b 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -17,7 +17,7 @@
#ifndef HASH_H
#define HASH_H
-#include "access/genam.h"
+#include "access/amapi.h"
#include "access/itup.h"
#include "access/sdir.h"
#include "access/xlogreader.h"
@@ -243,19 +243,29 @@ typedef HashMetaPageData *HashMetaPage;
/* public routines */
-extern Datum hashbuild(PG_FUNCTION_ARGS);
-extern Datum hashbuildempty(PG_FUNCTION_ARGS);
-extern Datum hashinsert(PG_FUNCTION_ARGS);
-extern Datum hashbeginscan(PG_FUNCTION_ARGS);
-extern Datum hashgettuple(PG_FUNCTION_ARGS);
-extern Datum hashgetbitmap(PG_FUNCTION_ARGS);
-extern Datum hashrescan(PG_FUNCTION_ARGS);
-extern Datum hashendscan(PG_FUNCTION_ARGS);
-extern Datum hashmarkpos(PG_FUNCTION_ARGS);
-extern Datum hashrestrpos(PG_FUNCTION_ARGS);
-extern Datum hashbulkdelete(PG_FUNCTION_ARGS);
-extern Datum hashvacuumcleanup(PG_FUNCTION_ARGS);
-extern Datum hashoptions(PG_FUNCTION_ARGS);
+extern Datum hashhandler(PG_FUNCTION_ARGS);
+extern void hashvalidate(OpClassInfo *opclass);
+extern IndexBuildResult *hashbuild(Relation heap, Relation index,
+ IndexInfo *indexInfo);
+extern void hashbuildempty(Relation index);
+extern bool hashinsert(Relation rel, Datum *values, bool *isnull,
+ ItemPointer ht_ctid, Relation heapRel,
+ IndexUniqueCheck checkUnique);
+extern IndexScanDesc hashbeginscan(Relation rel, int nkeys, int norderbys);
+extern bool hashgettuple(IndexScanDesc scan, ScanDirection dir);
+extern int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
+extern void hashrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
+ ScanKey orderbys, int norderbys);
+extern void hashendscan(IndexScanDesc scan);
+extern void hashmarkpos(IndexScanDesc scan);
+extern void hashrestrpos(IndexScanDesc scan);
+extern IndexBulkDeleteResult *hashbulkdelete(IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+extern IndexBulkDeleteResult *hashvacuumcleanup(IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
+extern bytea *hashoptions(Datum reloptions, bool validate);
/*
* Datatype-specific hash functions in hashfunc.c.
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index 9e48efd..4fab0a3 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -14,13 +14,14 @@
#ifndef NBTREE_H
#define NBTREE_H
-#include "access/genam.h"
+#include "access/amapi.h"
#include "access/itup.h"
#include "access/sdir.h"
#include "access/xlogreader.h"
#include "catalog/pg_index.h"
#include "lib/stringinfo.h"
#include "storage/bufmgr.h"
+#include "utils/selfuncs.h"
/* There's room for a 16-bit vacuum cycle ID in BTPageOpaqueData */
typedef uint16 BTCycleId;
@@ -652,20 +653,31 @@ typedef BTScanOpaqueData *BTScanOpaque;
/*
* prototypes for functions in nbtree.c (external entry points for btree)
*/
-extern Datum btbuild(PG_FUNCTION_ARGS);
-extern Datum btbuildempty(PG_FUNCTION_ARGS);
-extern Datum btinsert(PG_FUNCTION_ARGS);
-extern Datum btbeginscan(PG_FUNCTION_ARGS);
-extern Datum btgettuple(PG_FUNCTION_ARGS);
-extern Datum btgetbitmap(PG_FUNCTION_ARGS);
-extern Datum btrescan(PG_FUNCTION_ARGS);
-extern Datum btendscan(PG_FUNCTION_ARGS);
-extern Datum btmarkpos(PG_FUNCTION_ARGS);
-extern Datum btrestrpos(PG_FUNCTION_ARGS);
-extern Datum btbulkdelete(PG_FUNCTION_ARGS);
-extern Datum btvacuumcleanup(PG_FUNCTION_ARGS);
-extern Datum btcanreturn(PG_FUNCTION_ARGS);
-extern Datum btoptions(PG_FUNCTION_ARGS);
+extern Datum bthandler(PG_FUNCTION_ARGS);
+extern void btvalidate(OpClassInfo *opclass);
+extern IndexBuildResult *btbuild(Relation heap, Relation index,
+ IndexInfo *indexInfo);
+extern void btbuildempty(Relation index);
+extern bool btinsert(Relation rel, Datum *values, bool *isnull,
+ ItemPointer ht_ctid, Relation heapRel,
+ IndexUniqueCheck checkUnique);
+extern IndexScanDesc btbeginscan(Relation indexRelation,
+ int nkeys, int norderbys);
+extern bool btgettuple(IndexScanDesc scan, ScanDirection dir);
+extern int64 btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
+extern void btrescan(IndexScanDesc scan, ScanKey keys, int nkeys,
+ ScanKey orderbys, int norderbys);
+extern void btendscan(IndexScanDesc scan);
+extern void btmarkpos(IndexScanDesc scan);
+extern void btrestrpos(IndexScanDesc scan);
+extern IndexBulkDeleteResult *btbulkdelete(IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+extern IndexBulkDeleteResult *btvacuumcleanup(IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
+extern bool btcanreturn(Relation index, int attno);
+extern bytea *btoptions(Datum reloptions, bool validate);
/*
* prototypes for functions in nbtinsert.c
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index 2a3cbcd..7de02d2 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -19,6 +19,7 @@
#ifndef RELOPTIONS_H
#define RELOPTIONS_H
+#include "access/amapi.h"
#include "access/htup.h"
#include "access/tupdesc.h"
#include "nodes/pg_list.h"
@@ -258,7 +259,7 @@ extern Datum transformRelOptions(Datum oldOptions, List *defList,
bool ignoreOids, bool isReset);
extern List *untransformRelOptions(Datum options);
extern bytea *extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
- Oid amoptions);
+ amoptions_function amoptions);
extern relopt_value *parseRelOptions(Datum options, bool validate,
relopt_kind kind, int *numrelopts);
extern void *allocateReloptStruct(Size base, relopt_value *options,
@@ -272,7 +273,7 @@ extern bytea *default_reloptions(Datum reloptions, bool validate,
relopt_kind kind);
extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate);
extern bytea *view_reloptions(Datum reloptions, bool validate);
-extern bytea *index_reloptions(RegProcedure amoptions, Datum reloptions,
+extern bytea *index_reloptions(amoptions_function amoptions, Datum reloptions,
bool validate);
extern bytea *attribute_reloptions(Datum reloptions, bool validate);
extern bytea *tablespace_reloptions(Datum reloptions, bool validate);
diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h
index 0cb8fd9..ba2c1c1 100644
--- a/src/include/access/spgist.h
+++ b/src/include/access/spgist.h
@@ -14,7 +14,7 @@
#ifndef SPGIST_H
#define SPGIST_H
-#include "access/skey.h"
+#include "access/amapi.h"
#include "access/xlogreader.h"
#include "fmgr.h"
#include "lib/stringinfo.h"
@@ -174,27 +174,39 @@ typedef struct spgLeafConsistentOut
} spgLeafConsistentOut;
+/* spgutils.c */
+extern Datum spghandler(PG_FUNCTION_ARGS);
+extern void spgvalidate(OpClassInfo *opclass);
+
/* spginsert.c */
-extern Datum spgbuild(PG_FUNCTION_ARGS);
-extern Datum spgbuildempty(PG_FUNCTION_ARGS);
-extern Datum spginsert(PG_FUNCTION_ARGS);
+extern IndexBuildResult *spgbuild(Relation heap, Relation index,
+ IndexInfo *indexInfo);
+extern void spgbuildempty(Relation indexRelation);
+extern bool spginsert(Relation index, Datum *values, bool *isnull,
+ ItemPointer ht_ctid, Relation heapRel,
+ IndexUniqueCheck checkUnique);
/* spgscan.c */
-extern Datum spgbeginscan(PG_FUNCTION_ARGS);
-extern Datum spgendscan(PG_FUNCTION_ARGS);
-extern Datum spgrescan(PG_FUNCTION_ARGS);
-extern Datum spgmarkpos(PG_FUNCTION_ARGS);
-extern Datum spgrestrpos(PG_FUNCTION_ARGS);
-extern Datum spggetbitmap(PG_FUNCTION_ARGS);
-extern Datum spggettuple(PG_FUNCTION_ARGS);
-extern Datum spgcanreturn(PG_FUNCTION_ARGS);
+extern IndexScanDesc spgbeginscan(Relation rel, int keysz, int orderbysz);
+extern void spgendscan(IndexScanDesc scan);
+extern void spgrescan(IndexScanDesc scan, ScanKey key, int nkeys,
+ ScanKey orderbys, int norderbys);
+extern void spgmarkpos(IndexScanDesc scan);
+extern void spgrestrpos(IndexScanDesc scan);
+extern int64 spggetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
+extern bool spggettuple(IndexScanDesc scan, ScanDirection dir);
+extern bool spgcanreturn(Relation index, int attno);
/* spgutils.c */
-extern Datum spgoptions(PG_FUNCTION_ARGS);
+extern bytea *spgoptions(Datum reloptions, bool validate);
/* spgvacuum.c */
-extern Datum spgbulkdelete(PG_FUNCTION_ARGS);
-extern Datum spgvacuumcleanup(PG_FUNCTION_ARGS);
+extern IndexBulkDeleteResult *spgbulkdelete(IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+extern IndexBulkDeleteResult *spgvacuumcleanup(IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
/* spgxlog.c */
extern void spg_redo(XLogReaderState *record);
diff --git a/src/include/catalog/opfam_internal.h b/src/include/catalog/opfam_internal.h
index 32195a7..5cc0208 100644
--- a/src/include/catalog/opfam_internal.h
+++ b/src/include/catalog/opfam_internal.h
@@ -25,4 +25,16 @@ typedef struct
Oid sortfamily; /* ordering operator's sort opfamily, or 0 */
} OpFamilyMember;
+/*
+ * Opclass data for validation by access method.
+ */
+typedef struct
+{
+ Oid intype; /* input datatype */
+ Oid keytype; /* key datatype */
+ List *procedures; /* list of OpFamilyMember */
+ List *operators; /* list of OpFamilyMember */
+} OpClassInfo;
+
+
#endif /* OPFAM_INTERNAL_H */
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
index 8a28b8e..f19a873 100644
--- a/src/include/catalog/pg_am.h
+++ b/src/include/catalog/pg_am.h
@@ -34,39 +34,7 @@
CATALOG(pg_am,2601)
{
NameData amname; /* access method name */
- int16 amstrategies; /* total number of strategies (operators) by
- * which we can traverse/search this AM. Zero
- * if AM does not have a fixed set of strategy
- * assignments. */
- int16 amsupport; /* total number of support functions that this
- * AM uses */
- bool amcanorder; /* does AM support order by column value? */
- bool amcanorderbyop; /* does AM support order by operator result? */
- bool amcanbackward; /* does AM support backward scan? */
- bool amcanunique; /* does AM support UNIQUE indexes? */
- bool amcanmulticol; /* does AM support multi-column indexes? */
- bool amoptionalkey; /* can query omit key for the first column? */
- bool amsearcharray; /* can AM handle ScalarArrayOpExpr quals? */
- bool amsearchnulls; /* can AM search for NULL/NOT NULL entries? */
- bool amstorage; /* can storage type differ from column type? */
- bool amclusterable; /* does AM support cluster command? */
- bool ampredlocks; /* does AM handle predicate locks? */
- Oid amkeytype; /* type of data in index, or InvalidOid */
- regproc aminsert; /* "insert this tuple" function */
- regproc ambeginscan; /* "prepare for index scan" function */
- regproc amgettuple; /* "next valid tuple" function, or 0 */
- regproc amgetbitmap; /* "fetch all valid tuples" function, or 0 */
- regproc amrescan; /* "(re)start index scan" function */
- regproc amendscan; /* "end index scan" function */
- regproc ammarkpos; /* "mark current scan position" function */
- regproc amrestrpos; /* "restore marked scan position" function */
- regproc ambuild; /* "build new index" function */
- regproc ambuildempty; /* "build empty index" function */
- regproc ambulkdelete; /* bulk-delete function */
- regproc amvacuumcleanup; /* post-VACUUM cleanup function */
- regproc amcanreturn; /* can indexscan return IndexTuples? */
- regproc amcostestimate; /* estimate cost of an indexscan */
- regproc amoptions; /* parse AM-specific parameters */
+ regproc amhandler; /* handler function */
} FormData_pg_am;
/* ----------------
@@ -80,59 +48,31 @@ typedef FormData_pg_am *Form_pg_am;
* compiler constants for pg_am
* ----------------
*/
-#define Natts_pg_am 30
+#define Natts_pg_am 2
#define Anum_pg_am_amname 1
-#define Anum_pg_am_amstrategies 2
-#define Anum_pg_am_amsupport 3
-#define Anum_pg_am_amcanorder 4
-#define Anum_pg_am_amcanorderbyop 5
-#define Anum_pg_am_amcanbackward 6
-#define Anum_pg_am_amcanunique 7
-#define Anum_pg_am_amcanmulticol 8
-#define Anum_pg_am_amoptionalkey 9
-#define Anum_pg_am_amsearcharray 10
-#define Anum_pg_am_amsearchnulls 11
-#define Anum_pg_am_amstorage 12
-#define Anum_pg_am_amclusterable 13
-#define Anum_pg_am_ampredlocks 14
-#define Anum_pg_am_amkeytype 15
-#define Anum_pg_am_aminsert 16
-#define Anum_pg_am_ambeginscan 17
-#define Anum_pg_am_amgettuple 18
-#define Anum_pg_am_amgetbitmap 19
-#define Anum_pg_am_amrescan 20
-#define Anum_pg_am_amendscan 21
-#define Anum_pg_am_ammarkpos 22
-#define Anum_pg_am_amrestrpos 23
-#define Anum_pg_am_ambuild 24
-#define Anum_pg_am_ambuildempty 25
-#define Anum_pg_am_ambulkdelete 26
-#define Anum_pg_am_amvacuumcleanup 27
-#define Anum_pg_am_amcanreturn 28
-#define Anum_pg_am_amcostestimate 29
-#define Anum_pg_am_amoptions 30
+#define Anum_pg_am_amhandler 2
/* ----------------
* initial contents of pg_am
* ----------------
*/
-DATA(insert OID = 403 ( btree 5 2 t f t t t t t t f t t 0 btinsert btbeginscan btgettuple btgetbitmap btrescan btendscan btmarkpos btrestrpos btbuild btbuildempty btbulkdelete btvacuumcleanup btcanreturn btcostestimate btoptions ));
+DATA(insert OID = 403 ( btree bthandler ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
-DATA(insert OID = 405 ( hash 1 1 f f t f f f f f f f f 23 hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbuildempty hashbulkdelete hashvacuumcleanup - hashcostestimate hashoptions ));
+DATA(insert OID = 405 ( hash hashhandler ));
DESCR("hash index access method");
#define HASH_AM_OID 405
-DATA(insert OID = 783 ( gist 0 9 f t f f t t f t t t f 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbuildempty gistbulkdelete gistvacuumcleanup gistcanreturn gistcostestimate gistoptions ));
+DATA(insert OID = 783 ( gist gisthandler ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
-DATA(insert OID = 2742 ( gin 0 6 f f f f t t f f t f f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbuildempty ginbulkdelete ginvacuumcleanup - gincostestimate ginoptions ));
+DATA(insert OID = 2742 ( gin ginhandler ));
DESCR("GIN index access method");
#define GIN_AM_OID 2742
-DATA(insert OID = 4000 ( spgist 0 5 f f f f f t f t f f f 0 spginsert spgbeginscan spggettuple spggetbitmap spgrescan spgendscan spgmarkpos spgrestrpos spgbuild spgbuildempty spgbulkdelete spgvacuumcleanup spgcanreturn spgcostestimate spgoptions ));
+DATA(insert OID = 4000 ( spgist spghandler ));
DESCR("SP-GiST index access method");
#define SPGIST_AM_OID 4000
-DATA(insert OID = 3580 ( brin 0 15 f f f f t t f t t f f 0 brininsert brinbeginscan - bringetbitmap brinrescan brinendscan brinmarkpos brinrestrpos brinbuild brinbuildempty brinbulkdelete brinvacuumcleanup - brincostestimate brinoptions ));
+DATA(insert OID = 3580 ( brin brinhandler ));
DESCR("block range index (BRIN) access method");
#define BRIN_AM_OID 3580
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index eb55b3a..587aaac 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -547,63 +547,6 @@ DESCR("convert int4 to float4");
DATA(insert OID = 319 ( int4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "700" _null_ _null_ _null_ _null_ _null_ ftoi4 _null_ _null_ _null_ ));
DESCR("convert float4 to int4");
-DATA(insert OID = 330 ( btgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgettuple _null_ _null_ _null_ ));
-DESCR("btree(internal)");
-DATA(insert OID = 636 ( btgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgetbitmap _null_ _null_ _null_ ));
-DESCR("btree(internal)");
-DATA(insert OID = 331 ( btinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btinsert _null_ _null_ _null_ ));
-DESCR("btree(internal)");
-DATA(insert OID = 333 ( btbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbeginscan _null_ _null_ _null_ ));
-DESCR("btree(internal)");
-DATA(insert OID = 334 ( btrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btrescan _null_ _null_ _null_ ));
-DESCR("btree(internal)");
-DATA(insert OID = 335 ( btendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btendscan _null_ _null_ _null_ ));
-DESCR("btree(internal)");
-DATA(insert OID = 336 ( btmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btmarkpos _null_ _null_ _null_ ));
-DESCR("btree(internal)");
-DATA(insert OID = 337 ( btrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btrestrpos _null_ _null_ _null_ ));
-DESCR("btree(internal)");
-DATA(insert OID = 338 ( btbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbuild _null_ _null_ _null_ ));
-DESCR("btree(internal)");
-DATA(insert OID = 328 ( btbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btbuildempty _null_ _null_ _null_ ));
-DESCR("btree(internal)");
-DATA(insert OID = 332 ( btbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbulkdelete _null_ _null_ _null_ ));
-DESCR("btree(internal)");
-DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ btvacuumcleanup _null_ _null_ _null_ ));
-DESCR("btree(internal)");
-DATA(insert OID = 276 ( btcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ btcanreturn _null_ _null_ _null_ ));
-DESCR("btree(internal)");
-DATA(insert OID = 1268 ( btcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btcostestimate _null_ _null_ _null_ ));
-DESCR("btree(internal)");
-DATA(insert OID = 2785 ( btoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ btoptions _null_ _null_ _null_ ));
-DESCR("btree(internal)");
-
-DATA(insert OID = 3789 ( bringetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ bringetbitmap _null_ _null_ _null_ ));
-DESCR("brin(internal)");
-DATA(insert OID = 3790 ( brininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brininsert _null_ _null_ _null_ ));
-DESCR("brin(internal)");
-DATA(insert OID = 3791 ( brinbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbeginscan _null_ _null_ _null_ ));
-DESCR("brin(internal)");
-DATA(insert OID = 3792 ( brinrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinrescan _null_ _null_ _null_ ));
-DESCR("brin(internal)");
-DATA(insert OID = 3793 ( brinendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinendscan _null_ _null_ _null_ ));
-DESCR("brin(internal)");
-DATA(insert OID = 3794 ( brinmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinmarkpos _null_ _null_ _null_ ));
-DESCR("brin(internal)");
-DATA(insert OID = 3795 ( brinrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinrestrpos _null_ _null_ _null_ ));
-DESCR("brin(internal)");
-DATA(insert OID = 3796 ( brinbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbuild _null_ _null_ _null_ ));
-DESCR("brin(internal)");
-DATA(insert OID = 3797 ( brinbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinbuildempty _null_ _null_ _null_ ));
-DESCR("brin(internal)");
-DATA(insert OID = 3798 ( brinbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbulkdelete _null_ _null_ _null_ ));
-DESCR("brin(internal)");
-DATA(insert OID = 3799 ( brinvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ brinvacuumcleanup _null_ _null_ _null_ ));
-DESCR("brin(internal)");
-DATA(insert OID = 3800 ( brincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brincostestimate _null_ _null_ _null_ ));
-DESCR("brin(internal)");
-DATA(insert OID = 3801 ( brinoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ brinoptions _null_ _null_ _null_ ));
-DESCR("brin(internal)");
DATA(insert OID = 3952 ( brin_summarize_new_values PGNSP PGUID 12 1 0 0 0 f f f f f f v s 1 0 23 "2205" _null_ _null_ _null_ _null_ _null_ brin_summarize_new_values _null_ _null_ _null_ ));
DESCR("brin: standalone scan new table pages");
@@ -694,35 +637,6 @@ DESCR("convert name to char(n)");
DATA(insert OID = 409 ( name PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 19 "1042" _null_ _null_ _null_ _null_ _null_ bpchar_name _null_ _null_ _null_ ));
DESCR("convert char(n) to name");
-DATA(insert OID = 440 ( hashgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgettuple _null_ _null_ _null_ ));
-DESCR("hash(internal)");
-DATA(insert OID = 637 ( hashgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgetbitmap _null_ _null_ _null_ ));
-DESCR("hash(internal)");
-DATA(insert OID = 441 ( hashinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashinsert _null_ _null_ _null_ ));
-DESCR("hash(internal)");
-DATA(insert OID = 443 ( hashbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbeginscan _null_ _null_ _null_ ));
-DESCR("hash(internal)");
-DATA(insert OID = 444 ( hashrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashrescan _null_ _null_ _null_ ));
-DESCR("hash(internal)");
-DATA(insert OID = 445 ( hashendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashendscan _null_ _null_ _null_ ));
-DESCR("hash(internal)");
-DATA(insert OID = 446 ( hashmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashmarkpos _null_ _null_ _null_ ));
-DESCR("hash(internal)");
-DATA(insert OID = 447 ( hashrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashrestrpos _null_ _null_ _null_ ));
-DESCR("hash(internal)");
-DATA(insert OID = 448 ( hashbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbuild _null_ _null_ _null_ ));
-DESCR("hash(internal)");
-DATA(insert OID = 327 ( hashbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashbuildempty _null_ _null_ _null_ ));
-DESCR("hash(internal)");
-DATA(insert OID = 442 ( hashbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbulkdelete _null_ _null_ _null_ ));
-DESCR("hash(internal)");
-DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashvacuumcleanup _null_ _null_ _null_ ));
-DESCR("hash(internal)");
-DATA(insert OID = 438 ( hashcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashcostestimate _null_ _null_ _null_ ));
-DESCR("hash(internal)");
-DATA(insert OID = 2786 ( hashoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ hashoptions _null_ _null_ _null_ ));
-DESCR("hash(internal)");
-
DATA(insert OID = 449 ( hashint2 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "21" _null_ _null_ _null_ _null_ _null_ hashint2 _null_ _null_ _null_ ));
DESCR("hash");
DATA(insert OID = 450 ( hashint4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ hashint4 _null_ _null_ _null_ ));
@@ -978,37 +892,6 @@ DESCR("larger of two");
DATA(insert OID = 771 ( int2smaller PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2smaller _null_ _null_ _null_ ));
DESCR("smaller of two");
-DATA(insert OID = 774 ( gistgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgettuple _null_ _null_ _null_ ));
-DESCR("gist(internal)");
-DATA(insert OID = 638 ( gistgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgetbitmap _null_ _null_ _null_ ));
-DESCR("gist(internal)");
-DATA(insert OID = 775 ( gistinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistinsert _null_ _null_ _null_ ));
-DESCR("gist(internal)");
-DATA(insert OID = 777 ( gistbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbeginscan _null_ _null_ _null_ ));
-DESCR("gist(internal)");
-DATA(insert OID = 778 ( gistrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistrescan _null_ _null_ _null_ ));
-DESCR("gist(internal)");
-DATA(insert OID = 779 ( gistendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistendscan _null_ _null_ _null_ ));
-DESCR("gist(internal)");
-DATA(insert OID = 780 ( gistmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistmarkpos _null_ _null_ _null_ ));
-DESCR("gist(internal)");
-DATA(insert OID = 781 ( gistrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistrestrpos _null_ _null_ _null_ ));
-DESCR("gist(internal)");
-DATA(insert OID = 782 ( gistbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbuild _null_ _null_ _null_ ));
-DESCR("gist(internal)");
-DATA(insert OID = 326 ( gistbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistbuildempty _null_ _null_ _null_ ));
-DESCR("gist(internal)");
-DATA(insert OID = 776 ( gistbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbulkdelete _null_ _null_ _null_ ));
-DESCR("gist(internal)");
-DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistvacuumcleanup _null_ _null_ _null_ ));
-DESCR("gist(internal)");
-DATA(insert OID = 3280 ( gistcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ gistcanreturn _null_ _null_ _null_ ));
-DESCR("gist(internal)");
-DATA(insert OID = 772 ( gistcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistcostestimate _null_ _null_ _null_ ));
-DESCR("gist(internal)");
-DATA(insert OID = 2787 ( gistoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ gistoptions _null_ _null_ _null_ ));
-DESCR("gist(internal)");
-
DATA(insert OID = 784 ( tintervaleq PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervaleq _null_ _null_ _null_ ));
DATA(insert OID = 785 ( tintervalne PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervalne _null_ _null_ _null_ ));
DATA(insert OID = 786 ( tintervallt PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervallt _null_ _null_ _null_ ));
@@ -3740,6 +3623,10 @@ DATA(insert OID = 3311 ( tsm_handler_in PGNSP PGUID 12 1 0 0 0 f f f f f f i s
DESCR("I/O");
DATA(insert OID = 3312 ( tsm_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "3310" _null_ _null_ _null_ _null_ _null_ tsm_handler_out _null_ _null_ _null_ ));
DESCR("I/O");
+DATA(insert OID = 326 ( index_am_handler_in PGNSP PGUID 12 1 0 0 0 f f f f f f i s 1 0 325 "2275" _null_ _null_ _null_ _null_ _null_ index_am_handler_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 327 ( index_am_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "325" _null_ _null_ _null_ _null_ _null_ index_am_handler_out _null_ _null_ _null_ ));
+DESCR("I/O");
/* tablesample method handlers */
DATA(insert OID = 3313 ( bernoulli PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 3310 "2281" _null_ _null_ _null_ _null_ _null_ tsm_bernoulli_handler _null_ _null_ _null_ ));
@@ -4196,34 +4083,6 @@ DESCR("GiST support");
DATA(insert OID = 3288 ( gist_bbox_distance PGNSP PGUID 12 1 0 0 0 f f f f t f i s 4 0 701 "2281 600 23 26" _null_ _null_ _null_ _null_ _null_ gist_bbox_distance _null_ _null_ _null_ ));
DESCR("GiST support");
-/* GIN */
-DATA(insert OID = 2731 ( gingetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gingetbitmap _null_ _null_ _null_ ));
-DESCR("gin(internal)");
-DATA(insert OID = 2732 ( gininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gininsert _null_ _null_ _null_ ));
-DESCR("gin(internal)");
-DATA(insert OID = 2733 ( ginbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbeginscan _null_ _null_ _null_ ));
-DESCR("gin(internal)");
-DATA(insert OID = 2734 ( ginrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginrescan _null_ _null_ _null_ ));
-DESCR("gin(internal)");
-DATA(insert OID = 2735 ( ginendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginendscan _null_ _null_ _null_ ));
-DESCR("gin(internal)");
-DATA(insert OID = 2736 ( ginmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginmarkpos _null_ _null_ _null_ ));
-DESCR("gin(internal)");
-DATA(insert OID = 2737 ( ginrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginrestrpos _null_ _null_ _null_ ));
-DESCR("gin(internal)");
-DATA(insert OID = 2738 ( ginbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbuild _null_ _null_ _null_ ));
-DESCR("gin(internal)");
-DATA(insert OID = 325 ( ginbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginbuildempty _null_ _null_ _null_ ));
-DESCR("gin(internal)");
-DATA(insert OID = 2739 ( ginbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbulkdelete _null_ _null_ _null_ ));
-DESCR("gin(internal)");
-DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ ginvacuumcleanup _null_ _null_ _null_ ));
-DESCR("gin(internal)");
-DATA(insert OID = 2741 ( gincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gincostestimate _null_ _null_ _null_ ));
-DESCR("gin(internal)");
-DATA(insert OID = 2788 ( ginoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ ginoptions _null_ _null_ _null_ ));
-DESCR("gin(internal)");
-
/* GIN array support */
DATA(insert OID = 2743 ( ginarrayextract PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 2281 "2277 2281 2281" _null_ _null_ _null_ _null_ _null_ ginarrayextract _null_ _null_ _null_ ));
DESCR("GIN array support");
@@ -5119,38 +4978,6 @@ DESCR("construct timestamp with time zone");
DATA(insert OID = 3464 ( make_interval PGNSP PGUID 12 1 0 0 0 f f f f t f i s 7 0 1186 "23 23 23 23 23 23 701" _null_ _null_ "{years,months,weeks,days,hours,mins,secs}" _null_ _null_ make_interval _null_ _null_ _null_ ));
DESCR("construct interval");
-/* spgist support functions */
-DATA(insert OID = 4001 ( spggettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggettuple _null_ _null_ _null_ ));
-DESCR("spgist(internal)");
-DATA(insert OID = 4002 ( spggetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggetbitmap _null_ _null_ _null_ ));
-DESCR("spgist(internal)");
-DATA(insert OID = 4003 ( spginsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spginsert _null_ _null_ _null_ ));
-DESCR("spgist(internal)");
-DATA(insert OID = 4004 ( spgbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbeginscan _null_ _null_ _null_ ));
-DESCR("spgist(internal)");
-DATA(insert OID = 4005 ( spgrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgrescan _null_ _null_ _null_ ));
-DESCR("spgist(internal)");
-DATA(insert OID = 4006 ( spgendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgendscan _null_ _null_ _null_ ));
-DESCR("spgist(internal)");
-DATA(insert OID = 4007 ( spgmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgmarkpos _null_ _null_ _null_ ));
-DESCR("spgist(internal)");
-DATA(insert OID = 4008 ( spgrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgrestrpos _null_ _null_ _null_ ));
-DESCR("spgist(internal)");
-DATA(insert OID = 4009 ( spgbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbuild _null_ _null_ _null_ ));
-DESCR("spgist(internal)");
-DATA(insert OID = 4010 ( spgbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgbuildempty _null_ _null_ _null_ ));
-DESCR("spgist(internal)");
-DATA(insert OID = 4011 ( spgbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbulkdelete _null_ _null_ _null_ ));
-DESCR("spgist(internal)");
-DATA(insert OID = 4012 ( spgvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ spgvacuumcleanup _null_ _null_ _null_ ));
-DESCR("spgist(internal)");
-DATA(insert OID = 4032 ( spgcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ spgcanreturn _null_ _null_ _null_ ));
-DESCR("spgist(internal)");
-DATA(insert OID = 4013 ( spgcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgcostestimate _null_ _null_ _null_ ));
-DESCR("spgist(internal)");
-DATA(insert OID = 4014 ( spgoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ spgoptions _null_ _null_ _null_ ));
-DESCR("spgist(internal)");
-
/* spgist opclasses */
DATA(insert OID = 4018 ( spg_quad_config PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_quad_config _null_ _null_ _null_ ));
DESCR("SP-GiST support for quad tree over point");
@@ -5333,6 +5160,25 @@ DESCR("get an individual replication origin's replication progress");
DATA(insert OID = 6014 ( pg_show_replication_origin_status PGNSP PGUID 12 1 100 0 0 f f f f f t v r 0 0 2249 "" "{26,25,3220,3220}" "{o,o,o,o}" "{local_id, external_id, remote_lsn, local_lsn}" _null_ _null_ pg_show_replication_origin_status _null_ _null_ _null_ ));
DESCR("get progress for all replication origins");
+/* Access methods handlers */
+DATA(insert OID = 330 ( bthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ bthandler _null_ _null_ _null_ ));
+DESCR("btree handler");
+DATA(insert OID = 331 ( hashhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ hashhandler _null_ _null_ _null_ ));
+DESCR("hash handler");
+DATA(insert OID = 332 ( gisthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ gisthandler _null_ _null_ _null_ ));
+DESCR("gist handler");
+DATA(insert OID = 333 ( ginhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ ginhandler _null_ _null_ _null_ ));
+DESCR("gin handler");
+DATA(insert OID = 334 ( spghandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ spghandler _null_ _null_ _null_ ));
+DESCR("spgist handler");
+DATA(insert OID = 335 ( brinhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ brinhandler _null_ _null_ _null_ ));
+DESCR("brin handler");
+
+DATA(insert OID = 336 ( amvalidate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 16 "26" _null_ _null_ _null_ _null_ _null_ amvalidate _null_ _null_ _null_ ));
+DESCR("ask access method to validate opclass");
+
+
+
/*
* Symbolic values for provolatile column: these indicate whether the result
* of a function is dependent *only* on the values of its explicit arguments,
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 7dc95c8..59b04ac 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -696,6 +696,8 @@ DATA(insert OID = 3115 ( fdw_handler PGNSP PGUID 4 t p P f t \054 0 0 0 fdw_han
#define FDW_HANDLEROID 3115
DATA(insert OID = 3310 ( tsm_handler PGNSP PGUID 4 t p P f t \054 0 0 0 tsm_handler_in tsm_handler_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
#define TSM_HANDLEROID 3310
+DATA(insert OID = 325 ( index_am_handler PGNSP PGUID 4 t p P f t \054 0 0 0 index_am_handler_in index_am_handler_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+#define INDEX_AM_HANDLEROID 325
DATA(insert OID = 3831 ( anyrange PGNSP PGUID -1 f p P f t \054 0 0 0 anyrange_in anyrange_out - - - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
#define ANYRANGEOID 3831
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index adae296..d8b9649 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -95,6 +95,7 @@ extern Oid get_am_oid(const char *amname, bool missing_ok);
extern char *get_am_name(Oid amOid);
extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+extern Datum amvalidate(PG_FUNCTION_ARGS);
/* commands/tsearchcmds.c */
extern ObjectAddress DefineTSParser(List *names, List *parameters);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 4ae2f3e..be4a1e2 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -14,7 +14,7 @@
#ifndef EXECNODES_H
#define EXECNODES_H
-#include "access/genam.h"
+#include "access/amapi.h"
#include "access/heapam.h"
#include "executor/instrument.h"
#include "lib/pairingheap.h"
@@ -55,7 +55,7 @@
* they're conventionally set to false otherwise.
* ----------------
*/
-typedef struct IndexInfo
+struct IndexInfo
{
NodeTag type;
int ii_NumIndexAttrs;
@@ -74,7 +74,7 @@ typedef struct IndexInfo
bool ii_ReadyForInserts;
bool ii_Concurrent;
bool ii_BrokenHotChain;
-} IndexInfo;
+};
/* ----------------
* ExprContext_CB
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 274480e..9a5ff45 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -452,7 +452,8 @@ typedef enum NodeTag
T_TIDBitmap, /* in nodes/tidbitmap.h */
T_InlineCodeBlock, /* in nodes/parsenodes.h */
T_FdwRoutine, /* in foreign/fdwapi.h */
- T_TsmRoutine /* in access/tsmapi.h */
+ T_TsmRoutine, /* in access/tsmapi.h */
+ T_IndexAmRoutine /* in access/amapi.h */
} NodeTag;
/*
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 79bed33..7427900 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -19,6 +19,7 @@
#include "nodes/params.h"
#include "nodes/parsenodes.h"
#include "storage/block.h"
+#include "utils/relcache.h"
/*
@@ -546,8 +547,7 @@ typedef struct IndexOptInfo
bool *canreturn; /* which index cols can be returned in an
* index-only scan? */
Oid relam; /* OID of the access method (in pg_am) */
-
- RegProcedure amcostestimate; /* OID of the access method's cost fcn */
+ IndexAmRoutine *amroutine; /* routine of access method */
List *indexprs; /* expressions for non-simple index columns */
List *indpred; /* predicate if a partial index, else NIL */
@@ -558,12 +558,12 @@ typedef struct IndexOptInfo
bool unique; /* true if a unique index */
bool immediate; /* is uniqueness enforced immediately? */
bool hypothetical; /* true if index doesn't really exist */
- bool amcanorderbyop; /* does AM support order by operator result? */
+ bool amcanorderbyop; /* does AM support order by operator result? */
bool amoptionalkey; /* can query omit key for the first column? */
bool amsearcharray; /* can AM handle ScalarArrayOpExpr quals? */
bool amsearchnulls; /* can AM search for NULL/NOT NULL entries? */
bool amhasgettuple; /* does AM have amgettuple interface? */
- bool amhasgetbitmap; /* does AM have amgetbitmap interface? */
+ bool amhasgetbitmap; /* does AM have amgetbitmap interface? */
} IndexOptInfo;
@@ -817,7 +817,7 @@ typedef struct Path
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
-typedef struct IndexPath
+struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
@@ -829,7 +829,7 @@ typedef struct IndexPath
ScanDirection indexscandir;
Cost indextotalcost;
Selectivity indexselectivity;
-} IndexPath;
+};
/*
* BitmapHeapPath represents one or more indexscans that generate TID bitmaps
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index fc1679e..8e59b8c 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -568,6 +568,8 @@ extern Datum fdw_handler_in(PG_FUNCTION_ARGS);
extern Datum fdw_handler_out(PG_FUNCTION_ARGS);
extern Datum tsm_handler_in(PG_FUNCTION_ARGS);
extern Datum tsm_handler_out(PG_FUNCTION_ARGS);
+extern Datum index_am_handler_in(PG_FUNCTION_ARGS);
+extern Datum index_am_handler_out(PG_FUNCTION_ARGS);
extern Datum internal_in(PG_FUNCTION_ARGS);
extern Datum internal_out(PG_FUNCTION_ARGS);
extern Datum opaque_in(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 8a55a09..483b840 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -129,6 +129,7 @@ typedef struct RelationData
/* use "struct" here to avoid needing to include htup.h: */
struct HeapTupleData *rd_indextuple; /* all of pg_index tuple */
Form_pg_am rd_am; /* pg_am tuple for index's AM */
+ IndexAmRoutine *amroutine;
/*
* index access support info (used only for an index relation)
diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h
index 6953281..7cad109 100644
--- a/src/include/utils/relcache.h
+++ b/src/include/utils/relcache.h
@@ -19,6 +19,9 @@
typedef struct RelationData *Relation;
+typedef struct IndexPath IndexPath;
+typedef struct IndexInfo IndexInfo;
+
/* ----------------
* RelationPtr is used in the executor to support index scans
@@ -28,6 +31,14 @@ typedef struct RelationData *Relation;
*/
typedef Relation *RelationPtr;
+typedef struct IndexAmRoutine IndexAmRoutine;
+
+/*
+ * Routines to retreive IndexAmRoutine
+ */
+extern IndexAmRoutine *GetIndexAmRoutine(Oid amoid);
+extern void InitIndexAmRoutine(Relation relation);
+
/*
* Routines to open (lookup) and close a relcache entry
*/
diff --git a/src/include/utils/selfuncs.h b/src/include/utils/selfuncs.h
index a7433d9..3745d1c 100644
--- a/src/include/utils/selfuncs.h
+++ b/src/include/utils/selfuncs.h
@@ -191,12 +191,36 @@ extern double estimate_num_groups(PlannerInfo *root, List *groupExprs,
extern Selectivity estimate_hash_bucketsize(PlannerInfo *root, Node *hashkey,
double nbuckets);
-extern Datum brincostestimate(PG_FUNCTION_ARGS);
-extern Datum btcostestimate(PG_FUNCTION_ARGS);
-extern Datum hashcostestimate(PG_FUNCTION_ARGS);
-extern Datum gistcostestimate(PG_FUNCTION_ARGS);
-extern Datum spgcostestimate(PG_FUNCTION_ARGS);
-extern Datum gincostestimate(PG_FUNCTION_ARGS);
+extern void brincostestimate(PlannerInfo *root, IndexPath *path,
+ double loop_count, Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+extern void btcostestimate(PlannerInfo *root, IndexPath *path,
+ double loop_count, Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+extern void hashcostestimate(PlannerInfo *root, IndexPath *path,
+ double loop_count, Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+extern void gistcostestimate(PlannerInfo *root, IndexPath *path,
+ double loop_count, Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+extern void spgcostestimate(PlannerInfo *root, IndexPath *path,
+ double loop_count, Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+extern void gincostestimate(PlannerInfo *root, IndexPath *path,
+ double loop_count, Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
/* Functions in array_selfuncs.c */
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 28422ea..c403b80 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -2111,8 +2111,11 @@ create type alter1.ctype as (f1 int, f2 text);
create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql
as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
+create function alter1.hash(alter1.ctype) returns int4 language sql
+as 'select hashint4($1.f1) # hashtext($1.f2)';
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
- operator 1 alter1.=(alter1.ctype, alter1.ctype);
+ operator 1 alter1.=(alter1.ctype, alter1.ctype),
+ function 1 alter1.hash(alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
create text search configuration alter1.cfg(parser = alter1.prs);
@@ -2128,6 +2131,7 @@ alter operator class alter1.ctype_hash_ops using hash set schema alter2;
alter operator family alter1.ctype_hash_ops using hash set schema alter2;
alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
+alter function alter1.hash(alter1.ctype) set schema alter2;
alter type alter1.ctype set schema alter2;
alter conversion alter1.ascii_to_utf8 set schema alter2;
alter text search parser alter1.prs set schema alter2;
@@ -2164,7 +2168,7 @@ select alter2.plus1(41);
-- clean up
drop schema alter2 cascade;
-NOTICE: drop cascades to 13 other objects
+NOTICE: drop cascades to 14 other objects
DETAIL: drop cascades to table alter2.t1
drop cascades to view alter2.v1
drop cascades to function alter2.plus1(integer)
@@ -2173,6 +2177,7 @@ drop cascades to operator family alter2.ctype_hash_ops for access method hash
drop cascades to type alter2.ctype
drop cascades to function alter2.same(alter2.ctype,alter2.ctype)
drop cascades to operator alter2.=(alter2.ctype,alter2.ctype)
+drop cascades to function alter2.hash(alter2.ctype)
drop cascades to conversion ascii_to_utf8
drop cascades to text search parser prs
drop cascades to text search configuration cfg
diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out
index d85bc83..d1a322d 100644
--- a/src/test/regress/expected/oidjoins.out
+++ b/src/test/regress/expected/oidjoins.out
@@ -73,134 +73,6 @@ WHERE aggmtranstype != 0 AND
------+---------------
(0 rows)
-SELECT ctid, amkeytype
-FROM pg_catalog.pg_am fk
-WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
- ctid | amkeytype
-------+-----------
-(0 rows)
-
-SELECT ctid, aminsert
-FROM pg_catalog.pg_am fk
-WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
- ctid | aminsert
-------+----------
-(0 rows)
-
-SELECT ctid, ambeginscan
-FROM pg_catalog.pg_am fk
-WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
- ctid | ambeginscan
-------+-------------
-(0 rows)
-
-SELECT ctid, amgettuple
-FROM pg_catalog.pg_am fk
-WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- ctid | amgettuple
-------+------------
-(0 rows)
-
-SELECT ctid, amgetbitmap
-FROM pg_catalog.pg_am fk
-WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
- ctid | amgetbitmap
-------+-------------
-(0 rows)
-
-SELECT ctid, amrescan
-FROM pg_catalog.pg_am fk
-WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
- ctid | amrescan
-------+----------
-(0 rows)
-
-SELECT ctid, amendscan
-FROM pg_catalog.pg_am fk
-WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
- ctid | amendscan
-------+-----------
-(0 rows)
-
-SELECT ctid, ammarkpos
-FROM pg_catalog.pg_am fk
-WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
- ctid | ammarkpos
-------+-----------
-(0 rows)
-
-SELECT ctid, amrestrpos
-FROM pg_catalog.pg_am fk
-WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
- ctid | amrestrpos
-------+------------
-(0 rows)
-
-SELECT ctid, ambuild
-FROM pg_catalog.pg_am fk
-WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
- ctid | ambuild
-------+---------
-(0 rows)
-
-SELECT ctid, ambuildempty
-FROM pg_catalog.pg_am fk
-WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
- ctid | ambuildempty
-------+--------------
-(0 rows)
-
-SELECT ctid, ambulkdelete
-FROM pg_catalog.pg_am fk
-WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
- ctid | ambulkdelete
-------+--------------
-(0 rows)
-
-SELECT ctid, amvacuumcleanup
-FROM pg_catalog.pg_am fk
-WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
- ctid | amvacuumcleanup
-------+-----------------
-(0 rows)
-
-SELECT ctid, amcanreturn
-FROM pg_catalog.pg_am fk
-WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
- ctid | amcanreturn
-------+-------------
-(0 rows)
-
-SELECT ctid, amcostestimate
-FROM pg_catalog.pg_am fk
-WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
- ctid | amcostestimate
-------+----------------
-(0 rows)
-
-SELECT ctid, amoptions
-FROM pg_catalog.pg_am fk
-WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
- ctid | amoptions
-------+-----------
-(0 rows)
-
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index df29fe5..708d84c 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -1479,6 +1479,12 @@ WHERE p1.oid != p2.oid AND
-----+-----
(0 rows)
+-- Ask access methods to validate opclasses
+SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid);
+ oid
+-----
+(0 rows)
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
SELECT p1.amopfamily, p1.amopstrategy
@@ -1524,49 +1530,6 @@ WHERE p1.amopsortfamily <> 0 AND NOT EXISTS
------------+--------------
(0 rows)
--- check for ordering operators not supported by parent AM
-SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
-FROM pg_amop AS p1, pg_am AS p2
-WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
- amopfamily | amopopr | oid | amname
-------------+---------+-----+--------
-(0 rows)
-
--- Cross-check amopstrategy index against parent AM
-SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
-FROM pg_amop AS p1, pg_am AS p2
-WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
- amopfamily | amopopr | oid | amname
-------------+---------+-----+--------
-(0 rows)
-
--- Detect missing pg_amop entries: should have as many strategy operators
--- as AM expects for each datatype combination supported by the opfamily.
--- We can't check this for AMs with variable strategy sets.
-SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
-FROM pg_am AS p1, pg_amop AS p2
-WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
- amname | amoplefttype | amoprighttype
---------+--------------+---------------
-(0 rows)
-
--- Currently, none of the AMs with fixed strategy sets support ordering ops.
-SELECT p1.amname, p2.amopfamily, p2.amopstrategy
-FROM pg_am AS p1, pg_amop AS p2
-WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
- amname | amopfamily | amopstrategy
---------+------------+--------------
-(0 rows)
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
@@ -1849,15 +1812,6 @@ WHERE p1.amprocfamily = 0 OR p1.amproclefttype = 0 OR p1.amprocrighttype = 0
--------------+-----------
(0 rows)
--- Cross-check amprocnum index against parent AM
-SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
-FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
-WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
- amprocfamily | amprocnum | oid | amname
---------------+-----------+-----+--------
-(0 rows)
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
SELECT * FROM (
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index 3ef55d9..0c784e1 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -1448,8 +1448,12 @@ as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
+create function alter1.hash(alter1.ctype) returns int4 language sql
+as 'select hashint4($1.f1) # hashtext($1.f2)';
+
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
- operator 1 alter1.=(alter1.ctype, alter1.ctype);
+ operator 1 alter1.=(alter1.ctype, alter1.ctype),
+ function 1 alter1.hash(alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
@@ -1469,6 +1473,7 @@ alter operator class alter1.ctype_hash_ops using hash set schema alter2;
alter operator family alter1.ctype_hash_ops using hash set schema alter2;
alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
+alter function alter1.hash(alter1.ctype) set schema alter2;
alter type alter1.ctype set schema alter2;
alter conversion alter1.ascii_to_utf8 set schema alter2;
alter text search parser alter1.prs set schema alter2;
diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql
index 2fa628d..ca419fd 100644
--- a/src/test/regress/sql/oidjoins.sql
+++ b/src/test/regress/sql/oidjoins.sql
@@ -37,70 +37,6 @@ SELECT ctid, aggmtranstype
FROM pg_catalog.pg_aggregate fk
WHERE aggmtranstype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
-SELECT ctid, amkeytype
-FROM pg_catalog.pg_am fk
-WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
-SELECT ctid, aminsert
-FROM pg_catalog.pg_am fk
-WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
-SELECT ctid, ambeginscan
-FROM pg_catalog.pg_am fk
-WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
-SELECT ctid, amgettuple
-FROM pg_catalog.pg_am fk
-WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
-SELECT ctid, amgetbitmap
-FROM pg_catalog.pg_am fk
-WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
-SELECT ctid, amrescan
-FROM pg_catalog.pg_am fk
-WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
-SELECT ctid, amendscan
-FROM pg_catalog.pg_am fk
-WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
-SELECT ctid, ammarkpos
-FROM pg_catalog.pg_am fk
-WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
-SELECT ctid, amrestrpos
-FROM pg_catalog.pg_am fk
-WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
-SELECT ctid, ambuild
-FROM pg_catalog.pg_am fk
-WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
-SELECT ctid, ambuildempty
-FROM pg_catalog.pg_am fk
-WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
-SELECT ctid, ambulkdelete
-FROM pg_catalog.pg_am fk
-WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
-SELECT ctid, amvacuumcleanup
-FROM pg_catalog.pg_am fk
-WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
-SELECT ctid, amcanreturn
-FROM pg_catalog.pg_am fk
-WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
-SELECT ctid, amcostestimate
-FROM pg_catalog.pg_am fk
-WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
-SELECT ctid, amoptions
-FROM pg_catalog.pg_am fk
-WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index c9bdd77..0e0506e 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -960,6 +960,10 @@ WHERE p1.oid != p2.oid AND
p1.opcmethod = p2.opcmethod AND p1.opcintype = p2.opcintype AND
p1.opcdefault AND p2.opcdefault;
+-- Ask access methods to validate opclasses
+
+SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid);
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
@@ -995,41 +999,6 @@ WHERE p1.amopsortfamily <> 0 AND NOT EXISTS
(SELECT 1 from pg_opfamily op WHERE op.oid = p1.amopsortfamily
AND op.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree'));
--- check for ordering operators not supported by parent AM
-
-SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
-FROM pg_amop AS p1, pg_am AS p2
-WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
-
--- Cross-check amopstrategy index against parent AM
-
-SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
-FROM pg_amop AS p1, pg_am AS p2
-WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
-
--- Detect missing pg_amop entries: should have as many strategy operators
--- as AM expects for each datatype combination supported by the opfamily.
--- We can't check this for AMs with variable strategy sets.
-
-SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
-FROM pg_am AS p1, pg_amop AS p2
-WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
-
--- Currently, none of the AMs with fixed strategy sets support ordering ops.
-
-SELECT p1.amname, p2.amopfamily, p2.amopstrategy
-FROM pg_am AS p1, pg_amop AS p2
-WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
@@ -1176,13 +1145,6 @@ FROM pg_amproc as p1
WHERE p1.amprocfamily = 0 OR p1.amproclefttype = 0 OR p1.amprocrighttype = 0
OR p1.amprocnum < 1 OR p1.amproc = 0;
--- Cross-check amprocnum index against parent AM
-
-SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
-FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
-WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
On 2015-09-25 16:11, Teodor Sigaev wrote:
I'm OK about continuing work on amvalidate if we can build consuensus
on its design.
Could you give some feedback on amvalidate version of patch please?
/messages/by-id/CAPpHfds8ZyWenz9vW6tE5RZXboL1vU_wSW181vEq+mU+v1dsiw@mail.gmail.comIn attach a bit modified patch based on 4-th version, and if there are
no strong objections, I will commit it. Waiting this patch stops
Alexander's development on CREATE ACCESS METHOD and he needs to move
forward.
The code itself looks ok to me, but before we can think about committing
this the documentation has to be updated.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Petr Jelinek <petr@2ndquadrant.com> writes:
On 2015-09-25 16:11, Teodor Sigaev wrote:
In attach a bit modified patch based on 4-th version, and if there are
no strong objections, I will commit it. Waiting this patch stops
Alexander's development on CREATE ACCESS METHOD and he needs to move
forward.
The code itself looks ok to me, but before we can think about committing
this the documentation has to be updated.
Yes. Also, for a major change like this, it would be a good thing if
the documentation got a review from a native English speaker. I will
volunteer to handle it if someone else does the first draft.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Sep 25, 2015 at 6:25 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Petr Jelinek <petr@2ndquadrant.com> writes:
On 2015-09-25 16:11, Teodor Sigaev wrote:
In attach a bit modified patch based on 4-th version, and if there are
no strong objections, I will commit it. Waiting this patch stops
Alexander's development on CREATE ACCESS METHOD and he needs to move
forward.The code itself looks ok to me, but before we can think about committing
this the documentation has to be updated.Yes. Also, for a major change like this, it would be a good thing if
the documentation got a review from a native English speaker. I will
volunteer to handle it if someone else does the first draft.
Great! I'll write this documentation.
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Teodor Sigaev wrote:
I'm OK about continuing work on amvalidate if we can build consuensus on its design.
Could you give some feedback on amvalidate version of patch please?
/messages/by-id/CAPpHfds8ZyWenz9vW6tE5RZXboL1vU_wSW181vEq+mU+v1dsiw@mail.gmail.comIn attach a bit modified patch based on 4-th version, and if there are no
strong objections, I will commit it. Waiting this patch stops Alexander's
development on CREATE ACCESS METHOD and he needs to move forward.
I think the messages in ereport() need some work -- at the bare minimum,
do not uppercase the initial. Also things such as whether operation
names such as "order by" ought to be uppercase or in quotes, for example
here:
+ ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("BRIN doesn't support order by operators")));
I think the API of getOpFamilyInfo is a bit odd; is the caller expected
to fill intype and keytype always, and then it only sets the procs/opers
lists? I wonder if it would be more sensible to have that routine
receive the pg_opclass tuple (or even the opclass OID) instead of the
opfamily OID.
I think "amapi.h" is not a great file name. What about am_api.h?
I'm unsure about BRIN_NPROC. Why did you set it to 15? It's not
unthinkable that future opclass frameworks will have different numbers
of support procs. For BRIN I'm thinking that we could add another
support proc which validates the opclass definition using the specific
framework; that way we will be able to check that the set of operators
defined are correct, etc (something that the current approach cannot
do).
I think another pgindent run would be good -- there's some broken
whitespace here and there.
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-09-25 17:45, Alvaro Herrera wrote:
I think the API of getOpFamilyInfo is a bit odd; is the caller expected
to fill intype and keytype always, and then it only sets the procs/opers
lists? I wonder if it would be more sensible to have that routine
receive the pg_opclass tuple (or even the opclass OID) instead of the
opfamily OID.I think "amapi.h" is not a great file name. What about am_api.h?
Well we have related fdwapi.h and tsmapi.h (and several unrelated *api.h
which also don't use "_" in the name) so amapi.h seems fine to me.
I'm unsure about BRIN_NPROC. Why did you set it to 15? It's not
unthinkable that future opclass frameworks will have different numbers
The BRIN_NPROC should be probably defined in brin.c since it's only used
for sizing local array variable in amvalidate and should be used to set
amsupport in the init function as well then.
of support procs. For BRIN I'm thinking that we could add another
support proc which validates the opclass definition using the specific
framework; that way we will be able to check that the set of operators
defined are correct, etc (something that the current approach cannot
do).
As I said before in the thread I would prefer more granular approach to
validation - have amvalidateopclass in the struct for the current
functionality so that we can easily add more validators in the future.
There can still be one amvalidate function exposed on SQL level that
just calls all the amvalidate* functions that the am defines.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Sep 25, 2015 at 7:41 PM, Teodor Sigaev <teodor@sigaev.ru> wrote:
I'm OK about continuing work on amvalidate if we can build consuensus on
its design.
Could you give some feedback on amvalidate version of patch please?/messages/by-id/CAPpHfds8ZyWenz9vW6tE5RZXboL1vU_wSW181vEq+mU+v1dsiw@mail.gmail.com
In attach a bit modified patch based on 4-th version, and if there are no
strong objections, I will commit it. Waiting this patch stops Alexander's
development on CREATE ACCESS METHOD and he needs to move forward.
1.
+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;
+}
Is it appropriate to use CacheMemoryContext here?
Currently in load_relcache_init_file(), all the other information
like rd_indoption, rd_aminfo in Relation is allocated in indexcxt
which ofcourse in allocated in CacheMemoryContext, but still is
there a reason why this also shouldn't be allocated in same
context.
2.
- aform = (Form_pg_am) MemoryContextAlloc(CacheMemoryContext, sizeof
*aform);
+ aform = (Form_pg_am)MemoryContextAlloc(CacheMemoryContext, sizeof *aform);
Spurious change.
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com
On Sat, Sep 26, 2015 at 12:55 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
On 2015-09-25 17:45, Alvaro Herrera wrote:
I think the API of getOpFamilyInfo is a bit odd; is the caller expected
to fill intype and keytype always, and then it only sets the procs/opers
lists? I wonder if it would be more sensible to have that routine
receive the pg_opclass tuple (or even the opclass OID) instead of the
opfamily OID.I think "amapi.h" is not a great file name. What about am_api.h?
Well we have related fdwapi.h and tsmapi.h (and several unrelated *api.h
which also don't use "_" in the name) so amapi.h seems fine to me.
Makes sense. I leave it amapi.h.
I'm unsure about BRIN_NPROC. Why did you set it to 15? It's not
unthinkable that future opclass frameworks will have different numbers
The BRIN_NPROC should be probably defined in brin.c since it's only used
for sizing local array variable in amvalidate and should be used to set
amsupport in the init function as well then.
Problem is that in BRIN, access method use only first 4 support procedures.
However, operator class can define more and call them from first 4 support
procedures. That allows operator classes to re-use same support procedures
and build additional levels of abstractions. I've
declared BRIN_MANDATORY_NPROCS, and brinvalidate checks only their
presence. We could check BRIN opclass more precisely, by introducing new
support procedure for validation. I think it's a subject of a separate
patch since it would change interface of BRIN.
of support procs. For BRIN I'm thinking that we could add another
support proc which validates the opclass definition using the specific
framework; that way we will be able to check that the set of operators
defined are correct, etc (something that the current approach cannot
do).As I said before in the thread I would prefer more granular approach to
validation - have amvalidateopclass in the struct for the current
functionality so that we can easily add more validators in the future.
There can still be one amvalidate function exposed on SQL level that just
calls all the amvalidate* functions that the am defines.
I agree about staying with one SQL-visible function.
Other changes:
* Documentation reflects interface changes.
* IndexAmRoutine moved from CacheMemoryContext to indexcxt.
* Various minor formatting improvements.
* Error messages are corrected.
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Attachments:
aminterface-7.patchapplication/octet-stream; name=aminterface-7.patchDownload
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
new file mode 100644
index e8bd3a1..59e3001
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 549,762 ****
</row>
<row>
! <entry><structfield>amstrategies</structfield></entry>
! <entry><type>int2</type></entry>
! <entry></entry>
! <entry>Number of operator strategies for this access method,
! or zero if access method does not have a fixed set of operator
! strategies</entry>
! </row>
!
! <row>
! <entry><structfield>amsupport</structfield></entry>
! <entry><type>int2</type></entry>
! <entry></entry>
! <entry>Number of support routines for this access method</entry>
! </row>
!
! <row>
! <entry><structfield>amcanorder</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support ordered scans sorted by the
! indexed column's value?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanorderbyop</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support ordered scans sorted by the result
! of an operator on the indexed column?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanbackward</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support backward scanning?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanunique</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support unique indexes?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanmulticol</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support multicolumn indexes?</entry>
! </row>
!
! <row>
! <entry><structfield>amoptionalkey</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support a scan without any constraint
! for the first index column?</entry>
! </row>
!
! <row>
! <entry><structfield>amsearcharray</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support <literal>ScalarArrayOpExpr</> searches?</entry>
! </row>
!
! <row>
! <entry><structfield>amsearchnulls</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support <literal>IS NULL</>/<literal>NOT NULL</> searches?</entry>
! </row>
!
! <row>
! <entry><structfield>amstorage</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Can index storage data type differ from column data type?</entry>
! </row>
!
! <row>
! <entry><structfield>amclusterable</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Can an index of this type be clustered on?</entry>
! </row>
!
! <row>
! <entry><structfield>ampredlocks</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does an index of this type manage fine-grained predicate locks?</entry>
! </row>
!
! <row>
! <entry><structfield>amkeytype</structfield></entry>
<entry><type>oid</type></entry>
- <entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
- <entry>Type of data stored in index, or zero if not a fixed type</entry>
- </row>
-
- <row>
- <entry><structfield>aminsert</structfield></entry>
- <entry><type>regproc</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Insert this tuple</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambeginscan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Prepare for index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amgettuple</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Next valid tuple</quote> function, or zero if none</entry>
! </row>
!
! <row>
! <entry><structfield>amgetbitmap</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Fetch all valid tuples</quote> function, or zero if none</entry>
! </row>
!
! <row>
! <entry><structfield>amrescan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>(Re)start index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amendscan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Clean up after index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ammarkpos</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Mark current scan position</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amrestrpos</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Restore marked scan position</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambuild</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Build new index</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambuildempty</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Build empty index</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambulkdelete</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Bulk-delete function</entry>
! </row>
!
! <row>
! <entry><structfield>amvacuumcleanup</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Post-<command>VACUUM</command> cleanup function</entry>
! </row>
!
! <row>
! <entry><structfield>amcanreturn</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to check whether an index column supports index-only
! scans. Can be zero if index-only scans are never supported.</entry>
! </row>
!
! <row>
! <entry><structfield>amcostestimate</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to estimate cost of an index scan</entry>
! </row>
!
! <row>
! <entry><structfield>amoptions</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to parse and validate <structfield>reloptions</> for an index</entry>
</row>
-
</tbody>
</tgroup>
</table>
--- 549,562 ----
</row>
<row>
! <entry><structfield>amhandler</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>
! References a handler function that is responsible for
! supplying execution routines for the access method.
! </entry>
</row>
</tbody>
</tgroup>
</table>
diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml
new file mode 100644
index 1c09bae..3248ae5
*** a/doc/src/sgml/indexam.sgml
--- b/doc/src/sgml/indexam.sgml
***************
*** 49,61 ****
<para>
Each index access method is described by a row in the
<structname>pg_am</structname> system catalog (see
! <xref linkend="catalog-pg-am">). The principal contents of a
! <structname>pg_am</structname> row are references to
! <link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>
! entries that identify the index access
! functions supplied by the access method. The APIs for these functions
! are defined later in this chapter. In addition, the
! <structname>pg_am</structname> row specifies a few fixed properties of
the access method, such as whether it can support multicolumn indexes.
There is not currently any special support
for creating or deleting <structname>pg_am</structname> entries;
--- 49,63 ----
<para>
Each index access method is described by a row in the
<structname>pg_am</structname> system catalog (see
! <xref linkend="catalog-pg-am">). In the <structname>pg_am</structname> row
! the handler function is specified by the reference to
! <link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.
! Handler function must be written in a compiled language such as C, using
! the version-1 interface. The handler function simply returns a
! <structname>IndexAmRoutine</structname> struct which contains function
! pointers to callback functions that will be called by the planner, executor,
! and various maintenance commands. In addition, the
! <structname>IndexAmRoutine</structname> contains a few fixed properties of
the access method, such as whether it can support multicolumn indexes.
There is not currently any special support
for creating or deleting <structname>pg_am</structname> entries;
***************
*** 96,102 ****
</para>
<para>
! Some of the flag columns of <structname>pg_am</structname> have nonobvious
implications. The requirements of <structfield>amcanunique</structfield>
are discussed in <xref linkend="index-unique-checks">.
The <structfield>amcanmulticol</structfield> flag asserts that the
--- 98,104 ----
</para>
<para>
! Some of the flag fields of <structname>IndexAmRoutine</structname> have nonobvious
implications. The requirements of <structfield>amcanunique</structfield>
are discussed in <xref linkend="index-unique-checks">.
The <structfield>amcanmulticol</structfield> flag asserts that the
***************
*** 143,149 ****
<para>
The index construction and maintenance functions that an index access
! method must provide are:
</para>
<para>
--- 145,151 ----
<para>
The index construction and maintenance functions that an index access
! method must provide in <structname>IndexAmRoutine</structname> are:
</para>
<para>
*************** aminsert (Relation indexRelation,
*** 188,194 ****
<literal>isnull</> arrays give the key values to be indexed, and
<literal>heap_tid</> is the TID to be indexed.
If the access method supports unique indexes (its
! <structname>pg_am</>.<structfield>amcanunique</> flag is true) then
<literal>checkUnique</> indicates the type of uniqueness check to
perform. This varies depending on whether the unique constraint is
deferrable; see <xref linkend="index-unique-checks"> for details.
--- 190,196 ----
<literal>isnull</> arrays give the key values to be indexed, and
<literal>heap_tid</> is the TID to be indexed.
If the access method supports unique indexes (its
! <structfield>amcanunique</> flag is true) then
<literal>checkUnique</> indicates the type of uniqueness check to
perform. This varies depending on whether the unique constraint is
deferrable; see <xref linkend="index-unique-checks"> for details.
*************** amcanreturn (Relation indexRelation, int
*** 281,288 ****
the form of an <structname>IndexTuple</structname>. The attribute number
is 1-based, i.e. the first columns attno is 1. Returns TRUE if supported,
else FALSE. If the access method does not support index-only scans at all,
! the <structfield>amcanreturn</> field in its <structname>pg_am</> row can
! be set to zero.
</para>
<para>
--- 283,290 ----
the form of an <structname>IndexTuple</structname>. The attribute number
is 1-based, i.e. the first columns attno is 1. Returns TRUE if supported,
else FALSE. If the access method does not support index-only scans at all,
! the <structfield>amcanreturn</> field in its <structname>IndexAmRoutine</>
! struct can be set to NULL.
</para>
<para>
*************** amgettuple (IndexScanDesc scan,
*** 414,421 ****
<para>
The <function>amgettuple</> function need only be provided if the access
method supports <quote>plain</> index scans. If it doesn't, the
! <structfield>amgettuple</> field in its <structname>pg_am</> row must
! be set to zero.
</para>
<para>
--- 416,423 ----
<para>
The <function>amgettuple</> function need only be provided if the access
method supports <quote>plain</> index scans. If it doesn't, the
! <structfield>amgettuple</> field in its <structname>IndexAmRoutine</>
! struct must be set to NULL.
</para>
<para>
*************** amgetbitmap (IndexScanDesc scan,
*** 445,452 ****
<para>
The <function>amgetbitmap</> function need only be provided if the access
method supports <quote>bitmap</> index scans. If it doesn't, the
! <structfield>amgetbitmap</> field in its <structname>pg_am</> row must
! be set to zero.
</para>
<para>
--- 447,454 ----
<para>
The <function>amgetbitmap</> function need only be provided if the access
method supports <quote>bitmap</> index scans. If it doesn't, the
! <structfield>amgetbitmap</> field in its <structname>IndexAmRoutine</>
! struct must be set to NULL.
</para>
<para>
*************** amrestrpos (IndexScanDesc scan);
*** 477,494 ****
</para>
<para>
! By convention, the <literal>pg_proc</literal> entry for an index
! access method function should show the correct number of arguments,
! but declare them all as type <type>internal</> (since most of the arguments
! have types that are not known to SQL, and we don't want users calling
! the functions directly anyway). The return type is declared as
! <type>void</>, <type>internal</>, or <type>boolean</> as appropriate.
! The only exception is <function>amoptions</>, which should be correctly
! declared as taking <type>text[]</> and <type>bool</> and returning
! <type>bytea</>. This provision allows client code to execute
! <function>amoptions</> to test validity of options settings.
</para>
-
</sect1>
<sect1 id="index-scanning">
--- 479,491 ----
</para>
<para>
! <programlisting>
! void
! amvalidate (OpClassInfo *opclass);
! </programlisting>
! Validates given operator class by access method. The <function>amvalidate</>
! must throw an error if opclass is invalid.
</para>
</sect1>
<sect1 id="index-scanning">
*************** amrestrpos (IndexScanDesc scan);
*** 548,554 ****
<para>
Access methods that always return entries in the natural ordering
of their data (such as btree) should set
! <structname>pg_am</>.<structfield>amcanorder</> to true.
Currently, such access methods must use btree-compatible strategy
numbers for their equality and ordering operators.
</para>
--- 545,551 ----
<para>
Access methods that always return entries in the natural ordering
of their data (such as btree) should set
! <structfield>amcanorder</> to true.
Currently, such access methods must use btree-compatible strategy
numbers for their equality and ordering operators.
</para>
*************** amrestrpos (IndexScanDesc scan);
*** 556,562 ****
<listitem>
<para>
Access methods that support ordering operators should set
! <structname>pg_am</>.<structfield>amcanorderbyop</> to true.
This indicates that the index is capable of returning entries in
an order satisfying <literal>ORDER BY</> <replaceable>index_key</>
<replaceable>operator</> <replaceable>constant</>. Scan modifiers
--- 553,559 ----
<listitem>
<para>
Access methods that support ordering operators should set
! <structfield>amcanorderbyop</> to true.
This indicates that the index is capable of returning entries in
an order satisfying <literal>ORDER BY</> <replaceable>index_key</>
<replaceable>operator</> <replaceable>constant</>. Scan modifiers
*************** amrestrpos (IndexScanDesc scan);
*** 579,585 ****
methods that set <structfield>amcanorder</> to true.) After the
first call, <function>amgettuple</> must be prepared to advance the scan in
either direction from the most recently returned entry. (But if
! <structname>pg_am</>.<structfield>amcanbackward</> is false, all subsequent
calls will have the same direction as the first one.)
</para>
--- 576,582 ----
methods that set <structfield>amcanorder</> to true.) After the
first call, <function>amgettuple</> must be prepared to advance the scan in
either direction from the most recently returned entry. (But if
! <structfield>amcanbackward</> is false, all subsequent
calls will have the same direction as the first one.)
</para>
*************** amrestrpos (IndexScanDesc scan);
*** 590,597 ****
be remembered per scan; a new <function>ammarkpos</> call overrides the
previously marked position. An access method that does not support
ordered scans should still provide mark and restore functions in
! <structname>pg_am</>, but it is sufficient to have them throw errors if
! called.
</para>
<para>
--- 587,594 ----
be remembered per scan; a new <function>ammarkpos</> call overrides the
previously marked position. An access method that does not support
ordered scans should still provide mark and restore functions in
! <structname>IndexAmRoutine</>, but it is sufficient to have them throw
! errors if called.
</para>
<para>
*************** amrestrpos (IndexScanDesc scan);
*** 766,772 ****
<productname>PostgreSQL</productname> enforces SQL uniqueness constraints
using <firstterm>unique indexes</>, which are indexes that disallow
multiple entries with identical keys. An access method that supports this
! feature sets <structname>pg_am</>.<structfield>amcanunique</> true.
(At present, only b-tree supports it.)
</para>
--- 763,769 ----
<productname>PostgreSQL</productname> enforces SQL uniqueness constraints
using <firstterm>unique indexes</>, which are indexes that disallow
multiple entries with identical keys. An access method that supports this
! feature sets <structfield>amcanunique</> true.
(At present, only b-tree supports it.)
</para>
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
new file mode 100644
index 99337b0..a029eb1
*** a/src/backend/access/brin/brin.c
--- b/src/backend/access/brin/brin.c
***************
*** 35,40 ****
--- 35,143 ----
/*
+ * BRIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ brinhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 15;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = brininsert;
+ amroutine->ambeginscan = brinbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = bringetbitmap;
+ amroutine->amrescan = brinrescan;
+ amroutine->amendscan = brinendscan;
+ amroutine->ammarkpos = brinmarkpos;
+ amroutine->amrestrpos = brinrestrpos;
+ amroutine->ambuild = brinbuild;
+ amroutine->ambuildempty = brinbuildempty;
+ amroutine->ambulkdelete = brinbulkdelete;
+ amroutine->amvacuumcleanup = brinvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = brincostestimate;
+ amroutine->amoptions = brinoptions;
+ amroutine->amvalidate = brinvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ brinvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[BRIN_MANDATORY_NPROCS];
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype ||
+ proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for BRIN: %u",
+ proc->number)));
+
+ /* BRIN opclasses could contain any number of non-mandatory procedures */
+ if (proc->number > BRIN_MANDATORY_NPROCS)
+ continue;
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u was defined more than once",
+ proc->number)));
+
+ procsPresent[proc->number - 1] = true;
+ }
+
+ /*
+ * Don't use BRIN_NPROC because some procnumbers
+ * are reserved for future use
+ */
+ for (i = 0; i < BRIN_MANDATORY_NPROCS; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN doesn't support ORDER BY operators")));
+ }
+ }
+
+ /*
* We use a BrinBuildState during initial construction of a BRIN index.
* The running state is kept in a BrinMemTuple.
*/
*************** 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;
--- 183,193 ----
* 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);
}
/*
--- 325,331 ----
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;
--- 335,343 ----
* 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);
}
/*
--- 348,354 ----
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;
--- 363,371 ----
* 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
--- 545,560 ----
* 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();
}
/*
--- 566,596 ----
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;
--- 662,670 ----
/*
* 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. */
--- 743,754 ----
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();
}
/*
--- 765,770 ----
*************** 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));
--- 776,804 ----
* 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;
--- 815,829 ----
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);
--- 836,842 ----
/* 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);
}
/*
--- 845,851 ----
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 d817eba..978d2dc
*** a/src/backend/access/common/reloptions.c
--- b/src/backend/access/common/reloptions.c
*************** untransformRelOptions(Datum options)
*** 891,897 ****
* 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;
--- 891,897 ----
* 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
*** 1379,1412 ****
* 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);
}
/*
--- 1379,1393 ----
* 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 49e9185..92701b9
*** 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..51c1559
*** a/src/backend/access/gin/ginutil.c
--- b/src/backend/access/gin/ginutil.c
***************
*** 22,28 ****
--- 22,140 ----
#include "miscadmin.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
+ #include "utils/selfuncs.h"
+
+
+ /*
+ * GIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ ginhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 6;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = gininsert;
+ amroutine->ambeginscan = ginbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = gingetbitmap;
+ amroutine->amrescan = ginrescan;
+ amroutine->amendscan = ginendscan;
+ amroutine->ammarkpos = ginmarkpos;
+ amroutine->amrestrpos = ginrestrpos;
+ amroutine->ambuild = ginbuild;
+ amroutine->ambuildempty = ginbuildempty;
+ amroutine->ambulkdelete = ginbulkdelete;
+ amroutine->amvacuumcleanup = ginvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = gincostestimate;
+ amroutine->amoptions = ginoptions;
+ amroutine->amvalidate = ginvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ ginvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[GINNProcs];
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype ||
+ proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > GINNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for GIN: %u",
+ proc->number)));
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u was defined more than once",
+ proc->number)));
+
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < GINNProcs; i++)
+ {
+ if (i+1 == GIN_COMPARE_PARTIAL_PROC)
+ continue; /* optional method */
+ if (i+1 == GIN_CONSISTENT_PROC || i+1 == GIN_TRICONSISTENT_PROC)
+ continue; /* don't need to have both, see check below loop */
+
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u is required", i + 1)));
+ }
+
+ if (!procsPresent[GIN_CONSISTENT_PROC - 1]
+ && !procsPresent[GIN_TRICONSISTENT_PROC - 1])
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("at least one of consistent support (number %u) "
+ "and triconsistent support (number %u) is "
+ "is required",
+ GIN_CONSISTENT_PROC, GIN_TRICONSISTENT_PROC)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN doesn't support ORDER BY operators")));
+ }
+ }
/*
* initGinState: fill in an empty GinState struct to describe the index
*************** 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;
--- 628,636 ----
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);
--- 645,651 ----
/* 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);
}
/*
--- 654,660 ----
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 323cfb0..5b38607
*** 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, true, stats);
}
! PG_RETURN_POINTER(stats);
}
/*
--- 656,662 ----
initGinState(&ginstate, index);
ginInsertCleanup(&ginstate, true, 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 53bccf6..12224b6
*** 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 void gistfinishsplit(GISTInsertSt
*** 38,43 ****
--- 40,143 ----
GISTSTATE *giststate, List *splitinfo, bool releasebuf);
static void gistvacuumpage(Relation rel, Page page, Buffer buffer);
+ /*
+ * GiST handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ gisthandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 9;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = true;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = true;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = gistinsert;
+ amroutine->ambeginscan = gistbeginscan;
+ amroutine->amgettuple = gistgettuple;
+ amroutine->amgetbitmap = gistgetbitmap;
+ amroutine->amrescan = gistrescan;
+ amroutine->amendscan = gistendscan;
+ amroutine->ammarkpos = gistmarkpos;
+ amroutine->amrestrpos = gistrestrpos;
+ amroutine->ambuild = gistbuild;
+ amroutine->ambuildempty = gistbuildempty;
+ amroutine->ambulkdelete = gistbulkdelete;
+ amroutine->amvacuumcleanup = gistvacuumcleanup;
+ amroutine->amcanreturn = gistcanreturn;
+ amroutine->amcostestimate = gistcostestimate;
+ amroutine->amoptions = gistoptions;
+ amroutine->amvalidate = gistvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ gistvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[GISTNProcs];
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype ||
+ proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > GISTNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for GiST: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u was defined more than once",
+ proc->number)));
+
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < GISTNProcs; i++)
+ {
+ if (i+1 == GIST_DISTANCE_PROC || i+1 == GIST_FETCH_PROC)
+ continue; /* optional methods */
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily)
+ && !procsPresent[GIST_DISTANCE_PROC - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST distance support function %u is required "
+ "for ORDER BY operators", GIST_DISTANCE_PROC)));
+ }
+ }
#define ROTATEDIST(d) do { \
SplitedPageLayout *tmp=(SplitedPageLayout*)palloc(sizeof(SplitedPageLayout)); \
*************** createTempGistContext(void)
*** 70,79 ****
/*
* 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 */
--- 170,178 ----
/*
* gistbuildempty() -- build an empty gist index in the initialization fork
*/
! void
! gistbuildempty(Relation index)
{
Buffer buffer;
/* Initialize the root page */
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 89,96 ****
/* Unlock and release the buffer */
UnlockReleaseBuffer(buffer);
-
- PG_RETURN_VOID();
}
/*
--- 188,193 ----
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 99,116 ****
* 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;
--- 196,206 ----
* 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)
*** 136,142 ****
MemoryContextSwitchTo(oldCxt);
freeGISTstate(giststate);
! PG_RETURN_BOOL(false);
}
--- 226,232 ----
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 ce8e582..1adf92f
*** a/src/backend/access/gist/gistget.c
--- b/src/backend/access/gist/gistget.c
*************** getNextNearest(IndexScanDesc scan)
*** 618,628 ****
/*
* 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)
--- 618,626 ----
/*
* 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)
*** 651,657 ****
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! PG_RETURN_BOOL(getNextNearest(scan));
}
else
{
--- 649,655 ----
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! return getNextNearest(scan);
}
else
{
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 688,694 ****
so->curPageData++;
! PG_RETURN_BOOL(true);
}
/*
--- 686,692 ----
so->curPageData++;
! return true;
}
/*
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 726,732 ****
item = getNextGISTSearchItem(so);
if (!item)
! PG_RETURN_BOOL(false);
CHECK_FOR_INTERRUPTS();
--- 724,730 ----
item = getNextGISTSearchItem(so);
if (!item)
! return false;
CHECK_FOR_INTERRUPTS();
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 750,766 ****
/*
* 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);
--- 748,762 ----
/*
* 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)
*** 791,797 ****
pfree(item);
}
! PG_RETURN_INT64(ntids);
}
/*
--- 787,793 ----
pfree(item);
}
! return ntids;
}
/*
*************** gistgetbitmap(PG_FUNCTION_ARGS)
*** 799,812 ****
*
* 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);
}
--- 795,805 ----
*
* 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 a17c5bc..22f0c68
*** 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)
*** 107,121 ****
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;
--- 104,116 ----
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)
*** 314,341 ****
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;
/*
--- 309,331 ----
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)
*** 343,348 ****
* as well as the queueCxt if there is a separate context for it.
*/
freeGISTstate(so->giststate);
-
- PG_RETURN_VOID();
}
--- 333,336 ----
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 a0b0eeb..e0ce620
*** 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)
*** 276,280 ****
vacuum_delay_point();
}
! PG_RETURN_POINTER(stats);
}
--- 271,275 ----
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..a51fa7c
*** 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,150 ----
bool tupleIsAlive,
void *state);
+ /*
+ * Hash handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ hashhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 1;
+ amroutine->amsupport = 1;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = true;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = false;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = INT4OID;
+
+ amroutine->aminsert = hashinsert;
+ amroutine->ambeginscan = hashbeginscan;
+ amroutine->amgettuple = hashgettuple;
+ amroutine->amgetbitmap = hashgetbitmap;
+ amroutine->amrescan = hashrescan;
+ amroutine->amendscan = hashendscan;
+ amroutine->ammarkpos = hashmarkpos;
+ amroutine->amrestrpos = hashrestrpos;
+ amroutine->ambuild = hashbuild;
+ amroutine->ambuildempty = hashbuildempty;
+ amroutine->ambulkdelete = hashbulkdelete;
+ amroutine->amvacuumcleanup = hashvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = hashcostestimate;
+ amroutine->amoptions = hashoptions;
+ amroutine->amvalidate = hashvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ hashvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->number != HASHPROC)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for hash: %u",
+ proc->number)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+ bool leftFound = false, rightFound = false;
+ ListCell *ll;
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("hash doesn't support ORDER BY operators")));
+
+ if (opr->number < 1 || opr->number > HTMaxStrategyNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid strategy number for hash: %u",
+ opr->number)));
+
+ foreach(ll, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(ll);
+
+ if (proc->lefttype == opr->lefttype)
+ leftFound = true;
+ if (proc->lefttype == opr->righttype)
+ rightFound = true;
+ }
+
+ if (!leftFound || !rightFound)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("no hash procedure found for operator: %u",
+ opr->object)));
+ }
+ }
/*
* hashbuild() -- build a new hash index.
*/
! 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();
}
/*
--- 205,220 ----
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;
/*
--- 256,266 ----
* 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);
--- 273,279 ----
* 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;
--- 283,298 ----
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;
--- 394,409 ----
/* 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;
--- 440,455 ----
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;
--- 471,486 ----
/* 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;
--- 506,519 ----
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();
}
/*
--- 532,555 ----
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;
--- 559,568 ----
*
* 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);
}
/*
--- 732,738 ----
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);
}
--- 740,761 ----
*
* 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..ee623ae
*** 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,182 ----
/*
! * 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;
! amroutine->amvalidate = btvalidate;
!
! PG_RETURN_POINTER(amroutine);
! }
!
! void
! btvalidate(OpClassInfo *opclass)
! {
! ListCell *l;
!
! foreach(l, opclass->procedures)
! {
! OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
!
! if (proc->number != BTORDER_PROC &&
! proc->number != BTSORTSUPPORT_PROC)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("invalid support number for btree: %u",
! proc->number)));
! }
!
! foreach(l, opclass->operators)
! {
! OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
! bool found = false;
! ListCell *ll;
!
! if (OidIsValid(opr->sortfamily))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("btree doesn't support ORDER BY operators")));
!
! if (opr->number < 1 || opr->number > BTMaxStrategyNumber)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("invalid strategy number for btree: %u",
! opr->number)));
!
! foreach(ll, opclass->procedures)
! {
! OpFamilyMember *proc = (OpFamilyMember *) lfirst(ll);
!
! if (proc->number == BTORDER_PROC &&
! proc->lefttype == opr->lefttype &&
! proc->righttype == opr->righttype)
! found = true;
! }
!
! if (!found)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("no ordering procedure found for operator: %u",
! opr->object)));
! }
! }
!
! /*
! * btbuild() -- build a new btree index.
! */
! IndexBuildResult *
! btbuild(Relation heap, Relation index, IndexInfo *indexInfo)
{
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);
}
/*
--- 248,254 ----
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);
--- 283,292 ----
/*
* 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();
}
/*
--- 306,311 ----
*************** 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;
--- 314,324 ----
* 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;
--- 330,344 ----
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);
}
--- 354,360 ----
{
/* 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;
--- 404,418 ----
/* ... 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);
}
--- 424,430 ----
{
/* 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;
--- 462,476 ----
/* 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 */
--- 508,523 ----
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 */
--- 568,581 ----
/* 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). */
--- 604,617 ----
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 */
--- 634,647 ----
/* 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();
}
/*
--- 709,714 ----
*************** 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;
--- 718,727 ----
*
* 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);
}
/*
--- 740,746 ----
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
--- 748,759 ----
*
* 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);
}
/*
--- 785,791 ----
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);
}
--- 1186,1193 ----
*
* 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..09c679b
*** a/src/backend/access/spgist/spgutils.c
--- b/src/backend/access/spgist/spgutils.c
***************
*** 24,30 ****
--- 24,126 ----
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "utils/lsyscache.h"
+ #include "utils/selfuncs.h"
+
+
+ /*
+ * SP-GiST handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ spghandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 5;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = spginsert;
+ amroutine->ambeginscan = spgbeginscan;
+ amroutine->amgettuple = spggettuple;
+ amroutine->amgetbitmap = spggetbitmap;
+ amroutine->amrescan = spgrescan;
+ amroutine->amendscan = spgendscan;
+ amroutine->ammarkpos = spgmarkpos;
+ amroutine->amrestrpos = spgrestrpos;
+ amroutine->ambuild = spgbuild;
+ amroutine->ambuildempty = spgbuildempty;
+ amroutine->ambulkdelete = spgbulkdelete;
+ amroutine->amvacuumcleanup = spgvacuumcleanup;
+ amroutine->amcanreturn = spgcanreturn;
+ amroutine->amcostestimate = spgcostestimate;
+ amroutine->amoptions = spgoptions;
+ amroutine->amvalidate = spgvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ spgvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[SPGISTNProc];
+ int i;
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype ||
+ proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > SPGISTNProc)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for SP-GiST: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u was defined more than once",
+ proc->number)));
+
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < SPGISTNProc; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST doesn't support ORDER BY operators")));
+ }
+ }
/* Fill in a SpGistTypeDesc struct with info about the specified data type */
static void
*************** 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();
}
/*
--- 585,600 ----
/*
* 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 <unistd.h>
+ #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/opclasscmds.c b/src/backend/commands/opclasscmds.c
new file mode 100644
index 3375f10..d066298
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
***************
*** 42,47 ****
--- 42,48 ----
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
+ #include "utils/catcache.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 334,346 ****
ListCell *l;
Relation rel;
HeapTuple tup;
- Form_pg_am pg_am;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
--- 335,348 ----
ListCell *l;
Relation rel;
HeapTuple tup;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
+ IndexAmRoutine *amroutine;
+ OpClassInfo opclassinfo;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 361,373 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
! amstorage = pg_am->amstorage;
/* XXX Should we make any privilege check against the AM? */
--- 363,377 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
!
! amroutine = GetIndexAmRoutine(amoid);
!
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
! amstorage = amroutine->amstorage;
/* XXX Should we make any privilege check against the AM? */
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 582,587 ****
--- 586,597 ----
stmt->amname)));
}
+ opclassinfo.intype = typeoid;
+ opclassinfo.keytype = storageoid;
+ opclassinfo.procedures = procedures;
+ opclassinfo.operators = operators;
+ amroutine->amvalidate(&opclassinfo);
+
rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
/*
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 718,723 ****
--- 728,816 ----
return myself;
}
+ /*
+ * Collect opclass information for validation.
+ */
+ static void
+ getOpClassInfo(OpClassInfo *opclassinfo, Oid opclassoid)
+ {
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid;
+ CatCList *catlist;
+ int i;
+
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ opclassinfo->intype = classform->opcintype;
+ opclassinfo->keytype = classform->opckeytype;
+ opclassinfo->amoid = classform->opcmethod;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+
+ opclassinfo->operators = NIL;
+ opclassinfo->procedures = NIL;
+
+ /* Find operators */
+ catlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ for (i = 0; i < catlist->n_members; i++)
+ {
+ HeapTuple oprtup = &catlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+ OpFamilyMember *opmember = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
+
+ opmember->object = oprform->amopopr;
+ opmember->number = oprform->amopstrategy;
+ opmember->lefttype = oprform->amoplefttype;
+ opmember->righttype = oprform->amoprighttype;
+ opmember->sortfamily = oprform->amopsortfamily;
+
+ opclassinfo->operators = lappend(opclassinfo->operators, opmember);
+ }
+ ReleaseCatCacheList(catlist);
+
+ /* Find support functions */
+ catlist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+ for (i = 0; i < catlist->n_members; i++)
+ {
+ HeapTuple proctup = &catlist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+ OpFamilyMember *procmember = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
+
+ procmember->object = procform->amproc;
+ procmember->number = procform->amprocnum;
+ procmember->lefttype = procform->amproclefttype;
+ procmember->righttype = procform->amprocrighttype;
+
+ opclassinfo->procedures = lappend(opclassinfo->procedures, procmember);
+ }
+ ReleaseCatCacheList(catlist);
+ }
+
+ /*
+ * Ask access method to validate given opclass.
+ */
+ Datum
+ amvalidate(PG_FUNCTION_ARGS)
+ {
+ OpClassInfo opclassinfo;
+ Oid opclassoid = PG_GETARG_OID(0);
+ IndexAmRoutine *amroutine;
+
+ getOpClassInfo(&opclassinfo, opclassoid);
+
+ amroutine = GetIndexAmRoutine(opclassinfo.amoid);
+
+ amroutine->amvalidate(&opclassinfo);
+
+ PG_RETURN_BOOL(true);
+ }
+
/*
* DefineOpFamily
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 776,782 ****
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! Form_pg_am pg_am;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
--- 869,875 ----
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! IndexAmRoutine *amroutine;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 787,802 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
/* XXX Should we make any privilege check against the AM? */
- ReleaseSysCache(tup);
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
--- 880,895 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! amroutine = GetIndexAmRoutine(amoid);
! ReleaseSysCache(tup);
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
/* XXX Should we make any privilege check against the AM? */
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
*************** assignOperTypes(OpFamilyMember *member,
*** 1099,1119 ****
* the family has been created but not yet populated with the required
* operators.)
*/
! HeapTuple amtup;
! Form_pg_am pg_am;
! amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
! if (amtup == NULL)
! elog(ERROR, "cache lookup failed for access method %u", amoid);
! pg_am = (Form_pg_am) GETSTRUCT(amtup);
! if (!pg_am->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! NameStr(pg_am->amname))));
!
! ReleaseSysCache(amtup);
}
else
{
--- 1192,1206 ----
* the family has been created but not yet populated with the required
* operators.)
*/
! IndexAmRoutine *amroutine;
! amroutine = GetIndexAmRoutine(amoid);
! if (!amroutine->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! get_am_name(amoid))));
}
else
{
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 163650c..e2f3d8f
*** 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)
*** 536,541 ****
--- 537,543 ----
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)
*** 549,557 ****
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);
--- 551,561 ----
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 1b61fd9..3fa37e2
*** a/src/backend/optimizer/path/costsize.c
--- b/src/backend/optimizer/path/costsize.c
*************** cost_index(IndexPath *path, PlannerInfo
*** 406,419 ****
* 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.
--- 406,413 ----
* 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 <unistd.h>
#include <fcntl.h>
+ #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 37fad86..9a83e10
*** a/src/backend/utils/adt/selfuncs.c
--- b/src/backend/utils/adt/selfuncs.c
*************** add_predicate_to_quals(IndexOptInfo *ind
*** 6443,6458 ****
}
! 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;
--- 6443,6453 ----
}
! 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)
*** 6741,6760 ****
*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;
--- 6736,6748 ----
*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)
*** 6794,6813 ****
*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;
--- 6782,6794 ----
*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)
*** 6860,6879 ****
*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;
--- 6841,6853 ----
*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)
*** 6926,6933 ****
*indexTotalCost = costs.indexTotalCost;
*indexSelectivity = costs.indexSelectivity;
*indexCorrelation = costs.indexCorrelation;
-
- PG_RETURN_VOID();
}
--- 6900,6905 ----
*************** gincost_scalararrayopexpr(PlannerInfo *r
*** 7222,7237 ****
/*
* 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;
--- 7194,7204 ----
/*
* 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)
*** 7382,7388 ****
*indexStartupCost = 0;
*indexTotalCost = 0;
*indexSelectivity = 0;
! PG_RETURN_VOID();
}
if (counts.haveFullScan || indexQuals == NIL)
--- 7349,7355 ----
*indexStartupCost = 0;
*indexTotalCost = 0;
*indexSelectivity = 0;
! return;
}
if (counts.haveFullScan || indexQuals == NIL)
*************** gincostestimate(PG_FUNCTION_ARGS)
*** 7504,7526 ****
*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;
--- 7471,7486 ----
*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)
*** 7573,7578 ****
*indexTotalCost += (numTuples * *indexSelectivity) * (cpu_index_tuple_cost + qual_op_cost);
/* XXX what about pages_per_range? */
-
- PG_RETURN_VOID();
}
--- 7533,7536 ----
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
new file mode 100644
index 9c3d096..0e9d5a2
*** a/src/backend/utils/cache/relcache.c
--- b/src/backend/utils/cache/relcache.c
*************** 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
--- 445,451 ----
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
*** 1160,1172 ****
}
/*
* 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;
--- 1160,1217 ----
}
/*
+ * Get IndexAmRoutine structure from access method oid.
+ */
+ IndexAmRoutine *
+ GetIndexAmRoutine(Oid amoid)
+ {
+ IndexAmRoutine *result;
+ HeapTuple tuple;
+ regproc amhandler;
+
+ tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for access method %u",
+ amoid);
+ amhandler = ((Form_pg_am)GETSTRUCT(tuple))->amhandler;
+
+ if (!RegProcedureIsValid(amhandler))
+ elog(ERROR, "invalid %u regproc", amhandler);
+
+ result = (IndexAmRoutine *)DatumGetPointer(OidFunctionCall0(amhandler));
+
+ if (result == NULL || !IsA(result, IndexAmRoutine))
+ elog(ERROR, "index access method handler function %u did not return an IndexAmRoutine struct",
+ amhandler);
+
+ ReleaseSysCache(tuple);
+
+ return result;
+ }
+
+ /*
+ * Initialize IndexAmRoutine for relation.
+ */
+ void
+ InitIndexAmRoutine(Relation relation)
+ {
+ IndexAmRoutine *result, *tmp;
+
+ result = (IndexAmRoutine *)MemoryContextAlloc(relation->rd_indexcxt,
+ sizeof(IndexAmRoutine));
+ tmp = (IndexAmRoutine *)DatumGetPointer(
+ OidFunctionCall0(relation->rd_am->amhandler));
+ memcpy(result, tmp, sizeof(IndexAmRoutine));
+ relation->amroutine = result;
+ }
+
+ /*
* Initialize index-access-method support data for an index relation
*/
void
RelationInitIndexAccessInfo(Relation relation)
{
HeapTuple tuple;
Datum indcollDatum;
Datum indclassDatum;
Datum indoptionDatum;
*************** RelationInitIndexAccessInfo(Relation rel
*** 1178,1183 ****
--- 1223,1229 ----
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
*** 1211,1217 ****
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
--- 1257,1262 ----
*************** RelationInitIndexAccessInfo(Relation rel
*** 1228,1233 ****
--- 1273,1283 ----
ALLOCSET_SMALL_MAXSIZE);
relation->rd_indexcxt = indexcxt;
+ /* Initialize index AM routine */
+ InitIndexAmRoutine(relation);
+
+ amsupport = relation->amroutine->amsupport;
+
/*
* Allocate arrays to hold data
*/
*************** load_relcache_init_file(bool shared)
*** 4743,4749 ****
Oid *opfamily;
Oid *opcintype;
RegProcedure *support;
- int nsupport;
int16 *indoption;
Oid *indcollation;
--- 4793,4798 ----
*************** load_relcache_init_file(bool shared)
*** 4771,4776 ****
--- 4820,4826 ----
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)
*** 4832,4843 ****
rel->rd_indoption = indoption;
/* 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
{
--- 4882,4894 ----
rel->rd_indoption = indoption;
+ InitIndexAmRoutine(rel);
+
/* set up zeroed fmgr-info vectors */
rel->rd_aminfo = (RelationAmInfo *)
MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
rel->rd_supportinfo = (FmgrInfo *)
! MemoryContextAllocZero(indexcxt, relform->relnatts * rel->amroutine->amsupport * sizeof(FmgrInfo));
}
else
{
*************** write_relcache_init_file(bool shared)
*** 5106,5112 ****
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
--- 5157,5163 ----
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (rel->amroutine->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h
new file mode 100644
index ...2e0257a
*** a/src/include/access/amapi.h
--- b/src/include/access/amapi.h
***************
*** 0 ****
--- 1,169 ----
+ /*-------------------------------------------------------------------------
+ *
+ * amapi.h
+ * API for access methods
+ *
+ * Copyright (c) 2015, PostgreSQL Global Development Group
+ *
+ * src/include/access/amapi.h
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef AMAPI_H
+ #define AMAPI_H
+
+ #include "access/genam.h"
+ #include "catalog/opfam_internal.h"
+ #include "nodes/relation.h"
+
+ /*
+ * Callback function signatures --- see indexam.sgml for more info.
+ */
+
+ /* "insert this tuple" function */
+ typedef bool
+ (*aminsert_function) (Relation indexRelation,
+ Datum *values,
+ bool *isnull,
+ ItemPointer heap_tid,
+ Relation heapRelation,
+ IndexUniqueCheck checkUnique);
+
+ /* "prepare for index scan" function */
+ typedef IndexScanDesc
+ (*ambeginscan_function) (Relation indexRelation,
+ int nkeys,
+ int norderbys);
+
+ /* "next valid tuple" function, or NULL */
+ typedef bool
+ (*amgettuple_function) (IndexScanDesc scan,
+ ScanDirection direction);
+
+ /* "fetch all valid tuples" function, or NULL */
+ typedef int64
+ (*amgetbitmap_function) (IndexScanDesc scan,
+ TIDBitmap *tbm);
+
+ /* "(re)start index scan" function */
+ typedef void
+ (*amrescan_function) (IndexScanDesc scan,
+ ScanKey keys,
+ int nkeys,
+ ScanKey orderbys,
+ int norderbys);
+
+ /* "end index scan" function */
+ typedef void
+ (*amendscan_function) (IndexScanDesc scan);
+
+ /* "mark current scan position" function */
+ typedef void
+ (*ammarkpos_function) (IndexScanDesc scan);
+
+ /* "restore marked scan position" function */
+ typedef void
+ (*amrestrpos_function) (IndexScanDesc scan);
+
+ /* "build new index" function */
+ typedef IndexBuildResult *
+ (*ambuild_function) (Relation heapRelation,
+ Relation indexRelation,
+ IndexInfo *indexInfo);
+
+ /* "build empty index" function */
+ typedef void
+ (*ambuildempty_function) (Relation indexRelation);
+
+ /* bulk-delete function */
+ typedef IndexBulkDeleteResult *
+ (*ambulkdelete_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+
+ /* post-VACUUM cleanup function */
+ typedef IndexBulkDeleteResult *
+ (*amvacuumcleanup_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
+
+ /* can indexscan return IndexTuples? */
+ typedef bool
+ (*amcanreturn_function) (Relation indexRelation, int attno);
+
+ /* estimate cost of an indexscan */
+ typedef void
+ (*amcostestimate_function) (PlannerInfo *root,
+ IndexPath *path,
+ double loop_count,
+ Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+
+ /* parse AM-specific parameters */
+ typedef bytea *
+ (*amoptions_function) (Datum reloptions,
+ bool validate);
+
+ /* validate oplass */
+ typedef void
+ (*amvalidate_function) (OpClassInfo *opclass);
+
+
+ struct IndexAmRoutine
+ {
+ NodeTag type;
+
+ /*
+ * Total number of strategies (operators) by which we can traverse/search
+ * this AM. Zero if AM does not have a fixed set of strategy assignments.
+ */
+ int16 amstrategies;
+ /* total number of support functions that this AM uses */
+ int16 amsupport;
+ /* does AM support order by column value? */
+ bool amcanorder;
+ /* does AM support order by operator result? */
+ bool amcanorderbyop;
+ /* does AM support backward scan? */
+ bool amcanbackward;
+ /* does AM support UNIQUE indexes? */
+ bool amcanunique;
+ /* does AM support multi-column indexes? */
+ bool amcanmulticol;
+ /* can query omit key for the first column? */
+ bool amoptionalkey;
+ /* can AM handle ScalarArrayOpExpr quals? */
+ bool amsearcharray;
+ /* can AM search for NULL/NOT NULL entries? */
+ bool amsearchnulls;
+ /* can storage type differ from column type? */
+ bool amstorage;
+ /* does AM support cluster command? */
+ bool amclusterable;
+ /* does AM handle predicate locks? */
+ bool ampredlocks;
+ /* type of data in index, or InvalidOid */
+ Oid amkeytype;
+
+ /* interface functions */
+ aminsert_function aminsert;
+ ambeginscan_function ambeginscan;
+ amgettuple_function amgettuple;
+ amgetbitmap_function amgetbitmap;
+ amrescan_function amrescan;
+ amendscan_function amendscan;
+ ammarkpos_function ammarkpos;
+ amrestrpos_function amrestrpos;
+ ambuild_function ambuild;
+ ambuildempty_function ambuildempty;
+ ambulkdelete_function ambulkdelete;
+ amvacuumcleanup_function amvacuumcleanup;
+ amcanreturn_function amcanreturn;
+ amcostestimate_function amcostestimate;
+ amoptions_function amoptions;
+ amvalidate_function amvalidate;
+ };
+
+ #endif /* AMAPI_H */
diff --git a/src/include/access/brin.h b/src/include/access/brin.h
new file mode 100644
index e72fb2d..5ae5722
*** 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,51 ----
/*
* prototypes for functions in brin.c (external entry points for BRIN)
*/
! extern Datum brinhandler(PG_FUNCTION_ARGS);
! extern void brinvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *brinbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void brinbuildempty(Relation index);
! extern bool brininsert(Relation idxRel, Datum *values, bool *nulls,
! ItemPointer heaptid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys);
! extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
! ScanKey orderbys, int norderbys);
! extern void brinendscan(IndexScanDesc scan);
! extern void brinmarkpos(IndexScanDesc scan);
! extern void brinrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *brinbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *brinvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern void brincostestimate(PlannerInfo *root, IndexPath *path,
! double loop_count, Cost *indexStartupCost,
! Cost *indexTotalCost,
! Selectivity *indexSelectivity,
! double *indexCorrelation);
! extern bytea *brinoptions(Datum reloptions, bool validate);
/*
* Storage type for BRIN's reloptions
diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h
new file mode 100644
index 6be199e..cd72544
*** a/src/include/access/brin_internal.h
--- b/src/include/access/brin_internal.h
*************** typedef struct BrinDesc
*** 71,76 ****
--- 71,77 ----
#define BRIN_PROCNUM_ADDVALUE 2
#define BRIN_PROCNUM_CONSISTENT 3
#define BRIN_PROCNUM_UNION 4
+ #define BRIN_MANDATORY_NPROCS 4
/* procedure numbers up to 10 are reserved for BRIN future expansion */
#undef BRIN_DEBUG
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 5021887..a77d43f
*** 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,601 ----
/* ginutil.c */
! extern Datum ginhandler(PG_FUNCTION_ARGS);
! extern void ginvalidate(OpClassInfo *opclass);
! extern bytea *ginoptions(Datum reloptions, bool validate);
extern void initGinState(GinState *state, Relation index);
extern Buffer GinNewBuffer(Relation index);
extern void GinInitBuffer(Buffer b, uint32 f);
*************** 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,
--- 616,627 ----
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);
--- 872,899 ----
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 1a77982..35fb34a
*** 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
*** 426,434 ****
} 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);
--- 427,439 ----
} GiSTOptions;
/* gist.c */
! extern Datum gisthandler(PG_FUNCTION_ARGS);
! extern void gistvalidate(OpClassInfo *opclass);
! extern void gistbuildempty(Relation index);
! extern bool gistinsert(Relation r, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern bool gistcanreturn(Relation index, int attno);
extern MemoryContext createTempGistContext(void);
extern GISTSTATE *initGISTstate(Relation index);
extern void freeGISTstate(GISTSTATE *giststate);
*************** extern XLogRecPtr gistXLogSplit(RelFileN
*** 474,481 ****
Buffer leftchild, bool markfollowright);
/* gistget.c */
! extern Datum gistgettuple(PG_FUNCTION_ARGS);
! extern Datum gistgetbitmap(PG_FUNCTION_ARGS);
/* gistutil.c */
--- 479,486 ----
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
*** 485,491 ****
#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);
--- 490,496 ----
#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 *
*** 534,541 ****
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,
--- 539,550 ----
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
*** 544,550 ****
int attno);
/* gistbuild.c */
! extern Datum gistbuild(PG_FUNCTION_ARGS);
extern void gistValidateBufferingOption(char *value);
/* gistbuildbuffers.c */
--- 553,560 ----
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..9595c6b
*** 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,271 ----
/* public routines */
! extern Datum hashhandler(PG_FUNCTION_ARGS);
! extern void hashvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *hashbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void hashbuildempty(Relation index);
! extern bool hashinsert(Relation rel, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc hashbeginscan(Relation rel, int nkeys, int norderbys);
! extern bool hashgettuple(IndexScanDesc scan, ScanDirection dir);
! extern int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void hashrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
! ScanKey orderbys, int norderbys);
! extern void hashendscan(IndexScanDesc scan);
! extern void hashmarkpos(IndexScanDesc scan);
! extern void hashrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *hashbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *hashvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern bytea *hashoptions(Datum reloptions, bool validate);
/*
* Datatype-specific hash functions in hashfunc.c.
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
new file mode 100644
index 9e48efd..4fab0a3
*** 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,683 ----
/*
* prototypes for functions in nbtree.c (external entry points for btree)
*/
! extern Datum bthandler(PG_FUNCTION_ARGS);
! extern void btvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *btbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void btbuildempty(Relation index);
! extern bool btinsert(Relation rel, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc btbeginscan(Relation indexRelation,
! int nkeys, int norderbys);
! extern bool btgettuple(IndexScanDesc scan, ScanDirection dir);
! extern int64 btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void btrescan(IndexScanDesc scan, ScanKey keys, int nkeys,
! ScanKey orderbys, int norderbys);
! extern void btendscan(IndexScanDesc scan);
! extern void btmarkpos(IndexScanDesc scan);
! extern void btrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *btbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *btvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern bool btcanreturn(Relation index, int attno);
! extern bytea *btoptions(Datum reloptions, bool validate);
/*
* prototypes for functions in nbtinsert.c
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
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..ba2c1c1
*** 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,212 ----
} spgLeafConsistentOut;
+ /* spgutils.c */
+ extern Datum spghandler(PG_FUNCTION_ARGS);
+ extern void spgvalidate(OpClassInfo *opclass);
+
/* 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/opfam_internal.h b/src/include/catalog/opfam_internal.h
new file mode 100644
index 32195a7..2cbefe9
*** a/src/include/catalog/opfam_internal.h
--- b/src/include/catalog/opfam_internal.h
*************** typedef struct
*** 25,28 ****
--- 25,41 ----
Oid sortfamily; /* ordering operator's sort opfamily, or 0 */
} OpFamilyMember;
+ /*
+ * Opclass data for validation by access method.
+ */
+ typedef struct
+ {
+ Oid amoid; /* access method OID */
+ Oid intype; /* input datatype */
+ Oid keytype; /* key datatype */
+ List *procedures; /* list of OpFamilyMember */
+ List *operators; /* list of OpFamilyMember */
+ } OpClassInfo;
+
+
#endif /* OPFAM_INTERNAL_H */
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
new file mode 100644
index 8a28b8e..f19a873
*** 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,40 ----
CATALOG(pg_am,2601)
{
NameData amname; /* access method name */
! regproc amhandler; /* handler function */
} 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
--- 48,78 ----
* compiler constants for pg_am
* ----------------
*/
! #define Natts_pg_am 2
#define Anum_pg_am_amname 1
! #define Anum_pg_am_amhandler 2
/* ----------------
* initial contents of pg_am
* ----------------
*/
! DATA(insert OID = 403 ( btree bthandler ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
! DATA(insert OID = 405 ( hash hashhandler ));
DESCR("hash index access method");
#define HASH_AM_OID 405
! DATA(insert OID = 783 ( gist gisthandler ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
! DATA(insert OID = 2742 ( gin ginhandler ));
DESCR("GIN index access method");
#define GIN_AM_OID 2742
! DATA(insert OID = 4000 ( spgist spghandler ));
DESCR("SP-GiST index access method");
#define SPGIST_AM_OID 4000
! DATA(insert OID = 3580 ( brin brinhandler ));
DESCR("block range index (BRIN) access method");
#define BRIN_AM_OID 3580
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index eb55b3a..587aaac
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DESCR("convert int4 to float4");
*** 547,609 ****
DATA(insert OID = 319 ( int4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "700" _null_ _null_ _null_ _null_ _null_ ftoi4 _null_ _null_ _null_ ));
DESCR("convert float4 to int4");
- DATA(insert OID = 330 ( btgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgettuple _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 636 ( btgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgetbitmap _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 331 ( btinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btinsert _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 333 ( btbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbeginscan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 334 ( btrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btrescan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 335 ( btendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btendscan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 336 ( btmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btmarkpos _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 337 ( btrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btrestrpos _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 338 ( btbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbuild _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 328 ( btbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btbuildempty _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 332 ( btbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbulkdelete _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ btvacuumcleanup _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 276 ( btcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ btcanreturn _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 1268 ( btcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btcostestimate _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 2785 ( btoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ btoptions _null_ _null_ _null_ ));
- DESCR("btree(internal)");
-
- DATA(insert OID = 3789 ( bringetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ bringetbitmap _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3790 ( brininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brininsert _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3791 ( brinbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbeginscan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3792 ( brinrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinrescan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3793 ( brinendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinendscan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3794 ( brinmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinmarkpos _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3795 ( brinrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinrestrpos _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3796 ( brinbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbuild _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3797 ( brinbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinbuildempty _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3798 ( brinbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbulkdelete _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3799 ( brinvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ brinvacuumcleanup _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3800 ( brincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brincostestimate _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3801 ( brinoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ brinoptions _null_ _null_ _null_ ));
- DESCR("brin(internal)");
DATA(insert OID = 3952 ( brin_summarize_new_values PGNSP PGUID 12 1 0 0 0 f f f f f f v s 1 0 23 "2205" _null_ _null_ _null_ _null_ _null_ brin_summarize_new_values _null_ _null_ _null_ ));
DESCR("brin: standalone scan new table pages");
--- 547,552 ----
*************** DESCR("convert name to char(n)");
*** 694,728 ****
DATA(insert OID = 409 ( name PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 19 "1042" _null_ _null_ _null_ _null_ _null_ bpchar_name _null_ _null_ _null_ ));
DESCR("convert char(n) to name");
- DATA(insert OID = 440 ( hashgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgettuple _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 637 ( hashgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgetbitmap _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 441 ( hashinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashinsert _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 443 ( hashbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbeginscan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 444 ( hashrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashrescan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 445 ( hashendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashendscan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 446 ( hashmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashmarkpos _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 447 ( hashrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashrestrpos _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 448 ( hashbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbuild _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 327 ( hashbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashbuildempty _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 442 ( hashbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbulkdelete _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashvacuumcleanup _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 438 ( hashcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashcostestimate _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 2786 ( hashoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ hashoptions _null_ _null_ _null_ ));
- DESCR("hash(internal)");
-
DATA(insert OID = 449 ( hashint2 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "21" _null_ _null_ _null_ _null_ _null_ hashint2 _null_ _null_ _null_ ));
DESCR("hash");
DATA(insert OID = 450 ( hashint4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ hashint4 _null_ _null_ _null_ ));
--- 637,642 ----
*************** DESCR("larger of two");
*** 978,1014 ****
DATA(insert OID = 771 ( int2smaller PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2smaller _null_ _null_ _null_ ));
DESCR("smaller of two");
- DATA(insert OID = 774 ( gistgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgettuple _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 638 ( gistgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgetbitmap _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 775 ( gistinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistinsert _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 777 ( gistbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbeginscan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 778 ( gistrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistrescan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 779 ( gistendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistendscan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 780 ( gistmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistmarkpos _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 781 ( gistrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistrestrpos _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 782 ( gistbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbuild _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 326 ( gistbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistbuildempty _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 776 ( gistbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbulkdelete _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistvacuumcleanup _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 3280 ( gistcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ gistcanreturn _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 772 ( gistcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistcostestimate _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 2787 ( gistoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ gistoptions _null_ _null_ _null_ ));
- DESCR("gist(internal)");
-
DATA(insert OID = 784 ( tintervaleq PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervaleq _null_ _null_ _null_ ));
DATA(insert OID = 785 ( tintervalne PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervalne _null_ _null_ _null_ ));
DATA(insert OID = 786 ( tintervallt PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervallt _null_ _null_ _null_ ));
--- 892,897 ----
*************** DATA(insert OID = 3311 ( tsm_handler_in
*** 3740,3745 ****
--- 3623,3632 ----
DESCR("I/O");
DATA(insert OID = 3312 ( tsm_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "3310" _null_ _null_ _null_ _null_ _null_ tsm_handler_out _null_ _null_ _null_ ));
DESCR("I/O");
+ DATA(insert OID = 326 ( index_am_handler_in PGNSP PGUID 12 1 0 0 0 f f f f f f i s 1 0 325 "2275" _null_ _null_ _null_ _null_ _null_ index_am_handler_in _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 327 ( index_am_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "325" _null_ _null_ _null_ _null_ _null_ index_am_handler_out _null_ _null_ _null_ ));
+ DESCR("I/O");
/* tablesample method handlers */
DATA(insert OID = 3313 ( bernoulli PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 3310 "2281" _null_ _null_ _null_ _null_ _null_ tsm_bernoulli_handler _null_ _null_ _null_ ));
*************** DESCR("GiST support");
*** 4196,4229 ****
DATA(insert OID = 3288 ( gist_bbox_distance PGNSP PGUID 12 1 0 0 0 f f f f t f i s 4 0 701 "2281 600 23 26" _null_ _null_ _null_ _null_ _null_ gist_bbox_distance _null_ _null_ _null_ ));
DESCR("GiST support");
- /* GIN */
- DATA(insert OID = 2731 ( gingetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gingetbitmap _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2732 ( gininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gininsert _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2733 ( ginbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbeginscan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2734 ( ginrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginrescan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2735 ( ginendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginendscan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2736 ( ginmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginmarkpos _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2737 ( ginrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginrestrpos _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2738 ( ginbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbuild _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 325 ( ginbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginbuildempty _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2739 ( ginbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbulkdelete _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ ginvacuumcleanup _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2741 ( gincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gincostestimate _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2788 ( ginoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ ginoptions _null_ _null_ _null_ ));
- DESCR("gin(internal)");
-
/* GIN array support */
DATA(insert OID = 2743 ( ginarrayextract PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 2281 "2277 2281 2281" _null_ _null_ _null_ _null_ _null_ ginarrayextract _null_ _null_ _null_ ));
DESCR("GIN array support");
--- 4083,4088 ----
*************** DESCR("construct timestamp with time zon
*** 5119,5156 ****
DATA(insert OID = 3464 ( make_interval PGNSP PGUID 12 1 0 0 0 f f f f t f i s 7 0 1186 "23 23 23 23 23 23 701" _null_ _null_ "{years,months,weeks,days,hours,mins,secs}" _null_ _null_ make_interval _null_ _null_ _null_ ));
DESCR("construct interval");
- /* spgist support functions */
- DATA(insert OID = 4001 ( spggettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggettuple _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4002 ( spggetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggetbitmap _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4003 ( spginsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spginsert _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4004 ( spgbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbeginscan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4005 ( spgrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgrescan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4006 ( spgendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgendscan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4007 ( spgmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgmarkpos _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4008 ( spgrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgrestrpos _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4009 ( spgbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbuild _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4010 ( spgbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgbuildempty _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4011 ( spgbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbulkdelete _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4012 ( spgvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ spgvacuumcleanup _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4032 ( spgcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ spgcanreturn _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4013 ( spgcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgcostestimate _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4014 ( spgoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ spgoptions _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
-
/* spgist opclasses */
DATA(insert OID = 4018 ( spg_quad_config PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_quad_config _null_ _null_ _null_ ));
DESCR("SP-GiST support for quad tree over point");
--- 4978,4983 ----
*************** DESCR("get an individual replication ori
*** 5333,5338 ****
--- 5160,5184 ----
DATA(insert OID = 6014 ( pg_show_replication_origin_status PGNSP PGUID 12 1 100 0 0 f f f f f t v r 0 0 2249 "" "{26,25,3220,3220}" "{o,o,o,o}" "{local_id, external_id, remote_lsn, local_lsn}" _null_ _null_ pg_show_replication_origin_status _null_ _null_ _null_ ));
DESCR("get progress for all replication origins");
+ /* Access methods handlers */
+ DATA(insert OID = 330 ( bthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ bthandler _null_ _null_ _null_ ));
+ DESCR("btree handler");
+ DATA(insert OID = 331 ( hashhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ hashhandler _null_ _null_ _null_ ));
+ DESCR("hash handler");
+ DATA(insert OID = 332 ( gisthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ gisthandler _null_ _null_ _null_ ));
+ DESCR("gist handler");
+ DATA(insert OID = 333 ( ginhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ ginhandler _null_ _null_ _null_ ));
+ DESCR("gin handler");
+ DATA(insert OID = 334 ( spghandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ spghandler _null_ _null_ _null_ ));
+ DESCR("spgist handler");
+ DATA(insert OID = 335 ( brinhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ brinhandler _null_ _null_ _null_ ));
+ DESCR("brin handler");
+
+ DATA(insert OID = 336 ( amvalidate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 16 "26" _null_ _null_ _null_ _null_ _null_ amvalidate _null_ _null_ _null_ ));
+ DESCR("ask access method to validate opclass");
+
+
+
/*
* Symbolic values for provolatile column: these indicate whether the result
* of a function is dependent *only* on the values of its explicit arguments,
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
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/commands/defrem.h b/src/include/commands/defrem.h
new file mode 100644
index adae296..d8b9649
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
*************** extern Oid get_am_oid(const char *amname
*** 95,100 ****
--- 95,101 ----
extern char *get_am_name(Oid amOid);
extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+ extern Datum amvalidate(PG_FUNCTION_ARGS);
/* commands/tsearchcmds.c */
extern ObjectAddress DefineTSParser(List *names, List *parameters);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
new file mode 100644
index b6895f9..0ed8a96
*** 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 94bdb7c..84e4a36
*** a/src/include/nodes/nodes.h
--- b/src/include/nodes/nodes.h
*************** typedef enum NodeTag
*** 455,461 ****
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;
/*
--- 455,462 ----
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 6cf2e24..3c51bf3
*** 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
*** 548,555 ****
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 */
--- 549,555 ----
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
*** 560,571 ****
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;
--- 560,571 ----
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
*** 819,825 ****
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! typedef struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
--- 819,825 ----
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
*************** typedef struct IndexPath
*** 831,837 ****
ScanDirection indexscandir;
Cost indextotalcost;
Selectivity indexselectivity;
! } IndexPath;
/*
* BitmapHeapPath represents one or more indexscans that generate TID bitmaps
--- 831,837 ----
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 a7433d9..3745d1c
*** a/src/include/utils/selfuncs.h
--- b/src/include/utils/selfuncs.h
*************** extern double estimate_num_groups(Planne
*** 191,202 ****
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 */
--- 191,226 ----
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/alter_table.out b/src/test/regress/expected/alter_table.out
new file mode 100644
index 28422ea..c403b80
*** a/src/test/regress/expected/alter_table.out
--- b/src/test/regress/expected/alter_table.out
*************** create type alter1.ctype as (f1 int, f2
*** 2111,2118 ****
create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql
as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
create text search configuration alter1.cfg(parser = alter1.prs);
--- 2111,2121 ----
create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql
as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
+ create function alter1.hash(alter1.ctype) returns int4 language sql
+ as 'select hashint4($1.f1) # hashtext($1.f2)';
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype),
! function 1 alter1.hash(alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
create text search configuration alter1.cfg(parser = alter1.prs);
*************** alter operator class alter1.ctype_hash_o
*** 2128,2133 ****
--- 2131,2137 ----
alter operator family alter1.ctype_hash_ops using hash set schema alter2;
alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
+ alter function alter1.hash(alter1.ctype) set schema alter2;
alter type alter1.ctype set schema alter2;
alter conversion alter1.ascii_to_utf8 set schema alter2;
alter text search parser alter1.prs set schema alter2;
*************** select alter2.plus1(41);
*** 2164,2170 ****
-- clean up
drop schema alter2 cascade;
! NOTICE: drop cascades to 13 other objects
DETAIL: drop cascades to table alter2.t1
drop cascades to view alter2.v1
drop cascades to function alter2.plus1(integer)
--- 2168,2174 ----
-- clean up
drop schema alter2 cascade;
! NOTICE: drop cascades to 14 other objects
DETAIL: drop cascades to table alter2.t1
drop cascades to view alter2.v1
drop cascades to function alter2.plus1(integer)
*************** drop cascades to operator family alter2.
*** 2173,2178 ****
--- 2177,2183 ----
drop cascades to type alter2.ctype
drop cascades to function alter2.same(alter2.ctype,alter2.ctype)
drop cascades to operator alter2.=(alter2.ctype,alter2.ctype)
+ drop cascades to function alter2.hash(alter2.ctype)
drop cascades to conversion ascii_to_utf8
drop cascades to text search parser prs
drop cascades to text search configuration cfg
diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out
new file mode 100644
index d85bc83..d1a322d
*** a/src/test/regress/expected/oidjoins.out
--- b/src/test/regress/expected/oidjoins.out
*************** WHERE aggmtranstype != 0 AND
*** 73,206 ****
------+---------------
(0 rows)
- SELECT ctid, amkeytype
- FROM pg_catalog.pg_am fk
- WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
- ctid | amkeytype
- ------+-----------
- (0 rows)
-
- SELECT ctid, aminsert
- FROM pg_catalog.pg_am fk
- WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
- ctid | aminsert
- ------+----------
- (0 rows)
-
- SELECT ctid, ambeginscan
- FROM pg_catalog.pg_am fk
- WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
- ctid | ambeginscan
- ------+-------------
- (0 rows)
-
- SELECT ctid, amgettuple
- FROM pg_catalog.pg_am fk
- WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- ctid | amgettuple
- ------+------------
- (0 rows)
-
- SELECT ctid, amgetbitmap
- FROM pg_catalog.pg_am fk
- WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
- ctid | amgetbitmap
- ------+-------------
- (0 rows)
-
- SELECT ctid, amrescan
- FROM pg_catalog.pg_am fk
- WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
- ctid | amrescan
- ------+----------
- (0 rows)
-
- SELECT ctid, amendscan
- FROM pg_catalog.pg_am fk
- WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
- ctid | amendscan
- ------+-----------
- (0 rows)
-
- SELECT ctid, ammarkpos
- FROM pg_catalog.pg_am fk
- WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
- ctid | ammarkpos
- ------+-----------
- (0 rows)
-
- SELECT ctid, amrestrpos
- FROM pg_catalog.pg_am fk
- WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
- ctid | amrestrpos
- ------+------------
- (0 rows)
-
- SELECT ctid, ambuild
- FROM pg_catalog.pg_am fk
- WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
- ctid | ambuild
- ------+---------
- (0 rows)
-
- SELECT ctid, ambuildempty
- FROM pg_catalog.pg_am fk
- WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
- ctid | ambuildempty
- ------+--------------
- (0 rows)
-
- SELECT ctid, ambulkdelete
- FROM pg_catalog.pg_am fk
- WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
- ctid | ambulkdelete
- ------+--------------
- (0 rows)
-
- SELECT ctid, amvacuumcleanup
- FROM pg_catalog.pg_am fk
- WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
- ctid | amvacuumcleanup
- ------+-----------------
- (0 rows)
-
- SELECT ctid, amcanreturn
- FROM pg_catalog.pg_am fk
- WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
- ctid | amcanreturn
- ------+-------------
- (0 rows)
-
- SELECT ctid, amcostestimate
- FROM pg_catalog.pg_am fk
- WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
- ctid | amcostestimate
- ------+----------------
- (0 rows)
-
- SELECT ctid, amoptions
- FROM pg_catalog.pg_am fk
- WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
- ctid | amoptions
- ------+-----------
- (0 rows)
-
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 73,78 ----
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
new file mode 100644
index df29fe5..708d84c
*** a/src/test/regress/expected/opr_sanity.out
--- b/src/test/regress/expected/opr_sanity.out
*************** WHERE p1.oid != p2.oid AND
*** 1479,1484 ****
--- 1479,1490 ----
-----+-----
(0 rows)
+ -- Ask access methods to validate opclasses
+ SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid);
+ oid
+ -----
+ (0 rows)
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
SELECT p1.amopfamily, p1.amopstrategy
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 1524,1572 ****
------------+--------------
(0 rows)
- -- check for ordering operators not supported by parent AM
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
- amopfamily | amopopr | oid | amname
- ------------+---------+-----+--------
- (0 rows)
-
- -- Cross-check amopstrategy index against parent AM
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
- amopfamily | amopopr | oid | amname
- ------------+---------+-----+--------
- (0 rows)
-
- -- Detect missing pg_amop entries: should have as many strategy operators
- -- as AM expects for each datatype combination supported by the opfamily.
- -- We can't check this for AMs with variable strategy sets.
- SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
- amname | amoplefttype | amoprighttype
- --------+--------------+---------------
- (0 rows)
-
- -- Currently, none of the AMs with fixed strategy sets support ordering ops.
- SELECT p1.amname, p2.amopfamily, p2.amopstrategy
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
- amname | amopfamily | amopstrategy
- --------+------------+--------------
- (0 rows)
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
--- 1530,1535 ----
*************** WHERE p1.amprocfamily = 0 OR p1.amprocle
*** 1849,1863 ****
--------------+-----------
(0 rows)
- -- Cross-check amprocnum index against parent AM
- SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
- FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
- WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
- amprocfamily | amprocnum | oid | amname
- --------------+-----------+-----+--------
- (0 rows)
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
SELECT * FROM (
--- 1812,1817 ----
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
new file mode 100644
index 3ef55d9..0c784e1
*** a/src/test/regress/sql/alter_table.sql
--- b/src/test/regress/sql/alter_table.sql
*************** as 'select $1.f1 is not distinct from $2
*** 1448,1455 ****
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
--- 1448,1459 ----
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
+ create function alter1.hash(alter1.ctype) returns int4 language sql
+ as 'select hashint4($1.f1) # hashtext($1.f2)';
+
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype),
! function 1 alter1.hash(alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
*************** alter operator class alter1.ctype_hash_o
*** 1469,1474 ****
--- 1473,1479 ----
alter operator family alter1.ctype_hash_ops using hash set schema alter2;
alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
+ alter function alter1.hash(alter1.ctype) set schema alter2;
alter type alter1.ctype set schema alter2;
alter conversion alter1.ascii_to_utf8 set schema alter2;
alter text search parser alter1.prs set schema alter2;
diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql
new file mode 100644
index 2fa628d..ca419fd
*** a/src/test/regress/sql/oidjoins.sql
--- b/src/test/regress/sql/oidjoins.sql
*************** SELECT ctid, aggmtranstype
*** 37,106 ****
FROM pg_catalog.pg_aggregate fk
WHERE aggmtranstype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
- SELECT ctid, amkeytype
- FROM pg_catalog.pg_am fk
- WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
- SELECT ctid, aminsert
- FROM pg_catalog.pg_am fk
- WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
- SELECT ctid, ambeginscan
- FROM pg_catalog.pg_am fk
- WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
- SELECT ctid, amgettuple
- FROM pg_catalog.pg_am fk
- WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- SELECT ctid, amgetbitmap
- FROM pg_catalog.pg_am fk
- WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
- SELECT ctid, amrescan
- FROM pg_catalog.pg_am fk
- WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
- SELECT ctid, amendscan
- FROM pg_catalog.pg_am fk
- WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
- SELECT ctid, ammarkpos
- FROM pg_catalog.pg_am fk
- WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
- SELECT ctid, amrestrpos
- FROM pg_catalog.pg_am fk
- WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
- SELECT ctid, ambuild
- FROM pg_catalog.pg_am fk
- WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
- SELECT ctid, ambuildempty
- FROM pg_catalog.pg_am fk
- WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
- SELECT ctid, ambulkdelete
- FROM pg_catalog.pg_am fk
- WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
- SELECT ctid, amvacuumcleanup
- FROM pg_catalog.pg_am fk
- WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
- SELECT ctid, amcanreturn
- FROM pg_catalog.pg_am fk
- WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
- SELECT ctid, amcostestimate
- FROM pg_catalog.pg_am fk
- WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
- SELECT ctid, amoptions
- FROM pg_catalog.pg_am fk
- WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 37,42 ----
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
new file mode 100644
index c9bdd77..0e0506e
*** a/src/test/regress/sql/opr_sanity.sql
--- b/src/test/regress/sql/opr_sanity.sql
*************** WHERE p1.oid != p2.oid AND
*** 960,965 ****
--- 960,969 ----
p1.opcmethod = p2.opcmethod AND p1.opcintype = p2.opcintype AND
p1.opcdefault AND p2.opcdefault;
+ -- Ask access methods to validate opclasses
+
+ SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid);
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 995,1035 ****
(SELECT 1 from pg_opfamily op WHERE op.oid = p1.amopsortfamily
AND op.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree'));
- -- check for ordering operators not supported by parent AM
-
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
-
- -- Cross-check amopstrategy index against parent AM
-
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
-
- -- Detect missing pg_amop entries: should have as many strategy operators
- -- as AM expects for each datatype combination supported by the opfamily.
- -- We can't check this for AMs with variable strategy sets.
-
- SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
-
- -- Currently, none of the AMs with fixed strategy sets support ordering ops.
-
- SELECT p1.amname, p2.amopfamily, p2.amopstrategy
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
--- 999,1004 ----
*************** FROM pg_amproc as p1
*** 1176,1188 ****
WHERE p1.amprocfamily = 0 OR p1.amproclefttype = 0 OR p1.amprocrighttype = 0
OR p1.amprocnum < 1 OR p1.amproc = 0;
- -- Cross-check amprocnum index against parent AM
-
- SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
- FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
- WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
--- 1145,1150 ----
On Fri, Oct 2, 2015 at 8:14 PM, Alexander Korotkov <
a.korotkov@postgrespro.ru> wrote:
I agree about staying with one SQL-visible function.
Other changes:
* Documentation reflects interface changes.
* IndexAmRoutine moved from CacheMemoryContext to indexcxt.
* Various minor formatting improvements.
* Error messages are corrected.
Few assorted comments:
1.
+ * 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);
I have noticed that currently, the above kind of error is reported slightly
differently as in below code:
if (!RegProcedureIsValid(procOid)) \
elog(ERROR, "invalid %s regproc", CppAsString
(pname)); \
If you feel it is better to do the way as it is in current code, then you
can change accordingly.
2.
<para>
Access methods that always return entries in the natural ordering
of their data (such
as btree) should set
! <structname>pg_am</>.<structfield>amcanorder</> to true.
Currently, such
access methods must use btree-compatible strategy
numbers for their equality and ordering operators.
</para>
--- 545,551 ----
<para>
Access methods that always return entries in the natural
ordering
of their data (such as btree) should set
! <structfield>amcanorder</> to true.
Currently, such access methods must use btree-compatible strategy
numbers for their equality and
ordering operators.
Isn't it better to use structure while referencing the field of it?
3.
! Handler function must be written in a compiled language such as C,
using
! the version-1 interface.
Here, it is not completely clear, what do you refer to as version-1
interface.
4.
xindex.sgml
<title>Index Methods and Operator Classes</title>
..
It is possible to add a
new index method by defining the required interface routines and
then creating a row in <classname>pg_am</classname> — but that is
beyond the scope of this chapter (see <xref linkend="indexam">).
</para>
I think changing above to indicate something about handler function
could be useful.
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com
On 2015-10-03 08:27, Amit Kapila wrote:
On Fri, Oct 2, 2015 at 8:14 PM, Alexander Korotkov
<a.korotkov@postgrespro.ru <mailto:a.korotkov@postgrespro.ru>> wrote:I agree about staying with one SQL-visible function.
Okay, this does not necessarily mean there should be only one validation
function in the C struct though. I wonder if it would be more future
proof to name the C interface as something else than the current generic
amvalidate. Especially considering that it basically only does opclass
validation at the moment (It's IMHO saner in terms of API evolution to
expand the struct with more validator functions in the future compared
to adding arguments to the existing function).
Few assorted comments:
1. + * Get IndexAmRoutine structure from access method oid. + */ + IndexAmRoutine * + GetIndexAmRoutine(Oid amoid) ... + if (!RegProcedureIsValid (amhandler)) + elog(ERROR, "invalid %u regproc", amhandler);I have noticed that currently, the above kind of error is reported slightly
differently as in below code:
if (!RegProcedureIsValid(procOid)) \
elog(ERROR, "invalid %s regproc", CppAsString
(pname)); \If you feel it is better to do the way as it is in current code, then you
can change accordingly.
It's completely different use-case from existing code. And tbh I think
it should have completely different and more informative error message
something in the style of "index access method %s does not have a
handler" (see for example GetFdwRoutineByServerId or
transformRangeTableSample how this is handled for similar cases currently).
This however brings another comment - I think it would be better if the
GetIndexAmRoutine would be split into two interfaces. The
GetIndexAmRoutine itself would accept the amhandler Oid and should just
do the OidFunctionCall and then check the result is not NULL and
possibly that it is an IndexAmRoutine node. And then all the
(IndexAmRoutine*)DatumGetPointer(!OidFunctionCall0(accessMethodForm->amhandler));
calls in the code should be replaced with calls to the GetIndexAmRoutine
instead.
The other routine (let's call it GetIndexAmRoutineByAmId for example)
would get IndexAmRoutine from amoid by looking up catalog, doing that
validation of amhandler Oid/regproc and calling the GetIndexAmRoutine.
3.
! Handler function must be written in a compiled language such as C,
using
! the version-1 interface.Here, it is not completely clear, what do you refer to as version-1
interface.
This seems to be copy paste from fdw docs, if we decide this should be
explained differently then it should be explained differently there as well.
4.
xindex.sgml
<title>Index Methods and Operator Classes</title>
..
It is possible to add a
new index method by defining the required interface routines and
then creating a row in <classname>pg_am</classname> — but that is
beyond the scope of this chapter (see <xref linkend="indexam">).
</para>I think changing above to indicate something about handler function
could be useful.
+1
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi,
this topic has seen a lot of activity/review. As development is ongoing
I'm moving the patch to the next CF.
Greetings,
Andres Freund
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sat, Oct 3, 2015 at 5:07 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
On 2015-10-03 08:27, Amit Kapila wrote:
On Fri, Oct 2, 2015 at 8:14 PM, Alexander Korotkov
<a.korotkov@postgrespro.ru <mailto:a.korotkov@postgrespro.ru>> wrote:I agree about staying with one SQL-visible function.
Okay, this does not necessarily mean there should be only one validation
function in the C struct though. I wonder if it would be more future proof
to name the C interface as something else than the current generic
amvalidate. Especially considering that it basically only does opclass
validation at the moment (It's IMHO saner in terms of API evolution to
expand the struct with more validator functions in the future compared to
adding arguments to the existing function).
I also agree with you that adding more arguments in future might
not be a good idea for exposed API. I don't know how much improvement
we can get if we use structure and then keep on adding more members
to it based on future need, but atleast that way it will be less prone to
breakage.
I think adding multiple validator functions is another option, but that
also doesn't sound like a good way as it can pose difficulty in
understanding the right version of API to be used.
Few assorted comments:
1. + * Get IndexAmRoutine structure from access method oid. + */ + IndexAmRoutine * + GetIndexAmRoutine(Oid amoid) ... + if (!RegProcedureIsValid (amhandler)) + elog(ERROR, "invalid %u regproc", amhandler);I have noticed that currently, the above kind of error is reported
slightly
differently as in below code:
if (!RegProcedureIsValid(procOid)) \
elog(ERROR, "invalid %s regproc", CppAsString
(pname)); \If you feel it is better to do the way as it is in current code, then you
can change accordingly.It's completely different use-case from existing code. And tbh I think it
should have completely different and more informative error message
something in the style of "index access method %s does not have a handler"
(see for example GetFdwRoutineByServerId or transformRangeTableSample how
this is handled for similar cases currently).
makes sense to me, but in that case isn't it better to use ereport
(as used in GetFdwRoutineByServerId()) rather than elog?
This however brings another comment - I think it would be better if the
GetIndexAmRoutine would be split into two interfaces. The GetIndexAmRoutine
itself would accept the amhandler Oid and should just do the
OidFunctionCall and then check the result is not NULL and possibly that it
is an IndexAmRoutine node. And then all the(IndexAmRoutine*)DatumGetPointer(!OidFunctionCall0(accessMethodForm->amhandler));
calls in the code should be replaced with calls to the GetIndexAmRoutine
instead.The other routine (let's call it GetIndexAmRoutineByAmId for example)
would get IndexAmRoutine from amoid by looking up catalog, doing that
validation of amhandler Oid/regproc and calling the GetIndexAmRoutine.
+1, I think that will make this API's design closer to what we have
for corresponding FDW API.
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com
On Sun, Oct 4, 2015 at 4:27 PM, Amit Kapila <amit.kapila16@gmail.com> wrote:
On Sat, Oct 3, 2015 at 5:07 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
On 2015-10-03 08:27, Amit Kapila wrote:
On Fri, Oct 2, 2015 at 8:14 PM, Alexander Korotkov
<a.korotkov@postgrespro.ru <mailto:a.korotkov@postgrespro.ru>> wrote:I agree about staying with one SQL-visible function.
Okay, this does not necessarily mean there should be only one validation
function in the C struct though. I wonder if it would be more future proof
to name the C interface as something else than the current generic
amvalidate. Especially considering that it basically only does opclass
validation at the moment (It's IMHO saner in terms of API evolution to
expand the struct with more validator functions in the future compared to
adding arguments to the existing function).I also agree with you that adding more arguments in future might
not be a good idea for exposed API. I don't know how much improvement
we can get if we use structure and then keep on adding more members
to it based on future need, but atleast that way it will be less prone to
breakage.I think adding multiple validator functions is another option, but that
also doesn't sound like a good way as it can pose difficulty in
understanding the right version of API to be used.
I think the major priority is to keep compatibility. For now, user can
easily define invalid opclass and he will just get the error runtime. Thus,
the opclass validation looks like improvement which is not strictly needed.
We can add new validator functions in the future but make them not
required. Thus, old access method wouldn't loose compatibility from this.
Few assorted comments:
1. + * Get IndexAmRoutine structure from access method oid. + */ + IndexAmRoutine * + GetIndexAmRoutine(Oid amoid) ... + if (!RegProcedureIsValid (amhandler)) + elog(ERROR, "invalid %u regproc", amhandler);I have noticed that currently, the above kind of error is reported
slightly
differently as in below code:
if (!RegProcedureIsValid(procOid)) \
elog(ERROR, "invalid %s regproc", CppAsString
(pname)); \If you feel it is better to do the way as it is in current code, then you
can change accordingly.It's completely different use-case from existing code. And tbh I think it
should have completely different and more informative error message
something in the style of "index access method %s does not have a handler"
(see for example GetFdwRoutineByServerId or transformRangeTableSample how
this is handled for similar cases currently).makes sense to me, but in that case isn't it better to use ereport
(as used in GetFdwRoutineByServerId()) rather than elog?
Changed to ereport.
This however brings another comment - I think it would be better if the
GetIndexAmRoutine would be split into two interfaces. The GetIndexAmRoutine
itself would accept the amhandler Oid and should just do the
OidFunctionCall and then check the result is not NULL and possibly that it
is an IndexAmRoutine node. And then all the(IndexAmRoutine*)DatumGetPointer(!OidFunctionCall0(accessMethodForm->amhandler));
calls in the code should be replaced with calls to the GetIndexAmRoutine
instead.The other routine (let's call it GetIndexAmRoutineByAmId for example)
would get IndexAmRoutine from amoid by looking up catalog, doing that
validation of amhandler Oid/regproc and calling the GetIndexAmRoutine.+1, I think that will make this API's design closer to what we have
for corresponding FDW API.
Good, I've changed interface.
2.
<para>
Access methods that always return entries in the natural ordering
of their data (such
as btree) should set
! <structname>pg_am</>.<structfield>amcanorder</> to true.
Currently, such
access methods must use btree-compatible strategy
numbers for their equality and ordering operators.</para> --- 545,551 ---- <para> Access methods that always return entries in the natural ordering of their data (such as btree) should set ! <structfield>amcanorder</> to true.Currently, such access methods must use btree-compatible strategy
numbers for their equality and
ordering operators.Isn't it better to use structure while referencing the field of it?
Done.
3.
! Handler function must be written in a compiled language such as C,
using
! the version-1 interface.
Here, it is not completely clear, what do you refer to as version-1
interface.
As, Peter commented upthread it is the same in FDW and we should change
both places if needed.
It refers to version 1 calling convention for C-function.
http://www.postgresql.org/docs/devel/static/xfunc-c.html#AEN57330
However, I'm not sure that it can't be version 0 calling convention. It
probably could work, but nobody use it.
4.
xindex.sgml
<title>Index Methods and Operator Classes</title>
..
It is possible to add a
new index method by defining the required interface routines and
then creating a row in <classname>pg_am</classname> — but that is
beyond the scope of this chapter (see <xref linkend="indexam">).
</para>
I think changing above to indicate something about handler function
could be useful.
Done.
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Attachments:
aminterface-8.patchapplication/octet-stream; name=aminterface-8.patchDownload
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
new file mode 100644
index 97ef618..48f208a
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 549,762 ****
</row>
<row>
! <entry><structfield>amstrategies</structfield></entry>
! <entry><type>int2</type></entry>
! <entry></entry>
! <entry>Number of operator strategies for this access method,
! or zero if access method does not have a fixed set of operator
! strategies</entry>
! </row>
!
! <row>
! <entry><structfield>amsupport</structfield></entry>
! <entry><type>int2</type></entry>
! <entry></entry>
! <entry>Number of support routines for this access method</entry>
! </row>
!
! <row>
! <entry><structfield>amcanorder</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support ordered scans sorted by the
! indexed column's value?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanorderbyop</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support ordered scans sorted by the result
! of an operator on the indexed column?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanbackward</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support backward scanning?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanunique</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support unique indexes?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanmulticol</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support multicolumn indexes?</entry>
! </row>
!
! <row>
! <entry><structfield>amoptionalkey</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support a scan without any constraint
! for the first index column?</entry>
! </row>
!
! <row>
! <entry><structfield>amsearcharray</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support <literal>ScalarArrayOpExpr</> searches?</entry>
! </row>
!
! <row>
! <entry><structfield>amsearchnulls</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support <literal>IS NULL</>/<literal>NOT NULL</> searches?</entry>
! </row>
!
! <row>
! <entry><structfield>amstorage</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Can index storage data type differ from column data type?</entry>
! </row>
!
! <row>
! <entry><structfield>amclusterable</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Can an index of this type be clustered on?</entry>
! </row>
!
! <row>
! <entry><structfield>ampredlocks</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does an index of this type manage fine-grained predicate locks?</entry>
! </row>
!
! <row>
! <entry><structfield>amkeytype</structfield></entry>
<entry><type>oid</type></entry>
- <entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
- <entry>Type of data stored in index, or zero if not a fixed type</entry>
- </row>
-
- <row>
- <entry><structfield>aminsert</structfield></entry>
- <entry><type>regproc</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Insert this tuple</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambeginscan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Prepare for index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amgettuple</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Next valid tuple</quote> function, or zero if none</entry>
! </row>
!
! <row>
! <entry><structfield>amgetbitmap</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Fetch all valid tuples</quote> function, or zero if none</entry>
! </row>
!
! <row>
! <entry><structfield>amrescan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>(Re)start index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amendscan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Clean up after index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ammarkpos</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Mark current scan position</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amrestrpos</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Restore marked scan position</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambuild</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Build new index</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambuildempty</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Build empty index</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambulkdelete</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Bulk-delete function</entry>
! </row>
!
! <row>
! <entry><structfield>amvacuumcleanup</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Post-<command>VACUUM</command> cleanup function</entry>
! </row>
!
! <row>
! <entry><structfield>amcanreturn</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to check whether an index column supports index-only
! scans. Can be zero if index-only scans are never supported.</entry>
! </row>
!
! <row>
! <entry><structfield>amcostestimate</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to estimate cost of an index scan</entry>
! </row>
!
! <row>
! <entry><structfield>amoptions</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to parse and validate <structfield>reloptions</> for an index</entry>
</row>
-
</tbody>
</tgroup>
</table>
--- 549,562 ----
</row>
<row>
! <entry><structfield>amhandler</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>
! References a handler function that is responsible for
! supplying execution routines for the access method.
! </entry>
</row>
</tbody>
</tgroup>
</table>
diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml
new file mode 100644
index 1c09bae..3ff3651
*** a/doc/src/sgml/indexam.sgml
--- b/doc/src/sgml/indexam.sgml
***************
*** 49,61 ****
<para>
Each index access method is described by a row in the
<structname>pg_am</structname> system catalog (see
! <xref linkend="catalog-pg-am">). The principal contents of a
! <structname>pg_am</structname> row are references to
! <link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>
! entries that identify the index access
! functions supplied by the access method. The APIs for these functions
! are defined later in this chapter. In addition, the
! <structname>pg_am</structname> row specifies a few fixed properties of
the access method, such as whether it can support multicolumn indexes.
There is not currently any special support
for creating or deleting <structname>pg_am</structname> entries;
--- 49,63 ----
<para>
Each index access method is described by a row in the
<structname>pg_am</structname> system catalog (see
! <xref linkend="catalog-pg-am">). In the <structname>pg_am</structname> row
! the handler function is specified by the reference to
! <link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.
! Handler function must be written in a compiled language such as C, using
! the version-1 interface. The handler function simply returns a
! <structname>IndexAmRoutine</structname> struct which contains function
! pointers to callback functions that will be called by the planner, executor,
! and various maintenance commands. In addition, the
! <structname>IndexAmRoutine</structname> contains a few fixed properties of
the access method, such as whether it can support multicolumn indexes.
There is not currently any special support
for creating or deleting <structname>pg_am</structname> entries;
***************
*** 96,126 ****
</para>
<para>
! Some of the flag columns of <structname>pg_am</structname> have nonobvious
! implications. The requirements of <structfield>amcanunique</structfield>
! are discussed in <xref linkend="index-unique-checks">.
! The <structfield>amcanmulticol</structfield> flag asserts that the
! access method supports multicolumn indexes, while
! <structfield>amoptionalkey</structfield> asserts that it allows scans
where no indexable restriction clause is given for the first index column.
! When <structfield>amcanmulticol</structfield> is false,
! <structfield>amoptionalkey</structfield> essentially says whether the
access method supports full-index scans without any restriction clause.
Access methods that support multiple index columns <emphasis>must</>
support scans that omit restrictions on any or all of the columns after
the first; however they are permitted to require some restriction to
appear for the first index column, and this is signaled by setting
! <structfield>amoptionalkey</structfield> false.
! One reason that an index AM might set
! <structfield>amoptionalkey</structfield> false is if it doesn't index
! null values. Since most indexable operators are
strict and hence cannot return true for null inputs,
it is at first sight attractive to not store index entries for null values:
they could never be returned by an index scan anyway. However, this
argument fails when an index scan has no restriction clause for a given
index column. In practice this means that
! indexes that have <structfield>amoptionalkey</structfield> true must
! index nulls, since the planner might decide to use such an index
with no scan keys at all. A related restriction is that an index
access method that supports multiple index columns <emphasis>must</>
support indexing null values in columns after the first, because the planner
--- 98,133 ----
</para>
<para>
! Some of the flag fields of <structname>IndexAmRoutine</structname> have nonobvious
! implications. The requirements of
! <structname>IndexAmRoutine</structname>.<structfield>amcanunique</structfield>
! are discussed in <xref linkend="index-unique-checks">. The
! <structname>IndexAmRoutine</structname>.<structfield>amcanmulticol</structfield>
! flag asserts that the access method supports multicolumn indexes, while
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! asserts that it allows scans
where no indexable restriction clause is given for the first index column.
! When <structname>IndexAmRoutine</structname>.<structfield>amcanmulticol</structfield>
! is false,
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! essentially says whether the
access method supports full-index scans without any restriction clause.
Access methods that support multiple index columns <emphasis>must</>
support scans that omit restrictions on any or all of the columns after
the first; however they are permitted to require some restriction to
appear for the first index column, and this is signaled by setting
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! false. One reason that an index AM might set
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! false is if it doesn't index null values. Since most indexable operators are
strict and hence cannot return true for null inputs,
it is at first sight attractive to not store index entries for null values:
they could never be returned by an index scan anyway. However, this
argument fails when an index scan has no restriction clause for a given
index column. In practice this means that
! indexes that have
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! true must index nulls, since the planner might decide to use such an index
with no scan keys at all. A related restriction is that an index
access method that supports multiple index columns <emphasis>must</>
support indexing null values in columns after the first, because the planner
***************
*** 131,139 ****
index omits rows where <literal>b</> is null.
It is, however, OK to omit rows where the first indexed column is null.
An index access method that does index nulls may also set
! <structfield>amsearchnulls</structfield>, indicating that it supports
! <literal>IS NULL</> and <literal>IS NOT NULL</> clauses as search
! conditions.
</para>
</sect1>
--- 138,146 ----
index omits rows where <literal>b</> is null.
It is, however, OK to omit rows where the first indexed column is null.
An index access method that does index nulls may also set
! <structname>IndexAmRoutine</structname>.<structfield>amsearchnulls</structfield>,
! indicating that it supports <literal>IS NULL</> and <literal>IS NOT NULL</>
! clauses as search conditions.
</para>
</sect1>
***************
*** 143,149 ****
<para>
The index construction and maintenance functions that an index access
! method must provide are:
</para>
<para>
--- 150,156 ----
<para>
The index construction and maintenance functions that an index access
! method must provide in <structname>IndexAmRoutine</structname> are:
</para>
<para>
*************** aminsert (Relation indexRelation,
*** 188,194 ****
<literal>isnull</> arrays give the key values to be indexed, and
<literal>heap_tid</> is the TID to be indexed.
If the access method supports unique indexes (its
! <structname>pg_am</>.<structfield>amcanunique</> flag is true) then
<literal>checkUnique</> indicates the type of uniqueness check to
perform. This varies depending on whether the unique constraint is
deferrable; see <xref linkend="index-unique-checks"> for details.
--- 195,201 ----
<literal>isnull</> arrays give the key values to be indexed, and
<literal>heap_tid</> is the TID to be indexed.
If the access method supports unique indexes (its
! <structfield>amcanunique</> flag is true) then
<literal>checkUnique</> indicates the type of uniqueness check to
perform. This varies depending on whether the unique constraint is
deferrable; see <xref linkend="index-unique-checks"> for details.
*************** amcanreturn (Relation indexRelation, int
*** 281,288 ****
the form of an <structname>IndexTuple</structname>. The attribute number
is 1-based, i.e. the first columns attno is 1. Returns TRUE if supported,
else FALSE. If the access method does not support index-only scans at all,
! the <structfield>amcanreturn</> field in its <structname>pg_am</> row can
! be set to zero.
</para>
<para>
--- 288,295 ----
the form of an <structname>IndexTuple</structname>. The attribute number
is 1-based, i.e. the first columns attno is 1. Returns TRUE if supported,
else FALSE. If the access method does not support index-only scans at all,
! the <structfield>amcanreturn</> field in its <structname>IndexAmRoutine</>
! struct can be set to NULL.
</para>
<para>
*************** amgettuple (IndexScanDesc scan,
*** 414,421 ****
<para>
The <function>amgettuple</> function need only be provided if the access
method supports <quote>plain</> index scans. If it doesn't, the
! <structfield>amgettuple</> field in its <structname>pg_am</> row must
! be set to zero.
</para>
<para>
--- 421,428 ----
<para>
The <function>amgettuple</> function need only be provided if the access
method supports <quote>plain</> index scans. If it doesn't, the
! <structfield>amgettuple</> field in its <structname>IndexAmRoutine</>
! struct must be set to NULL.
</para>
<para>
*************** amgetbitmap (IndexScanDesc scan,
*** 445,452 ****
<para>
The <function>amgetbitmap</> function need only be provided if the access
method supports <quote>bitmap</> index scans. If it doesn't, the
! <structfield>amgetbitmap</> field in its <structname>pg_am</> row must
! be set to zero.
</para>
<para>
--- 452,459 ----
<para>
The <function>amgetbitmap</> function need only be provided if the access
method supports <quote>bitmap</> index scans. If it doesn't, the
! <structfield>amgetbitmap</> field in its <structname>IndexAmRoutine</>
! struct must be set to NULL.
</para>
<para>
*************** amrestrpos (IndexScanDesc scan);
*** 477,494 ****
</para>
<para>
! By convention, the <literal>pg_proc</literal> entry for an index
! access method function should show the correct number of arguments,
! but declare them all as type <type>internal</> (since most of the arguments
! have types that are not known to SQL, and we don't want users calling
! the functions directly anyway). The return type is declared as
! <type>void</>, <type>internal</>, or <type>boolean</> as appropriate.
! The only exception is <function>amoptions</>, which should be correctly
! declared as taking <type>text[]</> and <type>bool</> and returning
! <type>bytea</>. This provision allows client code to execute
! <function>amoptions</> to test validity of options settings.
</para>
-
</sect1>
<sect1 id="index-scanning">
--- 484,496 ----
</para>
<para>
! <programlisting>
! void
! amvalidate (OpClassInfo *opclass);
! </programlisting>
! Validates given operator class by access method. The <function>amvalidate</>
! must throw an error if opclass is invalid.
</para>
</sect1>
<sect1 id="index-scanning">
*************** amrestrpos (IndexScanDesc scan);
*** 548,554 ****
<para>
Access methods that always return entries in the natural ordering
of their data (such as btree) should set
! <structname>pg_am</>.<structfield>amcanorder</> to true.
Currently, such access methods must use btree-compatible strategy
numbers for their equality and ordering operators.
</para>
--- 550,556 ----
<para>
Access methods that always return entries in the natural ordering
of their data (such as btree) should set
! <structfield>amcanorder</> to true.
Currently, such access methods must use btree-compatible strategy
numbers for their equality and ordering operators.
</para>
*************** amrestrpos (IndexScanDesc scan);
*** 556,562 ****
<listitem>
<para>
Access methods that support ordering operators should set
! <structname>pg_am</>.<structfield>amcanorderbyop</> to true.
This indicates that the index is capable of returning entries in
an order satisfying <literal>ORDER BY</> <replaceable>index_key</>
<replaceable>operator</> <replaceable>constant</>. Scan modifiers
--- 558,564 ----
<listitem>
<para>
Access methods that support ordering operators should set
! <structfield>amcanorderbyop</> to true.
This indicates that the index is capable of returning entries in
an order satisfying <literal>ORDER BY</> <replaceable>index_key</>
<replaceable>operator</> <replaceable>constant</>. Scan modifiers
*************** amrestrpos (IndexScanDesc scan);
*** 579,585 ****
methods that set <structfield>amcanorder</> to true.) After the
first call, <function>amgettuple</> must be prepared to advance the scan in
either direction from the most recently returned entry. (But if
! <structname>pg_am</>.<structfield>amcanbackward</> is false, all subsequent
calls will have the same direction as the first one.)
</para>
--- 581,587 ----
methods that set <structfield>amcanorder</> to true.) After the
first call, <function>amgettuple</> must be prepared to advance the scan in
either direction from the most recently returned entry. (But if
! <structfield>amcanbackward</> is false, all subsequent
calls will have the same direction as the first one.)
</para>
*************** amrestrpos (IndexScanDesc scan);
*** 590,597 ****
be remembered per scan; a new <function>ammarkpos</> call overrides the
previously marked position. An access method that does not support
ordered scans should still provide mark and restore functions in
! <structname>pg_am</>, but it is sufficient to have them throw errors if
! called.
</para>
<para>
--- 592,599 ----
be remembered per scan; a new <function>ammarkpos</> call overrides the
previously marked position. An access method that does not support
ordered scans should still provide mark and restore functions in
! <structname>IndexAmRoutine</>, but it is sufficient to have them throw
! errors if called.
</para>
<para>
*************** amrestrpos (IndexScanDesc scan);
*** 766,772 ****
<productname>PostgreSQL</productname> enforces SQL uniqueness constraints
using <firstterm>unique indexes</>, which are indexes that disallow
multiple entries with identical keys. An access method that supports this
! feature sets <structname>pg_am</>.<structfield>amcanunique</> true.
(At present, only b-tree supports it.)
</para>
--- 768,774 ----
<productname>PostgreSQL</productname> enforces SQL uniqueness constraints
using <firstterm>unique indexes</>, which are indexes that disallow
multiple entries with identical keys. An access method that supports this
! feature sets <structfield>amcanunique</> true.
(At present, only b-tree supports it.)
</para>
diff --git a/doc/src/sgml/xindex.sgml b/doc/src/sgml/xindex.sgml
new file mode 100644
index 4fac018..a2d3fd8
*** a/doc/src/sgml/xindex.sgml
--- b/doc/src/sgml/xindex.sgml
***************
*** 34,40 ****
regular access to tables is built into
<productname>PostgreSQL</productname>, but all index methods are
described in <classname>pg_am</classname>. It is possible to add a
! new index method by defining the required interface routines and
then creating a row in <classname>pg_am</classname> — but that is
beyond the scope of this chapter (see <xref linkend="indexam">).
</para>
--- 34,41 ----
regular access to tables is built into
<productname>PostgreSQL</productname>, but all index methods are
described in <classname>pg_am</classname>. It is possible to add a
! new index access method by defining the handler function, which returns
! C-struct with required interface routines and parameters, and
then creating a row in <classname>pg_am</classname> — but that is
beyond the scope of this chapter (see <xref linkend="indexam">).
</para>
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
new file mode 100644
index 99337b0..a029eb1
*** a/src/backend/access/brin/brin.c
--- b/src/backend/access/brin/brin.c
***************
*** 35,40 ****
--- 35,143 ----
/*
+ * BRIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ brinhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 15;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = brininsert;
+ amroutine->ambeginscan = brinbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = bringetbitmap;
+ amroutine->amrescan = brinrescan;
+ amroutine->amendscan = brinendscan;
+ amroutine->ammarkpos = brinmarkpos;
+ amroutine->amrestrpos = brinrestrpos;
+ amroutine->ambuild = brinbuild;
+ amroutine->ambuildempty = brinbuildempty;
+ amroutine->ambulkdelete = brinbulkdelete;
+ amroutine->amvacuumcleanup = brinvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = brincostestimate;
+ amroutine->amoptions = brinoptions;
+ amroutine->amvalidate = brinvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ brinvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[BRIN_MANDATORY_NPROCS];
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype ||
+ proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for BRIN: %u",
+ proc->number)));
+
+ /* BRIN opclasses could contain any number of non-mandatory procedures */
+ if (proc->number > BRIN_MANDATORY_NPROCS)
+ continue;
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u was defined more than once",
+ proc->number)));
+
+ procsPresent[proc->number - 1] = true;
+ }
+
+ /*
+ * Don't use BRIN_NPROC because some procnumbers
+ * are reserved for future use
+ */
+ for (i = 0; i < BRIN_MANDATORY_NPROCS; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN doesn't support ORDER BY operators")));
+ }
+ }
+
+ /*
* We use a BrinBuildState during initial construction of a BRIN index.
* The running state is kept in a BrinMemTuple.
*/
*************** 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;
--- 183,193 ----
* 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);
}
/*
--- 325,331 ----
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;
--- 335,343 ----
* 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);
}
/*
--- 348,354 ----
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;
--- 363,371 ----
* 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
--- 545,560 ----
* 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();
}
/*
--- 566,596 ----
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;
--- 662,670 ----
/*
* 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. */
--- 743,754 ----
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();
}
/*
--- 765,770 ----
*************** 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));
--- 776,804 ----
* 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;
--- 815,829 ----
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);
--- 836,842 ----
/* 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);
}
/*
--- 845,851 ----
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 931dceb..b52846f
*** a/src/backend/access/common/reloptions.c
--- b/src/backend/access/common/reloptions.c
*************** untransformRelOptions(Datum options)
*** 891,897 ****
* 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;
--- 891,897 ----
* 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
*** 1379,1412 ****
* 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);
}
/*
--- 1379,1393 ----
* 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 49e9185..92701b9
*** 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..51c1559
*** a/src/backend/access/gin/ginutil.c
--- b/src/backend/access/gin/ginutil.c
***************
*** 22,28 ****
--- 22,140 ----
#include "miscadmin.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
+ #include "utils/selfuncs.h"
+
+
+ /*
+ * GIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ ginhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 6;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = gininsert;
+ amroutine->ambeginscan = ginbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = gingetbitmap;
+ amroutine->amrescan = ginrescan;
+ amroutine->amendscan = ginendscan;
+ amroutine->ammarkpos = ginmarkpos;
+ amroutine->amrestrpos = ginrestrpos;
+ amroutine->ambuild = ginbuild;
+ amroutine->ambuildempty = ginbuildempty;
+ amroutine->ambulkdelete = ginbulkdelete;
+ amroutine->amvacuumcleanup = ginvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = gincostestimate;
+ amroutine->amoptions = ginoptions;
+ amroutine->amvalidate = ginvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ ginvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[GINNProcs];
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype ||
+ proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > GINNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for GIN: %u",
+ proc->number)));
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u was defined more than once",
+ proc->number)));
+
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < GINNProcs; i++)
+ {
+ if (i+1 == GIN_COMPARE_PARTIAL_PROC)
+ continue; /* optional method */
+ if (i+1 == GIN_CONSISTENT_PROC || i+1 == GIN_TRICONSISTENT_PROC)
+ continue; /* don't need to have both, see check below loop */
+
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u is required", i + 1)));
+ }
+
+ if (!procsPresent[GIN_CONSISTENT_PROC - 1]
+ && !procsPresent[GIN_TRICONSISTENT_PROC - 1])
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("at least one of consistent support (number %u) "
+ "and triconsistent support (number %u) is "
+ "is required",
+ GIN_CONSISTENT_PROC, GIN_TRICONSISTENT_PROC)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN doesn't support ORDER BY operators")));
+ }
+ }
/*
* initGinState: fill in an empty GinState struct to describe the index
*************** 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;
--- 628,636 ----
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);
--- 645,651 ----
/* 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);
}
/*
--- 654,660 ----
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 323cfb0..5b38607
*** 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, true, stats);
}
! PG_RETURN_POINTER(stats);
}
/*
--- 656,662 ----
initGinState(&ginstate, index);
ginInsertCleanup(&ginstate, true, 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 53bccf6..12224b6
*** 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 void gistfinishsplit(GISTInsertSt
*** 38,43 ****
--- 40,143 ----
GISTSTATE *giststate, List *splitinfo, bool releasebuf);
static void gistvacuumpage(Relation rel, Page page, Buffer buffer);
+ /*
+ * GiST handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ gisthandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 9;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = true;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = true;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = gistinsert;
+ amroutine->ambeginscan = gistbeginscan;
+ amroutine->amgettuple = gistgettuple;
+ amroutine->amgetbitmap = gistgetbitmap;
+ amroutine->amrescan = gistrescan;
+ amroutine->amendscan = gistendscan;
+ amroutine->ammarkpos = gistmarkpos;
+ amroutine->amrestrpos = gistrestrpos;
+ amroutine->ambuild = gistbuild;
+ amroutine->ambuildempty = gistbuildempty;
+ amroutine->ambulkdelete = gistbulkdelete;
+ amroutine->amvacuumcleanup = gistvacuumcleanup;
+ amroutine->amcanreturn = gistcanreturn;
+ amroutine->amcostestimate = gistcostestimate;
+ amroutine->amoptions = gistoptions;
+ amroutine->amvalidate = gistvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ gistvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[GISTNProcs];
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype ||
+ proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > GISTNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for GiST: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u was defined more than once",
+ proc->number)));
+
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < GISTNProcs; i++)
+ {
+ if (i+1 == GIST_DISTANCE_PROC || i+1 == GIST_FETCH_PROC)
+ continue; /* optional methods */
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily)
+ && !procsPresent[GIST_DISTANCE_PROC - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST distance support function %u is required "
+ "for ORDER BY operators", GIST_DISTANCE_PROC)));
+ }
+ }
#define ROTATEDIST(d) do { \
SplitedPageLayout *tmp=(SplitedPageLayout*)palloc(sizeof(SplitedPageLayout)); \
*************** createTempGistContext(void)
*** 70,79 ****
/*
* 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 */
--- 170,178 ----
/*
* gistbuildempty() -- build an empty gist index in the initialization fork
*/
! void
! gistbuildempty(Relation index)
{
Buffer buffer;
/* Initialize the root page */
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 89,96 ****
/* Unlock and release the buffer */
UnlockReleaseBuffer(buffer);
-
- PG_RETURN_VOID();
}
/*
--- 188,193 ----
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 99,116 ****
* 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;
--- 196,206 ----
* 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)
*** 136,142 ****
MemoryContextSwitchTo(oldCxt);
freeGISTstate(giststate);
! PG_RETURN_BOOL(false);
}
--- 226,232 ----
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 ce8e582..1adf92f
*** a/src/backend/access/gist/gistget.c
--- b/src/backend/access/gist/gistget.c
*************** getNextNearest(IndexScanDesc scan)
*** 618,628 ****
/*
* 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)
--- 618,626 ----
/*
* 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)
*** 651,657 ****
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! PG_RETURN_BOOL(getNextNearest(scan));
}
else
{
--- 649,655 ----
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! return getNextNearest(scan);
}
else
{
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 688,694 ****
so->curPageData++;
! PG_RETURN_BOOL(true);
}
/*
--- 686,692 ----
so->curPageData++;
! return true;
}
/*
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 726,732 ****
item = getNextGISTSearchItem(so);
if (!item)
! PG_RETURN_BOOL(false);
CHECK_FOR_INTERRUPTS();
--- 724,730 ----
item = getNextGISTSearchItem(so);
if (!item)
! return false;
CHECK_FOR_INTERRUPTS();
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 750,766 ****
/*
* 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);
--- 748,762 ----
/*
* 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)
*** 791,797 ****
pfree(item);
}
! PG_RETURN_INT64(ntids);
}
/*
--- 787,793 ----
pfree(item);
}
! return ntids;
}
/*
*************** gistgetbitmap(PG_FUNCTION_ARGS)
*** 799,812 ****
*
* 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);
}
--- 795,805 ----
*
* 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 a17c5bc..22f0c68
*** 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)
*** 107,121 ****
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;
--- 104,116 ----
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)
*** 314,341 ****
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;
/*
--- 309,331 ----
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)
*** 343,348 ****
* as well as the queueCxt if there is a separate context for it.
*/
freeGISTstate(so->giststate);
-
- PG_RETURN_VOID();
}
--- 333,336 ----
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 a0b0eeb..e0ce620
*** 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)
*** 276,280 ****
vacuum_delay_point();
}
! PG_RETURN_POINTER(stats);
}
--- 271,275 ----
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..a51fa7c
*** 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,150 ----
bool tupleIsAlive,
void *state);
+ /*
+ * Hash handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ hashhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 1;
+ amroutine->amsupport = 1;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = true;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = false;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = INT4OID;
+
+ amroutine->aminsert = hashinsert;
+ amroutine->ambeginscan = hashbeginscan;
+ amroutine->amgettuple = hashgettuple;
+ amroutine->amgetbitmap = hashgetbitmap;
+ amroutine->amrescan = hashrescan;
+ amroutine->amendscan = hashendscan;
+ amroutine->ammarkpos = hashmarkpos;
+ amroutine->amrestrpos = hashrestrpos;
+ amroutine->ambuild = hashbuild;
+ amroutine->ambuildempty = hashbuildempty;
+ amroutine->ambulkdelete = hashbulkdelete;
+ amroutine->amvacuumcleanup = hashvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = hashcostestimate;
+ amroutine->amoptions = hashoptions;
+ amroutine->amvalidate = hashvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ hashvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->number != HASHPROC)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for hash: %u",
+ proc->number)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+ bool leftFound = false, rightFound = false;
+ ListCell *ll;
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("hash doesn't support ORDER BY operators")));
+
+ if (opr->number < 1 || opr->number > HTMaxStrategyNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid strategy number for hash: %u",
+ opr->number)));
+
+ foreach(ll, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(ll);
+
+ if (proc->lefttype == opr->lefttype)
+ leftFound = true;
+ if (proc->lefttype == opr->righttype)
+ rightFound = true;
+ }
+
+ if (!leftFound || !rightFound)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("no hash procedure found for operator: %u",
+ opr->object)));
+ }
+ }
/*
* hashbuild() -- build a new hash index.
*/
! 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();
}
/*
--- 205,220 ----
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;
/*
--- 256,266 ----
* 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);
--- 273,279 ----
* 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;
--- 283,298 ----
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;
--- 394,409 ----
/* 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;
--- 440,455 ----
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;
--- 471,486 ----
/* 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;
--- 506,519 ----
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();
}
/*
--- 532,555 ----
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;
--- 559,568 ----
*
* 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);
}
/*
--- 732,738 ----
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);
}
--- 740,761 ----
*
* 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..ee623ae
*** 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,182 ----
/*
! * 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;
! amroutine->amvalidate = btvalidate;
!
! PG_RETURN_POINTER(amroutine);
! }
!
! void
! btvalidate(OpClassInfo *opclass)
! {
! ListCell *l;
!
! foreach(l, opclass->procedures)
! {
! OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
!
! if (proc->number != BTORDER_PROC &&
! proc->number != BTSORTSUPPORT_PROC)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("invalid support number for btree: %u",
! proc->number)));
! }
!
! foreach(l, opclass->operators)
! {
! OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
! bool found = false;
! ListCell *ll;
!
! if (OidIsValid(opr->sortfamily))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("btree doesn't support ORDER BY operators")));
!
! if (opr->number < 1 || opr->number > BTMaxStrategyNumber)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("invalid strategy number for btree: %u",
! opr->number)));
!
! foreach(ll, opclass->procedures)
! {
! OpFamilyMember *proc = (OpFamilyMember *) lfirst(ll);
!
! if (proc->number == BTORDER_PROC &&
! proc->lefttype == opr->lefttype &&
! proc->righttype == opr->righttype)
! found = true;
! }
!
! if (!found)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("no ordering procedure found for operator: %u",
! opr->object)));
! }
! }
!
! /*
! * btbuild() -- build a new btree index.
! */
! IndexBuildResult *
! btbuild(Relation heap, Relation index, IndexInfo *indexInfo)
{
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);
}
/*
--- 248,254 ----
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);
--- 283,292 ----
/*
* 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();
}
/*
--- 306,311 ----
*************** 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;
--- 314,324 ----
* 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;
--- 330,344 ----
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);
}
--- 354,360 ----
{
/* 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;
--- 404,418 ----
/* ... 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);
}
--- 424,430 ----
{
/* 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;
--- 462,476 ----
/* 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 */
--- 508,523 ----
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 */
--- 568,581 ----
/* 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). */
--- 604,617 ----
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 */
--- 634,647 ----
/* 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();
}
/*
--- 709,714 ----
*************** 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;
--- 718,727 ----
*
* 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);
}
/*
--- 740,746 ----
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
--- 748,759 ----
*
* 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);
}
/*
--- 785,791 ----
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);
}
--- 1186,1193 ----
*
* 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..09c679b
*** a/src/backend/access/spgist/spgutils.c
--- b/src/backend/access/spgist/spgutils.c
***************
*** 24,30 ****
--- 24,126 ----
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "utils/lsyscache.h"
+ #include "utils/selfuncs.h"
+
+
+ /*
+ * SP-GiST handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ spghandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 5;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = spginsert;
+ amroutine->ambeginscan = spgbeginscan;
+ amroutine->amgettuple = spggettuple;
+ amroutine->amgetbitmap = spggetbitmap;
+ amroutine->amrescan = spgrescan;
+ amroutine->amendscan = spgendscan;
+ amroutine->ammarkpos = spgmarkpos;
+ amroutine->amrestrpos = spgrestrpos;
+ amroutine->ambuild = spgbuild;
+ amroutine->ambuildempty = spgbuildempty;
+ amroutine->ambulkdelete = spgbulkdelete;
+ amroutine->amvacuumcleanup = spgvacuumcleanup;
+ amroutine->amcanreturn = spgcanreturn;
+ amroutine->amcostestimate = spgcostestimate;
+ amroutine->amoptions = spgoptions;
+ amroutine->amvalidate = spgvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ spgvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[SPGISTNProc];
+ int i;
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype ||
+ proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > SPGISTNProc)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for SP-GiST: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u was defined more than once",
+ proc->number)));
+
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < SPGISTNProc; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST doesn't support ORDER BY operators")));
+ }
+ }
/* Fill in a SpGistTypeDesc struct with info about the specified data type */
static void
*************** 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();
}
/*
--- 585,600 ----
/*
* 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..4e21304
*** a/src/backend/catalog/index.c
--- b/src/backend/catalog/index.c
***************
*** 23,28 ****
--- 23,29 ----
#include <unistd.h>
+ #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 = GetIndexAmRoutineByAmId(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..b794d59
*** 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,169 ----
accessMethodName)));
accessMethodId = HeapTupleGetOid(tuple);
accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
! amRoutine = GetIndexAmRoutine(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;
--- 318,326 ----
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);
--- 493,523 ----
}
accessMethodId = HeapTupleGetOid(tuple);
accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
+ amRoutine = GetIndexAmRoutine(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/opclasscmds.c b/src/backend/commands/opclasscmds.c
new file mode 100644
index 3375f10..4319dd7
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
***************
*** 42,47 ****
--- 42,48 ----
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
+ #include "utils/catcache.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 334,346 ****
ListCell *l;
Relation rel;
HeapTuple tup;
- Form_pg_am pg_am;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
--- 335,348 ----
ListCell *l;
Relation rel;
HeapTuple tup;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
+ IndexAmRoutine *amroutine;
+ OpClassInfo opclassinfo;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 361,373 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
! amstorage = pg_am->amstorage;
/* XXX Should we make any privilege check against the AM? */
--- 363,377 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
!
! amroutine = GetIndexAmRoutineByAmId(amoid);
!
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
! amstorage = amroutine->amstorage;
/* XXX Should we make any privilege check against the AM? */
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 582,587 ****
--- 586,597 ----
stmt->amname)));
}
+ opclassinfo.intype = typeoid;
+ opclassinfo.keytype = storageoid;
+ opclassinfo.procedures = procedures;
+ opclassinfo.operators = operators;
+ amroutine->amvalidate(&opclassinfo);
+
rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
/*
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 718,723 ****
--- 728,816 ----
return myself;
}
+ /*
+ * Collect opclass information for validation.
+ */
+ static void
+ getOpClassInfo(OpClassInfo *opclassinfo, Oid opclassoid)
+ {
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid;
+ CatCList *catlist;
+ int i;
+
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ opclassinfo->intype = classform->opcintype;
+ opclassinfo->keytype = classform->opckeytype;
+ opclassinfo->amoid = classform->opcmethod;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+
+ opclassinfo->operators = NIL;
+ opclassinfo->procedures = NIL;
+
+ /* Find operators */
+ catlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ for (i = 0; i < catlist->n_members; i++)
+ {
+ HeapTuple oprtup = &catlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+ OpFamilyMember *opmember = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
+
+ opmember->object = oprform->amopopr;
+ opmember->number = oprform->amopstrategy;
+ opmember->lefttype = oprform->amoplefttype;
+ opmember->righttype = oprform->amoprighttype;
+ opmember->sortfamily = oprform->amopsortfamily;
+
+ opclassinfo->operators = lappend(opclassinfo->operators, opmember);
+ }
+ ReleaseCatCacheList(catlist);
+
+ /* Find support functions */
+ catlist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+ for (i = 0; i < catlist->n_members; i++)
+ {
+ HeapTuple proctup = &catlist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+ OpFamilyMember *procmember = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
+
+ procmember->object = procform->amproc;
+ procmember->number = procform->amprocnum;
+ procmember->lefttype = procform->amproclefttype;
+ procmember->righttype = procform->amprocrighttype;
+
+ opclassinfo->procedures = lappend(opclassinfo->procedures, procmember);
+ }
+ ReleaseCatCacheList(catlist);
+ }
+
+ /*
+ * Ask access method to validate given opclass.
+ */
+ Datum
+ amvalidate(PG_FUNCTION_ARGS)
+ {
+ OpClassInfo opclassinfo;
+ Oid opclassoid = PG_GETARG_OID(0);
+ IndexAmRoutine *amroutine;
+
+ getOpClassInfo(&opclassinfo, opclassoid);
+
+ amroutine = GetIndexAmRoutineByAmId(opclassinfo.amoid);
+
+ amroutine->amvalidate(&opclassinfo);
+
+ PG_RETURN_BOOL(true);
+ }
+
/*
* DefineOpFamily
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 776,782 ****
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! Form_pg_am pg_am;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
--- 869,875 ----
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! IndexAmRoutine *amroutine;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 787,802 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
/* XXX Should we make any privilege check against the AM? */
- ReleaseSysCache(tup);
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
--- 880,895 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! amroutine = GetIndexAmRoutineByAmId(amoid);
! ReleaseSysCache(tup);
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
/* XXX Should we make any privilege check against the AM? */
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
*************** assignOperTypes(OpFamilyMember *member,
*** 1099,1119 ****
* the family has been created but not yet populated with the required
* operators.)
*/
! HeapTuple amtup;
! Form_pg_am pg_am;
! amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
! if (amtup == NULL)
! elog(ERROR, "cache lookup failed for access method %u", amoid);
! pg_am = (Form_pg_am) GETSTRUCT(amtup);
! if (!pg_am->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! NameStr(pg_am->amname))));
!
! ReleaseSysCache(amtup);
}
else
{
--- 1192,1206 ----
* the family has been created but not yet populated with the required
* operators.)
*/
! IndexAmRoutine *amroutine;
! amroutine = GetIndexAmRoutineByAmId(amoid);
! if (!amroutine->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! get_am_name(amoid))));
}
else
{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
new file mode 100644
index 7668c9d..36b6403
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
*************** ATExecSetRelOptions(Relation rel, List *
*** 9374,9380 ****
(void) view_reloptions(newOptions, true);
break;
case RELKIND_INDEX:
! (void) index_reloptions(rel->rd_am->amoptions, newOptions, true);
break;
default:
ereport(ERROR,
--- 9374,9380 ----
(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
*** 10965,10971 ****
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",
--- 10965,10971 ----
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 163650c..78695e0
*** 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)
*** 536,541 ****
--- 537,543 ----
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)
*** 549,557 ****
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);
--- 551,561 ----
elog(ERROR, "cache lookup failed for access method %u",
idxrelrec->relam);
amrec = (Form_pg_am) GETSTRUCT(ht_am);
+ amroutine = GetIndexAmRoutine(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 1b61fd9..3fa37e2
*** a/src/backend/optimizer/path/costsize.c
--- b/src/backend/optimizer/path/costsize.c
*************** cost_index(IndexPath *path, PlannerInfo
*** 406,419 ****
* 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.
--- 406,413 ----
* 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..06f122b
*** a/src/backend/utils/adt/ruleutils.c
--- b/src/backend/utils/adt/ruleutils.c
***************
*** 19,24 ****
--- 19,25 ----
#include <unistd.h>
#include <fcntl.h>
+ #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,1188 ----
/* Add the operator class name, if not default */
get_opclass_name(indclass->values[keyno], keycoltype, &buf);
+ amroutine = GetIndexAmRoutine(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 37fad86..9a83e10
*** a/src/backend/utils/adt/selfuncs.c
--- b/src/backend/utils/adt/selfuncs.c
*************** add_predicate_to_quals(IndexOptInfo *ind
*** 6443,6458 ****
}
! 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;
--- 6443,6453 ----
}
! 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)
*** 6741,6760 ****
*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;
--- 6736,6748 ----
*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)
*** 6794,6813 ****
*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;
--- 6782,6794 ----
*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)
*** 6860,6879 ****
*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;
--- 6841,6853 ----
*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)
*** 6926,6933 ****
*indexTotalCost = costs.indexTotalCost;
*indexSelectivity = costs.indexSelectivity;
*indexCorrelation = costs.indexCorrelation;
-
- PG_RETURN_VOID();
}
--- 6900,6905 ----
*************** gincost_scalararrayopexpr(PlannerInfo *r
*** 7222,7237 ****
/*
* 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;
--- 7194,7204 ----
/*
* 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)
*** 7382,7388 ****
*indexStartupCost = 0;
*indexTotalCost = 0;
*indexSelectivity = 0;
! PG_RETURN_VOID();
}
if (counts.haveFullScan || indexQuals == NIL)
--- 7349,7355 ----
*indexStartupCost = 0;
*indexTotalCost = 0;
*indexSelectivity = 0;
! return;
}
if (counts.haveFullScan || indexQuals == NIL)
*************** gincostestimate(PG_FUNCTION_ARGS)
*** 7504,7526 ****
*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;
--- 7471,7486 ----
*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)
*** 7573,7578 ****
*indexTotalCost += (numTuples * *indexSelectivity) * (cpu_index_tuple_cost + qual_op_cost);
/* XXX what about pages_per_range? */
-
- PG_RETURN_VOID();
}
--- 7533,7536 ----
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
new file mode 100644
index 9c3d096..feed71e
*** a/src/backend/utils/cache/relcache.c
--- b/src/backend/utils/cache/relcache.c
*************** 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
--- 445,451 ----
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
*** 1160,1172 ****
}
/*
* 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;
--- 1160,1237 ----
}
/*
+ * GetIndexAmRoutine - call the specified access method handler routine
+ * to get its IndexAmRoutine struct.
+ */
+ IndexAmRoutine *
+ GetIndexAmRoutine(Oid amhandler)
+ {
+ Datum datum;
+ IndexAmRoutine *routine;
+
+ datum = OidFunctionCall0(amhandler);
+ routine = (IndexAmRoutine *) DatumGetPointer(datum);
+
+ if (routine == NULL || !IsA(routine, IndexAmRoutine))
+ elog(ERROR, "index access method handler function %u did not return an IndexAmRoutine struct",
+ amhandler);
+
+ return routine;
+ }
+
+ /*
+ * GetIndexAmRoutine - look up the handler of the access method
+ * for the given OID, and retrieve its IndexAmRoutine struct.
+ */
+ IndexAmRoutine *
+ GetIndexAmRoutineByAmId(Oid amoid)
+ {
+ HeapTuple tuple;
+ regproc amhandler;
+ Form_pg_am amform;
+
+ /* Get handler function OID for the access method */
+ tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for access method %u",
+ amoid);
+ amform = (Form_pg_am) GETSTRUCT(tuple);
+ amhandler = amform->amhandler;
+
+ /* Complain if handler OID is invalid */
+ if (!RegProcedureIsValid(amhandler))
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("index access method \"%s\" does not have a handler",
+ NameStr(amform->amname))));
+ ReleaseSysCache(tuple);
+
+ /* And finally, call the handler function. */
+ return GetIndexAmRoutine(amhandler);
+ }
+
+ /*
+ * Initialize IndexAmRoutine for relation.
+ */
+ void
+ InitIndexAmRoutine(Relation relation)
+ {
+ IndexAmRoutine *result, *tmp;
+
+ result = (IndexAmRoutine *) MemoryContextAlloc(relation->rd_indexcxt,
+ sizeof(IndexAmRoutine));
+ tmp = GetIndexAmRoutine(relation->rd_am->amhandler);
+ memcpy(result, tmp, sizeof(IndexAmRoutine));
+ relation->amroutine = result;
+ }
+
+ /*
* Initialize index-access-method support data for an index relation
*/
void
RelationInitIndexAccessInfo(Relation relation)
{
HeapTuple tuple;
Datum indcollDatum;
Datum indclassDatum;
Datum indoptionDatum;
*************** RelationInitIndexAccessInfo(Relation rel
*** 1178,1183 ****
--- 1243,1249 ----
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
*** 1211,1217 ****
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
--- 1277,1282 ----
*************** RelationInitIndexAccessInfo(Relation rel
*** 1228,1233 ****
--- 1293,1303 ----
ALLOCSET_SMALL_MAXSIZE);
relation->rd_indexcxt = indexcxt;
+ /* Initialize index AM routine */
+ InitIndexAmRoutine(relation);
+
+ amsupport = relation->amroutine->amsupport;
+
/*
* Allocate arrays to hold data
*/
*************** load_relcache_init_file(bool shared)
*** 4743,4749 ****
Oid *opfamily;
Oid *opcintype;
RegProcedure *support;
- int nsupport;
int16 *indoption;
Oid *indcollation;
--- 4813,4818 ----
*************** load_relcache_init_file(bool shared)
*** 4771,4776 ****
--- 4840,4846 ----
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)
*** 4832,4843 ****
rel->rd_indoption = indoption;
/* 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
{
--- 4902,4914 ----
rel->rd_indoption = indoption;
+ InitIndexAmRoutine(rel);
+
/* set up zeroed fmgr-info vectors */
rel->rd_aminfo = (RelationAmInfo *)
MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
rel->rd_supportinfo = (FmgrInfo *)
! MemoryContextAllocZero(indexcxt, relform->relnatts * rel->amroutine->amsupport * sizeof(FmgrInfo));
}
else
{
*************** write_relcache_init_file(bool shared)
*** 5106,5112 ****
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
--- 5177,5183 ----
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (rel->amroutine->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h
new file mode 100644
index ...2e0257a
*** a/src/include/access/amapi.h
--- b/src/include/access/amapi.h
***************
*** 0 ****
--- 1,169 ----
+ /*-------------------------------------------------------------------------
+ *
+ * amapi.h
+ * API for access methods
+ *
+ * Copyright (c) 2015, PostgreSQL Global Development Group
+ *
+ * src/include/access/amapi.h
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef AMAPI_H
+ #define AMAPI_H
+
+ #include "access/genam.h"
+ #include "catalog/opfam_internal.h"
+ #include "nodes/relation.h"
+
+ /*
+ * Callback function signatures --- see indexam.sgml for more info.
+ */
+
+ /* "insert this tuple" function */
+ typedef bool
+ (*aminsert_function) (Relation indexRelation,
+ Datum *values,
+ bool *isnull,
+ ItemPointer heap_tid,
+ Relation heapRelation,
+ IndexUniqueCheck checkUnique);
+
+ /* "prepare for index scan" function */
+ typedef IndexScanDesc
+ (*ambeginscan_function) (Relation indexRelation,
+ int nkeys,
+ int norderbys);
+
+ /* "next valid tuple" function, or NULL */
+ typedef bool
+ (*amgettuple_function) (IndexScanDesc scan,
+ ScanDirection direction);
+
+ /* "fetch all valid tuples" function, or NULL */
+ typedef int64
+ (*amgetbitmap_function) (IndexScanDesc scan,
+ TIDBitmap *tbm);
+
+ /* "(re)start index scan" function */
+ typedef void
+ (*amrescan_function) (IndexScanDesc scan,
+ ScanKey keys,
+ int nkeys,
+ ScanKey orderbys,
+ int norderbys);
+
+ /* "end index scan" function */
+ typedef void
+ (*amendscan_function) (IndexScanDesc scan);
+
+ /* "mark current scan position" function */
+ typedef void
+ (*ammarkpos_function) (IndexScanDesc scan);
+
+ /* "restore marked scan position" function */
+ typedef void
+ (*amrestrpos_function) (IndexScanDesc scan);
+
+ /* "build new index" function */
+ typedef IndexBuildResult *
+ (*ambuild_function) (Relation heapRelation,
+ Relation indexRelation,
+ IndexInfo *indexInfo);
+
+ /* "build empty index" function */
+ typedef void
+ (*ambuildempty_function) (Relation indexRelation);
+
+ /* bulk-delete function */
+ typedef IndexBulkDeleteResult *
+ (*ambulkdelete_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+
+ /* post-VACUUM cleanup function */
+ typedef IndexBulkDeleteResult *
+ (*amvacuumcleanup_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
+
+ /* can indexscan return IndexTuples? */
+ typedef bool
+ (*amcanreturn_function) (Relation indexRelation, int attno);
+
+ /* estimate cost of an indexscan */
+ typedef void
+ (*amcostestimate_function) (PlannerInfo *root,
+ IndexPath *path,
+ double loop_count,
+ Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+
+ /* parse AM-specific parameters */
+ typedef bytea *
+ (*amoptions_function) (Datum reloptions,
+ bool validate);
+
+ /* validate oplass */
+ typedef void
+ (*amvalidate_function) (OpClassInfo *opclass);
+
+
+ struct IndexAmRoutine
+ {
+ NodeTag type;
+
+ /*
+ * Total number of strategies (operators) by which we can traverse/search
+ * this AM. Zero if AM does not have a fixed set of strategy assignments.
+ */
+ int16 amstrategies;
+ /* total number of support functions that this AM uses */
+ int16 amsupport;
+ /* does AM support order by column value? */
+ bool amcanorder;
+ /* does AM support order by operator result? */
+ bool amcanorderbyop;
+ /* does AM support backward scan? */
+ bool amcanbackward;
+ /* does AM support UNIQUE indexes? */
+ bool amcanunique;
+ /* does AM support multi-column indexes? */
+ bool amcanmulticol;
+ /* can query omit key for the first column? */
+ bool amoptionalkey;
+ /* can AM handle ScalarArrayOpExpr quals? */
+ bool amsearcharray;
+ /* can AM search for NULL/NOT NULL entries? */
+ bool amsearchnulls;
+ /* can storage type differ from column type? */
+ bool amstorage;
+ /* does AM support cluster command? */
+ bool amclusterable;
+ /* does AM handle predicate locks? */
+ bool ampredlocks;
+ /* type of data in index, or InvalidOid */
+ Oid amkeytype;
+
+ /* interface functions */
+ aminsert_function aminsert;
+ ambeginscan_function ambeginscan;
+ amgettuple_function amgettuple;
+ amgetbitmap_function amgetbitmap;
+ amrescan_function amrescan;
+ amendscan_function amendscan;
+ ammarkpos_function ammarkpos;
+ amrestrpos_function amrestrpos;
+ ambuild_function ambuild;
+ ambuildempty_function ambuildempty;
+ ambulkdelete_function ambulkdelete;
+ amvacuumcleanup_function amvacuumcleanup;
+ amcanreturn_function amcanreturn;
+ amcostestimate_function amcostestimate;
+ amoptions_function amoptions;
+ amvalidate_function amvalidate;
+ };
+
+ #endif /* AMAPI_H */
diff --git a/src/include/access/brin.h b/src/include/access/brin.h
new file mode 100644
index e72fb2d..5ae5722
*** 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,51 ----
/*
* prototypes for functions in brin.c (external entry points for BRIN)
*/
! extern Datum brinhandler(PG_FUNCTION_ARGS);
! extern void brinvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *brinbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void brinbuildempty(Relation index);
! extern bool brininsert(Relation idxRel, Datum *values, bool *nulls,
! ItemPointer heaptid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys);
! extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
! ScanKey orderbys, int norderbys);
! extern void brinendscan(IndexScanDesc scan);
! extern void brinmarkpos(IndexScanDesc scan);
! extern void brinrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *brinbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *brinvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern void brincostestimate(PlannerInfo *root, IndexPath *path,
! double loop_count, Cost *indexStartupCost,
! Cost *indexTotalCost,
! Selectivity *indexSelectivity,
! double *indexCorrelation);
! extern bytea *brinoptions(Datum reloptions, bool validate);
/*
* Storage type for BRIN's reloptions
diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h
new file mode 100644
index 6be199e..cd72544
*** a/src/include/access/brin_internal.h
--- b/src/include/access/brin_internal.h
*************** typedef struct BrinDesc
*** 71,76 ****
--- 71,77 ----
#define BRIN_PROCNUM_ADDVALUE 2
#define BRIN_PROCNUM_CONSISTENT 3
#define BRIN_PROCNUM_UNION 4
+ #define BRIN_MANDATORY_NPROCS 4
/* procedure numbers up to 10 are reserved for BRIN future expansion */
#undef BRIN_DEBUG
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 5021887..a77d43f
*** 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,601 ----
/* ginutil.c */
! extern Datum ginhandler(PG_FUNCTION_ARGS);
! extern void ginvalidate(OpClassInfo *opclass);
! extern bytea *ginoptions(Datum reloptions, bool validate);
extern void initGinState(GinState *state, Relation index);
extern Buffer GinNewBuffer(Relation index);
extern void GinInitBuffer(Buffer b, uint32 f);
*************** 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,
--- 616,627 ----
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);
--- 872,899 ----
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 1a77982..35fb34a
*** 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
*** 426,434 ****
} 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);
--- 427,439 ----
} GiSTOptions;
/* gist.c */
! extern Datum gisthandler(PG_FUNCTION_ARGS);
! extern void gistvalidate(OpClassInfo *opclass);
! extern void gistbuildempty(Relation index);
! extern bool gistinsert(Relation r, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern bool gistcanreturn(Relation index, int attno);
extern MemoryContext createTempGistContext(void);
extern GISTSTATE *initGISTstate(Relation index);
extern void freeGISTstate(GISTSTATE *giststate);
*************** extern XLogRecPtr gistXLogSplit(RelFileN
*** 474,481 ****
Buffer leftchild, bool markfollowright);
/* gistget.c */
! extern Datum gistgettuple(PG_FUNCTION_ARGS);
! extern Datum gistgetbitmap(PG_FUNCTION_ARGS);
/* gistutil.c */
--- 479,486 ----
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
*** 485,491 ****
#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);
--- 490,496 ----
#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 *
*** 534,541 ****
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,
--- 539,550 ----
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
*** 544,550 ****
int attno);
/* gistbuild.c */
! extern Datum gistbuild(PG_FUNCTION_ARGS);
extern void gistValidateBufferingOption(char *value);
/* gistbuildbuffers.c */
--- 553,560 ----
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..9595c6b
*** 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,271 ----
/* public routines */
! extern Datum hashhandler(PG_FUNCTION_ARGS);
! extern void hashvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *hashbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void hashbuildempty(Relation index);
! extern bool hashinsert(Relation rel, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc hashbeginscan(Relation rel, int nkeys, int norderbys);
! extern bool hashgettuple(IndexScanDesc scan, ScanDirection dir);
! extern int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void hashrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
! ScanKey orderbys, int norderbys);
! extern void hashendscan(IndexScanDesc scan);
! extern void hashmarkpos(IndexScanDesc scan);
! extern void hashrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *hashbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *hashvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern bytea *hashoptions(Datum reloptions, bool validate);
/*
* Datatype-specific hash functions in hashfunc.c.
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
new file mode 100644
index 9e48efd..4fab0a3
*** 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,683 ----
/*
* prototypes for functions in nbtree.c (external entry points for btree)
*/
! extern Datum bthandler(PG_FUNCTION_ARGS);
! extern void btvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *btbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void btbuildempty(Relation index);
! extern bool btinsert(Relation rel, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc btbeginscan(Relation indexRelation,
! int nkeys, int norderbys);
! extern bool btgettuple(IndexScanDesc scan, ScanDirection dir);
! extern int64 btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void btrescan(IndexScanDesc scan, ScanKey keys, int nkeys,
! ScanKey orderbys, int norderbys);
! extern void btendscan(IndexScanDesc scan);
! extern void btmarkpos(IndexScanDesc scan);
! extern void btrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *btbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *btvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern bool btcanreturn(Relation index, int attno);
! extern bytea *btoptions(Datum reloptions, bool validate);
/*
* prototypes for functions in nbtinsert.c
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
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..ba2c1c1
*** 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,212 ----
} spgLeafConsistentOut;
+ /* spgutils.c */
+ extern Datum spghandler(PG_FUNCTION_ARGS);
+ extern void spgvalidate(OpClassInfo *opclass);
+
/* 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/opfam_internal.h b/src/include/catalog/opfam_internal.h
new file mode 100644
index 32195a7..2cbefe9
*** a/src/include/catalog/opfam_internal.h
--- b/src/include/catalog/opfam_internal.h
*************** typedef struct
*** 25,28 ****
--- 25,41 ----
Oid sortfamily; /* ordering operator's sort opfamily, or 0 */
} OpFamilyMember;
+ /*
+ * Opclass data for validation by access method.
+ */
+ typedef struct
+ {
+ Oid amoid; /* access method OID */
+ Oid intype; /* input datatype */
+ Oid keytype; /* key datatype */
+ List *procedures; /* list of OpFamilyMember */
+ List *operators; /* list of OpFamilyMember */
+ } OpClassInfo;
+
+
#endif /* OPFAM_INTERNAL_H */
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
new file mode 100644
index 8a28b8e..f19a873
*** 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,40 ----
CATALOG(pg_am,2601)
{
NameData amname; /* access method name */
! regproc amhandler; /* handler function */
} 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
--- 48,78 ----
* compiler constants for pg_am
* ----------------
*/
! #define Natts_pg_am 2
#define Anum_pg_am_amname 1
! #define Anum_pg_am_amhandler 2
/* ----------------
* initial contents of pg_am
* ----------------
*/
! DATA(insert OID = 403 ( btree bthandler ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
! DATA(insert OID = 405 ( hash hashhandler ));
DESCR("hash index access method");
#define HASH_AM_OID 405
! DATA(insert OID = 783 ( gist gisthandler ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
! DATA(insert OID = 2742 ( gin ginhandler ));
DESCR("GIN index access method");
#define GIN_AM_OID 2742
! DATA(insert OID = 4000 ( spgist spghandler ));
DESCR("SP-GiST index access method");
#define SPGIST_AM_OID 4000
! DATA(insert OID = 3580 ( brin brinhandler ));
DESCR("block range index (BRIN) access method");
#define BRIN_AM_OID 3580
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index eb55b3a..587aaac
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DESCR("convert int4 to float4");
*** 547,609 ****
DATA(insert OID = 319 ( int4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "700" _null_ _null_ _null_ _null_ _null_ ftoi4 _null_ _null_ _null_ ));
DESCR("convert float4 to int4");
- DATA(insert OID = 330 ( btgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgettuple _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 636 ( btgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgetbitmap _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 331 ( btinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btinsert _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 333 ( btbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbeginscan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 334 ( btrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btrescan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 335 ( btendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btendscan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 336 ( btmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btmarkpos _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 337 ( btrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btrestrpos _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 338 ( btbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbuild _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 328 ( btbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btbuildempty _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 332 ( btbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbulkdelete _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ btvacuumcleanup _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 276 ( btcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ btcanreturn _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 1268 ( btcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btcostestimate _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 2785 ( btoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ btoptions _null_ _null_ _null_ ));
- DESCR("btree(internal)");
-
- DATA(insert OID = 3789 ( bringetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ bringetbitmap _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3790 ( brininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brininsert _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3791 ( brinbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbeginscan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3792 ( brinrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinrescan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3793 ( brinendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinendscan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3794 ( brinmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinmarkpos _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3795 ( brinrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinrestrpos _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3796 ( brinbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbuild _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3797 ( brinbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinbuildempty _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3798 ( brinbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbulkdelete _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3799 ( brinvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ brinvacuumcleanup _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3800 ( brincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brincostestimate _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3801 ( brinoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ brinoptions _null_ _null_ _null_ ));
- DESCR("brin(internal)");
DATA(insert OID = 3952 ( brin_summarize_new_values PGNSP PGUID 12 1 0 0 0 f f f f f f v s 1 0 23 "2205" _null_ _null_ _null_ _null_ _null_ brin_summarize_new_values _null_ _null_ _null_ ));
DESCR("brin: standalone scan new table pages");
--- 547,552 ----
*************** DESCR("convert name to char(n)");
*** 694,728 ****
DATA(insert OID = 409 ( name PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 19 "1042" _null_ _null_ _null_ _null_ _null_ bpchar_name _null_ _null_ _null_ ));
DESCR("convert char(n) to name");
- DATA(insert OID = 440 ( hashgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgettuple _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 637 ( hashgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgetbitmap _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 441 ( hashinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashinsert _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 443 ( hashbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbeginscan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 444 ( hashrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashrescan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 445 ( hashendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashendscan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 446 ( hashmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashmarkpos _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 447 ( hashrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashrestrpos _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 448 ( hashbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbuild _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 327 ( hashbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashbuildempty _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 442 ( hashbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbulkdelete _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashvacuumcleanup _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 438 ( hashcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashcostestimate _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 2786 ( hashoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ hashoptions _null_ _null_ _null_ ));
- DESCR("hash(internal)");
-
DATA(insert OID = 449 ( hashint2 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "21" _null_ _null_ _null_ _null_ _null_ hashint2 _null_ _null_ _null_ ));
DESCR("hash");
DATA(insert OID = 450 ( hashint4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ hashint4 _null_ _null_ _null_ ));
--- 637,642 ----
*************** DESCR("larger of two");
*** 978,1014 ****
DATA(insert OID = 771 ( int2smaller PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2smaller _null_ _null_ _null_ ));
DESCR("smaller of two");
- DATA(insert OID = 774 ( gistgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgettuple _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 638 ( gistgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgetbitmap _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 775 ( gistinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistinsert _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 777 ( gistbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbeginscan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 778 ( gistrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistrescan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 779 ( gistendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistendscan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 780 ( gistmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistmarkpos _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 781 ( gistrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistrestrpos _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 782 ( gistbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbuild _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 326 ( gistbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistbuildempty _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 776 ( gistbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbulkdelete _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistvacuumcleanup _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 3280 ( gistcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ gistcanreturn _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 772 ( gistcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistcostestimate _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 2787 ( gistoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ gistoptions _null_ _null_ _null_ ));
- DESCR("gist(internal)");
-
DATA(insert OID = 784 ( tintervaleq PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervaleq _null_ _null_ _null_ ));
DATA(insert OID = 785 ( tintervalne PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervalne _null_ _null_ _null_ ));
DATA(insert OID = 786 ( tintervallt PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervallt _null_ _null_ _null_ ));
--- 892,897 ----
*************** DATA(insert OID = 3311 ( tsm_handler_in
*** 3740,3745 ****
--- 3623,3632 ----
DESCR("I/O");
DATA(insert OID = 3312 ( tsm_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "3310" _null_ _null_ _null_ _null_ _null_ tsm_handler_out _null_ _null_ _null_ ));
DESCR("I/O");
+ DATA(insert OID = 326 ( index_am_handler_in PGNSP PGUID 12 1 0 0 0 f f f f f f i s 1 0 325 "2275" _null_ _null_ _null_ _null_ _null_ index_am_handler_in _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 327 ( index_am_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "325" _null_ _null_ _null_ _null_ _null_ index_am_handler_out _null_ _null_ _null_ ));
+ DESCR("I/O");
/* tablesample method handlers */
DATA(insert OID = 3313 ( bernoulli PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 3310 "2281" _null_ _null_ _null_ _null_ _null_ tsm_bernoulli_handler _null_ _null_ _null_ ));
*************** DESCR("GiST support");
*** 4196,4229 ****
DATA(insert OID = 3288 ( gist_bbox_distance PGNSP PGUID 12 1 0 0 0 f f f f t f i s 4 0 701 "2281 600 23 26" _null_ _null_ _null_ _null_ _null_ gist_bbox_distance _null_ _null_ _null_ ));
DESCR("GiST support");
- /* GIN */
- DATA(insert OID = 2731 ( gingetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gingetbitmap _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2732 ( gininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gininsert _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2733 ( ginbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbeginscan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2734 ( ginrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginrescan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2735 ( ginendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginendscan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2736 ( ginmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginmarkpos _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2737 ( ginrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginrestrpos _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2738 ( ginbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbuild _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 325 ( ginbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginbuildempty _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2739 ( ginbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbulkdelete _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ ginvacuumcleanup _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2741 ( gincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gincostestimate _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2788 ( ginoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ ginoptions _null_ _null_ _null_ ));
- DESCR("gin(internal)");
-
/* GIN array support */
DATA(insert OID = 2743 ( ginarrayextract PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 2281 "2277 2281 2281" _null_ _null_ _null_ _null_ _null_ ginarrayextract _null_ _null_ _null_ ));
DESCR("GIN array support");
--- 4083,4088 ----
*************** DESCR("construct timestamp with time zon
*** 5119,5156 ****
DATA(insert OID = 3464 ( make_interval PGNSP PGUID 12 1 0 0 0 f f f f t f i s 7 0 1186 "23 23 23 23 23 23 701" _null_ _null_ "{years,months,weeks,days,hours,mins,secs}" _null_ _null_ make_interval _null_ _null_ _null_ ));
DESCR("construct interval");
- /* spgist support functions */
- DATA(insert OID = 4001 ( spggettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggettuple _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4002 ( spggetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggetbitmap _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4003 ( spginsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spginsert _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4004 ( spgbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbeginscan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4005 ( spgrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgrescan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4006 ( spgendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgendscan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4007 ( spgmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgmarkpos _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4008 ( spgrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgrestrpos _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4009 ( spgbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbuild _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4010 ( spgbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgbuildempty _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4011 ( spgbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbulkdelete _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4012 ( spgvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ spgvacuumcleanup _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4032 ( spgcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ spgcanreturn _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4013 ( spgcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgcostestimate _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4014 ( spgoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ spgoptions _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
-
/* spgist opclasses */
DATA(insert OID = 4018 ( spg_quad_config PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_quad_config _null_ _null_ _null_ ));
DESCR("SP-GiST support for quad tree over point");
--- 4978,4983 ----
*************** DESCR("get an individual replication ori
*** 5333,5338 ****
--- 5160,5184 ----
DATA(insert OID = 6014 ( pg_show_replication_origin_status PGNSP PGUID 12 1 100 0 0 f f f f f t v r 0 0 2249 "" "{26,25,3220,3220}" "{o,o,o,o}" "{local_id, external_id, remote_lsn, local_lsn}" _null_ _null_ pg_show_replication_origin_status _null_ _null_ _null_ ));
DESCR("get progress for all replication origins");
+ /* Access methods handlers */
+ DATA(insert OID = 330 ( bthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ bthandler _null_ _null_ _null_ ));
+ DESCR("btree handler");
+ DATA(insert OID = 331 ( hashhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ hashhandler _null_ _null_ _null_ ));
+ DESCR("hash handler");
+ DATA(insert OID = 332 ( gisthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ gisthandler _null_ _null_ _null_ ));
+ DESCR("gist handler");
+ DATA(insert OID = 333 ( ginhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ ginhandler _null_ _null_ _null_ ));
+ DESCR("gin handler");
+ DATA(insert OID = 334 ( spghandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ spghandler _null_ _null_ _null_ ));
+ DESCR("spgist handler");
+ DATA(insert OID = 335 ( brinhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ brinhandler _null_ _null_ _null_ ));
+ DESCR("brin handler");
+
+ DATA(insert OID = 336 ( amvalidate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 16 "26" _null_ _null_ _null_ _null_ _null_ amvalidate _null_ _null_ _null_ ));
+ DESCR("ask access method to validate opclass");
+
+
+
/*
* Symbolic values for provolatile column: these indicate whether the result
* of a function is dependent *only* on the values of its explicit arguments,
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
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/commands/defrem.h b/src/include/commands/defrem.h
new file mode 100644
index adae296..d8b9649
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
*************** extern Oid get_am_oid(const char *amname
*** 95,100 ****
--- 95,101 ----
extern char *get_am_name(Oid amOid);
extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+ extern Datum amvalidate(PG_FUNCTION_ARGS);
/* commands/tsearchcmds.c */
extern ObjectAddress DefineTSParser(List *names, List *parameters);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
new file mode 100644
index b6895f9..0ed8a96
*** 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 94bdb7c..84e4a36
*** a/src/include/nodes/nodes.h
--- b/src/include/nodes/nodes.h
*************** typedef enum NodeTag
*** 455,461 ****
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;
/*
--- 455,462 ----
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 6cf2e24..3c51bf3
*** 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
*** 548,555 ****
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 */
--- 549,555 ----
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
*** 560,571 ****
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;
--- 560,571 ----
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
*** 819,825 ****
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! typedef struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
--- 819,825 ----
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
*************** typedef struct IndexPath
*** 831,837 ****
ScanDirection indexscandir;
Cost indextotalcost;
Selectivity indexselectivity;
! } IndexPath;
/*
* BitmapHeapPath represents one or more indexscans that generate TID bitmaps
--- 831,837 ----
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..e686c9e
*** 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,45 ----
*/
typedef Relation *RelationPtr;
+ typedef struct IndexAmRoutine IndexAmRoutine;
+
+ /*
+ * Routines to retreive IndexAmRoutine
+ */
+ extern IndexAmRoutine *GetIndexAmRoutine(Oid amhandler);
+ extern IndexAmRoutine *GetIndexAmRoutineByAmId(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 a7433d9..3745d1c
*** a/src/include/utils/selfuncs.h
--- b/src/include/utils/selfuncs.h
*************** extern double estimate_num_groups(Planne
*** 191,202 ****
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 */
--- 191,226 ----
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/alter_table.out b/src/test/regress/expected/alter_table.out
new file mode 100644
index 44ce6f5..9e3b599
*** a/src/test/regress/expected/alter_table.out
--- b/src/test/regress/expected/alter_table.out
*************** create type alter1.ctype as (f1 int, f2
*** 2124,2131 ****
create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql
as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
create text search configuration alter1.cfg(parser = alter1.prs);
--- 2124,2134 ----
create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql
as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
+ create function alter1.hash(alter1.ctype) returns int4 language sql
+ as 'select hashint4($1.f1) # hashtext($1.f2)';
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype),
! function 1 alter1.hash(alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
create text search configuration alter1.cfg(parser = alter1.prs);
*************** alter operator class alter1.ctype_hash_o
*** 2141,2146 ****
--- 2144,2150 ----
alter operator family alter1.ctype_hash_ops using hash set schema alter2;
alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
+ alter function alter1.hash(alter1.ctype) set schema alter2;
alter type alter1.ctype set schema alter2;
alter conversion alter1.ascii_to_utf8 set schema alter2;
alter text search parser alter1.prs set schema alter2;
*************** select alter2.plus1(41);
*** 2177,2183 ****
-- clean up
drop schema alter2 cascade;
! NOTICE: drop cascades to 13 other objects
DETAIL: drop cascades to table alter2.t1
drop cascades to view alter2.v1
drop cascades to function alter2.plus1(integer)
--- 2181,2187 ----
-- clean up
drop schema alter2 cascade;
! NOTICE: drop cascades to 14 other objects
DETAIL: drop cascades to table alter2.t1
drop cascades to view alter2.v1
drop cascades to function alter2.plus1(integer)
*************** drop cascades to operator family alter2.
*** 2186,2191 ****
--- 2190,2196 ----
drop cascades to type alter2.ctype
drop cascades to function alter2.same(alter2.ctype,alter2.ctype)
drop cascades to operator alter2.=(alter2.ctype,alter2.ctype)
+ drop cascades to function alter2.hash(alter2.ctype)
drop cascades to conversion ascii_to_utf8
drop cascades to text search parser prs
drop cascades to text search configuration cfg
diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out
new file mode 100644
index d85bc83..d1a322d
*** a/src/test/regress/expected/oidjoins.out
--- b/src/test/regress/expected/oidjoins.out
*************** WHERE aggmtranstype != 0 AND
*** 73,206 ****
------+---------------
(0 rows)
- SELECT ctid, amkeytype
- FROM pg_catalog.pg_am fk
- WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
- ctid | amkeytype
- ------+-----------
- (0 rows)
-
- SELECT ctid, aminsert
- FROM pg_catalog.pg_am fk
- WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
- ctid | aminsert
- ------+----------
- (0 rows)
-
- SELECT ctid, ambeginscan
- FROM pg_catalog.pg_am fk
- WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
- ctid | ambeginscan
- ------+-------------
- (0 rows)
-
- SELECT ctid, amgettuple
- FROM pg_catalog.pg_am fk
- WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- ctid | amgettuple
- ------+------------
- (0 rows)
-
- SELECT ctid, amgetbitmap
- FROM pg_catalog.pg_am fk
- WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
- ctid | amgetbitmap
- ------+-------------
- (0 rows)
-
- SELECT ctid, amrescan
- FROM pg_catalog.pg_am fk
- WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
- ctid | amrescan
- ------+----------
- (0 rows)
-
- SELECT ctid, amendscan
- FROM pg_catalog.pg_am fk
- WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
- ctid | amendscan
- ------+-----------
- (0 rows)
-
- SELECT ctid, ammarkpos
- FROM pg_catalog.pg_am fk
- WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
- ctid | ammarkpos
- ------+-----------
- (0 rows)
-
- SELECT ctid, amrestrpos
- FROM pg_catalog.pg_am fk
- WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
- ctid | amrestrpos
- ------+------------
- (0 rows)
-
- SELECT ctid, ambuild
- FROM pg_catalog.pg_am fk
- WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
- ctid | ambuild
- ------+---------
- (0 rows)
-
- SELECT ctid, ambuildempty
- FROM pg_catalog.pg_am fk
- WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
- ctid | ambuildempty
- ------+--------------
- (0 rows)
-
- SELECT ctid, ambulkdelete
- FROM pg_catalog.pg_am fk
- WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
- ctid | ambulkdelete
- ------+--------------
- (0 rows)
-
- SELECT ctid, amvacuumcleanup
- FROM pg_catalog.pg_am fk
- WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
- ctid | amvacuumcleanup
- ------+-----------------
- (0 rows)
-
- SELECT ctid, amcanreturn
- FROM pg_catalog.pg_am fk
- WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
- ctid | amcanreturn
- ------+-------------
- (0 rows)
-
- SELECT ctid, amcostestimate
- FROM pg_catalog.pg_am fk
- WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
- ctid | amcostestimate
- ------+----------------
- (0 rows)
-
- SELECT ctid, amoptions
- FROM pg_catalog.pg_am fk
- WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
- ctid | amoptions
- ------+-----------
- (0 rows)
-
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 73,78 ----
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
new file mode 100644
index df29fe5..708d84c
*** a/src/test/regress/expected/opr_sanity.out
--- b/src/test/regress/expected/opr_sanity.out
*************** WHERE p1.oid != p2.oid AND
*** 1479,1484 ****
--- 1479,1490 ----
-----+-----
(0 rows)
+ -- Ask access methods to validate opclasses
+ SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid);
+ oid
+ -----
+ (0 rows)
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
SELECT p1.amopfamily, p1.amopstrategy
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 1524,1572 ****
------------+--------------
(0 rows)
- -- check for ordering operators not supported by parent AM
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
- amopfamily | amopopr | oid | amname
- ------------+---------+-----+--------
- (0 rows)
-
- -- Cross-check amopstrategy index against parent AM
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
- amopfamily | amopopr | oid | amname
- ------------+---------+-----+--------
- (0 rows)
-
- -- Detect missing pg_amop entries: should have as many strategy operators
- -- as AM expects for each datatype combination supported by the opfamily.
- -- We can't check this for AMs with variable strategy sets.
- SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
- amname | amoplefttype | amoprighttype
- --------+--------------+---------------
- (0 rows)
-
- -- Currently, none of the AMs with fixed strategy sets support ordering ops.
- SELECT p1.amname, p2.amopfamily, p2.amopstrategy
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
- amname | amopfamily | amopstrategy
- --------+------------+--------------
- (0 rows)
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
--- 1530,1535 ----
*************** WHERE p1.amprocfamily = 0 OR p1.amprocle
*** 1849,1863 ****
--------------+-----------
(0 rows)
- -- Cross-check amprocnum index against parent AM
- SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
- FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
- WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
- amprocfamily | amprocnum | oid | amname
- --------------+-----------+-----+--------
- (0 rows)
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
SELECT * FROM (
--- 1812,1817 ----
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
new file mode 100644
index 778791d..a426ef5
*** a/src/test/regress/sql/alter_table.sql
--- b/src/test/regress/sql/alter_table.sql
*************** as 'select $1.f1 is not distinct from $2
*** 1452,1459 ****
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
--- 1452,1463 ----
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
+ create function alter1.hash(alter1.ctype) returns int4 language sql
+ as 'select hashint4($1.f1) # hashtext($1.f2)';
+
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype),
! function 1 alter1.hash(alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
*************** alter operator class alter1.ctype_hash_o
*** 1473,1478 ****
--- 1477,1483 ----
alter operator family alter1.ctype_hash_ops using hash set schema alter2;
alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
+ alter function alter1.hash(alter1.ctype) set schema alter2;
alter type alter1.ctype set schema alter2;
alter conversion alter1.ascii_to_utf8 set schema alter2;
alter text search parser alter1.prs set schema alter2;
diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql
new file mode 100644
index 2fa628d..ca419fd
*** a/src/test/regress/sql/oidjoins.sql
--- b/src/test/regress/sql/oidjoins.sql
*************** SELECT ctid, aggmtranstype
*** 37,106 ****
FROM pg_catalog.pg_aggregate fk
WHERE aggmtranstype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
- SELECT ctid, amkeytype
- FROM pg_catalog.pg_am fk
- WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
- SELECT ctid, aminsert
- FROM pg_catalog.pg_am fk
- WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
- SELECT ctid, ambeginscan
- FROM pg_catalog.pg_am fk
- WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
- SELECT ctid, amgettuple
- FROM pg_catalog.pg_am fk
- WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- SELECT ctid, amgetbitmap
- FROM pg_catalog.pg_am fk
- WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
- SELECT ctid, amrescan
- FROM pg_catalog.pg_am fk
- WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
- SELECT ctid, amendscan
- FROM pg_catalog.pg_am fk
- WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
- SELECT ctid, ammarkpos
- FROM pg_catalog.pg_am fk
- WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
- SELECT ctid, amrestrpos
- FROM pg_catalog.pg_am fk
- WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
- SELECT ctid, ambuild
- FROM pg_catalog.pg_am fk
- WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
- SELECT ctid, ambuildempty
- FROM pg_catalog.pg_am fk
- WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
- SELECT ctid, ambulkdelete
- FROM pg_catalog.pg_am fk
- WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
- SELECT ctid, amvacuumcleanup
- FROM pg_catalog.pg_am fk
- WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
- SELECT ctid, amcanreturn
- FROM pg_catalog.pg_am fk
- WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
- SELECT ctid, amcostestimate
- FROM pg_catalog.pg_am fk
- WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
- SELECT ctid, amoptions
- FROM pg_catalog.pg_am fk
- WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 37,42 ----
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
new file mode 100644
index c9bdd77..0e0506e
*** a/src/test/regress/sql/opr_sanity.sql
--- b/src/test/regress/sql/opr_sanity.sql
*************** WHERE p1.oid != p2.oid AND
*** 960,965 ****
--- 960,969 ----
p1.opcmethod = p2.opcmethod AND p1.opcintype = p2.opcintype AND
p1.opcdefault AND p2.opcdefault;
+ -- Ask access methods to validate opclasses
+
+ SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid);
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 995,1035 ****
(SELECT 1 from pg_opfamily op WHERE op.oid = p1.amopsortfamily
AND op.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree'));
- -- check for ordering operators not supported by parent AM
-
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
-
- -- Cross-check amopstrategy index against parent AM
-
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
-
- -- Detect missing pg_amop entries: should have as many strategy operators
- -- as AM expects for each datatype combination supported by the opfamily.
- -- We can't check this for AMs with variable strategy sets.
-
- SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
-
- -- Currently, none of the AMs with fixed strategy sets support ordering ops.
-
- SELECT p1.amname, p2.amopfamily, p2.amopstrategy
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
--- 999,1004 ----
*************** FROM pg_amproc as p1
*** 1176,1188 ****
WHERE p1.amprocfamily = 0 OR p1.amproclefttype = 0 OR p1.amprocrighttype = 0
OR p1.amprocnum < 1 OR p1.amproc = 0;
- -- Cross-check amprocnum index against parent AM
-
- SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
- FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
- WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
--- 1145,1150 ----
On 2015-10-05 19:25, Alexander Korotkov wrote:
On Sun, Oct 4, 2015 at 4:27 PM, Amit Kapila <amit.kapila16@gmail.com
<mailto:amit.kapila16@gmail.com>> wrote:On Sat, Oct 3, 2015 at 5:07 PM, Petr Jelinek <petr@2ndquadrant.com
<mailto:petr@2ndquadrant.com>> wrote:On 2015-10-03 08:27, Amit Kapila wrote:
On Fri, Oct 2, 2015 at 8:14 PM, Alexander Korotkov
<a.korotkov@postgrespro.ru
<mailto:a.korotkov@postgrespro.ru>
<mailto:a.korotkov@postgrespro.ru
<mailto:a.korotkov@postgrespro.ru>>> wrote:I agree about staying with one SQL-visible function.
Okay, this does not necessarily mean there should be only one
validation function in the C struct though. I wonder if it would
be more future proof to name the C interface as something else
than the current generic amvalidate. Especially considering that
it basically only does opclass validation at the moment (It's
IMHO saner in terms of API evolution to expand the struct with
more validator functions in the future compared to adding
arguments to the existing function).I also agree with you that adding more arguments in future might
not be a good idea for exposed API. I don't know how much improvement
we can get if we use structure and then keep on adding more members
to it based on future need, but atleast that way it will be less
prone to
breakage.I think adding multiple validator functions is another option, but that
also doesn't sound like a good way as it can pose difficulty in
understanding the right version of API to be used.I think the major priority is to keep compatibility. For now, user can
easily define invalid opclass and he will just get the error runtime.
Thus, the opclass validation looks like improvement which is not
strictly needed. We can add new validator functions in the future but
make them not required. Thus, old access method wouldn't loose
compatibility from this.
Yes that was what I was thinking as well. We don't want to break
anything in this patch as it's mainly API change, but we want to have
API that can potentially evolve. I think evolving the API by adding more
interfaces in the *Routine struct so far worked well for the FDW for
example and given that those structs are nodes, the individual pointers
get initialized to NULL automatically so it's easy to add optional
interfaces (like validators) without breaking anything. Besides, it's
not unreasonable to expect that custom AM authors will have to check if
their implementation is compatible with new major version.
But this is also why I don't think it's good idea to call the opclass
validator just "amvalidate" in the IndexAmRoutine struct because it
implies to be the only validate function we'll ever have.
Other than the above gripe and the following spurious change, the patch
seems good to me now.
RelationInitIndexAccessInfo(Relation relation)
{
HeapTuple tuple;
- Form_pg_am aform;
Datum indcollDatum;
Datum indclassDatum;
Datum indoptionDatum;
@@ -1178,6 +1243,7 @@ RelationInitIndexAccessInfo(Relation relation)
MemoryContext oldcontext;
int natts;
uint16 amsupport;
+ Form_pg_am aform;
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sat, Oct 10, 2015 at 6:03 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
On 2015-10-05 19:25, Alexander Korotkov wrote:
On Sun, Oct 4, 2015 at 4:27 PM, Amit Kapila <amit.kapila16@gmail.com
<mailto:amit.kapila16@gmail.com>> wrote:On Sat, Oct 3, 2015 at 5:07 PM, Petr Jelinek <petr@2ndquadrant.com
<mailto:petr@2ndquadrant.com>> wrote:On 2015-10-03 08:27, Amit Kapila wrote:
On Fri, Oct 2, 2015 at 8:14 PM, Alexander Korotkov
<a.korotkov@postgrespro.ru
<mailto:a.korotkov@postgrespro.ru>
<mailto:a.korotkov@postgrespro.ru<mailto:a.korotkov@postgrespro.ru>>> wrote:
I agree about staying with one SQL-visible function.
Okay, this does not necessarily mean there should be only one
validation function in the C struct though. I wonder if it would
be more future proof to name the C interface as something else
than the current generic amvalidate. Especially considering that
it basically only does opclass validation at the moment (It's
IMHO saner in terms of API evolution to expand the struct with
more validator functions in the future compared to adding
arguments to the existing function).I also agree with you that adding more arguments in future might
not be a good idea for exposed API. I don't know how much improvement
we can get if we use structure and then keep on adding more members
to it based on future need, but atleast that way it will be less
prone to
breakage.I think adding multiple validator functions is another option, but
that
also doesn't sound like a good way as it can pose difficulty in
understanding the right version of API to be used.I think the major priority is to keep compatibility. For now, user can
easily define invalid opclass and he will just get the error runtime.
Thus, the opclass validation looks like improvement which is not
strictly needed. We can add new validator functions in the future but
make them not required. Thus, old access method wouldn't loose
compatibility from this.Yes that was what I was thinking as well. We don't want to break anything
in this patch as it's mainly API change, but we want to have API that can
potentially evolve. I think evolving the API by adding more interfaces in
the *Routine struct so far worked well for the FDW for example and given
that those structs are nodes, the individual pointers get initialized to
NULL automatically so it's easy to add optional interfaces (like
validators) without breaking anything. Besides, it's not unreasonable to
expect that custom AM authors will have to check if their implementation is
compatible with new major version.But this is also why I don't think it's good idea to call the opclass
validator just "amvalidate" in the IndexAmRoutine struct because it implies
to be the only validate function we'll ever have.Other than the above gripe and the following spurious change, the patch
seems good to me now.RelationInitIndexAccessInfo(Relation relation)
{
HeapTuple tuple;
- Form_pg_am aform;
Datum indcollDatum;
Datum indclassDatum;
Datum indoptionDatum;
@@ -1178,6 +1243,7 @@ RelationInitIndexAccessInfo(Relation relation)
MemoryContext oldcontext;
int natts;
uint16 amsupport;
+ Form_pg_am aform;
Good catch, this change was reverted.
Also, it was planned that documentation changes would be reviewed by native
english speaker.
Tom, could you take a look at them?
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Attachments:
aminterface-9.patchapplication/octet-stream; name=aminterface-9.patchDownload
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
new file mode 100644
index 97ef618..48f208a
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 549,762 ****
</row>
<row>
! <entry><structfield>amstrategies</structfield></entry>
! <entry><type>int2</type></entry>
! <entry></entry>
! <entry>Number of operator strategies for this access method,
! or zero if access method does not have a fixed set of operator
! strategies</entry>
! </row>
!
! <row>
! <entry><structfield>amsupport</structfield></entry>
! <entry><type>int2</type></entry>
! <entry></entry>
! <entry>Number of support routines for this access method</entry>
! </row>
!
! <row>
! <entry><structfield>amcanorder</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support ordered scans sorted by the
! indexed column's value?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanorderbyop</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support ordered scans sorted by the result
! of an operator on the indexed column?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanbackward</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support backward scanning?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanunique</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support unique indexes?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanmulticol</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support multicolumn indexes?</entry>
! </row>
!
! <row>
! <entry><structfield>amoptionalkey</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support a scan without any constraint
! for the first index column?</entry>
! </row>
!
! <row>
! <entry><structfield>amsearcharray</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support <literal>ScalarArrayOpExpr</> searches?</entry>
! </row>
!
! <row>
! <entry><structfield>amsearchnulls</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support <literal>IS NULL</>/<literal>NOT NULL</> searches?</entry>
! </row>
!
! <row>
! <entry><structfield>amstorage</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Can index storage data type differ from column data type?</entry>
! </row>
!
! <row>
! <entry><structfield>amclusterable</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Can an index of this type be clustered on?</entry>
! </row>
!
! <row>
! <entry><structfield>ampredlocks</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does an index of this type manage fine-grained predicate locks?</entry>
! </row>
!
! <row>
! <entry><structfield>amkeytype</structfield></entry>
<entry><type>oid</type></entry>
- <entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
- <entry>Type of data stored in index, or zero if not a fixed type</entry>
- </row>
-
- <row>
- <entry><structfield>aminsert</structfield></entry>
- <entry><type>regproc</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Insert this tuple</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambeginscan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Prepare for index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amgettuple</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Next valid tuple</quote> function, or zero if none</entry>
! </row>
!
! <row>
! <entry><structfield>amgetbitmap</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Fetch all valid tuples</quote> function, or zero if none</entry>
! </row>
!
! <row>
! <entry><structfield>amrescan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>(Re)start index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amendscan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Clean up after index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ammarkpos</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Mark current scan position</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amrestrpos</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Restore marked scan position</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambuild</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Build new index</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambuildempty</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Build empty index</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambulkdelete</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Bulk-delete function</entry>
! </row>
!
! <row>
! <entry><structfield>amvacuumcleanup</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Post-<command>VACUUM</command> cleanup function</entry>
! </row>
!
! <row>
! <entry><structfield>amcanreturn</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to check whether an index column supports index-only
! scans. Can be zero if index-only scans are never supported.</entry>
! </row>
!
! <row>
! <entry><structfield>amcostestimate</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to estimate cost of an index scan</entry>
! </row>
!
! <row>
! <entry><structfield>amoptions</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to parse and validate <structfield>reloptions</> for an index</entry>
</row>
-
</tbody>
</tgroup>
</table>
--- 549,562 ----
</row>
<row>
! <entry><structfield>amhandler</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>
! References a handler function that is responsible for
! supplying execution routines for the access method.
! </entry>
</row>
</tbody>
</tgroup>
</table>
diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml
new file mode 100644
index 1c09bae..3ff3651
*** a/doc/src/sgml/indexam.sgml
--- b/doc/src/sgml/indexam.sgml
***************
*** 49,61 ****
<para>
Each index access method is described by a row in the
<structname>pg_am</structname> system catalog (see
! <xref linkend="catalog-pg-am">). The principal contents of a
! <structname>pg_am</structname> row are references to
! <link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>
! entries that identify the index access
! functions supplied by the access method. The APIs for these functions
! are defined later in this chapter. In addition, the
! <structname>pg_am</structname> row specifies a few fixed properties of
the access method, such as whether it can support multicolumn indexes.
There is not currently any special support
for creating or deleting <structname>pg_am</structname> entries;
--- 49,63 ----
<para>
Each index access method is described by a row in the
<structname>pg_am</structname> system catalog (see
! <xref linkend="catalog-pg-am">). In the <structname>pg_am</structname> row
! the handler function is specified by the reference to
! <link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.
! Handler function must be written in a compiled language such as C, using
! the version-1 interface. The handler function simply returns a
! <structname>IndexAmRoutine</structname> struct which contains function
! pointers to callback functions that will be called by the planner, executor,
! and various maintenance commands. In addition, the
! <structname>IndexAmRoutine</structname> contains a few fixed properties of
the access method, such as whether it can support multicolumn indexes.
There is not currently any special support
for creating or deleting <structname>pg_am</structname> entries;
***************
*** 96,126 ****
</para>
<para>
! Some of the flag columns of <structname>pg_am</structname> have nonobvious
! implications. The requirements of <structfield>amcanunique</structfield>
! are discussed in <xref linkend="index-unique-checks">.
! The <structfield>amcanmulticol</structfield> flag asserts that the
! access method supports multicolumn indexes, while
! <structfield>amoptionalkey</structfield> asserts that it allows scans
where no indexable restriction clause is given for the first index column.
! When <structfield>amcanmulticol</structfield> is false,
! <structfield>amoptionalkey</structfield> essentially says whether the
access method supports full-index scans without any restriction clause.
Access methods that support multiple index columns <emphasis>must</>
support scans that omit restrictions on any or all of the columns after
the first; however they are permitted to require some restriction to
appear for the first index column, and this is signaled by setting
! <structfield>amoptionalkey</structfield> false.
! One reason that an index AM might set
! <structfield>amoptionalkey</structfield> false is if it doesn't index
! null values. Since most indexable operators are
strict and hence cannot return true for null inputs,
it is at first sight attractive to not store index entries for null values:
they could never be returned by an index scan anyway. However, this
argument fails when an index scan has no restriction clause for a given
index column. In practice this means that
! indexes that have <structfield>amoptionalkey</structfield> true must
! index nulls, since the planner might decide to use such an index
with no scan keys at all. A related restriction is that an index
access method that supports multiple index columns <emphasis>must</>
support indexing null values in columns after the first, because the planner
--- 98,133 ----
</para>
<para>
! Some of the flag fields of <structname>IndexAmRoutine</structname> have nonobvious
! implications. The requirements of
! <structname>IndexAmRoutine</structname>.<structfield>amcanunique</structfield>
! are discussed in <xref linkend="index-unique-checks">. The
! <structname>IndexAmRoutine</structname>.<structfield>amcanmulticol</structfield>
! flag asserts that the access method supports multicolumn indexes, while
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! asserts that it allows scans
where no indexable restriction clause is given for the first index column.
! When <structname>IndexAmRoutine</structname>.<structfield>amcanmulticol</structfield>
! is false,
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! essentially says whether the
access method supports full-index scans without any restriction clause.
Access methods that support multiple index columns <emphasis>must</>
support scans that omit restrictions on any or all of the columns after
the first; however they are permitted to require some restriction to
appear for the first index column, and this is signaled by setting
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! false. One reason that an index AM might set
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! false is if it doesn't index null values. Since most indexable operators are
strict and hence cannot return true for null inputs,
it is at first sight attractive to not store index entries for null values:
they could never be returned by an index scan anyway. However, this
argument fails when an index scan has no restriction clause for a given
index column. In practice this means that
! indexes that have
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! true must index nulls, since the planner might decide to use such an index
with no scan keys at all. A related restriction is that an index
access method that supports multiple index columns <emphasis>must</>
support indexing null values in columns after the first, because the planner
***************
*** 131,139 ****
index omits rows where <literal>b</> is null.
It is, however, OK to omit rows where the first indexed column is null.
An index access method that does index nulls may also set
! <structfield>amsearchnulls</structfield>, indicating that it supports
! <literal>IS NULL</> and <literal>IS NOT NULL</> clauses as search
! conditions.
</para>
</sect1>
--- 138,146 ----
index omits rows where <literal>b</> is null.
It is, however, OK to omit rows where the first indexed column is null.
An index access method that does index nulls may also set
! <structname>IndexAmRoutine</structname>.<structfield>amsearchnulls</structfield>,
! indicating that it supports <literal>IS NULL</> and <literal>IS NOT NULL</>
! clauses as search conditions.
</para>
</sect1>
***************
*** 143,149 ****
<para>
The index construction and maintenance functions that an index access
! method must provide are:
</para>
<para>
--- 150,156 ----
<para>
The index construction and maintenance functions that an index access
! method must provide in <structname>IndexAmRoutine</structname> are:
</para>
<para>
*************** aminsert (Relation indexRelation,
*** 188,194 ****
<literal>isnull</> arrays give the key values to be indexed, and
<literal>heap_tid</> is the TID to be indexed.
If the access method supports unique indexes (its
! <structname>pg_am</>.<structfield>amcanunique</> flag is true) then
<literal>checkUnique</> indicates the type of uniqueness check to
perform. This varies depending on whether the unique constraint is
deferrable; see <xref linkend="index-unique-checks"> for details.
--- 195,201 ----
<literal>isnull</> arrays give the key values to be indexed, and
<literal>heap_tid</> is the TID to be indexed.
If the access method supports unique indexes (its
! <structfield>amcanunique</> flag is true) then
<literal>checkUnique</> indicates the type of uniqueness check to
perform. This varies depending on whether the unique constraint is
deferrable; see <xref linkend="index-unique-checks"> for details.
*************** amcanreturn (Relation indexRelation, int
*** 281,288 ****
the form of an <structname>IndexTuple</structname>. The attribute number
is 1-based, i.e. the first columns attno is 1. Returns TRUE if supported,
else FALSE. If the access method does not support index-only scans at all,
! the <structfield>amcanreturn</> field in its <structname>pg_am</> row can
! be set to zero.
</para>
<para>
--- 288,295 ----
the form of an <structname>IndexTuple</structname>. The attribute number
is 1-based, i.e. the first columns attno is 1. Returns TRUE if supported,
else FALSE. If the access method does not support index-only scans at all,
! the <structfield>amcanreturn</> field in its <structname>IndexAmRoutine</>
! struct can be set to NULL.
</para>
<para>
*************** amgettuple (IndexScanDesc scan,
*** 414,421 ****
<para>
The <function>amgettuple</> function need only be provided if the access
method supports <quote>plain</> index scans. If it doesn't, the
! <structfield>amgettuple</> field in its <structname>pg_am</> row must
! be set to zero.
</para>
<para>
--- 421,428 ----
<para>
The <function>amgettuple</> function need only be provided if the access
method supports <quote>plain</> index scans. If it doesn't, the
! <structfield>amgettuple</> field in its <structname>IndexAmRoutine</>
! struct must be set to NULL.
</para>
<para>
*************** amgetbitmap (IndexScanDesc scan,
*** 445,452 ****
<para>
The <function>amgetbitmap</> function need only be provided if the access
method supports <quote>bitmap</> index scans. If it doesn't, the
! <structfield>amgetbitmap</> field in its <structname>pg_am</> row must
! be set to zero.
</para>
<para>
--- 452,459 ----
<para>
The <function>amgetbitmap</> function need only be provided if the access
method supports <quote>bitmap</> index scans. If it doesn't, the
! <structfield>amgetbitmap</> field in its <structname>IndexAmRoutine</>
! struct must be set to NULL.
</para>
<para>
*************** amrestrpos (IndexScanDesc scan);
*** 477,494 ****
</para>
<para>
! By convention, the <literal>pg_proc</literal> entry for an index
! access method function should show the correct number of arguments,
! but declare them all as type <type>internal</> (since most of the arguments
! have types that are not known to SQL, and we don't want users calling
! the functions directly anyway). The return type is declared as
! <type>void</>, <type>internal</>, or <type>boolean</> as appropriate.
! The only exception is <function>amoptions</>, which should be correctly
! declared as taking <type>text[]</> and <type>bool</> and returning
! <type>bytea</>. This provision allows client code to execute
! <function>amoptions</> to test validity of options settings.
</para>
-
</sect1>
<sect1 id="index-scanning">
--- 484,496 ----
</para>
<para>
! <programlisting>
! void
! amvalidate (OpClassInfo *opclass);
! </programlisting>
! Validates given operator class by access method. The <function>amvalidate</>
! must throw an error if opclass is invalid.
</para>
</sect1>
<sect1 id="index-scanning">
*************** amrestrpos (IndexScanDesc scan);
*** 548,554 ****
<para>
Access methods that always return entries in the natural ordering
of their data (such as btree) should set
! <structname>pg_am</>.<structfield>amcanorder</> to true.
Currently, such access methods must use btree-compatible strategy
numbers for their equality and ordering operators.
</para>
--- 550,556 ----
<para>
Access methods that always return entries in the natural ordering
of their data (such as btree) should set
! <structfield>amcanorder</> to true.
Currently, such access methods must use btree-compatible strategy
numbers for their equality and ordering operators.
</para>
*************** amrestrpos (IndexScanDesc scan);
*** 556,562 ****
<listitem>
<para>
Access methods that support ordering operators should set
! <structname>pg_am</>.<structfield>amcanorderbyop</> to true.
This indicates that the index is capable of returning entries in
an order satisfying <literal>ORDER BY</> <replaceable>index_key</>
<replaceable>operator</> <replaceable>constant</>. Scan modifiers
--- 558,564 ----
<listitem>
<para>
Access methods that support ordering operators should set
! <structfield>amcanorderbyop</> to true.
This indicates that the index is capable of returning entries in
an order satisfying <literal>ORDER BY</> <replaceable>index_key</>
<replaceable>operator</> <replaceable>constant</>. Scan modifiers
*************** amrestrpos (IndexScanDesc scan);
*** 579,585 ****
methods that set <structfield>amcanorder</> to true.) After the
first call, <function>amgettuple</> must be prepared to advance the scan in
either direction from the most recently returned entry. (But if
! <structname>pg_am</>.<structfield>amcanbackward</> is false, all subsequent
calls will have the same direction as the first one.)
</para>
--- 581,587 ----
methods that set <structfield>amcanorder</> to true.) After the
first call, <function>amgettuple</> must be prepared to advance the scan in
either direction from the most recently returned entry. (But if
! <structfield>amcanbackward</> is false, all subsequent
calls will have the same direction as the first one.)
</para>
*************** amrestrpos (IndexScanDesc scan);
*** 590,597 ****
be remembered per scan; a new <function>ammarkpos</> call overrides the
previously marked position. An access method that does not support
ordered scans should still provide mark and restore functions in
! <structname>pg_am</>, but it is sufficient to have them throw errors if
! called.
</para>
<para>
--- 592,599 ----
be remembered per scan; a new <function>ammarkpos</> call overrides the
previously marked position. An access method that does not support
ordered scans should still provide mark and restore functions in
! <structname>IndexAmRoutine</>, but it is sufficient to have them throw
! errors if called.
</para>
<para>
*************** amrestrpos (IndexScanDesc scan);
*** 766,772 ****
<productname>PostgreSQL</productname> enforces SQL uniqueness constraints
using <firstterm>unique indexes</>, which are indexes that disallow
multiple entries with identical keys. An access method that supports this
! feature sets <structname>pg_am</>.<structfield>amcanunique</> true.
(At present, only b-tree supports it.)
</para>
--- 768,774 ----
<productname>PostgreSQL</productname> enforces SQL uniqueness constraints
using <firstterm>unique indexes</>, which are indexes that disallow
multiple entries with identical keys. An access method that supports this
! feature sets <structfield>amcanunique</> true.
(At present, only b-tree supports it.)
</para>
diff --git a/doc/src/sgml/xindex.sgml b/doc/src/sgml/xindex.sgml
new file mode 100644
index 4fac018..a2d3fd8
*** a/doc/src/sgml/xindex.sgml
--- b/doc/src/sgml/xindex.sgml
***************
*** 34,40 ****
regular access to tables is built into
<productname>PostgreSQL</productname>, but all index methods are
described in <classname>pg_am</classname>. It is possible to add a
! new index method by defining the required interface routines and
then creating a row in <classname>pg_am</classname> — but that is
beyond the scope of this chapter (see <xref linkend="indexam">).
</para>
--- 34,41 ----
regular access to tables is built into
<productname>PostgreSQL</productname>, but all index methods are
described in <classname>pg_am</classname>. It is possible to add a
! new index access method by defining the handler function, which returns
! C-struct with required interface routines and parameters, and
then creating a row in <classname>pg_am</classname> — but that is
beyond the scope of this chapter (see <xref linkend="indexam">).
</para>
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
new file mode 100644
index 99337b0..a029eb1
*** a/src/backend/access/brin/brin.c
--- b/src/backend/access/brin/brin.c
***************
*** 35,40 ****
--- 35,143 ----
/*
+ * BRIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ brinhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 15;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = brininsert;
+ amroutine->ambeginscan = brinbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = bringetbitmap;
+ amroutine->amrescan = brinrescan;
+ amroutine->amendscan = brinendscan;
+ amroutine->ammarkpos = brinmarkpos;
+ amroutine->amrestrpos = brinrestrpos;
+ amroutine->ambuild = brinbuild;
+ amroutine->ambuildempty = brinbuildempty;
+ amroutine->ambulkdelete = brinbulkdelete;
+ amroutine->amvacuumcleanup = brinvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = brincostestimate;
+ amroutine->amoptions = brinoptions;
+ amroutine->amvalidate = brinvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ brinvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[BRIN_MANDATORY_NPROCS];
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype ||
+ proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for BRIN: %u",
+ proc->number)));
+
+ /* BRIN opclasses could contain any number of non-mandatory procedures */
+ if (proc->number > BRIN_MANDATORY_NPROCS)
+ continue;
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u was defined more than once",
+ proc->number)));
+
+ procsPresent[proc->number - 1] = true;
+ }
+
+ /*
+ * Don't use BRIN_NPROC because some procnumbers
+ * are reserved for future use
+ */
+ for (i = 0; i < BRIN_MANDATORY_NPROCS; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN doesn't support ORDER BY operators")));
+ }
+ }
+
+ /*
* We use a BrinBuildState during initial construction of a BRIN index.
* The running state is kept in a BrinMemTuple.
*/
*************** 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;
--- 183,193 ----
* 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);
}
/*
--- 325,331 ----
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;
--- 335,343 ----
* 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);
}
/*
--- 348,354 ----
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;
--- 363,371 ----
* 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
--- 545,560 ----
* 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();
}
/*
--- 566,596 ----
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;
--- 662,670 ----
/*
* 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. */
--- 743,754 ----
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();
}
/*
--- 765,770 ----
*************** 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));
--- 776,804 ----
* 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;
--- 815,829 ----
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);
--- 836,842 ----
/* 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);
}
/*
--- 845,851 ----
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 931dceb..b52846f
*** a/src/backend/access/common/reloptions.c
--- b/src/backend/access/common/reloptions.c
*************** untransformRelOptions(Datum options)
*** 891,897 ****
* 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;
--- 891,897 ----
* 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
*** 1379,1412 ****
* 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);
}
/*
--- 1379,1393 ----
* 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 49e9185..92701b9
*** 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..51c1559
*** a/src/backend/access/gin/ginutil.c
--- b/src/backend/access/gin/ginutil.c
***************
*** 22,28 ****
--- 22,140 ----
#include "miscadmin.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
+ #include "utils/selfuncs.h"
+
+
+ /*
+ * GIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ ginhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 6;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = gininsert;
+ amroutine->ambeginscan = ginbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = gingetbitmap;
+ amroutine->amrescan = ginrescan;
+ amroutine->amendscan = ginendscan;
+ amroutine->ammarkpos = ginmarkpos;
+ amroutine->amrestrpos = ginrestrpos;
+ amroutine->ambuild = ginbuild;
+ amroutine->ambuildempty = ginbuildempty;
+ amroutine->ambulkdelete = ginbulkdelete;
+ amroutine->amvacuumcleanup = ginvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = gincostestimate;
+ amroutine->amoptions = ginoptions;
+ amroutine->amvalidate = ginvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ ginvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[GINNProcs];
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype ||
+ proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > GINNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for GIN: %u",
+ proc->number)));
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u was defined more than once",
+ proc->number)));
+
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < GINNProcs; i++)
+ {
+ if (i+1 == GIN_COMPARE_PARTIAL_PROC)
+ continue; /* optional method */
+ if (i+1 == GIN_CONSISTENT_PROC || i+1 == GIN_TRICONSISTENT_PROC)
+ continue; /* don't need to have both, see check below loop */
+
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u is required", i + 1)));
+ }
+
+ if (!procsPresent[GIN_CONSISTENT_PROC - 1]
+ && !procsPresent[GIN_TRICONSISTENT_PROC - 1])
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("at least one of consistent support (number %u) "
+ "and triconsistent support (number %u) is "
+ "is required",
+ GIN_CONSISTENT_PROC, GIN_TRICONSISTENT_PROC)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN doesn't support ORDER BY operators")));
+ }
+ }
/*
* initGinState: fill in an empty GinState struct to describe the index
*************** 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;
--- 628,636 ----
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);
--- 645,651 ----
/* 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);
}
/*
--- 654,660 ----
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 323cfb0..5b38607
*** 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, true, stats);
}
! PG_RETURN_POINTER(stats);
}
/*
--- 656,662 ----
initGinState(&ginstate, index);
ginInsertCleanup(&ginstate, true, 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 53bccf6..12224b6
*** 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 void gistfinishsplit(GISTInsertSt
*** 38,43 ****
--- 40,143 ----
GISTSTATE *giststate, List *splitinfo, bool releasebuf);
static void gistvacuumpage(Relation rel, Page page, Buffer buffer);
+ /*
+ * GiST handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ gisthandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 9;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = true;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = true;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = gistinsert;
+ amroutine->ambeginscan = gistbeginscan;
+ amroutine->amgettuple = gistgettuple;
+ amroutine->amgetbitmap = gistgetbitmap;
+ amroutine->amrescan = gistrescan;
+ amroutine->amendscan = gistendscan;
+ amroutine->ammarkpos = gistmarkpos;
+ amroutine->amrestrpos = gistrestrpos;
+ amroutine->ambuild = gistbuild;
+ amroutine->ambuildempty = gistbuildempty;
+ amroutine->ambulkdelete = gistbulkdelete;
+ amroutine->amvacuumcleanup = gistvacuumcleanup;
+ amroutine->amcanreturn = gistcanreturn;
+ amroutine->amcostestimate = gistcostestimate;
+ amroutine->amoptions = gistoptions;
+ amroutine->amvalidate = gistvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ gistvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[GISTNProcs];
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype ||
+ proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > GISTNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for GiST: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u was defined more than once",
+ proc->number)));
+
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < GISTNProcs; i++)
+ {
+ if (i+1 == GIST_DISTANCE_PROC || i+1 == GIST_FETCH_PROC)
+ continue; /* optional methods */
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily)
+ && !procsPresent[GIST_DISTANCE_PROC - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST distance support function %u is required "
+ "for ORDER BY operators", GIST_DISTANCE_PROC)));
+ }
+ }
#define ROTATEDIST(d) do { \
SplitedPageLayout *tmp=(SplitedPageLayout*)palloc(sizeof(SplitedPageLayout)); \
*************** createTempGistContext(void)
*** 70,79 ****
/*
* 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 */
--- 170,178 ----
/*
* gistbuildempty() -- build an empty gist index in the initialization fork
*/
! void
! gistbuildempty(Relation index)
{
Buffer buffer;
/* Initialize the root page */
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 89,96 ****
/* Unlock and release the buffer */
UnlockReleaseBuffer(buffer);
-
- PG_RETURN_VOID();
}
/*
--- 188,193 ----
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 99,116 ****
* 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;
--- 196,206 ----
* 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)
*** 136,142 ****
MemoryContextSwitchTo(oldCxt);
freeGISTstate(giststate);
! PG_RETURN_BOOL(false);
}
--- 226,232 ----
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 ce8e582..1adf92f
*** a/src/backend/access/gist/gistget.c
--- b/src/backend/access/gist/gistget.c
*************** getNextNearest(IndexScanDesc scan)
*** 618,628 ****
/*
* 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)
--- 618,626 ----
/*
* 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)
*** 651,657 ****
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! PG_RETURN_BOOL(getNextNearest(scan));
}
else
{
--- 649,655 ----
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! return getNextNearest(scan);
}
else
{
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 688,694 ****
so->curPageData++;
! PG_RETURN_BOOL(true);
}
/*
--- 686,692 ----
so->curPageData++;
! return true;
}
/*
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 726,732 ****
item = getNextGISTSearchItem(so);
if (!item)
! PG_RETURN_BOOL(false);
CHECK_FOR_INTERRUPTS();
--- 724,730 ----
item = getNextGISTSearchItem(so);
if (!item)
! return false;
CHECK_FOR_INTERRUPTS();
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 750,766 ****
/*
* 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);
--- 748,762 ----
/*
* 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)
*** 791,797 ****
pfree(item);
}
! PG_RETURN_INT64(ntids);
}
/*
--- 787,793 ----
pfree(item);
}
! return ntids;
}
/*
*************** gistgetbitmap(PG_FUNCTION_ARGS)
*** 799,812 ****
*
* 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);
}
--- 795,805 ----
*
* 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 a17c5bc..22f0c68
*** 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)
*** 107,121 ****
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;
--- 104,116 ----
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)
*** 314,341 ****
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;
/*
--- 309,331 ----
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)
*** 343,348 ****
* as well as the queueCxt if there is a separate context for it.
*/
freeGISTstate(so->giststate);
-
- PG_RETURN_VOID();
}
--- 333,336 ----
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 a0b0eeb..e0ce620
*** 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)
*** 276,280 ****
vacuum_delay_point();
}
! PG_RETURN_POINTER(stats);
}
--- 271,275 ----
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..a51fa7c
*** 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,150 ----
bool tupleIsAlive,
void *state);
+ /*
+ * Hash handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ hashhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 1;
+ amroutine->amsupport = 1;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = true;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = false;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = INT4OID;
+
+ amroutine->aminsert = hashinsert;
+ amroutine->ambeginscan = hashbeginscan;
+ amroutine->amgettuple = hashgettuple;
+ amroutine->amgetbitmap = hashgetbitmap;
+ amroutine->amrescan = hashrescan;
+ amroutine->amendscan = hashendscan;
+ amroutine->ammarkpos = hashmarkpos;
+ amroutine->amrestrpos = hashrestrpos;
+ amroutine->ambuild = hashbuild;
+ amroutine->ambuildempty = hashbuildempty;
+ amroutine->ambulkdelete = hashbulkdelete;
+ amroutine->amvacuumcleanup = hashvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = hashcostestimate;
+ amroutine->amoptions = hashoptions;
+ amroutine->amvalidate = hashvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ hashvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->number != HASHPROC)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for hash: %u",
+ proc->number)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+ bool leftFound = false, rightFound = false;
+ ListCell *ll;
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("hash doesn't support ORDER BY operators")));
+
+ if (opr->number < 1 || opr->number > HTMaxStrategyNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid strategy number for hash: %u",
+ opr->number)));
+
+ foreach(ll, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(ll);
+
+ if (proc->lefttype == opr->lefttype)
+ leftFound = true;
+ if (proc->lefttype == opr->righttype)
+ rightFound = true;
+ }
+
+ if (!leftFound || !rightFound)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("no hash procedure found for operator: %u",
+ opr->object)));
+ }
+ }
/*
* hashbuild() -- build a new hash index.
*/
! 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();
}
/*
--- 205,220 ----
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;
/*
--- 256,266 ----
* 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);
--- 273,279 ----
* 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;
--- 283,298 ----
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;
--- 394,409 ----
/* 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;
--- 440,455 ----
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;
--- 471,486 ----
/* 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;
--- 506,519 ----
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();
}
/*
--- 532,555 ----
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;
--- 559,568 ----
*
* 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);
}
/*
--- 732,738 ----
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);
}
--- 740,761 ----
*
* 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..ee623ae
*** 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,182 ----
/*
! * 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;
! amroutine->amvalidate = btvalidate;
!
! PG_RETURN_POINTER(amroutine);
! }
!
! void
! btvalidate(OpClassInfo *opclass)
! {
! ListCell *l;
!
! foreach(l, opclass->procedures)
! {
! OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
!
! if (proc->number != BTORDER_PROC &&
! proc->number != BTSORTSUPPORT_PROC)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("invalid support number for btree: %u",
! proc->number)));
! }
!
! foreach(l, opclass->operators)
! {
! OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
! bool found = false;
! ListCell *ll;
!
! if (OidIsValid(opr->sortfamily))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("btree doesn't support ORDER BY operators")));
!
! if (opr->number < 1 || opr->number > BTMaxStrategyNumber)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("invalid strategy number for btree: %u",
! opr->number)));
!
! foreach(ll, opclass->procedures)
! {
! OpFamilyMember *proc = (OpFamilyMember *) lfirst(ll);
!
! if (proc->number == BTORDER_PROC &&
! proc->lefttype == opr->lefttype &&
! proc->righttype == opr->righttype)
! found = true;
! }
!
! if (!found)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("no ordering procedure found for operator: %u",
! opr->object)));
! }
! }
!
! /*
! * btbuild() -- build a new btree index.
! */
! IndexBuildResult *
! btbuild(Relation heap, Relation index, IndexInfo *indexInfo)
{
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);
}
/*
--- 248,254 ----
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);
--- 283,292 ----
/*
* 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();
}
/*
--- 306,311 ----
*************** 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;
--- 314,324 ----
* 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;
--- 330,344 ----
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);
}
--- 354,360 ----
{
/* 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;
--- 404,418 ----
/* ... 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);
}
--- 424,430 ----
{
/* 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;
--- 462,476 ----
/* 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 */
--- 508,523 ----
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 */
--- 568,581 ----
/* 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). */
--- 604,617 ----
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 */
--- 634,647 ----
/* 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();
}
/*
--- 709,714 ----
*************** 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;
--- 718,727 ----
*
* 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);
}
/*
--- 740,746 ----
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
--- 748,759 ----
*
* 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);
}
/*
--- 785,791 ----
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);
}
--- 1186,1193 ----
*
* 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..09c679b
*** a/src/backend/access/spgist/spgutils.c
--- b/src/backend/access/spgist/spgutils.c
***************
*** 24,30 ****
--- 24,126 ----
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "utils/lsyscache.h"
+ #include "utils/selfuncs.h"
+
+
+ /*
+ * SP-GiST handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ spghandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 5;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = spginsert;
+ amroutine->ambeginscan = spgbeginscan;
+ amroutine->amgettuple = spggettuple;
+ amroutine->amgetbitmap = spggetbitmap;
+ amroutine->amrescan = spgrescan;
+ amroutine->amendscan = spgendscan;
+ amroutine->ammarkpos = spgmarkpos;
+ amroutine->amrestrpos = spgrestrpos;
+ amroutine->ambuild = spgbuild;
+ amroutine->ambuildempty = spgbuildempty;
+ amroutine->ambulkdelete = spgbulkdelete;
+ amroutine->amvacuumcleanup = spgvacuumcleanup;
+ amroutine->amcanreturn = spgcanreturn;
+ amroutine->amcostestimate = spgcostestimate;
+ amroutine->amoptions = spgoptions;
+ amroutine->amvalidate = spgvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ spgvalidate(OpClassInfo *opclass)
+ {
+ ListCell *l;
+ bool procsPresent[SPGISTNProc];
+ int i;
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ foreach(l, opclass->procedures)
+ {
+ OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+
+ if (proc->lefttype != opclass->intype ||
+ proc->righttype != opclass->intype)
+ continue;
+
+ if (proc->number < 1 || proc->number > SPGISTNProc)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for SP-GiST: %u",
+ proc->number)));
+
+ if (procsPresent[proc->number - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u was defined more than once",
+ proc->number)));
+
+ procsPresent[proc->number - 1] = true;
+ }
+
+ for (i = 0; i < SPGISTNProc; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u is required", i + 1)));
+ }
+
+ foreach(l, opclass->operators)
+ {
+ OpFamilyMember *opr = (OpFamilyMember *) lfirst(l);
+
+ if (OidIsValid(opr->sortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST doesn't support ORDER BY operators")));
+ }
+ }
/* Fill in a SpGistTypeDesc struct with info about the specified data type */
static void
*************** 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();
}
/*
--- 585,600 ----
/*
* 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..4e21304
*** a/src/backend/catalog/index.c
--- b/src/backend/catalog/index.c
***************
*** 23,28 ****
--- 23,29 ----
#include <unistd.h>
+ #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 = GetIndexAmRoutineByAmId(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..b794d59
*** 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,169 ----
accessMethodName)));
accessMethodId = HeapTupleGetOid(tuple);
accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
! amRoutine = GetIndexAmRoutine(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;
--- 318,326 ----
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);
--- 493,523 ----
}
accessMethodId = HeapTupleGetOid(tuple);
accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
+ amRoutine = GetIndexAmRoutine(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/opclasscmds.c b/src/backend/commands/opclasscmds.c
new file mode 100644
index 3375f10..4319dd7
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
***************
*** 42,47 ****
--- 42,48 ----
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
+ #include "utils/catcache.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 334,346 ****
ListCell *l;
Relation rel;
HeapTuple tup;
- Form_pg_am pg_am;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
--- 335,348 ----
ListCell *l;
Relation rel;
HeapTuple tup;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
+ IndexAmRoutine *amroutine;
+ OpClassInfo opclassinfo;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 361,373 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
! amstorage = pg_am->amstorage;
/* XXX Should we make any privilege check against the AM? */
--- 363,377 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
!
! amroutine = GetIndexAmRoutineByAmId(amoid);
!
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
! amstorage = amroutine->amstorage;
/* XXX Should we make any privilege check against the AM? */
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 582,587 ****
--- 586,597 ----
stmt->amname)));
}
+ opclassinfo.intype = typeoid;
+ opclassinfo.keytype = storageoid;
+ opclassinfo.procedures = procedures;
+ opclassinfo.operators = operators;
+ amroutine->amvalidate(&opclassinfo);
+
rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
/*
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 718,723 ****
--- 728,816 ----
return myself;
}
+ /*
+ * Collect opclass information for validation.
+ */
+ static void
+ getOpClassInfo(OpClassInfo *opclassinfo, Oid opclassoid)
+ {
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid;
+ CatCList *catlist;
+ int i;
+
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ opclassinfo->intype = classform->opcintype;
+ opclassinfo->keytype = classform->opckeytype;
+ opclassinfo->amoid = classform->opcmethod;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+
+ opclassinfo->operators = NIL;
+ opclassinfo->procedures = NIL;
+
+ /* Find operators */
+ catlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ for (i = 0; i < catlist->n_members; i++)
+ {
+ HeapTuple oprtup = &catlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+ OpFamilyMember *opmember = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
+
+ opmember->object = oprform->amopopr;
+ opmember->number = oprform->amopstrategy;
+ opmember->lefttype = oprform->amoplefttype;
+ opmember->righttype = oprform->amoprighttype;
+ opmember->sortfamily = oprform->amopsortfamily;
+
+ opclassinfo->operators = lappend(opclassinfo->operators, opmember);
+ }
+ ReleaseCatCacheList(catlist);
+
+ /* Find support functions */
+ catlist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+ for (i = 0; i < catlist->n_members; i++)
+ {
+ HeapTuple proctup = &catlist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+ OpFamilyMember *procmember = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
+
+ procmember->object = procform->amproc;
+ procmember->number = procform->amprocnum;
+ procmember->lefttype = procform->amproclefttype;
+ procmember->righttype = procform->amprocrighttype;
+
+ opclassinfo->procedures = lappend(opclassinfo->procedures, procmember);
+ }
+ ReleaseCatCacheList(catlist);
+ }
+
+ /*
+ * Ask access method to validate given opclass.
+ */
+ Datum
+ amvalidate(PG_FUNCTION_ARGS)
+ {
+ OpClassInfo opclassinfo;
+ Oid opclassoid = PG_GETARG_OID(0);
+ IndexAmRoutine *amroutine;
+
+ getOpClassInfo(&opclassinfo, opclassoid);
+
+ amroutine = GetIndexAmRoutineByAmId(opclassinfo.amoid);
+
+ amroutine->amvalidate(&opclassinfo);
+
+ PG_RETURN_BOOL(true);
+ }
+
/*
* DefineOpFamily
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 776,782 ****
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! Form_pg_am pg_am;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
--- 869,875 ----
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! IndexAmRoutine *amroutine;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 787,802 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
/* XXX Should we make any privilege check against the AM? */
- ReleaseSysCache(tup);
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
--- 880,895 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! amroutine = GetIndexAmRoutineByAmId(amoid);
! ReleaseSysCache(tup);
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
/* XXX Should we make any privilege check against the AM? */
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
*************** assignOperTypes(OpFamilyMember *member,
*** 1099,1119 ****
* the family has been created but not yet populated with the required
* operators.)
*/
! HeapTuple amtup;
! Form_pg_am pg_am;
! amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
! if (amtup == NULL)
! elog(ERROR, "cache lookup failed for access method %u", amoid);
! pg_am = (Form_pg_am) GETSTRUCT(amtup);
! if (!pg_am->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! NameStr(pg_am->amname))));
!
! ReleaseSysCache(amtup);
}
else
{
--- 1192,1206 ----
* the family has been created but not yet populated with the required
* operators.)
*/
! IndexAmRoutine *amroutine;
! amroutine = GetIndexAmRoutineByAmId(amoid);
! if (!amroutine->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! get_am_name(amoid))));
}
else
{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
new file mode 100644
index 7668c9d..36b6403
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
*************** ATExecSetRelOptions(Relation rel, List *
*** 9374,9380 ****
(void) view_reloptions(newOptions, true);
break;
case RELKIND_INDEX:
! (void) index_reloptions(rel->rd_am->amoptions, newOptions, true);
break;
default:
ereport(ERROR,
--- 9374,9380 ----
(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
*** 10965,10971 ****
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",
--- 10965,10971 ----
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 163650c..78695e0
*** 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)
*** 536,541 ****
--- 537,543 ----
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)
*** 549,557 ****
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);
--- 551,561 ----
elog(ERROR, "cache lookup failed for access method %u",
idxrelrec->relam);
amrec = (Form_pg_am) GETSTRUCT(ht_am);
+ amroutine = GetIndexAmRoutine(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 1b61fd9..3fa37e2
*** a/src/backend/optimizer/path/costsize.c
--- b/src/backend/optimizer/path/costsize.c
*************** cost_index(IndexPath *path, PlannerInfo
*** 406,419 ****
* 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.
--- 406,413 ----
* 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 14384d5..ca3350b
*** 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
*** 1292,1298 ****
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
--- 1293,1299 ----
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..06f122b
*** a/src/backend/utils/adt/ruleutils.c
--- b/src/backend/utils/adt/ruleutils.c
***************
*** 19,24 ****
--- 19,25 ----
#include <unistd.h>
#include <fcntl.h>
+ #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,1188 ----
/* Add the operator class name, if not default */
get_opclass_name(indclass->values[keyno], keycoltype, &buf);
+ amroutine = GetIndexAmRoutine(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 37fad86..9a83e10
*** a/src/backend/utils/adt/selfuncs.c
--- b/src/backend/utils/adt/selfuncs.c
*************** add_predicate_to_quals(IndexOptInfo *ind
*** 6443,6458 ****
}
! 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;
--- 6443,6453 ----
}
! 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)
*** 6741,6760 ****
*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;
--- 6736,6748 ----
*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)
*** 6794,6813 ****
*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;
--- 6782,6794 ----
*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)
*** 6860,6879 ****
*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;
--- 6841,6853 ----
*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)
*** 6926,6933 ****
*indexTotalCost = costs.indexTotalCost;
*indexSelectivity = costs.indexSelectivity;
*indexCorrelation = costs.indexCorrelation;
-
- PG_RETURN_VOID();
}
--- 6900,6905 ----
*************** gincost_scalararrayopexpr(PlannerInfo *r
*** 7222,7237 ****
/*
* 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;
--- 7194,7204 ----
/*
* 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)
*** 7382,7388 ****
*indexStartupCost = 0;
*indexTotalCost = 0;
*indexSelectivity = 0;
! PG_RETURN_VOID();
}
if (counts.haveFullScan || indexQuals == NIL)
--- 7349,7355 ----
*indexStartupCost = 0;
*indexTotalCost = 0;
*indexSelectivity = 0;
! return;
}
if (counts.haveFullScan || indexQuals == NIL)
*************** gincostestimate(PG_FUNCTION_ARGS)
*** 7504,7526 ****
*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;
--- 7471,7486 ----
*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)
*** 7573,7578 ****
*indexTotalCost += (numTuples * *indexSelectivity) * (cpu_index_tuple_cost + qual_op_cost);
/* XXX what about pages_per_range? */
-
- PG_RETURN_VOID();
}
--- 7533,7536 ----
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
new file mode 100644
index 9c3d096..21f64bc
*** a/src/backend/utils/cache/relcache.c
--- b/src/backend/utils/cache/relcache.c
*************** 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
--- 445,451 ----
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
*** 1160,1165 ****
--- 1160,1231 ----
}
/*
+ * GetIndexAmRoutine - call the specified access method handler routine
+ * to get its IndexAmRoutine struct.
+ */
+ IndexAmRoutine *
+ GetIndexAmRoutine(Oid amhandler)
+ {
+ Datum datum;
+ IndexAmRoutine *routine;
+
+ datum = OidFunctionCall0(amhandler);
+ routine = (IndexAmRoutine *) DatumGetPointer(datum);
+
+ if (routine == NULL || !IsA(routine, IndexAmRoutine))
+ elog(ERROR, "index access method handler function %u did not return an IndexAmRoutine struct",
+ amhandler);
+
+ return routine;
+ }
+
+ /*
+ * GetIndexAmRoutine - look up the handler of the access method
+ * for the given OID, and retrieve its IndexAmRoutine struct.
+ */
+ IndexAmRoutine *
+ GetIndexAmRoutineByAmId(Oid amoid)
+ {
+ HeapTuple tuple;
+ regproc amhandler;
+ Form_pg_am amform;
+
+ /* Get handler function OID for the access method */
+ tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for access method %u",
+ amoid);
+ amform = (Form_pg_am) GETSTRUCT(tuple);
+ amhandler = amform->amhandler;
+
+ /* Complain if handler OID is invalid */
+ if (!RegProcedureIsValid(amhandler))
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("index access method \"%s\" does not have a handler",
+ NameStr(amform->amname))));
+ ReleaseSysCache(tuple);
+
+ /* And finally, call the handler function. */
+ return GetIndexAmRoutine(amhandler);
+ }
+
+ /*
+ * Initialize IndexAmRoutine for relation.
+ */
+ void
+ InitIndexAmRoutine(Relation relation)
+ {
+ IndexAmRoutine *result, *tmp;
+
+ result = (IndexAmRoutine *) MemoryContextAlloc(relation->rd_indexcxt,
+ sizeof(IndexAmRoutine));
+ tmp = GetIndexAmRoutine(relation->rd_am->amhandler);
+ memcpy(result, tmp, sizeof(IndexAmRoutine));
+ relation->amroutine = result;
+ }
+
+ /*
* Initialize index-access-method support data for an index relation
*/
void
*************** RelationInitIndexAccessInfo(Relation rel
*** 1211,1217 ****
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
--- 1277,1282 ----
*************** RelationInitIndexAccessInfo(Relation rel
*** 1228,1233 ****
--- 1293,1303 ----
ALLOCSET_SMALL_MAXSIZE);
relation->rd_indexcxt = indexcxt;
+ /* Initialize index AM routine */
+ InitIndexAmRoutine(relation);
+
+ amsupport = relation->amroutine->amsupport;
+
/*
* Allocate arrays to hold data
*/
*************** load_relcache_init_file(bool shared)
*** 4743,4749 ****
Oid *opfamily;
Oid *opcintype;
RegProcedure *support;
- int nsupport;
int16 *indoption;
Oid *indcollation;
--- 4813,4818 ----
*************** load_relcache_init_file(bool shared)
*** 4771,4776 ****
--- 4840,4846 ----
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)
*** 4832,4843 ****
rel->rd_indoption = indoption;
/* 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
{
--- 4902,4914 ----
rel->rd_indoption = indoption;
+ InitIndexAmRoutine(rel);
+
/* set up zeroed fmgr-info vectors */
rel->rd_aminfo = (RelationAmInfo *)
MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
rel->rd_supportinfo = (FmgrInfo *)
! MemoryContextAllocZero(indexcxt, relform->relnatts * rel->amroutine->amsupport * sizeof(FmgrInfo));
}
else
{
*************** write_relcache_init_file(bool shared)
*** 5106,5112 ****
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
--- 5177,5183 ----
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (rel->amroutine->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h
new file mode 100644
index ...2e0257a
*** a/src/include/access/amapi.h
--- b/src/include/access/amapi.h
***************
*** 0 ****
--- 1,169 ----
+ /*-------------------------------------------------------------------------
+ *
+ * amapi.h
+ * API for access methods
+ *
+ * Copyright (c) 2015, PostgreSQL Global Development Group
+ *
+ * src/include/access/amapi.h
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef AMAPI_H
+ #define AMAPI_H
+
+ #include "access/genam.h"
+ #include "catalog/opfam_internal.h"
+ #include "nodes/relation.h"
+
+ /*
+ * Callback function signatures --- see indexam.sgml for more info.
+ */
+
+ /* "insert this tuple" function */
+ typedef bool
+ (*aminsert_function) (Relation indexRelation,
+ Datum *values,
+ bool *isnull,
+ ItemPointer heap_tid,
+ Relation heapRelation,
+ IndexUniqueCheck checkUnique);
+
+ /* "prepare for index scan" function */
+ typedef IndexScanDesc
+ (*ambeginscan_function) (Relation indexRelation,
+ int nkeys,
+ int norderbys);
+
+ /* "next valid tuple" function, or NULL */
+ typedef bool
+ (*amgettuple_function) (IndexScanDesc scan,
+ ScanDirection direction);
+
+ /* "fetch all valid tuples" function, or NULL */
+ typedef int64
+ (*amgetbitmap_function) (IndexScanDesc scan,
+ TIDBitmap *tbm);
+
+ /* "(re)start index scan" function */
+ typedef void
+ (*amrescan_function) (IndexScanDesc scan,
+ ScanKey keys,
+ int nkeys,
+ ScanKey orderbys,
+ int norderbys);
+
+ /* "end index scan" function */
+ typedef void
+ (*amendscan_function) (IndexScanDesc scan);
+
+ /* "mark current scan position" function */
+ typedef void
+ (*ammarkpos_function) (IndexScanDesc scan);
+
+ /* "restore marked scan position" function */
+ typedef void
+ (*amrestrpos_function) (IndexScanDesc scan);
+
+ /* "build new index" function */
+ typedef IndexBuildResult *
+ (*ambuild_function) (Relation heapRelation,
+ Relation indexRelation,
+ IndexInfo *indexInfo);
+
+ /* "build empty index" function */
+ typedef void
+ (*ambuildempty_function) (Relation indexRelation);
+
+ /* bulk-delete function */
+ typedef IndexBulkDeleteResult *
+ (*ambulkdelete_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+
+ /* post-VACUUM cleanup function */
+ typedef IndexBulkDeleteResult *
+ (*amvacuumcleanup_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
+
+ /* can indexscan return IndexTuples? */
+ typedef bool
+ (*amcanreturn_function) (Relation indexRelation, int attno);
+
+ /* estimate cost of an indexscan */
+ typedef void
+ (*amcostestimate_function) (PlannerInfo *root,
+ IndexPath *path,
+ double loop_count,
+ Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+
+ /* parse AM-specific parameters */
+ typedef bytea *
+ (*amoptions_function) (Datum reloptions,
+ bool validate);
+
+ /* validate oplass */
+ typedef void
+ (*amvalidate_function) (OpClassInfo *opclass);
+
+
+ struct IndexAmRoutine
+ {
+ NodeTag type;
+
+ /*
+ * Total number of strategies (operators) by which we can traverse/search
+ * this AM. Zero if AM does not have a fixed set of strategy assignments.
+ */
+ int16 amstrategies;
+ /* total number of support functions that this AM uses */
+ int16 amsupport;
+ /* does AM support order by column value? */
+ bool amcanorder;
+ /* does AM support order by operator result? */
+ bool amcanorderbyop;
+ /* does AM support backward scan? */
+ bool amcanbackward;
+ /* does AM support UNIQUE indexes? */
+ bool amcanunique;
+ /* does AM support multi-column indexes? */
+ bool amcanmulticol;
+ /* can query omit key for the first column? */
+ bool amoptionalkey;
+ /* can AM handle ScalarArrayOpExpr quals? */
+ bool amsearcharray;
+ /* can AM search for NULL/NOT NULL entries? */
+ bool amsearchnulls;
+ /* can storage type differ from column type? */
+ bool amstorage;
+ /* does AM support cluster command? */
+ bool amclusterable;
+ /* does AM handle predicate locks? */
+ bool ampredlocks;
+ /* type of data in index, or InvalidOid */
+ Oid amkeytype;
+
+ /* interface functions */
+ aminsert_function aminsert;
+ ambeginscan_function ambeginscan;
+ amgettuple_function amgettuple;
+ amgetbitmap_function amgetbitmap;
+ amrescan_function amrescan;
+ amendscan_function amendscan;
+ ammarkpos_function ammarkpos;
+ amrestrpos_function amrestrpos;
+ ambuild_function ambuild;
+ ambuildempty_function ambuildempty;
+ ambulkdelete_function ambulkdelete;
+ amvacuumcleanup_function amvacuumcleanup;
+ amcanreturn_function amcanreturn;
+ amcostestimate_function amcostestimate;
+ amoptions_function amoptions;
+ amvalidate_function amvalidate;
+ };
+
+ #endif /* AMAPI_H */
diff --git a/src/include/access/brin.h b/src/include/access/brin.h
new file mode 100644
index e72fb2d..5ae5722
*** 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,51 ----
/*
* prototypes for functions in brin.c (external entry points for BRIN)
*/
! extern Datum brinhandler(PG_FUNCTION_ARGS);
! extern void brinvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *brinbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void brinbuildempty(Relation index);
! extern bool brininsert(Relation idxRel, Datum *values, bool *nulls,
! ItemPointer heaptid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys);
! extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
! ScanKey orderbys, int norderbys);
! extern void brinendscan(IndexScanDesc scan);
! extern void brinmarkpos(IndexScanDesc scan);
! extern void brinrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *brinbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *brinvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern void brincostestimate(PlannerInfo *root, IndexPath *path,
! double loop_count, Cost *indexStartupCost,
! Cost *indexTotalCost,
! Selectivity *indexSelectivity,
! double *indexCorrelation);
! extern bytea *brinoptions(Datum reloptions, bool validate);
/*
* Storage type for BRIN's reloptions
diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h
new file mode 100644
index 6be199e..cd72544
*** a/src/include/access/brin_internal.h
--- b/src/include/access/brin_internal.h
*************** typedef struct BrinDesc
*** 71,76 ****
--- 71,77 ----
#define BRIN_PROCNUM_ADDVALUE 2
#define BRIN_PROCNUM_CONSISTENT 3
#define BRIN_PROCNUM_UNION 4
+ #define BRIN_MANDATORY_NPROCS 4
/* procedure numbers up to 10 are reserved for BRIN future expansion */
#undef BRIN_DEBUG
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 5021887..a77d43f
*** 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,601 ----
/* ginutil.c */
! extern Datum ginhandler(PG_FUNCTION_ARGS);
! extern void ginvalidate(OpClassInfo *opclass);
! extern bytea *ginoptions(Datum reloptions, bool validate);
extern void initGinState(GinState *state, Relation index);
extern Buffer GinNewBuffer(Relation index);
extern void GinInitBuffer(Buffer b, uint32 f);
*************** 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,
--- 616,627 ----
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);
--- 872,899 ----
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 1a77982..35fb34a
*** 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
*** 426,434 ****
} 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);
--- 427,439 ----
} GiSTOptions;
/* gist.c */
! extern Datum gisthandler(PG_FUNCTION_ARGS);
! extern void gistvalidate(OpClassInfo *opclass);
! extern void gistbuildempty(Relation index);
! extern bool gistinsert(Relation r, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern bool gistcanreturn(Relation index, int attno);
extern MemoryContext createTempGistContext(void);
extern GISTSTATE *initGISTstate(Relation index);
extern void freeGISTstate(GISTSTATE *giststate);
*************** extern XLogRecPtr gistXLogSplit(RelFileN
*** 474,481 ****
Buffer leftchild, bool markfollowright);
/* gistget.c */
! extern Datum gistgettuple(PG_FUNCTION_ARGS);
! extern Datum gistgetbitmap(PG_FUNCTION_ARGS);
/* gistutil.c */
--- 479,486 ----
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
*** 485,491 ****
#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);
--- 490,496 ----
#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 *
*** 534,541 ****
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,
--- 539,550 ----
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
*** 544,550 ****
int attno);
/* gistbuild.c */
! extern Datum gistbuild(PG_FUNCTION_ARGS);
extern void gistValidateBufferingOption(char *value);
/* gistbuildbuffers.c */
--- 553,560 ----
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..9595c6b
*** 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,271 ----
/* public routines */
! extern Datum hashhandler(PG_FUNCTION_ARGS);
! extern void hashvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *hashbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void hashbuildempty(Relation index);
! extern bool hashinsert(Relation rel, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc hashbeginscan(Relation rel, int nkeys, int norderbys);
! extern bool hashgettuple(IndexScanDesc scan, ScanDirection dir);
! extern int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void hashrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
! ScanKey orderbys, int norderbys);
! extern void hashendscan(IndexScanDesc scan);
! extern void hashmarkpos(IndexScanDesc scan);
! extern void hashrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *hashbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *hashvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern bytea *hashoptions(Datum reloptions, bool validate);
/*
* Datatype-specific hash functions in hashfunc.c.
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
new file mode 100644
index 9e48efd..4fab0a3
*** 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,683 ----
/*
* prototypes for functions in nbtree.c (external entry points for btree)
*/
! extern Datum bthandler(PG_FUNCTION_ARGS);
! extern void btvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *btbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void btbuildempty(Relation index);
! extern bool btinsert(Relation rel, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc btbeginscan(Relation indexRelation,
! int nkeys, int norderbys);
! extern bool btgettuple(IndexScanDesc scan, ScanDirection dir);
! extern int64 btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void btrescan(IndexScanDesc scan, ScanKey keys, int nkeys,
! ScanKey orderbys, int norderbys);
! extern void btendscan(IndexScanDesc scan);
! extern void btmarkpos(IndexScanDesc scan);
! extern void btrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *btbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *btvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern bool btcanreturn(Relation index, int attno);
! extern bytea *btoptions(Datum reloptions, bool validate);
/*
* prototypes for functions in nbtinsert.c
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
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..ba2c1c1
*** 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,212 ----
} spgLeafConsistentOut;
+ /* spgutils.c */
+ extern Datum spghandler(PG_FUNCTION_ARGS);
+ extern void spgvalidate(OpClassInfo *opclass);
+
/* 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/opfam_internal.h b/src/include/catalog/opfam_internal.h
new file mode 100644
index 32195a7..2cbefe9
*** a/src/include/catalog/opfam_internal.h
--- b/src/include/catalog/opfam_internal.h
*************** typedef struct
*** 25,28 ****
--- 25,41 ----
Oid sortfamily; /* ordering operator's sort opfamily, or 0 */
} OpFamilyMember;
+ /*
+ * Opclass data for validation by access method.
+ */
+ typedef struct
+ {
+ Oid amoid; /* access method OID */
+ Oid intype; /* input datatype */
+ Oid keytype; /* key datatype */
+ List *procedures; /* list of OpFamilyMember */
+ List *operators; /* list of OpFamilyMember */
+ } OpClassInfo;
+
+
#endif /* OPFAM_INTERNAL_H */
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
new file mode 100644
index 8a28b8e..f19a873
*** 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,40 ----
CATALOG(pg_am,2601)
{
NameData amname; /* access method name */
! regproc amhandler; /* handler function */
} 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
--- 48,78 ----
* compiler constants for pg_am
* ----------------
*/
! #define Natts_pg_am 2
#define Anum_pg_am_amname 1
! #define Anum_pg_am_amhandler 2
/* ----------------
* initial contents of pg_am
* ----------------
*/
! DATA(insert OID = 403 ( btree bthandler ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
! DATA(insert OID = 405 ( hash hashhandler ));
DESCR("hash index access method");
#define HASH_AM_OID 405
! DATA(insert OID = 783 ( gist gisthandler ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
! DATA(insert OID = 2742 ( gin ginhandler ));
DESCR("GIN index access method");
#define GIN_AM_OID 2742
! DATA(insert OID = 4000 ( spgist spghandler ));
DESCR("SP-GiST index access method");
#define SPGIST_AM_OID 4000
! DATA(insert OID = 3580 ( brin brinhandler ));
DESCR("block range index (BRIN) access method");
#define BRIN_AM_OID 3580
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index eb55b3a..587aaac
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DESCR("convert int4 to float4");
*** 547,609 ****
DATA(insert OID = 319 ( int4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "700" _null_ _null_ _null_ _null_ _null_ ftoi4 _null_ _null_ _null_ ));
DESCR("convert float4 to int4");
- DATA(insert OID = 330 ( btgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgettuple _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 636 ( btgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgetbitmap _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 331 ( btinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btinsert _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 333 ( btbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbeginscan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 334 ( btrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btrescan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 335 ( btendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btendscan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 336 ( btmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btmarkpos _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 337 ( btrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btrestrpos _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 338 ( btbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbuild _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 328 ( btbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btbuildempty _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 332 ( btbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbulkdelete _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ btvacuumcleanup _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 276 ( btcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ btcanreturn _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 1268 ( btcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btcostestimate _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 2785 ( btoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ btoptions _null_ _null_ _null_ ));
- DESCR("btree(internal)");
-
- DATA(insert OID = 3789 ( bringetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ bringetbitmap _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3790 ( brininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brininsert _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3791 ( brinbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbeginscan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3792 ( brinrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinrescan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3793 ( brinendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinendscan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3794 ( brinmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinmarkpos _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3795 ( brinrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinrestrpos _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3796 ( brinbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbuild _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3797 ( brinbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinbuildempty _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3798 ( brinbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbulkdelete _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3799 ( brinvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ brinvacuumcleanup _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3800 ( brincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brincostestimate _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3801 ( brinoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ brinoptions _null_ _null_ _null_ ));
- DESCR("brin(internal)");
DATA(insert OID = 3952 ( brin_summarize_new_values PGNSP PGUID 12 1 0 0 0 f f f f f f v s 1 0 23 "2205" _null_ _null_ _null_ _null_ _null_ brin_summarize_new_values _null_ _null_ _null_ ));
DESCR("brin: standalone scan new table pages");
--- 547,552 ----
*************** DESCR("convert name to char(n)");
*** 694,728 ****
DATA(insert OID = 409 ( name PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 19 "1042" _null_ _null_ _null_ _null_ _null_ bpchar_name _null_ _null_ _null_ ));
DESCR("convert char(n) to name");
- DATA(insert OID = 440 ( hashgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgettuple _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 637 ( hashgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgetbitmap _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 441 ( hashinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashinsert _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 443 ( hashbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbeginscan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 444 ( hashrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashrescan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 445 ( hashendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashendscan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 446 ( hashmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashmarkpos _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 447 ( hashrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashrestrpos _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 448 ( hashbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbuild _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 327 ( hashbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashbuildempty _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 442 ( hashbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbulkdelete _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashvacuumcleanup _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 438 ( hashcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashcostestimate _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 2786 ( hashoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ hashoptions _null_ _null_ _null_ ));
- DESCR("hash(internal)");
-
DATA(insert OID = 449 ( hashint2 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "21" _null_ _null_ _null_ _null_ _null_ hashint2 _null_ _null_ _null_ ));
DESCR("hash");
DATA(insert OID = 450 ( hashint4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ hashint4 _null_ _null_ _null_ ));
--- 637,642 ----
*************** DESCR("larger of two");
*** 978,1014 ****
DATA(insert OID = 771 ( int2smaller PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2smaller _null_ _null_ _null_ ));
DESCR("smaller of two");
- DATA(insert OID = 774 ( gistgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgettuple _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 638 ( gistgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgetbitmap _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 775 ( gistinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistinsert _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 777 ( gistbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbeginscan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 778 ( gistrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistrescan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 779 ( gistendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistendscan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 780 ( gistmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistmarkpos _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 781 ( gistrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistrestrpos _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 782 ( gistbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbuild _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 326 ( gistbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistbuildempty _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 776 ( gistbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbulkdelete _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistvacuumcleanup _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 3280 ( gistcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ gistcanreturn _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 772 ( gistcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistcostestimate _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 2787 ( gistoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ gistoptions _null_ _null_ _null_ ));
- DESCR("gist(internal)");
-
DATA(insert OID = 784 ( tintervaleq PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervaleq _null_ _null_ _null_ ));
DATA(insert OID = 785 ( tintervalne PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervalne _null_ _null_ _null_ ));
DATA(insert OID = 786 ( tintervallt PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervallt _null_ _null_ _null_ ));
--- 892,897 ----
*************** DATA(insert OID = 3311 ( tsm_handler_in
*** 3740,3745 ****
--- 3623,3632 ----
DESCR("I/O");
DATA(insert OID = 3312 ( tsm_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "3310" _null_ _null_ _null_ _null_ _null_ tsm_handler_out _null_ _null_ _null_ ));
DESCR("I/O");
+ DATA(insert OID = 326 ( index_am_handler_in PGNSP PGUID 12 1 0 0 0 f f f f f f i s 1 0 325 "2275" _null_ _null_ _null_ _null_ _null_ index_am_handler_in _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 327 ( index_am_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "325" _null_ _null_ _null_ _null_ _null_ index_am_handler_out _null_ _null_ _null_ ));
+ DESCR("I/O");
/* tablesample method handlers */
DATA(insert OID = 3313 ( bernoulli PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 3310 "2281" _null_ _null_ _null_ _null_ _null_ tsm_bernoulli_handler _null_ _null_ _null_ ));
*************** DESCR("GiST support");
*** 4196,4229 ****
DATA(insert OID = 3288 ( gist_bbox_distance PGNSP PGUID 12 1 0 0 0 f f f f t f i s 4 0 701 "2281 600 23 26" _null_ _null_ _null_ _null_ _null_ gist_bbox_distance _null_ _null_ _null_ ));
DESCR("GiST support");
- /* GIN */
- DATA(insert OID = 2731 ( gingetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gingetbitmap _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2732 ( gininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gininsert _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2733 ( ginbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbeginscan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2734 ( ginrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginrescan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2735 ( ginendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginendscan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2736 ( ginmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginmarkpos _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2737 ( ginrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginrestrpos _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2738 ( ginbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbuild _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 325 ( ginbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginbuildempty _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2739 ( ginbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbulkdelete _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ ginvacuumcleanup _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2741 ( gincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gincostestimate _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2788 ( ginoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ ginoptions _null_ _null_ _null_ ));
- DESCR("gin(internal)");
-
/* GIN array support */
DATA(insert OID = 2743 ( ginarrayextract PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 2281 "2277 2281 2281" _null_ _null_ _null_ _null_ _null_ ginarrayextract _null_ _null_ _null_ ));
DESCR("GIN array support");
--- 4083,4088 ----
*************** DESCR("construct timestamp with time zon
*** 5119,5156 ****
DATA(insert OID = 3464 ( make_interval PGNSP PGUID 12 1 0 0 0 f f f f t f i s 7 0 1186 "23 23 23 23 23 23 701" _null_ _null_ "{years,months,weeks,days,hours,mins,secs}" _null_ _null_ make_interval _null_ _null_ _null_ ));
DESCR("construct interval");
- /* spgist support functions */
- DATA(insert OID = 4001 ( spggettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggettuple _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4002 ( spggetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggetbitmap _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4003 ( spginsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spginsert _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4004 ( spgbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbeginscan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4005 ( spgrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgrescan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4006 ( spgendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgendscan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4007 ( spgmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgmarkpos _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4008 ( spgrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgrestrpos _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4009 ( spgbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbuild _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4010 ( spgbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgbuildempty _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4011 ( spgbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbulkdelete _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4012 ( spgvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ spgvacuumcleanup _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4032 ( spgcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ spgcanreturn _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4013 ( spgcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgcostestimate _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4014 ( spgoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ spgoptions _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
-
/* spgist opclasses */
DATA(insert OID = 4018 ( spg_quad_config PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_quad_config _null_ _null_ _null_ ));
DESCR("SP-GiST support for quad tree over point");
--- 4978,4983 ----
*************** DESCR("get an individual replication ori
*** 5333,5338 ****
--- 5160,5184 ----
DATA(insert OID = 6014 ( pg_show_replication_origin_status PGNSP PGUID 12 1 100 0 0 f f f f f t v r 0 0 2249 "" "{26,25,3220,3220}" "{o,o,o,o}" "{local_id, external_id, remote_lsn, local_lsn}" _null_ _null_ pg_show_replication_origin_status _null_ _null_ _null_ ));
DESCR("get progress for all replication origins");
+ /* Access methods handlers */
+ DATA(insert OID = 330 ( bthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ bthandler _null_ _null_ _null_ ));
+ DESCR("btree handler");
+ DATA(insert OID = 331 ( hashhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ hashhandler _null_ _null_ _null_ ));
+ DESCR("hash handler");
+ DATA(insert OID = 332 ( gisthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ gisthandler _null_ _null_ _null_ ));
+ DESCR("gist handler");
+ DATA(insert OID = 333 ( ginhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ ginhandler _null_ _null_ _null_ ));
+ DESCR("gin handler");
+ DATA(insert OID = 334 ( spghandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ spghandler _null_ _null_ _null_ ));
+ DESCR("spgist handler");
+ DATA(insert OID = 335 ( brinhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ brinhandler _null_ _null_ _null_ ));
+ DESCR("brin handler");
+
+ DATA(insert OID = 336 ( amvalidate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 16 "26" _null_ _null_ _null_ _null_ _null_ amvalidate _null_ _null_ _null_ ));
+ DESCR("ask access method to validate opclass");
+
+
+
/*
* Symbolic values for provolatile column: these indicate whether the result
* of a function is dependent *only* on the values of its explicit arguments,
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
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/commands/defrem.h b/src/include/commands/defrem.h
new file mode 100644
index adae296..d8b9649
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
*************** extern Oid get_am_oid(const char *amname
*** 95,100 ****
--- 95,101 ----
extern char *get_am_name(Oid amOid);
extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+ extern Datum amvalidate(PG_FUNCTION_ARGS);
/* commands/tsearchcmds.c */
extern ObjectAddress DefineTSParser(List *names, List *parameters);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
new file mode 100644
index b6895f9..0ed8a96
*** 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 94bdb7c..84e4a36
*** a/src/include/nodes/nodes.h
--- b/src/include/nodes/nodes.h
*************** typedef enum NodeTag
*** 455,461 ****
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;
/*
--- 455,462 ----
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 6cf2e24..3c51bf3
*** 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
*** 548,555 ****
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 */
--- 549,555 ----
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
*** 560,571 ****
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;
--- 560,571 ----
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
*** 819,825 ****
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! typedef struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
--- 819,825 ----
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
*************** typedef struct IndexPath
*** 831,837 ****
ScanDirection indexscandir;
Cost indextotalcost;
Selectivity indexselectivity;
! } IndexPath;
/*
* BitmapHeapPath represents one or more indexscans that generate TID bitmaps
--- 831,837 ----
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..e686c9e
*** 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,45 ----
*/
typedef Relation *RelationPtr;
+ typedef struct IndexAmRoutine IndexAmRoutine;
+
+ /*
+ * Routines to retreive IndexAmRoutine
+ */
+ extern IndexAmRoutine *GetIndexAmRoutine(Oid amhandler);
+ extern IndexAmRoutine *GetIndexAmRoutineByAmId(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 a7433d9..3745d1c
*** a/src/include/utils/selfuncs.h
--- b/src/include/utils/selfuncs.h
*************** extern double estimate_num_groups(Planne
*** 191,202 ****
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 */
--- 191,226 ----
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/alter_table.out b/src/test/regress/expected/alter_table.out
new file mode 100644
index 44ce6f5..9e3b599
*** a/src/test/regress/expected/alter_table.out
--- b/src/test/regress/expected/alter_table.out
*************** create type alter1.ctype as (f1 int, f2
*** 2124,2131 ****
create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql
as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
create text search configuration alter1.cfg(parser = alter1.prs);
--- 2124,2134 ----
create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql
as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
+ create function alter1.hash(alter1.ctype) returns int4 language sql
+ as 'select hashint4($1.f1) # hashtext($1.f2)';
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype),
! function 1 alter1.hash(alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
create text search configuration alter1.cfg(parser = alter1.prs);
*************** alter operator class alter1.ctype_hash_o
*** 2141,2146 ****
--- 2144,2150 ----
alter operator family alter1.ctype_hash_ops using hash set schema alter2;
alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
+ alter function alter1.hash(alter1.ctype) set schema alter2;
alter type alter1.ctype set schema alter2;
alter conversion alter1.ascii_to_utf8 set schema alter2;
alter text search parser alter1.prs set schema alter2;
*************** select alter2.plus1(41);
*** 2177,2183 ****
-- clean up
drop schema alter2 cascade;
! NOTICE: drop cascades to 13 other objects
DETAIL: drop cascades to table alter2.t1
drop cascades to view alter2.v1
drop cascades to function alter2.plus1(integer)
--- 2181,2187 ----
-- clean up
drop schema alter2 cascade;
! NOTICE: drop cascades to 14 other objects
DETAIL: drop cascades to table alter2.t1
drop cascades to view alter2.v1
drop cascades to function alter2.plus1(integer)
*************** drop cascades to operator family alter2.
*** 2186,2191 ****
--- 2190,2196 ----
drop cascades to type alter2.ctype
drop cascades to function alter2.same(alter2.ctype,alter2.ctype)
drop cascades to operator alter2.=(alter2.ctype,alter2.ctype)
+ drop cascades to function alter2.hash(alter2.ctype)
drop cascades to conversion ascii_to_utf8
drop cascades to text search parser prs
drop cascades to text search configuration cfg
diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out
new file mode 100644
index d85bc83..d1a322d
*** a/src/test/regress/expected/oidjoins.out
--- b/src/test/regress/expected/oidjoins.out
*************** WHERE aggmtranstype != 0 AND
*** 73,206 ****
------+---------------
(0 rows)
- SELECT ctid, amkeytype
- FROM pg_catalog.pg_am fk
- WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
- ctid | amkeytype
- ------+-----------
- (0 rows)
-
- SELECT ctid, aminsert
- FROM pg_catalog.pg_am fk
- WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
- ctid | aminsert
- ------+----------
- (0 rows)
-
- SELECT ctid, ambeginscan
- FROM pg_catalog.pg_am fk
- WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
- ctid | ambeginscan
- ------+-------------
- (0 rows)
-
- SELECT ctid, amgettuple
- FROM pg_catalog.pg_am fk
- WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- ctid | amgettuple
- ------+------------
- (0 rows)
-
- SELECT ctid, amgetbitmap
- FROM pg_catalog.pg_am fk
- WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
- ctid | amgetbitmap
- ------+-------------
- (0 rows)
-
- SELECT ctid, amrescan
- FROM pg_catalog.pg_am fk
- WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
- ctid | amrescan
- ------+----------
- (0 rows)
-
- SELECT ctid, amendscan
- FROM pg_catalog.pg_am fk
- WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
- ctid | amendscan
- ------+-----------
- (0 rows)
-
- SELECT ctid, ammarkpos
- FROM pg_catalog.pg_am fk
- WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
- ctid | ammarkpos
- ------+-----------
- (0 rows)
-
- SELECT ctid, amrestrpos
- FROM pg_catalog.pg_am fk
- WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
- ctid | amrestrpos
- ------+------------
- (0 rows)
-
- SELECT ctid, ambuild
- FROM pg_catalog.pg_am fk
- WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
- ctid | ambuild
- ------+---------
- (0 rows)
-
- SELECT ctid, ambuildempty
- FROM pg_catalog.pg_am fk
- WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
- ctid | ambuildempty
- ------+--------------
- (0 rows)
-
- SELECT ctid, ambulkdelete
- FROM pg_catalog.pg_am fk
- WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
- ctid | ambulkdelete
- ------+--------------
- (0 rows)
-
- SELECT ctid, amvacuumcleanup
- FROM pg_catalog.pg_am fk
- WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
- ctid | amvacuumcleanup
- ------+-----------------
- (0 rows)
-
- SELECT ctid, amcanreturn
- FROM pg_catalog.pg_am fk
- WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
- ctid | amcanreturn
- ------+-------------
- (0 rows)
-
- SELECT ctid, amcostestimate
- FROM pg_catalog.pg_am fk
- WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
- ctid | amcostestimate
- ------+----------------
- (0 rows)
-
- SELECT ctid, amoptions
- FROM pg_catalog.pg_am fk
- WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
- ctid | amoptions
- ------+-----------
- (0 rows)
-
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 73,78 ----
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
new file mode 100644
index df29fe5..708d84c
*** a/src/test/regress/expected/opr_sanity.out
--- b/src/test/regress/expected/opr_sanity.out
*************** WHERE p1.oid != p2.oid AND
*** 1479,1484 ****
--- 1479,1490 ----
-----+-----
(0 rows)
+ -- Ask access methods to validate opclasses
+ SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid);
+ oid
+ -----
+ (0 rows)
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
SELECT p1.amopfamily, p1.amopstrategy
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 1524,1572 ****
------------+--------------
(0 rows)
- -- check for ordering operators not supported by parent AM
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
- amopfamily | amopopr | oid | amname
- ------------+---------+-----+--------
- (0 rows)
-
- -- Cross-check amopstrategy index against parent AM
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
- amopfamily | amopopr | oid | amname
- ------------+---------+-----+--------
- (0 rows)
-
- -- Detect missing pg_amop entries: should have as many strategy operators
- -- as AM expects for each datatype combination supported by the opfamily.
- -- We can't check this for AMs with variable strategy sets.
- SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
- amname | amoplefttype | amoprighttype
- --------+--------------+---------------
- (0 rows)
-
- -- Currently, none of the AMs with fixed strategy sets support ordering ops.
- SELECT p1.amname, p2.amopfamily, p2.amopstrategy
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
- amname | amopfamily | amopstrategy
- --------+------------+--------------
- (0 rows)
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
--- 1530,1535 ----
*************** WHERE p1.amprocfamily = 0 OR p1.amprocle
*** 1849,1863 ****
--------------+-----------
(0 rows)
- -- Cross-check amprocnum index against parent AM
- SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
- FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
- WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
- amprocfamily | amprocnum | oid | amname
- --------------+-----------+-----+--------
- (0 rows)
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
SELECT * FROM (
--- 1812,1817 ----
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
new file mode 100644
index 778791d..a426ef5
*** a/src/test/regress/sql/alter_table.sql
--- b/src/test/regress/sql/alter_table.sql
*************** as 'select $1.f1 is not distinct from $2
*** 1452,1459 ****
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
--- 1452,1463 ----
create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
+ create function alter1.hash(alter1.ctype) returns int4 language sql
+ as 'select hashint4($1.f1) # hashtext($1.f2)';
+
create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
! operator 1 alter1.=(alter1.ctype, alter1.ctype),
! function 1 alter1.hash(alter1.ctype);
create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
*************** alter operator class alter1.ctype_hash_o
*** 1473,1478 ****
--- 1477,1483 ----
alter operator family alter1.ctype_hash_ops using hash set schema alter2;
alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
+ alter function alter1.hash(alter1.ctype) set schema alter2;
alter type alter1.ctype set schema alter2;
alter conversion alter1.ascii_to_utf8 set schema alter2;
alter text search parser alter1.prs set schema alter2;
diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql
new file mode 100644
index 2fa628d..ca419fd
*** a/src/test/regress/sql/oidjoins.sql
--- b/src/test/regress/sql/oidjoins.sql
*************** SELECT ctid, aggmtranstype
*** 37,106 ****
FROM pg_catalog.pg_aggregate fk
WHERE aggmtranstype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
- SELECT ctid, amkeytype
- FROM pg_catalog.pg_am fk
- WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
- SELECT ctid, aminsert
- FROM pg_catalog.pg_am fk
- WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
- SELECT ctid, ambeginscan
- FROM pg_catalog.pg_am fk
- WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
- SELECT ctid, amgettuple
- FROM pg_catalog.pg_am fk
- WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- SELECT ctid, amgetbitmap
- FROM pg_catalog.pg_am fk
- WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
- SELECT ctid, amrescan
- FROM pg_catalog.pg_am fk
- WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
- SELECT ctid, amendscan
- FROM pg_catalog.pg_am fk
- WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
- SELECT ctid, ammarkpos
- FROM pg_catalog.pg_am fk
- WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
- SELECT ctid, amrestrpos
- FROM pg_catalog.pg_am fk
- WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
- SELECT ctid, ambuild
- FROM pg_catalog.pg_am fk
- WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
- SELECT ctid, ambuildempty
- FROM pg_catalog.pg_am fk
- WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
- SELECT ctid, ambulkdelete
- FROM pg_catalog.pg_am fk
- WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
- SELECT ctid, amvacuumcleanup
- FROM pg_catalog.pg_am fk
- WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
- SELECT ctid, amcanreturn
- FROM pg_catalog.pg_am fk
- WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
- SELECT ctid, amcostestimate
- FROM pg_catalog.pg_am fk
- WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
- SELECT ctid, amoptions
- FROM pg_catalog.pg_am fk
- WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 37,42 ----
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
new file mode 100644
index c9bdd77..0e0506e
*** a/src/test/regress/sql/opr_sanity.sql
--- b/src/test/regress/sql/opr_sanity.sql
*************** WHERE p1.oid != p2.oid AND
*** 960,965 ****
--- 960,969 ----
p1.opcmethod = p2.opcmethod AND p1.opcintype = p2.opcintype AND
p1.opcdefault AND p2.opcdefault;
+ -- Ask access methods to validate opclasses
+
+ SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid);
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 995,1035 ****
(SELECT 1 from pg_opfamily op WHERE op.oid = p1.amopsortfamily
AND op.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree'));
- -- check for ordering operators not supported by parent AM
-
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
-
- -- Cross-check amopstrategy index against parent AM
-
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
-
- -- Detect missing pg_amop entries: should have as many strategy operators
- -- as AM expects for each datatype combination supported by the opfamily.
- -- We can't check this for AMs with variable strategy sets.
-
- SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
-
- -- Currently, none of the AMs with fixed strategy sets support ordering ops.
-
- SELECT p1.amname, p2.amopfamily, p2.amopstrategy
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
--- 999,1004 ----
*************** FROM pg_amproc as p1
*** 1176,1188 ****
WHERE p1.amprocfamily = 0 OR p1.amproclefttype = 0 OR p1.amprocrighttype = 0
OR p1.amprocnum < 1 OR p1.amproc = 0;
- -- Cross-check amprocnum index against parent AM
-
- SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
- FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
- WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
--- 1145,1150 ----
On 2015-10-12 14:32, Alexander Korotkov wrote:
Also, it was planned that documentation changes would be reviewed by
native english speaker.
BTW I think this is ready for committer, except for the need to check
docs by native speaker.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Petr Jelinek <petr@2ndquadrant.com> writes:
On 2015-10-12 14:32, Alexander Korotkov wrote:
Also, it was planned that documentation changes would be reviewed by
native english speaker.
BTW I think this is ready for committer, except for the need to check
docs by native speaker.
I'm working at Salesforce this week, but will take a look after I get
home.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Thu, Oct 22, 2015 at 8:37 AM, Petr Jelinek wrote:
BTW I think this is ready for committer, except for the need to check docs
by native speaker.
If so, could you update the entry of this patch accordingly?
https://commitfest.postgresql.org/6/353/
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Alexander Korotkov <a.korotkov@postgrespro.ru> writes:
Tom, could you take a look at them?
I started to look at this today. (Apologies for the delay, but I came
back from San Francisco with a nasty head cold, and wasn't really up to
doing anything complicated last week.)
The thing that jumps out at me right away is that the proposed new amapi.h
header has this:
+ #include "nodes/relation.h"
to support declaring amcostestimate_function. This will result in
importing the planner's declarations into pretty much every part of the
executor, because not only is amapi.h #included by a lot of places, but
the proposed patch actually has execnodes.h including it, as well as some
other popular headers. We might as well shove everything into postgres.h
and forget about header modularity altogether.
Probably the least messy way to fix this is to drop that #include and
instead use dummy declarations like "struct PlannerInfo;" and "struct
IndexPath;" here. We could additionally dumb the amcostestimate
declaration down from using "Cost" and "Selectivity" to just saying
"double".
A different line of attack would be to try to divide amapi.h into
"executor" and "planner" parts, but I'm not sure I see how to make that
work. Somewhere you gotta declare the struct of function pointers.
(Note: I realize that there's a precedent in fdwapi.h of including planner
headers into what's otherwise mostly an executor thing. That one's not
quite as destructive to header modularity because it's not used in as many
places as amapi.h will be. But maybe we should rethink that as well.)
Thoughts, better ideas?
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Tom Lane wrote:
Probably the least messy way to fix this is to drop that #include and
instead use dummy declarations like "struct PlannerInfo;" and "struct
IndexPath;" here. We could additionally dumb the amcostestimate
declaration down from using "Cost" and "Selectivity" to just saying
"double".
I'm not a fan of this approach. I'd rather split the executor headers
in two, a leanone with the typedefs only and another with the actual
struct definitions. That way we have one very lean executor header that
can be included everywhere (in headers and .c files that only pass the
structs around), and a fat one that is only included by the executor .c
files (and the few extra .c files that need access to the struct
definitions).
This would be similar in spirit to the htup.h / htup_details.h split.
I think (almost?) all the headers that define nodes suffer from this
disease and could be cured in the same way.
(Note: I realize that there's a precedent in fdwapi.h of including planner
headers into what's otherwise mostly an executor thing. That one's not
quite as destructive to header modularity because it's not used in as many
places as amapi.h will be. But maybe we should rethink that as well.)
Yes, rethink++.
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
Tom Lane wrote:
Probably the least messy way to fix this is to drop that #include and
instead use dummy declarations like "struct PlannerInfo;" and "struct
IndexPath;" here. We could additionally dumb the amcostestimate
declaration down from using "Cost" and "Selectivity" to just saying
"double".
I'm not a fan of this approach. I'd rather split the executor headers
in two, a leanone with the typedefs only and another with the actual
struct definitions. That way we have one very lean executor header that
can be included everywhere (in headers and .c files that only pass the
structs around), and a fat one that is only included by the executor .c
files (and the few extra .c files that need access to the struct
definitions).
This would be similar in spirit to the htup.h / htup_details.h split.
I think (almost?) all the headers that define nodes suffer from this
disease and could be cured in the same way.
I follow your reasoning, but I don't particularly want to make this
patch wait on a large and invasive refactoring of existing headers.
As a down payment on this problem, maybe we could invent a new planner
header that provides just enough info to support amapi.h and fdwapi.h;
it looks like this would be "typedef struct PlannerInfo PlannerInfo;",
likewise for RelOptInfo, ForeignPath, and IndexPath, and real declarations
of Cost and Selectivity. Not sure what to name the new header.
Comments?
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Tom Lane wrote:
I follow your reasoning, but I don't particularly want to make this
patch wait on a large and invasive refactoring of existing headers.
Sure.
As a down payment on this problem, maybe we could invent a new planner
header that provides just enough info to support amapi.h and fdwapi.h;
it looks like this would be "typedef struct PlannerInfo PlannerInfo;",
likewise for RelOptInfo, ForeignPath, and IndexPath, and real declarations
of Cost and Selectivity.
Works for me, under the assumption that, down the road and without any
rush, we can shuffle some more stuff around to make this whole area a
bit cleaner.
Not sure what to name the new header.
Yeah, this is always a problem for such patches :-( I have no great
ideas ATM.
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
Tom Lane wrote:
As a down payment on this problem, maybe we could invent a new planner
header that provides just enough info to support amapi.h and fdwapi.h;
it looks like this would be "typedef struct PlannerInfo PlannerInfo;",
likewise for RelOptInfo, ForeignPath, and IndexPath, and real declarations
of Cost and Selectivity.
Works for me, under the assumption that, down the road and without any
rush, we can shuffle some more stuff around to make this whole area a
bit cleaner.
Well, since we're at the start of a devel cycle, we'd have the rest of 9.6
for somebody to whack it around to their heart's content. Once we ship
9.6 it would get a little harder to redefine the new header(s).
Not sure what to name the new header.
Yeah, this is always a problem for such patches :-( I have no great
ideas ATM.
I'll draft something, but in the meantime, file name ideas solicited.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
... btw, what is the point of catalog/opfam_internal.h? I see you added
it in b488c580aef4e05f, but it seems quite useless to have split it out
as a separate header, since only commands/opclasscmds.c uses it.
My attention got drawn to it because the current patch proposes to
#include it in amapi.h, which is as thorough a subversion of the concept
of "internal header" as I can readily think of. If we're going to do
that with it we'd definitely need to rename it. But I'm not following
why struct OpFamilyMember needs to be exposed at all.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Tom Lane wrote:
... btw, what is the point of catalog/opfam_internal.h? I see you added
it in b488c580aef4e05f, but it seems quite useless to have split it out
as a separate header, since only commands/opclasscmds.c uses it.My attention got drawn to it because the current patch proposes to
#include it in amapi.h, which is as thorough a subversion of the concept
of "internal header" as I can readily think of. If we're going to do
that with it we'd definitely need to rename it. But I'm not following
why struct OpFamilyMember needs to be exposed at all.
Oh, that slipped in there, didn't it. The JSON DDL-deparse bits need
it -- last posted by Alex Shulgin here:
/messages/by-id/CACACo5Q_UXYwF117LBhjZ3xaMPyrgqnqE=mXvRhEfjJ51aCfwQ@mail.gmail.com
I suppose it shouldn't have been committed, and be part of the extension
instead.
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
Tom Lane wrote:
... btw, what is the point of catalog/opfam_internal.h? I see you added
it in b488c580aef4e05f, but it seems quite useless to have split it out
as a separate header, since only commands/opclasscmds.c uses it.
Oh, that slipped in there, didn't it. The JSON DDL-deparse bits need
it -- last posted by Alex Shulgin here:
/messages/by-id/CACACo5Q_UXYwF117LBhjZ3xaMPyrgqnqE=mXvRhEfjJ51aCfwQ@mail.gmail.com
I still don't see any reference to OpFamilyMember in there?
I suppose it shouldn't have been committed, and be part of the extension
instead.
Previously, OpFamilyMember was just a transient internal data structure
inside commands/opclasscmds.c. Unless we intended that some chunks of
the code in there be exposed for use by extensions, it's not terribly
clear to me why extensions would need to access this struct. Perhaps
we ought to just revert struct OpFamilyMember back into opclasscmds.c.
Regardless of that, I'm a bit skeptical that any of these structs ought
to be defined as part of the amapi.h interface. They seem to be making
premature judgments as to what an opclass verifier will care about. In
any case, tying the opclass verifier API to DDL-command implementation
details doesn't seem like a good plan.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Tom Lane wrote:
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
Tom Lane wrote:
... btw, what is the point of catalog/opfam_internal.h? I see you added
it in b488c580aef4e05f, but it seems quite useless to have split it out
as a separate header, since only commands/opclasscmds.c uses it.Oh, that slipped in there, didn't it. The JSON DDL-deparse bits need
it -- last posted by Alex Shulgin here:
/messages/by-id/CACACo5Q_UXYwF117LBhjZ3xaMPyrgqnqE=mXvRhEfjJ51aCfwQ@mail.gmail.comI still don't see any reference to OpFamilyMember in there?
Sorry, that posting doesn't have the part that generates the JSON. It's
ddl_deparse.c in the .tar.gz earlier in that thread:
/messages/by-id/CACACo5QQuAV+n4Gi+YA1JF_a+QenR6SJuP8CYdPSrXKa+FHS3A@mail.gmail.com
I suppose it shouldn't have been committed, and be part of the extension
instead.Previously, OpFamilyMember was just a transient internal data structure
inside commands/opclasscmds.c. Unless we intended that some chunks of
the code in there be exposed for use by extensions, it's not terribly
clear to me why extensions would need to access this struct. Perhaps
we ought to just revert struct OpFamilyMember back into opclasscmds.c.
The whole point of splitting the struct declaration to a new header was
to get a DDL deparser to examine the list of objects being created, so
that it could construct the deparsed command. If the struct is opaque
to the outside world, there's no way to do that (as I recall, you can't
construct the full command starting from the parsed version only -- you
need access to the OIDs of the ops/procs actually added to the opclass.)
Regardless of that, I'm a bit skeptical that any of these structs ought
to be defined as part of the amapi.h interface. They seem to be making
premature judgments as to what an opclass verifier will care about. In
any case, tying the opclass verifier API to DDL-command implementation
details doesn't seem like a good plan.
That's a different argument, with which I don't necessarily disagree.
I think it's not unlikely that a verifier will want to examine the
contents of the struct, but I don't think that means we need to expose
the struct in amapi.h.
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
Tom Lane wrote:
... btw, what is the point of catalog/opfam_internal.h?
The whole point of splitting the struct declaration to a new header was
to get a DDL deparser to examine the list of objects being created, so
that it could construct the deparsed command. If the struct is opaque
to the outside world, there's no way to do that (as I recall, you can't
construct the full command starting from the parsed version only -- you
need access to the OIDs of the ops/procs actually added to the opclass.)
Hm. OK, looking closer, I see that we've effectively exposed these
structs as being what is passed to EventTriggerCollectCreateOpClass, so
even if there's not currently any committed code that can read that info,
we clearly need the structs to be accessible to interested event triggers.
I'm not sold that that was a great design, but it's what's there.
Regardless of that, I'm a bit skeptical that any of these structs ought
to be defined as part of the amapi.h interface. They seem to be making
premature judgments as to what an opclass verifier will care about. In
any case, tying the opclass verifier API to DDL-command implementation
details doesn't seem like a good plan.
That's a different argument, with which I don't necessarily disagree.
I think it's not unlikely that a verifier will want to examine the
contents of the struct, but I don't think that means we need to expose
the struct in amapi.h.
I think we'd be considerably better off to *not* re-use OpFamilyMember
in the verifier API. It's a struct that was only ever designed for
internal use in CREATE/ALTER OPERATOR CLASS.
I'm kind of inclined to just let the verifiers read the catalogs for
themselves. AFAICS, a loop around the results of SearchSysCacheList
is not going to be significantly more code than what this patch does,
and it avoids presuming that we know what the verifiers will wish to
look at.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Tom Lane wrote:
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
Tom Lane wrote:
... btw, what is the point of catalog/opfam_internal.h?
The whole point of splitting the struct declaration to a new header was
to get a DDL deparser to examine the list of objects being created, so
that it could construct the deparsed command. If the struct is opaque
to the outside world, there's no way to do that (as I recall, you can't
construct the full command starting from the parsed version only -- you
need access to the OIDs of the ops/procs actually added to the opclass.)Hm. OK, looking closer, I see that we've effectively exposed these
structs as being what is passed to EventTriggerCollectCreateOpClass, so
even if there's not currently any committed code that can read that info,
we clearly need the structs to be accessible to interested event triggers.
I'm not sold that that was a great design, but it's what's there.
All the deparsers are expected to be able to understand internal
representations of commands, though, such as OIDs and so on. If you
have a better idea (I don't), we can still rework the API we present to
deparser extensions.
That's a different argument, with which I don't necessarily disagree.
I think it's not unlikely that a verifier will want to examine the
contents of the struct, but I don't think that means we need to expose
the struct in amapi.h.I think we'd be considerably better off to *not* re-use OpFamilyMember
in the verifier API. It's a struct that was only ever designed for
internal use in CREATE/ALTER OPERATOR CLASS.I'm kind of inclined to just let the verifiers read the catalogs for
themselves. AFAICS, a loop around the results of SearchSysCacheList
is not going to be significantly more code than what this patch does,
and it avoids presuming that we know what the verifiers will wish to
look at.
Hmm, so this amounts to saying the verifier can only run after the
catalog rows are written. Is that okay?
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
Tom Lane wrote:
I'm kind of inclined to just let the verifiers read the catalogs for
themselves. AFAICS, a loop around the results of SearchSysCacheList
is not going to be significantly more code than what this patch does,
and it avoids presuming that we know what the verifiers will wish to
look at.
Hmm, so this amounts to saying the verifier can only run after the
catalog rows are written. Is that okay?
Why not? Surely we are not interested in performance-optimizing for
the case of a detectably incorrect CREATE OP CLASS command.
I don't actually care that much about running the verifiers during
CREATE/etc OP CLASS at all. It's at least as important to be able
to run them across the built-in opclasses, considering all the chances
for human error in constructing those things. Even in the ALTER OP CLASS
case, the verifier would likely need to look at existing catalog rows as
well as the new ones. So basically, I see zero value in exposing CREATE/
ALTER OP CLASS's internal working representation to the verifiers.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-11-02 23:28, Tom Lane wrote:
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
Tom Lane wrote:
Regardless of that, I'm a bit skeptical that any of these structs ought
to be defined as part of the amapi.h interface. They seem to be making
premature judgments as to what an opclass verifier will care about. In
any case, tying the opclass verifier API to DDL-command implementation
details doesn't seem like a good plan.That's a different argument, with which I don't necessarily disagree.
I think it's not unlikely that a verifier will want to examine the
contents of the struct, but I don't think that means we need to expose
the struct in amapi.h.I think we'd be considerably better off to *not* re-use OpFamilyMember
in the verifier API. It's a struct that was only ever designed for
internal use in CREATE/ALTER OPERATOR CLASS.I'm kind of inclined to just let the verifiers read the catalogs for
themselves. AFAICS, a loop around the results of SearchSysCacheList
is not going to be significantly more code than what this patch does,
and it avoids presuming that we know what the verifiers will wish to
look at.
I like this idea. I didn't like from beginning that verifier is tied to
opclass but didn't have better solution, but this seems reasonable.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Tue, Nov 3, 2015 at 2:36 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
Tom Lane wrote:
I'm kind of inclined to just let the verifiers read the catalogs for
themselves. AFAICS, a loop around the results of SearchSysCacheList
is not going to be significantly more code than what this patch does,
and it avoids presuming that we know what the verifiers will wish to
look at.Hmm, so this amounts to saying the verifier can only run after the
catalog rows are written. Is that okay?Why not? Surely we are not interested in performance-optimizing for
the case of a detectably incorrect CREATE OP CLASS command.I don't actually care that much about running the verifiers during
CREATE/etc OP CLASS at all. It's at least as important to be able
to run them across the built-in opclasses, considering all the chances
for human error in constructing those things. Even in the ALTER OP CLASS
case, the verifier would likely need to look at existing catalog rows as
well as the new ones. So basically, I see zero value in exposing CREATE/
ALTER OP CLASS's internal working representation to the verifiers.
I'm OK with validating opclass directly by system catalog, i.e. looping
over SearchSysCacheList results. Teodor was telling me something similar
personally.
I'll also try to rearrange header according to the comments upthread.
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
On Tue, Nov 3, 2015 at 3:16 PM, Alexander Korotkov <
a.korotkov@postgrespro.ru> wrote:
On Tue, Nov 3, 2015 at 2:36 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
Tom Lane wrote:
I'm kind of inclined to just let the verifiers read the catalogs for
themselves. AFAICS, a loop around the results of SearchSysCacheList
is not going to be significantly more code than what this patch does,
and it avoids presuming that we know what the verifiers will wish to
look at.Hmm, so this amounts to saying the verifier can only run after the
catalog rows are written. Is that okay?Why not? Surely we are not interested in performance-optimizing for
the case of a detectably incorrect CREATE OP CLASS command.I don't actually care that much about running the verifiers during
CREATE/etc OP CLASS at all. It's at least as important to be able
to run them across the built-in opclasses, considering all the chances
for human error in constructing those things. Even in the ALTER OP CLASS
case, the verifier would likely need to look at existing catalog rows as
well as the new ones. So basically, I see zero value in exposing CREATE/
ALTER OP CLASS's internal working representation to the verifiers.I'm OK with validating opclass directly by system catalog, i.e. looping
over SearchSysCacheList results. Teodor was telling me something similar
personally.
I'll also try to rearrange header according to the comments upthread.
The next revision of patch is attached.
The changes are following:
1. Definitions of Selectivity, Cost and declarations
of IndexAmRoutine, PlannerInfo, IndexPath, IndexInfo are moved into
separate header reldecls.h. That allows to get rid of #include
"nodes/relation.h" in amapi.h.
2. amvalidate method now gets opclass oid as parameter. Internally,
amvalidate implementations do catalog lookups. opfam_internal.h isn't
included from inappropriate places anymore.
3. I removed amvalidate calls from opclasscmds.c. Validating
user-defined opclasses is behavior change which can have issues with
backward compatibility. I think if we want to introduce this, it should be
considered separately of API rework.
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Attachments:
aminterface-10.patchapplication/octet-stream; name=aminterface-10.patchDownload
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
new file mode 100644
index 97ef618..48f208a
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 549,762 ****
</row>
<row>
! <entry><structfield>amstrategies</structfield></entry>
! <entry><type>int2</type></entry>
! <entry></entry>
! <entry>Number of operator strategies for this access method,
! or zero if access method does not have a fixed set of operator
! strategies</entry>
! </row>
!
! <row>
! <entry><structfield>amsupport</structfield></entry>
! <entry><type>int2</type></entry>
! <entry></entry>
! <entry>Number of support routines for this access method</entry>
! </row>
!
! <row>
! <entry><structfield>amcanorder</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support ordered scans sorted by the
! indexed column's value?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanorderbyop</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support ordered scans sorted by the result
! of an operator on the indexed column?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanbackward</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support backward scanning?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanunique</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support unique indexes?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanmulticol</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support multicolumn indexes?</entry>
! </row>
!
! <row>
! <entry><structfield>amoptionalkey</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support a scan without any constraint
! for the first index column?</entry>
! </row>
!
! <row>
! <entry><structfield>amsearcharray</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support <literal>ScalarArrayOpExpr</> searches?</entry>
! </row>
!
! <row>
! <entry><structfield>amsearchnulls</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support <literal>IS NULL</>/<literal>NOT NULL</> searches?</entry>
! </row>
!
! <row>
! <entry><structfield>amstorage</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Can index storage data type differ from column data type?</entry>
! </row>
!
! <row>
! <entry><structfield>amclusterable</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Can an index of this type be clustered on?</entry>
! </row>
!
! <row>
! <entry><structfield>ampredlocks</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does an index of this type manage fine-grained predicate locks?</entry>
! </row>
!
! <row>
! <entry><structfield>amkeytype</structfield></entry>
<entry><type>oid</type></entry>
- <entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
- <entry>Type of data stored in index, or zero if not a fixed type</entry>
- </row>
-
- <row>
- <entry><structfield>aminsert</structfield></entry>
- <entry><type>regproc</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Insert this tuple</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambeginscan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Prepare for index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amgettuple</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Next valid tuple</quote> function, or zero if none</entry>
! </row>
!
! <row>
! <entry><structfield>amgetbitmap</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Fetch all valid tuples</quote> function, or zero if none</entry>
! </row>
!
! <row>
! <entry><structfield>amrescan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>(Re)start index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amendscan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Clean up after index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ammarkpos</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Mark current scan position</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amrestrpos</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Restore marked scan position</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambuild</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Build new index</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambuildempty</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Build empty index</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambulkdelete</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Bulk-delete function</entry>
! </row>
!
! <row>
! <entry><structfield>amvacuumcleanup</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Post-<command>VACUUM</command> cleanup function</entry>
! </row>
!
! <row>
! <entry><structfield>amcanreturn</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to check whether an index column supports index-only
! scans. Can be zero if index-only scans are never supported.</entry>
! </row>
!
! <row>
! <entry><structfield>amcostestimate</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to estimate cost of an index scan</entry>
! </row>
!
! <row>
! <entry><structfield>amoptions</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to parse and validate <structfield>reloptions</> for an index</entry>
</row>
-
</tbody>
</tgroup>
</table>
--- 549,562 ----
</row>
<row>
! <entry><structfield>amhandler</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>
! References a handler function that is responsible for
! supplying execution routines for the access method.
! </entry>
</row>
</tbody>
</tgroup>
</table>
diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml
new file mode 100644
index 1c09bae..3ff3651
*** a/doc/src/sgml/indexam.sgml
--- b/doc/src/sgml/indexam.sgml
***************
*** 49,61 ****
<para>
Each index access method is described by a row in the
<structname>pg_am</structname> system catalog (see
! <xref linkend="catalog-pg-am">). The principal contents of a
! <structname>pg_am</structname> row are references to
! <link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>
! entries that identify the index access
! functions supplied by the access method. The APIs for these functions
! are defined later in this chapter. In addition, the
! <structname>pg_am</structname> row specifies a few fixed properties of
the access method, such as whether it can support multicolumn indexes.
There is not currently any special support
for creating or deleting <structname>pg_am</structname> entries;
--- 49,63 ----
<para>
Each index access method is described by a row in the
<structname>pg_am</structname> system catalog (see
! <xref linkend="catalog-pg-am">). In the <structname>pg_am</structname> row
! the handler function is specified by the reference to
! <link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.
! Handler function must be written in a compiled language such as C, using
! the version-1 interface. The handler function simply returns a
! <structname>IndexAmRoutine</structname> struct which contains function
! pointers to callback functions that will be called by the planner, executor,
! and various maintenance commands. In addition, the
! <structname>IndexAmRoutine</structname> contains a few fixed properties of
the access method, such as whether it can support multicolumn indexes.
There is not currently any special support
for creating or deleting <structname>pg_am</structname> entries;
***************
*** 96,126 ****
</para>
<para>
! Some of the flag columns of <structname>pg_am</structname> have nonobvious
! implications. The requirements of <structfield>amcanunique</structfield>
! are discussed in <xref linkend="index-unique-checks">.
! The <structfield>amcanmulticol</structfield> flag asserts that the
! access method supports multicolumn indexes, while
! <structfield>amoptionalkey</structfield> asserts that it allows scans
where no indexable restriction clause is given for the first index column.
! When <structfield>amcanmulticol</structfield> is false,
! <structfield>amoptionalkey</structfield> essentially says whether the
access method supports full-index scans without any restriction clause.
Access methods that support multiple index columns <emphasis>must</>
support scans that omit restrictions on any or all of the columns after
the first; however they are permitted to require some restriction to
appear for the first index column, and this is signaled by setting
! <structfield>amoptionalkey</structfield> false.
! One reason that an index AM might set
! <structfield>amoptionalkey</structfield> false is if it doesn't index
! null values. Since most indexable operators are
strict and hence cannot return true for null inputs,
it is at first sight attractive to not store index entries for null values:
they could never be returned by an index scan anyway. However, this
argument fails when an index scan has no restriction clause for a given
index column. In practice this means that
! indexes that have <structfield>amoptionalkey</structfield> true must
! index nulls, since the planner might decide to use such an index
with no scan keys at all. A related restriction is that an index
access method that supports multiple index columns <emphasis>must</>
support indexing null values in columns after the first, because the planner
--- 98,133 ----
</para>
<para>
! Some of the flag fields of <structname>IndexAmRoutine</structname> have nonobvious
! implications. The requirements of
! <structname>IndexAmRoutine</structname>.<structfield>amcanunique</structfield>
! are discussed in <xref linkend="index-unique-checks">. The
! <structname>IndexAmRoutine</structname>.<structfield>amcanmulticol</structfield>
! flag asserts that the access method supports multicolumn indexes, while
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! asserts that it allows scans
where no indexable restriction clause is given for the first index column.
! When <structname>IndexAmRoutine</structname>.<structfield>amcanmulticol</structfield>
! is false,
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! essentially says whether the
access method supports full-index scans without any restriction clause.
Access methods that support multiple index columns <emphasis>must</>
support scans that omit restrictions on any or all of the columns after
the first; however they are permitted to require some restriction to
appear for the first index column, and this is signaled by setting
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! false. One reason that an index AM might set
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! false is if it doesn't index null values. Since most indexable operators are
strict and hence cannot return true for null inputs,
it is at first sight attractive to not store index entries for null values:
they could never be returned by an index scan anyway. However, this
argument fails when an index scan has no restriction clause for a given
index column. In practice this means that
! indexes that have
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! true must index nulls, since the planner might decide to use such an index
with no scan keys at all. A related restriction is that an index
access method that supports multiple index columns <emphasis>must</>
support indexing null values in columns after the first, because the planner
***************
*** 131,139 ****
index omits rows where <literal>b</> is null.
It is, however, OK to omit rows where the first indexed column is null.
An index access method that does index nulls may also set
! <structfield>amsearchnulls</structfield>, indicating that it supports
! <literal>IS NULL</> and <literal>IS NOT NULL</> clauses as search
! conditions.
</para>
</sect1>
--- 138,146 ----
index omits rows where <literal>b</> is null.
It is, however, OK to omit rows where the first indexed column is null.
An index access method that does index nulls may also set
! <structname>IndexAmRoutine</structname>.<structfield>amsearchnulls</structfield>,
! indicating that it supports <literal>IS NULL</> and <literal>IS NOT NULL</>
! clauses as search conditions.
</para>
</sect1>
***************
*** 143,149 ****
<para>
The index construction and maintenance functions that an index access
! method must provide are:
</para>
<para>
--- 150,156 ----
<para>
The index construction and maintenance functions that an index access
! method must provide in <structname>IndexAmRoutine</structname> are:
</para>
<para>
*************** aminsert (Relation indexRelation,
*** 188,194 ****
<literal>isnull</> arrays give the key values to be indexed, and
<literal>heap_tid</> is the TID to be indexed.
If the access method supports unique indexes (its
! <structname>pg_am</>.<structfield>amcanunique</> flag is true) then
<literal>checkUnique</> indicates the type of uniqueness check to
perform. This varies depending on whether the unique constraint is
deferrable; see <xref linkend="index-unique-checks"> for details.
--- 195,201 ----
<literal>isnull</> arrays give the key values to be indexed, and
<literal>heap_tid</> is the TID to be indexed.
If the access method supports unique indexes (its
! <structfield>amcanunique</> flag is true) then
<literal>checkUnique</> indicates the type of uniqueness check to
perform. This varies depending on whether the unique constraint is
deferrable; see <xref linkend="index-unique-checks"> for details.
*************** amcanreturn (Relation indexRelation, int
*** 281,288 ****
the form of an <structname>IndexTuple</structname>. The attribute number
is 1-based, i.e. the first columns attno is 1. Returns TRUE if supported,
else FALSE. If the access method does not support index-only scans at all,
! the <structfield>amcanreturn</> field in its <structname>pg_am</> row can
! be set to zero.
</para>
<para>
--- 288,295 ----
the form of an <structname>IndexTuple</structname>. The attribute number
is 1-based, i.e. the first columns attno is 1. Returns TRUE if supported,
else FALSE. If the access method does not support index-only scans at all,
! the <structfield>amcanreturn</> field in its <structname>IndexAmRoutine</>
! struct can be set to NULL.
</para>
<para>
*************** amgettuple (IndexScanDesc scan,
*** 414,421 ****
<para>
The <function>amgettuple</> function need only be provided if the access
method supports <quote>plain</> index scans. If it doesn't, the
! <structfield>amgettuple</> field in its <structname>pg_am</> row must
! be set to zero.
</para>
<para>
--- 421,428 ----
<para>
The <function>amgettuple</> function need only be provided if the access
method supports <quote>plain</> index scans. If it doesn't, the
! <structfield>amgettuple</> field in its <structname>IndexAmRoutine</>
! struct must be set to NULL.
</para>
<para>
*************** amgetbitmap (IndexScanDesc scan,
*** 445,452 ****
<para>
The <function>amgetbitmap</> function need only be provided if the access
method supports <quote>bitmap</> index scans. If it doesn't, the
! <structfield>amgetbitmap</> field in its <structname>pg_am</> row must
! be set to zero.
</para>
<para>
--- 452,459 ----
<para>
The <function>amgetbitmap</> function need only be provided if the access
method supports <quote>bitmap</> index scans. If it doesn't, the
! <structfield>amgetbitmap</> field in its <structname>IndexAmRoutine</>
! struct must be set to NULL.
</para>
<para>
*************** amrestrpos (IndexScanDesc scan);
*** 477,494 ****
</para>
<para>
! By convention, the <literal>pg_proc</literal> entry for an index
! access method function should show the correct number of arguments,
! but declare them all as type <type>internal</> (since most of the arguments
! have types that are not known to SQL, and we don't want users calling
! the functions directly anyway). The return type is declared as
! <type>void</>, <type>internal</>, or <type>boolean</> as appropriate.
! The only exception is <function>amoptions</>, which should be correctly
! declared as taking <type>text[]</> and <type>bool</> and returning
! <type>bytea</>. This provision allows client code to execute
! <function>amoptions</> to test validity of options settings.
</para>
-
</sect1>
<sect1 id="index-scanning">
--- 484,496 ----
</para>
<para>
! <programlisting>
! void
! amvalidate (OpClassInfo *opclass);
! </programlisting>
! Validates given operator class by access method. The <function>amvalidate</>
! must throw an error if opclass is invalid.
</para>
</sect1>
<sect1 id="index-scanning">
*************** amrestrpos (IndexScanDesc scan);
*** 548,554 ****
<para>
Access methods that always return entries in the natural ordering
of their data (such as btree) should set
! <structname>pg_am</>.<structfield>amcanorder</> to true.
Currently, such access methods must use btree-compatible strategy
numbers for their equality and ordering operators.
</para>
--- 550,556 ----
<para>
Access methods that always return entries in the natural ordering
of their data (such as btree) should set
! <structfield>amcanorder</> to true.
Currently, such access methods must use btree-compatible strategy
numbers for their equality and ordering operators.
</para>
*************** amrestrpos (IndexScanDesc scan);
*** 556,562 ****
<listitem>
<para>
Access methods that support ordering operators should set
! <structname>pg_am</>.<structfield>amcanorderbyop</> to true.
This indicates that the index is capable of returning entries in
an order satisfying <literal>ORDER BY</> <replaceable>index_key</>
<replaceable>operator</> <replaceable>constant</>. Scan modifiers
--- 558,564 ----
<listitem>
<para>
Access methods that support ordering operators should set
! <structfield>amcanorderbyop</> to true.
This indicates that the index is capable of returning entries in
an order satisfying <literal>ORDER BY</> <replaceable>index_key</>
<replaceable>operator</> <replaceable>constant</>. Scan modifiers
*************** amrestrpos (IndexScanDesc scan);
*** 579,585 ****
methods that set <structfield>amcanorder</> to true.) After the
first call, <function>amgettuple</> must be prepared to advance the scan in
either direction from the most recently returned entry. (But if
! <structname>pg_am</>.<structfield>amcanbackward</> is false, all subsequent
calls will have the same direction as the first one.)
</para>
--- 581,587 ----
methods that set <structfield>amcanorder</> to true.) After the
first call, <function>amgettuple</> must be prepared to advance the scan in
either direction from the most recently returned entry. (But if
! <structfield>amcanbackward</> is false, all subsequent
calls will have the same direction as the first one.)
</para>
*************** amrestrpos (IndexScanDesc scan);
*** 590,597 ****
be remembered per scan; a new <function>ammarkpos</> call overrides the
previously marked position. An access method that does not support
ordered scans should still provide mark and restore functions in
! <structname>pg_am</>, but it is sufficient to have them throw errors if
! called.
</para>
<para>
--- 592,599 ----
be remembered per scan; a new <function>ammarkpos</> call overrides the
previously marked position. An access method that does not support
ordered scans should still provide mark and restore functions in
! <structname>IndexAmRoutine</>, but it is sufficient to have them throw
! errors if called.
</para>
<para>
*************** amrestrpos (IndexScanDesc scan);
*** 766,772 ****
<productname>PostgreSQL</productname> enforces SQL uniqueness constraints
using <firstterm>unique indexes</>, which are indexes that disallow
multiple entries with identical keys. An access method that supports this
! feature sets <structname>pg_am</>.<structfield>amcanunique</> true.
(At present, only b-tree supports it.)
</para>
--- 768,774 ----
<productname>PostgreSQL</productname> enforces SQL uniqueness constraints
using <firstterm>unique indexes</>, which are indexes that disallow
multiple entries with identical keys. An access method that supports this
! feature sets <structfield>amcanunique</> true.
(At present, only b-tree supports it.)
</para>
diff --git a/doc/src/sgml/xindex.sgml b/doc/src/sgml/xindex.sgml
new file mode 100644
index 4fac018..a2d3fd8
*** a/doc/src/sgml/xindex.sgml
--- b/doc/src/sgml/xindex.sgml
***************
*** 34,40 ****
regular access to tables is built into
<productname>PostgreSQL</productname>, but all index methods are
described in <classname>pg_am</classname>. It is possible to add a
! new index method by defining the required interface routines and
then creating a row in <classname>pg_am</classname> — but that is
beyond the scope of this chapter (see <xref linkend="indexam">).
</para>
--- 34,41 ----
regular access to tables is built into
<productname>PostgreSQL</productname>, but all index methods are
described in <classname>pg_am</classname>. It is possible to add a
! new index access method by defining the handler function, which returns
! C-struct with required interface routines and parameters, and
then creating a row in <classname>pg_am</classname> — but that is
beyond the scope of this chapter (see <xref linkend="indexam">).
</para>
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
new file mode 100644
index 99337b0..00e7538
*** a/src/backend/access/brin/brin.c
--- b/src/backend/access/brin/brin.c
***************
*** 25,38 ****
--- 25,176 ----
#include "access/xact.h"
#include "access/xloginsert.h"
#include "catalog/index.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
+ #include "catalog/pg_opclass.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "storage/bufmgr.h"
#include "storage/freespace.h"
+ #include "utils/catcache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
+ #include "utils/syscache.h"
+
+
+ /*
+ * BRIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ brinhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 15;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = brininsert;
+ amroutine->ambeginscan = brinbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = bringetbitmap;
+ amroutine->amrescan = brinrescan;
+ amroutine->amendscan = brinendscan;
+ amroutine->ammarkpos = brinmarkpos;
+ amroutine->amrestrpos = brinrestrpos;
+ amroutine->ambuild = brinbuild;
+ amroutine->ambuildempty = brinbuildempty;
+ amroutine->ambulkdelete = brinbulkdelete;
+ amroutine->amvacuumcleanup = brinvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = brincostestimate;
+ amroutine->amoptions = brinoptions;
+ amroutine->amvalidate = brinvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ brinvalidate(Oid opclassoid)
+ {
+ bool procsPresent[BRIN_MANDATORY_NPROCS];
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid,
+ intype,
+ keytype;
+ CatCList *proclist,
+ *oprlist;
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ /* Fetch opclass information */
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ intype = classform->opcintype;
+ keytype = classform->opckeytype;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+
+ /* Fetch opfamily information: operators and functions */
+ oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+
+ /* Check required procedure numbers exist */
+ for (i = 0; i < proclist->n_members; i++)
+ {
+ HeapTuple proctup = &proclist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype != intype ||
+ procform->amprocrighttype != intype)
+ continue;
+
+ if (procform->amprocnum < 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for BRIN: %u",
+ procform->amprocnum)));
+
+ /* BRIN opclasses could contain any number of non-mandatory procedures */
+ if (procform->amprocnum > BRIN_MANDATORY_NPROCS)
+ continue;
+
+ if (procsPresent[procform->amprocnum - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u was defined more than once",
+ procform->amprocnum)));
+
+ procsPresent[procform->amprocnum - 1] = true;
+ }
+
+ /*
+ * Don't use BRIN_NPROC because some procnumbers
+ * are reserved for future use
+ */
+ for (i = 0; i < BRIN_MANDATORY_NPROCS; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u is required", i + 1)));
+ }
+ /* Check operators: ORDER BY operators are not supported */
+ for (i = 0; i < oprlist->n_members; i++)
+ {
+ HeapTuple oprtup = &oprlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+
+ if (OidIsValid(oprform->amopsortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN doesn't support ORDER BY operators")));
+ }
+
+ ReleaseCatCacheList(proclist);
+ ReleaseCatCacheList(oprlist);
+ }
/*
* We use a BrinBuildState during initial construction of a BRIN index.
*************** 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;
--- 218,228 ----
* 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);
}
/*
--- 360,366 ----
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;
--- 370,378 ----
* 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);
}
/*
--- 383,389 ----
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;
--- 398,406 ----
* 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
--- 580,595 ----
* 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();
}
/*
--- 601,631 ----
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;
--- 697,705 ----
/*
* 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. */
--- 778,789 ----
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();
}
/*
--- 800,805 ----
*************** 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));
--- 811,839 ----
* 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;
--- 850,864 ----
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);
--- 871,877 ----
/* 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);
}
/*
--- 880,886 ----
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 931dceb..b52846f
*** a/src/backend/access/common/reloptions.c
--- b/src/backend/access/common/reloptions.c
*************** untransformRelOptions(Datum options)
*** 891,897 ****
* 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;
--- 891,897 ----
* 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
*** 1379,1412 ****
* 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);
}
/*
--- 1379,1393 ----
* 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 49e9185..92701b9
*** 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..08642e1
*** a/src/backend/access/gin/ginutil.c
--- b/src/backend/access/gin/ginutil.c
***************
*** 15,28 ****
--- 15,176 ----
#include "postgres.h"
#include "access/gin_private.h"
+ #include "access/htup_details.h"
#include "access/reloptions.h"
#include "access/xloginsert.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
#include "catalog/pg_collation.h"
+ #include "catalog/pg_opclass.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
+ #include "utils/catcache.h"
+ #include "utils/selfuncs.h"
+ #include "utils/syscache.h"
+
+
+ /*
+ * GIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ ginhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 6;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = gininsert;
+ amroutine->ambeginscan = ginbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = gingetbitmap;
+ amroutine->amrescan = ginrescan;
+ amroutine->amendscan = ginendscan;
+ amroutine->ammarkpos = ginmarkpos;
+ amroutine->amrestrpos = ginrestrpos;
+ amroutine->ambuild = ginbuild;
+ amroutine->ambuildempty = ginbuildempty;
+ amroutine->ambulkdelete = ginbulkdelete;
+ amroutine->amvacuumcleanup = ginvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = gincostestimate;
+ amroutine->amoptions = ginoptions;
+ amroutine->amvalidate = ginvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ ginvalidate(Oid opclassoid)
+ {
+ bool procsPresent[GINNProcs];
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid,
+ intype,
+ keytype;
+ CatCList *proclist,
+ *oprlist;
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ /* Fetch opclass information */
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ intype = classform->opcintype;
+ keytype = classform->opckeytype;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+
+ /* Fetch opfamily information: operators and functions */
+ oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+
+ /* Check required procedure numbers exist */
+ for (i = 0; i < proclist->n_members; i++)
+ {
+ HeapTuple proctup = &proclist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype != intype ||
+ procform->amprocrighttype != intype)
+ continue;
+
+ if (procform->amprocnum < 1 || procform->amprocnum > GINNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for GIN: %u",
+ procform->amprocnum)));
+
+ if (procsPresent[procform->amprocnum - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u was defined more than once",
+ procform->amprocnum)));
+
+ procsPresent[procform->amprocnum - 1] = true;
+ }
+ for (i = 0; i < GINNProcs; i++)
+ {
+ if (i+1 == GIN_COMPARE_PARTIAL_PROC)
+ continue; /* optional method */
+ if (i+1 == GIN_CONSISTENT_PROC || i+1 == GIN_TRICONSISTENT_PROC)
+ continue; /* don't need to have both, see check below loop */
+
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u is required", i + 1)));
+ }
+
+ if (!procsPresent[GIN_CONSISTENT_PROC - 1]
+ && !procsPresent[GIN_TRICONSISTENT_PROC - 1])
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("at least one of consistent support (number %u) "
+ "and triconsistent support (number %u) is "
+ "is required",
+ GIN_CONSISTENT_PROC, GIN_TRICONSISTENT_PROC)));
+ }
+
+ /* Check operators: ORDER BY operators are not supported */
+ for (i = 0; i < oprlist->n_members; i++)
+ {
+ HeapTuple oprtup = &oprlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+
+ if (OidIsValid(oprform->amopsortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN doesn't support ORDER BY operators")));
+ }
+
+ ReleaseCatCacheList(proclist);
+ ReleaseCatCacheList(oprlist);
+ }
/*
* 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;
--- 664,672 ----
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);
--- 681,687 ----
/* 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);
}
/*
--- 690,696 ----
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 323cfb0..5b38607
*** 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, true, stats);
}
! PG_RETURN_POINTER(stats);
}
/*
--- 656,662 ----
initGinState(&ginstate, index);
ginInsertCleanup(&ginstate, true, 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 53bccf6..bf031b9
*** a/src/backend/access/gist/gist.c
--- b/src/backend/access/gist/gist.c
***************
*** 16,29 ****
--- 16,37 ----
#include "access/genam.h"
#include "access/gist_private.h"
+ #include "access/gistscan.h"
+ #include "access/htup_details.h"
#include "access/xloginsert.h"
#include "catalog/index.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
#include "catalog/pg_collation.h"
+ #include "catalog/pg_opclass.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "storage/indexfsm.h"
#include "utils/memutils.h"
#include "utils/rel.h"
+ #include "utils/catcache.h"
+ #include "utils/selfuncs.h"
+ #include "utils/syscache.h"
/* non-export function prototypes */
static void gistfixsplit(GISTInsertState *state, GISTSTATE *giststate);
*************** static void gistfinishsplit(GISTInsertSt
*** 38,43 ****
--- 46,182 ----
GISTSTATE *giststate, List *splitinfo, bool releasebuf);
static void gistvacuumpage(Relation rel, Page page, Buffer buffer);
+ /*
+ * GiST handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ gisthandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 9;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = true;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = true;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = gistinsert;
+ amroutine->ambeginscan = gistbeginscan;
+ amroutine->amgettuple = gistgettuple;
+ amroutine->amgetbitmap = gistgetbitmap;
+ amroutine->amrescan = gistrescan;
+ amroutine->amendscan = gistendscan;
+ amroutine->ammarkpos = gistmarkpos;
+ amroutine->amrestrpos = gistrestrpos;
+ amroutine->ambuild = gistbuild;
+ amroutine->ambuildempty = gistbuildempty;
+ amroutine->ambulkdelete = gistbulkdelete;
+ amroutine->amvacuumcleanup = gistvacuumcleanup;
+ amroutine->amcanreturn = gistcanreturn;
+ amroutine->amcostestimate = gistcostestimate;
+ amroutine->amoptions = gistoptions;
+ amroutine->amvalidate = gistvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ gistvalidate(Oid opclassoid)
+ {
+ bool procsPresent[GISTNProcs];
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid,
+ intype,
+ keytype;
+ CatCList *proclist,
+ *oprlist;
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ /* Fetch opclass information */
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ intype = classform->opcintype;
+ keytype = classform->opckeytype;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+
+ /* Fetch opfamily information: operators and functions */
+ oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+
+ /* Check required procedure numbers exist */
+ for (i = 0; i < proclist->n_members; i++)
+ {
+ HeapTuple proctup = &proclist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype != intype ||
+ procform->amprocrighttype != intype)
+ continue;
+
+ if (procform->amprocnum < 1 || procform->amprocnum > GISTNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for GiST: %u",
+ procform->amprocnum)));
+
+ if (procsPresent[procform->amprocnum - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u was defined more than once",
+ procform->amprocnum)));
+
+ procsPresent[procform->amprocnum - 1] = true;
+ }
+
+ for (i = 0; i < GISTNProcs; i++)
+ {
+ if (i+1 == GIST_DISTANCE_PROC || i+1 == GIST_FETCH_PROC)
+ continue; /* optional methods */
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u is required", i+1)));
+ }
+
+ /*
+ * Check operators: ORDER BY operators are supported only if distance
+ * procedure is specified.
+ */
+ for (i = 0; i < oprlist->n_members; i++)
+ {
+ HeapTuple oprtup = &oprlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+
+ if (OidIsValid(oprform->amopsortfamily) &&
+ !procsPresent[GIST_DISTANCE_PROC - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST distance support function %u is required "
+ "for ORDER BY operators", GIST_DISTANCE_PROC)));
+ }
+
+ ReleaseCatCacheList(proclist);
+ ReleaseCatCacheList(oprlist);
+ }
#define ROTATEDIST(d) do { \
SplitedPageLayout *tmp=(SplitedPageLayout*)palloc(sizeof(SplitedPageLayout)); \
*************** createTempGistContext(void)
*** 70,79 ****
/*
* 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 */
--- 209,217 ----
/*
* gistbuildempty() -- build an empty gist index in the initialization fork
*/
! void
! gistbuildempty(Relation index)
{
Buffer buffer;
/* Initialize the root page */
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 89,96 ****
/* Unlock and release the buffer */
UnlockReleaseBuffer(buffer);
-
- PG_RETURN_VOID();
}
/*
--- 227,232 ----
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 99,116 ****
* 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;
--- 235,245 ----
* 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)
*** 136,142 ****
MemoryContextSwitchTo(oldCxt);
freeGISTstate(giststate);
! PG_RETURN_BOOL(false);
}
--- 265,271 ----
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 ce8e582..1adf92f
*** a/src/backend/access/gist/gistget.c
--- b/src/backend/access/gist/gistget.c
*************** getNextNearest(IndexScanDesc scan)
*** 618,628 ****
/*
* 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)
--- 618,626 ----
/*
* 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)
*** 651,657 ****
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! PG_RETURN_BOOL(getNextNearest(scan));
}
else
{
--- 649,655 ----
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! return getNextNearest(scan);
}
else
{
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 688,694 ****
so->curPageData++;
! PG_RETURN_BOOL(true);
}
/*
--- 686,692 ----
so->curPageData++;
! return true;
}
/*
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 726,732 ****
item = getNextGISTSearchItem(so);
if (!item)
! PG_RETURN_BOOL(false);
CHECK_FOR_INTERRUPTS();
--- 724,730 ----
item = getNextGISTSearchItem(so);
if (!item)
! return false;
CHECK_FOR_INTERRUPTS();
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 750,766 ****
/*
* 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);
--- 748,762 ----
/*
* 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)
*** 791,797 ****
pfree(item);
}
! PG_RETURN_INT64(ntids);
}
/*
--- 787,793 ----
pfree(item);
}
! return ntids;
}
/*
*************** gistgetbitmap(PG_FUNCTION_ARGS)
*** 799,812 ****
*
* 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);
}
--- 795,805 ----
*
* 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 a17c5bc..22f0c68
*** 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)
*** 107,121 ****
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;
--- 104,116 ----
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)
*** 314,341 ****
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;
/*
--- 309,331 ----
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)
*** 343,348 ****
* as well as the queueCxt if there is a separate context for it.
*/
freeGISTstate(so->giststate);
-
- PG_RETURN_VOID();
}
--- 333,336 ----
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 a0b0eeb..e0ce620
*** 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)
*** 276,280 ****
vacuum_delay_point();
}
! PG_RETURN_POINTER(stats);
}
--- 271,275 ----
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..109f8f1
*** a/src/backend/access/hash/hash.c
--- b/src/backend/access/hash/hash.c
***************
*** 18,31 ****
--- 18,38 ----
#include "postgres.h"
+ #include "access/amapi.h"
#include "access/hash.h"
#include "access/relscan.h"
#include "catalog/index.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
+ #include "catalog/pg_opclass.h"
#include "commands/vacuum.h"
#include "optimizer/cost.h"
#include "optimizer/plancat.h"
#include "storage/bufmgr.h"
+ #include "utils/catcache.h"
#include "utils/rel.h"
+ #include "utils/selfuncs.h"
+ #include "utils/syscache.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;
--- 49,196 ----
bool tupleIsAlive,
void *state);
+ /*
+ * Hash handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ hashhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 1;
+ amroutine->amsupport = 1;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = true;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = false;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = INT4OID;
+
+ amroutine->aminsert = hashinsert;
+ amroutine->ambeginscan = hashbeginscan;
+ amroutine->amgettuple = hashgettuple;
+ amroutine->amgetbitmap = hashgetbitmap;
+ amroutine->amrescan = hashrescan;
+ amroutine->amendscan = hashendscan;
+ amroutine->ammarkpos = hashmarkpos;
+ amroutine->amrestrpos = hashrestrpos;
+ amroutine->ambuild = hashbuild;
+ amroutine->ambuildempty = hashbuildempty;
+ amroutine->ambulkdelete = hashbulkdelete;
+ amroutine->amvacuumcleanup = hashvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = hashcostestimate;
+ amroutine->amoptions = hashoptions;
+ amroutine->amvalidate = hashvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ hashvalidate(Oid opclassoid)
+ {
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid,
+ intype,
+ keytype;
+ CatCList *proclist,
+ *oprlist;
+ int i,
+ j;
+
+ /* Fetch opclass information */
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ intype = classform->opcintype;
+ keytype = classform->opckeytype;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+
+ /* Fetch opfamily information: operators and functions */
+ oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+
+ /* Check hash procedure exists */
+ for (i = 0; i < proclist->n_members; i++)
+ {
+ HeapTuple proctup = &proclist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype != intype ||
+ procform->amprocrighttype != intype)
+ continue;
+
+ if (procform->amprocnum != HASHPROC)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for hash: %u",
+ procform->amprocnum)));
+ }
+
+ /* Check operators */
+ for (i = 0; i < oprlist->n_members; i++)
+ {
+ HeapTuple oprtup = &oprlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+ bool leftFound = false,
+ rightFound = false;
+
+ /* ORDER BY operators are not supported */
+ if (OidIsValid(oprform->amopsortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("hash doesn't support ORDER BY operators")));
+
+ /* Check strategy number */
+ if (oprform->amopstrategy < 1 ||
+ oprform->amopstrategy > HTMaxStrategyNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid strategy number for hash: %u",
+ oprform->amopstrategy)));
+
+ /* There should be relevant hash procedure for operator */
+ for (j = 0; j < proclist->n_members; j++)
+ {
+ HeapTuple proctup = &proclist->members[j]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype == oprform->amoplefttype)
+ leftFound = true;
+ if (procform->amproclefttype == oprform->amoprighttype)
+ rightFound = true;
+ }
+
+ if (!leftFound || !rightFound)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("no hash procedure found for operator: %u",
+ oprform->amopopr)));
+ }
+
+ ReleaseCatCacheList(proclist);
+ ReleaseCatCacheList(oprlist);
+ }
/*
* 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();
}
/*
--- 251,266 ----
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;
/*
--- 302,312 ----
* 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);
--- 319,325 ----
* 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;
--- 329,344 ----
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;
--- 440,455 ----
/* 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;
--- 486,501 ----
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;
--- 517,532 ----
/* 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;
--- 552,565 ----
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();
}
/*
--- 578,601 ----
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;
--- 605,614 ----
*
* 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);
}
/*
--- 778,784 ----
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);
}
--- 786,807 ----
*
* 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..ea8ae00
*** a/src/backend/access/nbtree/nbtree.c
--- b/src/backend/access/nbtree/nbtree.c
***************
*** 22,34 ****
--- 22,39 ----
#include "access/relscan.h"
#include "access/xlog.h"
#include "catalog/index.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
+ #include "catalog/pg_opclass.h"
#include "commands/vacuum.h"
#include "storage/indexfsm.h"
#include "storage/ipc.h"
#include "storage/lmgr.h"
#include "storage/smgr.h"
#include "tcop/tcopprot.h"
+ #include "utils/catcache.h"
#include "utils/memutils.h"
+ #include "utils/syscache.h"
/* Working state for btbuild and its callback */
*************** 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;
--- 81,221 ----
/*
! * 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;
! amroutine->amvalidate = btvalidate;
!
! PG_RETURN_POINTER(amroutine);
! }
!
! void
! btvalidate(Oid opclassoid)
! {
! HeapTuple classtup;
! Form_pg_opclass classform;
! Oid opfamilyoid,
! intype,
! keytype;
! CatCList *proclist,
! *oprlist;
! int i,
! j;
!
! /* Fetch opclass information */
! classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
!
! if (!HeapTupleIsValid(classtup))
! elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
!
! classform = (Form_pg_opclass) GETSTRUCT(classtup);
! intype = classform->opcintype;
! keytype = classform->opckeytype;
! opfamilyoid = classform->opcfamily;
!
! ReleaseSysCache(classtup);
!
! /* Fetch opfamily information: operators and functions */
! oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
! proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
!
! /* Check that only allowed procedure numbers exist */
! for (i = 0; i < proclist->n_members; i++)
! {
! HeapTuple proctup = &proclist->members[i]->tuple;
! Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
!
! if (procform->amprocnum != BTORDER_PROC &&
! procform->amprocnum != BTSORTSUPPORT_PROC)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("invalid support number for btree: %u",
! procform->amprocnum)));
!
! }
!
! /* Check operators */
! for (i = 0; i < oprlist->n_members; i++)
! {
! HeapTuple oprtup = &oprlist->members[i]->tuple;
! Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
! bool found = false;
!
! if (OidIsValid(oprform->amopsortfamily))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("btree doesn't support ORDER BY operators")));
!
! if (oprform->amopstrategy < 1 || oprform->amopstrategy > BTMaxStrategyNumber)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("invalid strategy number for btree: %u",
! oprform->amopstrategy)));
!
! /* There should be relevant support function for operator */
! for (j = 0; j < proclist->n_members; j++)
! {
! HeapTuple proctup = &proclist->members[j]->tuple;
! Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
!
! if (procform->amprocnum == BTORDER_PROC &&
! procform->amproclefttype == oprform->amoplefttype &&
! procform->amprocrighttype == oprform->amoprighttype)
! found = true;
! }
!
! if (!found)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("no ordering procedure found for operator: %u",
! oprform->amopopr)));
! }
!
! ReleaseCatCacheList(proclist);
! ReleaseCatCacheList(oprlist);
! }
!
! /*
! * 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);
}
/*
--- 287,293 ----
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);
--- 322,331 ----
/*
* 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();
}
/*
--- 345,350 ----
*************** 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;
--- 353,363 ----
* 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;
--- 369,383 ----
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);
}
--- 393,399 ----
{
/* 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;
--- 443,457 ----
/* ... 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);
}
--- 463,469 ----
{
/* 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;
--- 501,515 ----
/* 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 */
--- 547,562 ----
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 */
--- 607,620 ----
/* 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). */
--- 643,656 ----
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 */
--- 673,686 ----
/* 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();
}
/*
--- 748,753 ----
*************** 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;
--- 757,766 ----
*
* 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);
}
/*
--- 779,785 ----
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
--- 787,798 ----
*
* 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);
}
/*
--- 824,830 ----
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);
}
--- 1225,1232 ----
*
* 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..63e4537
*** a/src/backend/access/spgist/spgutils.c
--- b/src/backend/access/spgist/spgutils.c
***************
*** 16,30 ****
--- 16,162 ----
#include "postgres.h"
#include "access/genam.h"
+ #include "access/htup_details.h"
#include "access/reloptions.h"
#include "access/spgist_private.h"
#include "access/transam.h"
#include "access/xact.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
+ #include "catalog/pg_opclass.h"
#include "storage/bufmgr.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "utils/lsyscache.h"
+ #include "utils/catcache.h"
+ #include "utils/selfuncs.h"
+ #include "utils/syscache.h"
+
+
+ /*
+ * SP-GiST handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ spghandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 5;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = spginsert;
+ amroutine->ambeginscan = spgbeginscan;
+ amroutine->amgettuple = spggettuple;
+ amroutine->amgetbitmap = spggetbitmap;
+ amroutine->amrescan = spgrescan;
+ amroutine->amendscan = spgendscan;
+ amroutine->ammarkpos = spgmarkpos;
+ amroutine->amrestrpos = spgrestrpos;
+ amroutine->ambuild = spgbuild;
+ amroutine->ambuildempty = spgbuildempty;
+ amroutine->ambulkdelete = spgbulkdelete;
+ amroutine->amvacuumcleanup = spgvacuumcleanup;
+ amroutine->amcanreturn = spgcanreturn;
+ amroutine->amcostestimate = spgcostestimate;
+ amroutine->amoptions = spgoptions;
+ amroutine->amvalidate = spgvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ spgvalidate(Oid opclassoid)
+ {
+ bool procsPresent[SPGISTNProc];
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid,
+ intype,
+ keytype;
+ CatCList *proclist,
+ *oprlist;
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ /* Fetch opclass information */
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ intype = classform->opcintype;
+ keytype = classform->opckeytype;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+
+ /* Fetch opfamily information: operators and functions */
+ oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+
+ /* Check required procedure numbers exist */
+ for (i = 0; i < proclist->n_members; i++)
+ {
+ HeapTuple proctup = &proclist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype != intype ||
+ procform->amprocrighttype != intype)
+ continue;
+
+ if (procform->amprocnum < 1 || procform->amprocnum > SPGISTNProc)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for SP-GiST: %u",
+ procform->amprocnum)));
+ if (procsPresent[procform->amprocnum - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u was defined more than once",
+ procform->amprocnum)));
+
+ procsPresent[procform->amprocnum - 1] = true;
+ }
+
+ for (i = 0; i < SPGISTNProc; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u is required", i + 1)));
+ }
+
+ /* Check operators: ORDER BY operators are not supported */
+ for (i = 0; i < oprlist->n_members; i++)
+ {
+ HeapTuple oprtup = &oprlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+
+ if (OidIsValid(oprform->amopsortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST doesn't support ORDER BY operators")));
+ }
+
+ ReleaseCatCacheList(proclist);
+ ReleaseCatCacheList(oprlist);
+ }
/* 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();
}
/*
--- 621,636 ----
/*
* 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..4e21304
*** a/src/backend/catalog/index.c
--- b/src/backend/catalog/index.c
***************
*** 23,28 ****
--- 23,29 ----
#include <unistd.h>
+ #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 = GetIndexAmRoutineByAmId(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..b794d59
*** 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,169 ----
accessMethodName)));
accessMethodId = HeapTupleGetOid(tuple);
accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
! amRoutine = GetIndexAmRoutine(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;
--- 318,326 ----
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);
--- 493,523 ----
}
accessMethodId = HeapTupleGetOid(tuple);
accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
+ amRoutine = GetIndexAmRoutine(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/opclasscmds.c b/src/backend/commands/opclasscmds.c
new file mode 100644
index 3375f10..7a50b6a
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 334,346 ****
ListCell *l;
Relation rel;
HeapTuple tup;
- Form_pg_am pg_am;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
--- 334,346 ----
ListCell *l;
Relation rel;
HeapTuple tup;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
+ IndexAmRoutine *amroutine;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 361,373 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
! amstorage = pg_am->amstorage;
/* XXX Should we make any privilege check against the AM? */
--- 361,375 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
!
! amroutine = GetIndexAmRoutineByAmId(amoid);
!
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
! amstorage = amroutine->amstorage;
/* XXX Should we make any privilege check against the AM? */
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 720,725 ****
--- 722,757 ----
/*
+ * Ask access method to validate given opclass.
+ */
+ Datum
+ amvalidate(PG_FUNCTION_ARGS)
+ {
+ Oid opclassoid = PG_GETARG_OID(0),
+ amoid;
+ IndexAmRoutine *amroutine;
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ amoid = classform->opcmethod;
+
+ ReleaseSysCache(classtup);
+
+ amroutine = GetIndexAmRoutineByAmId(amoid);
+
+ amroutine->amvalidate(opclassoid);
+
+ PG_RETURN_BOOL(true);
+ }
+
+
+ /*
* DefineOpFamily
* Define a new index operator family.
*/
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 776,782 ****
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! Form_pg_am pg_am;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
--- 808,814 ----
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! IndexAmRoutine *amroutine;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 787,802 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
/* XXX Should we make any privilege check against the AM? */
- ReleaseSysCache(tup);
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
--- 819,834 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! amroutine = GetIndexAmRoutineByAmId(amoid);
! ReleaseSysCache(tup);
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
/* XXX Should we make any privilege check against the AM? */
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
*************** assignOperTypes(OpFamilyMember *member,
*** 1099,1119 ****
* the family has been created but not yet populated with the required
* operators.)
*/
! HeapTuple amtup;
! Form_pg_am pg_am;
! amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
! if (amtup == NULL)
! elog(ERROR, "cache lookup failed for access method %u", amoid);
! pg_am = (Form_pg_am) GETSTRUCT(amtup);
! if (!pg_am->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! NameStr(pg_am->amname))));
!
! ReleaseSysCache(amtup);
}
else
{
--- 1131,1145 ----
* the family has been created but not yet populated with the required
* operators.)
*/
! IndexAmRoutine *amroutine;
! amroutine = GetIndexAmRoutineByAmId(amoid);
! if (!amroutine->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! get_am_name(amoid))));
}
else
{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
new file mode 100644
index 55ab209..da5ec22
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
*************** ATExecSetRelOptions(Relation rel, List *
*** 9380,9386 ****
(void) view_reloptions(newOptions, true);
break;
case RELKIND_INDEX:
! (void) index_reloptions(rel->rd_am->amoptions, newOptions, true);
break;
default:
ereport(ERROR,
--- 9380,9386 ----
(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
*** 10971,10977 ****
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",
--- 10971,10977 ----
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 b969fc0..587b6e9
*** 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)
*** 545,550 ****
--- 546,552 ----
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)
*** 558,566 ****
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);
--- 560,570 ----
elog(ERROR, "cache lookup failed for access method %u",
idxrelrec->relam);
amrec = (Form_pg_am) GETSTRUCT(ht_am);
+ amroutine = GetIndexAmRoutine(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 990486c..1310613
*** a/src/backend/optimizer/path/costsize.c
--- b/src/backend/optimizer/path/costsize.c
*************** cost_index(IndexPath *path, PlannerInfo
*** 419,432 ****
* 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.
--- 419,426 ----
* 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 344a40c..f11c236
*** 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
*** 1292,1298 ****
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
--- 1293,1299 ----
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..06f122b
*** a/src/backend/utils/adt/ruleutils.c
--- b/src/backend/utils/adt/ruleutils.c
***************
*** 19,24 ****
--- 19,25 ----
#include <unistd.h>
#include <fcntl.h>
+ #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,1188 ----
/* Add the operator class name, if not default */
get_opclass_name(indclass->values[keyno], keycoltype, &buf);
+ amroutine = GetIndexAmRoutine(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 37fad86..9a83e10
*** a/src/backend/utils/adt/selfuncs.c
--- b/src/backend/utils/adt/selfuncs.c
*************** add_predicate_to_quals(IndexOptInfo *ind
*** 6443,6458 ****
}
! 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;
--- 6443,6453 ----
}
! 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)
*** 6741,6760 ****
*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;
--- 6736,6748 ----
*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)
*** 6794,6813 ****
*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;
--- 6782,6794 ----
*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)
*** 6860,6879 ****
*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;
--- 6841,6853 ----
*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)
*** 6926,6933 ****
*indexTotalCost = costs.indexTotalCost;
*indexSelectivity = costs.indexSelectivity;
*indexCorrelation = costs.indexCorrelation;
-
- PG_RETURN_VOID();
}
--- 6900,6905 ----
*************** gincost_scalararrayopexpr(PlannerInfo *r
*** 7222,7237 ****
/*
* 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;
--- 7194,7204 ----
/*
* 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)
*** 7382,7388 ****
*indexStartupCost = 0;
*indexTotalCost = 0;
*indexSelectivity = 0;
! PG_RETURN_VOID();
}
if (counts.haveFullScan || indexQuals == NIL)
--- 7349,7355 ----
*indexStartupCost = 0;
*indexTotalCost = 0;
*indexSelectivity = 0;
! return;
}
if (counts.haveFullScan || indexQuals == NIL)
*************** gincostestimate(PG_FUNCTION_ARGS)
*** 7504,7526 ****
*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;
--- 7471,7486 ----
*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)
*** 7573,7578 ****
*indexTotalCost += (numTuples * *indexSelectivity) * (cpu_index_tuple_cost + qual_op_cost);
/* XXX what about pages_per_range? */
-
- PG_RETURN_VOID();
}
--- 7533,7536 ----
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
new file mode 100644
index 6b0c0b7..7d19b45
*** a/src/backend/utils/cache/relcache.c
--- b/src/backend/utils/cache/relcache.c
*************** 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
--- 445,451 ----
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
*** 1160,1165 ****
--- 1160,1231 ----
}
/*
+ * GetIndexAmRoutine - call the specified access method handler routine
+ * to get its IndexAmRoutine struct.
+ */
+ IndexAmRoutine *
+ GetIndexAmRoutine(Oid amhandler)
+ {
+ Datum datum;
+ IndexAmRoutine *routine;
+
+ datum = OidFunctionCall0(amhandler);
+ routine = (IndexAmRoutine *) DatumGetPointer(datum);
+
+ if (routine == NULL || !IsA(routine, IndexAmRoutine))
+ elog(ERROR, "index access method handler function %u did not return an IndexAmRoutine struct",
+ amhandler);
+
+ return routine;
+ }
+
+ /*
+ * GetIndexAmRoutine - look up the handler of the access method
+ * for the given OID, and retrieve its IndexAmRoutine struct.
+ */
+ IndexAmRoutine *
+ GetIndexAmRoutineByAmId(Oid amoid)
+ {
+ HeapTuple tuple;
+ regproc amhandler;
+ Form_pg_am amform;
+
+ /* Get handler function OID for the access method */
+ tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for access method %u",
+ amoid);
+ amform = (Form_pg_am) GETSTRUCT(tuple);
+ amhandler = amform->amhandler;
+
+ /* Complain if handler OID is invalid */
+ if (!RegProcedureIsValid(amhandler))
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("index access method \"%s\" does not have a handler",
+ NameStr(amform->amname))));
+ ReleaseSysCache(tuple);
+
+ /* And finally, call the handler function. */
+ return GetIndexAmRoutine(amhandler);
+ }
+
+ /*
+ * Initialize IndexAmRoutine for relation.
+ */
+ void
+ InitIndexAmRoutine(Relation relation)
+ {
+ IndexAmRoutine *result, *tmp;
+
+ result = (IndexAmRoutine *) MemoryContextAlloc(relation->rd_indexcxt,
+ sizeof(IndexAmRoutine));
+ tmp = GetIndexAmRoutine(relation->rd_am->amhandler);
+ memcpy(result, tmp, sizeof(IndexAmRoutine));
+ relation->amroutine = result;
+ }
+
+ /*
* Initialize index-access-method support data for an index relation
*/
void
*************** RelationInitIndexAccessInfo(Relation rel
*** 1211,1217 ****
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
--- 1277,1282 ----
*************** RelationInitIndexAccessInfo(Relation rel
*** 1228,1233 ****
--- 1293,1303 ----
ALLOCSET_SMALL_MAXSIZE);
relation->rd_indexcxt = indexcxt;
+ /* Initialize index AM routine */
+ InitIndexAmRoutine(relation);
+
+ amsupport = relation->amroutine->amsupport;
+
/*
* Allocate arrays to hold data
*/
*************** load_relcache_init_file(bool shared)
*** 4743,4749 ****
Oid *opfamily;
Oid *opcintype;
RegProcedure *support;
- int nsupport;
int16 *indoption;
Oid *indcollation;
--- 4813,4818 ----
*************** load_relcache_init_file(bool shared)
*** 4771,4776 ****
--- 4840,4846 ----
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)
*** 4832,4843 ****
rel->rd_indoption = indoption;
/* 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
{
--- 4902,4914 ----
rel->rd_indoption = indoption;
+ InitIndexAmRoutine(rel);
+
/* set up zeroed fmgr-info vectors */
rel->rd_aminfo = (RelationAmInfo *)
MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
rel->rd_supportinfo = (FmgrInfo *)
! MemoryContextAllocZero(indexcxt, relform->relnatts * rel->amroutine->amsupport * sizeof(FmgrInfo));
}
else
{
*************** write_relcache_init_file(bool shared)
*** 5116,5122 ****
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
--- 5187,5193 ----
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (rel->amroutine->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h
new file mode 100644
index ...71d62d3
*** a/src/include/access/amapi.h
--- b/src/include/access/amapi.h
***************
*** 0 ****
--- 1,168 ----
+ /*-------------------------------------------------------------------------
+ *
+ * amapi.h
+ * API for generalized index access methods definition.
+ *
+ * Copyright (c) 2015, PostgreSQL Global Development Group
+ *
+ * src/include/access/amapi.h
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef AMAPI_H
+ #define AMAPI_H
+
+ #include "access/genam.h"
+ #include "nodes/reldecls.h"
+
+ /*
+ * Callback function signatures --- see indexam.sgml for more info.
+ */
+
+ /* "insert this tuple" function */
+ typedef bool
+ (*aminsert_function) (Relation indexRelation,
+ Datum *values,
+ bool *isnull,
+ ItemPointer heap_tid,
+ Relation heapRelation,
+ IndexUniqueCheck checkUnique);
+
+ /* "prepare for index scan" function */
+ typedef IndexScanDesc
+ (*ambeginscan_function) (Relation indexRelation,
+ int nkeys,
+ int norderbys);
+
+ /* "next valid tuple" function, or NULL */
+ typedef bool
+ (*amgettuple_function) (IndexScanDesc scan,
+ ScanDirection direction);
+
+ /* "fetch all valid tuples" function, or NULL */
+ typedef int64
+ (*amgetbitmap_function) (IndexScanDesc scan,
+ TIDBitmap *tbm);
+
+ /* "(re)start index scan" function */
+ typedef void
+ (*amrescan_function) (IndexScanDesc scan,
+ ScanKey keys,
+ int nkeys,
+ ScanKey orderbys,
+ int norderbys);
+
+ /* "end index scan" function */
+ typedef void
+ (*amendscan_function) (IndexScanDesc scan);
+
+ /* "mark current scan position" function */
+ typedef void
+ (*ammarkpos_function) (IndexScanDesc scan);
+
+ /* "restore marked scan position" function */
+ typedef void
+ (*amrestrpos_function) (IndexScanDesc scan);
+
+ /* "build new index" function */
+ typedef IndexBuildResult *
+ (*ambuild_function) (Relation heapRelation,
+ Relation indexRelation,
+ IndexInfo *indexInfo);
+
+ /* "build empty index" function */
+ typedef void
+ (*ambuildempty_function) (Relation indexRelation);
+
+ /* bulk-delete function */
+ typedef IndexBulkDeleteResult *
+ (*ambulkdelete_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+
+ /* post-VACUUM cleanup function */
+ typedef IndexBulkDeleteResult *
+ (*amvacuumcleanup_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
+
+ /* can indexscan return IndexTuples? */
+ typedef bool
+ (*amcanreturn_function) (Relation indexRelation, int attno);
+
+ /* estimate cost of an indexscan */
+ typedef void
+ (*amcostestimate_function) (PlannerInfo *root,
+ IndexPath *path,
+ double loop_count,
+ Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+
+ /* parse AM-specific parameters */
+ typedef bytea *
+ (*amoptions_function) (Datum reloptions,
+ bool validate);
+
+ /* validate oplass */
+ typedef void
+ (*amvalidate_function) (Oid opclassoid);
+
+
+ struct IndexAmRoutine
+ {
+ NodeTag type;
+
+ /*
+ * Total number of strategies (operators) by which we can traverse/search
+ * this AM. Zero if AM does not have a fixed set of strategy assignments.
+ */
+ int16 amstrategies;
+ /* total number of support functions that this AM uses */
+ int16 amsupport;
+ /* does AM support order by column value? */
+ bool amcanorder;
+ /* does AM support order by operator result? */
+ bool amcanorderbyop;
+ /* does AM support backward scan? */
+ bool amcanbackward;
+ /* does AM support UNIQUE indexes? */
+ bool amcanunique;
+ /* does AM support multi-column indexes? */
+ bool amcanmulticol;
+ /* can query omit key for the first column? */
+ bool amoptionalkey;
+ /* can AM handle ScalarArrayOpExpr quals? */
+ bool amsearcharray;
+ /* can AM search for NULL/NOT NULL entries? */
+ bool amsearchnulls;
+ /* can storage type differ from column type? */
+ bool amstorage;
+ /* does AM support cluster command? */
+ bool amclusterable;
+ /* does AM handle predicate locks? */
+ bool ampredlocks;
+ /* type of data in index, or InvalidOid */
+ Oid amkeytype;
+
+ /* interface functions */
+ aminsert_function aminsert;
+ ambeginscan_function ambeginscan;
+ amgettuple_function amgettuple;
+ amgetbitmap_function amgetbitmap;
+ amrescan_function amrescan;
+ amendscan_function amendscan;
+ ammarkpos_function ammarkpos;
+ amrestrpos_function amrestrpos;
+ ambuild_function ambuild;
+ ambuildempty_function ambuildempty;
+ ambulkdelete_function ambulkdelete;
+ amvacuumcleanup_function amvacuumcleanup;
+ amcanreturn_function amcanreturn;
+ amcostestimate_function amcostestimate;
+ amoptions_function amoptions;
+ amvalidate_function amvalidate;
+ };
+
+ #endif /* AMAPI_H */
diff --git a/src/include/access/brin.h b/src/include/access/brin.h
new file mode 100644
index e72fb2d..b9024fd
*** a/src/include/access/brin.h
--- b/src/include/access/brin.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
--- 18,50 ----
/*
* prototypes for functions in brin.c (external entry points for BRIN)
*/
! extern Datum brinhandler(PG_FUNCTION_ARGS);
! extern void brinvalidate(Oid opclassoid);
! extern IndexBuildResult *brinbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void brinbuildempty(Relation index);
! extern bool brininsert(Relation idxRel, Datum *values, bool *nulls,
! ItemPointer heaptid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys);
! extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
! ScanKey orderbys, int norderbys);
! extern void brinendscan(IndexScanDesc scan);
! extern void brinmarkpos(IndexScanDesc scan);
! extern void brinrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *brinbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *brinvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern void brincostestimate(PlannerInfo *root, IndexPath *path,
! double loop_count, Cost *indexStartupCost,
! Cost *indexTotalCost,
! Selectivity *indexSelectivity,
! double *indexCorrelation);
! extern bytea *brinoptions(Datum reloptions, bool validate);
/*
* Storage type for BRIN's reloptions
diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h
new file mode 100644
index 6be199e..3273fa7
*** a/src/include/access/brin_internal.h
--- b/src/include/access/brin_internal.h
***************
*** 11,16 ****
--- 11,17 ----
#ifndef BRIN_INTERNAL_H
#define BRIN_INTERNAL_H
+ #include "access/amapi.h"
#include "fmgr.h"
#include "storage/buf.h"
#include "storage/bufpage.h"
*************** typedef struct BrinDesc
*** 71,76 ****
--- 72,78 ----
#define BRIN_PROCNUM_ADDVALUE 2
#define BRIN_PROCNUM_CONSISTENT 3
#define BRIN_PROCNUM_UNION 4
+ #define BRIN_MANDATORY_NPROCS 4
/* procedure numbers up to 10 are reserved for BRIN future expansion */
#undef BRIN_DEBUG
*************** typedef struct BrinDesc
*** 85,89 ****
--- 87,117 ----
extern BrinDesc *brin_build_desc(Relation rel);
extern void brin_free_desc(BrinDesc *bdesc);
extern Datum brin_summarize_new_values(PG_FUNCTION_ARGS);
+ extern void brinvalidate(Oid opclassoid);
+ 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);
#endif /* BRIN_INTERNAL_H */
diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h
new file mode 100644
index 5021887..40c2fa0
*** 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,601 ----
/* ginutil.c */
! extern Datum ginhandler(PG_FUNCTION_ARGS);
! extern void ginvalidate(Oid opclassoid);
! 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,
--- 616,627 ----
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);
--- 872,899 ----
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 1a77982..c00b578
*** 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
*** 426,434 ****
} 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);
--- 427,439 ----
} GiSTOptions;
/* gist.c */
! extern Datum gisthandler(PG_FUNCTION_ARGS);
! extern void gistvalidate(Oid opclassoid);
! 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
*** 474,481 ****
Buffer leftchild, bool markfollowright);
/* gistget.c */
! extern Datum gistgettuple(PG_FUNCTION_ARGS);
! extern Datum gistgetbitmap(PG_FUNCTION_ARGS);
/* gistutil.c */
--- 479,486 ----
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
*** 485,491 ****
#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);
--- 490,496 ----
#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 *
*** 534,541 ****
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,
--- 539,550 ----
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
*** 544,550 ****
int attno);
/* gistbuild.c */
! extern Datum gistbuild(PG_FUNCTION_ARGS);
extern void gistValidateBufferingOption(char *value);
/* gistbuildbuffers.c */
--- 553,560 ----
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..866ad6b
*** 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,271 ----
/* public routines */
! extern Datum hashhandler(PG_FUNCTION_ARGS);
! extern void hashvalidate(Oid opclassoid);
! 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..50c66ee
*** 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,683 ----
/*
* prototypes for functions in nbtree.c (external entry points for btree)
*/
! extern Datum bthandler(PG_FUNCTION_ARGS);
! extern void btvalidate(Oid opclassoid);
! 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..d17aebd
*** 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,212 ----
} spgLeafConsistentOut;
+ /* spgutils.c */
+ extern Datum spghandler(PG_FUNCTION_ARGS);
+ extern void spgvalidate(Oid opclassoid);
+
/* 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..f19a873
*** 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,40 ----
CATALOG(pg_am,2601)
{
NameData amname; /* access method name */
! regproc amhandler; /* handler function */
} 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
--- 48,78 ----
* compiler constants for pg_am
* ----------------
*/
! #define Natts_pg_am 2
#define Anum_pg_am_amname 1
! #define Anum_pg_am_amhandler 2
/* ----------------
* initial contents of pg_am
* ----------------
*/
! DATA(insert OID = 403 ( btree bthandler ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
! DATA(insert OID = 405 ( hash hashhandler ));
DESCR("hash index access method");
#define HASH_AM_OID 405
! DATA(insert OID = 783 ( gist gisthandler ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
! DATA(insert OID = 2742 ( gin ginhandler ));
DESCR("GIN index access method");
#define GIN_AM_OID 2742
! DATA(insert OID = 4000 ( spgist spghandler ));
DESCR("SP-GiST index access method");
#define SPGIST_AM_OID 4000
! DATA(insert OID = 3580 ( brin brinhandler ));
DESCR("block range index (BRIN) access method");
#define BRIN_AM_OID 3580
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index d8640db..b3c6915
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DESCR("convert int4 to float4");
*** 548,610 ****
DATA(insert OID = 319 ( int4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "700" _null_ _null_ _null_ _null_ _null_ ftoi4 _null_ _null_ _null_ ));
DESCR("convert float4 to int4");
- DATA(insert OID = 330 ( btgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgettuple _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 636 ( btgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgetbitmap _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 331 ( btinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btinsert _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 333 ( btbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbeginscan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 334 ( btrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btrescan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 335 ( btendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btendscan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 336 ( btmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btmarkpos _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 337 ( btrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btrestrpos _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 338 ( btbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbuild _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 328 ( btbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btbuildempty _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 332 ( btbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbulkdelete _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ btvacuumcleanup _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 276 ( btcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ btcanreturn _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 1268 ( btcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btcostestimate _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 2785 ( btoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ btoptions _null_ _null_ _null_ ));
- DESCR("btree(internal)");
-
- DATA(insert OID = 3789 ( bringetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ bringetbitmap _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3790 ( brininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brininsert _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3791 ( brinbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbeginscan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3792 ( brinrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinrescan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3793 ( brinendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinendscan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3794 ( brinmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinmarkpos _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3795 ( brinrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinrestrpos _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3796 ( brinbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbuild _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3797 ( brinbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinbuildempty _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3798 ( brinbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbulkdelete _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3799 ( brinvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ brinvacuumcleanup _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3800 ( brincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brincostestimate _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3801 ( brinoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ brinoptions _null_ _null_ _null_ ));
- DESCR("brin(internal)");
DATA(insert OID = 3952 ( brin_summarize_new_values PGNSP PGUID 12 1 0 0 0 f f f f f f v s 1 0 23 "2205" _null_ _null_ _null_ _null_ _null_ brin_summarize_new_values _null_ _null_ _null_ ));
DESCR("brin: standalone scan new table pages");
--- 548,553 ----
*************** DESCR("convert name to char(n)");
*** 695,729 ****
DATA(insert OID = 409 ( name PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 19 "1042" _null_ _null_ _null_ _null_ _null_ bpchar_name _null_ _null_ _null_ ));
DESCR("convert char(n) to name");
- DATA(insert OID = 440 ( hashgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgettuple _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 637 ( hashgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgetbitmap _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 441 ( hashinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashinsert _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 443 ( hashbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbeginscan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 444 ( hashrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashrescan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 445 ( hashendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashendscan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 446 ( hashmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashmarkpos _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 447 ( hashrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashrestrpos _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 448 ( hashbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbuild _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 327 ( hashbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashbuildempty _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 442 ( hashbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbulkdelete _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashvacuumcleanup _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 438 ( hashcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashcostestimate _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 2786 ( hashoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ hashoptions _null_ _null_ _null_ ));
- DESCR("hash(internal)");
-
DATA(insert OID = 449 ( hashint2 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "21" _null_ _null_ _null_ _null_ _null_ hashint2 _null_ _null_ _null_ ));
DESCR("hash");
DATA(insert OID = 450 ( hashint4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ hashint4 _null_ _null_ _null_ ));
--- 638,643 ----
*************** DESCR("larger of two");
*** 979,1015 ****
DATA(insert OID = 771 ( int2smaller PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2smaller _null_ _null_ _null_ ));
DESCR("smaller of two");
- DATA(insert OID = 774 ( gistgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgettuple _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 638 ( gistgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgetbitmap _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 775 ( gistinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistinsert _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 777 ( gistbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbeginscan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 778 ( gistrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistrescan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 779 ( gistendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistendscan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 780 ( gistmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistmarkpos _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 781 ( gistrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistrestrpos _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 782 ( gistbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbuild _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 326 ( gistbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistbuildempty _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 776 ( gistbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbulkdelete _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistvacuumcleanup _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 3280 ( gistcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ gistcanreturn _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 772 ( gistcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistcostestimate _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 2787 ( gistoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ gistoptions _null_ _null_ _null_ ));
- DESCR("gist(internal)");
-
DATA(insert OID = 784 ( tintervaleq PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervaleq _null_ _null_ _null_ ));
DATA(insert OID = 785 ( tintervalne PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervalne _null_ _null_ _null_ ));
DATA(insert OID = 786 ( tintervallt PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervallt _null_ _null_ _null_ ));
--- 893,898 ----
*************** DATA(insert OID = 3311 ( tsm_handler_in
*** 3742,3747 ****
--- 3625,3634 ----
DESCR("I/O");
DATA(insert OID = 3312 ( tsm_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "3310" _null_ _null_ _null_ _null_ _null_ tsm_handler_out _null_ _null_ _null_ ));
DESCR("I/O");
+ DATA(insert OID = 326 ( index_am_handler_in PGNSP PGUID 12 1 0 0 0 f f f f f f i s 1 0 325 "2275" _null_ _null_ _null_ _null_ _null_ index_am_handler_in _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 327 ( index_am_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "325" _null_ _null_ _null_ _null_ _null_ index_am_handler_out _null_ _null_ _null_ ));
+ DESCR("I/O");
/* tablesample method handlers */
DATA(insert OID = 3313 ( bernoulli PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 3310 "2281" _null_ _null_ _null_ _null_ _null_ tsm_bernoulli_handler _null_ _null_ _null_ ));
*************** DESCR("GiST support");
*** 4198,4231 ****
DATA(insert OID = 3288 ( gist_bbox_distance PGNSP PGUID 12 1 0 0 0 f f f f t f i s 4 0 701 "2281 600 23 26" _null_ _null_ _null_ _null_ _null_ gist_bbox_distance _null_ _null_ _null_ ));
DESCR("GiST support");
- /* GIN */
- DATA(insert OID = 2731 ( gingetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gingetbitmap _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2732 ( gininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gininsert _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2733 ( ginbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbeginscan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2734 ( ginrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginrescan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2735 ( ginendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginendscan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2736 ( ginmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginmarkpos _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2737 ( ginrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginrestrpos _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2738 ( ginbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbuild _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 325 ( ginbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginbuildempty _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2739 ( ginbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbulkdelete _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ ginvacuumcleanup _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2741 ( gincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gincostestimate _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2788 ( ginoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ ginoptions _null_ _null_ _null_ ));
- DESCR("gin(internal)");
-
/* GIN array support */
DATA(insert OID = 2743 ( ginarrayextract PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 2281 "2277 2281 2281" _null_ _null_ _null_ _null_ _null_ ginarrayextract _null_ _null_ _null_ ));
DESCR("GIN array support");
--- 4085,4090 ----
*************** DESCR("construct timestamp with time zon
*** 5123,5160 ****
DATA(insert OID = 3464 ( make_interval PGNSP PGUID 12 1 0 0 0 f f f f t f i s 7 0 1186 "23 23 23 23 23 23 701" _null_ _null_ "{years,months,weeks,days,hours,mins,secs}" _null_ _null_ make_interval _null_ _null_ _null_ ));
DESCR("construct interval");
- /* spgist support functions */
- DATA(insert OID = 4001 ( spggettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggettuple _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4002 ( spggetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggetbitmap _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4003 ( spginsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spginsert _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4004 ( spgbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbeginscan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4005 ( spgrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgrescan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4006 ( spgendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgendscan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4007 ( spgmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgmarkpos _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4008 ( spgrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgrestrpos _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4009 ( spgbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbuild _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4010 ( spgbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgbuildempty _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4011 ( spgbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbulkdelete _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4012 ( spgvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ spgvacuumcleanup _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4032 ( spgcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ spgcanreturn _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4013 ( spgcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgcostestimate _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4014 ( spgoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ spgoptions _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
-
/* spgist opclasses */
DATA(insert OID = 4018 ( spg_quad_config PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_quad_config _null_ _null_ _null_ ));
DESCR("SP-GiST support for quad tree over point");
--- 4982,4987 ----
*************** DESCR("get an individual replication ori
*** 5337,5342 ****
--- 5164,5188 ----
DATA(insert OID = 6014 ( pg_show_replication_origin_status PGNSP PGUID 12 1 100 0 0 f f f f f t v r 0 0 2249 "" "{26,25,3220,3220}" "{o,o,o,o}" "{local_id, external_id, remote_lsn, local_lsn}" _null_ _null_ pg_show_replication_origin_status _null_ _null_ _null_ ));
DESCR("get progress for all replication origins");
+ /* Access methods handlers */
+ DATA(insert OID = 330 ( bthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ bthandler _null_ _null_ _null_ ));
+ DESCR("btree handler");
+ DATA(insert OID = 331 ( hashhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ hashhandler _null_ _null_ _null_ ));
+ DESCR("hash handler");
+ DATA(insert OID = 332 ( gisthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ gisthandler _null_ _null_ _null_ ));
+ DESCR("gist handler");
+ DATA(insert OID = 333 ( ginhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ ginhandler _null_ _null_ _null_ ));
+ DESCR("gin handler");
+ DATA(insert OID = 334 ( spghandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ spghandler _null_ _null_ _null_ ));
+ DESCR("spgist handler");
+ DATA(insert OID = 335 ( brinhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ brinhandler _null_ _null_ _null_ ));
+ DESCR("brin handler");
+
+ DATA(insert OID = 336 ( amvalidate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 16 "26" _null_ _null_ _null_ _null_ _null_ amvalidate _null_ _null_ _null_ ));
+ DESCR("ask access method to validate opclass");
+
+
+
/*
* Symbolic values for provolatile column: these indicate whether the result
* of a function is dependent *only* on the values of its explicit arguments,
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
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/commands/defrem.h b/src/include/commands/defrem.h
new file mode 100644
index adae296..112f9dc
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
*************** extern Oid get_am_oid(const char *amname
*** 95,100 ****
--- 95,101 ----
extern char *get_am_name(Oid amOid);
extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+ extern Datum amvalidate(PG_FUNCTION_ARGS);
/* commands/tsearchcmds.c */
extern ObjectAddress DefineTSParser(List *names, List *parameters);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
new file mode 100644
index eb3591a..419d5d2
*** 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 94bdb7c..9dd67f4
*** a/src/include/nodes/nodes.h
--- b/src/include/nodes/nodes.h
***************
*** 14,19 ****
--- 14,21 ----
#ifndef NODES_H
#define NODES_H
+ #include "nodes/reldecls.h"
+
/*
* The first field of every node is NodeTag. Each node created (with makeNode)
* will have one of the following tags as the value of its first field.
*************** typedef enum NodeTag
*** 455,461 ****
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;
/*
--- 457,464 ----
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;
/*
*************** extern bool equal(const void *a, const v
*** 544,561 ****
/*
- * Typedefs for identifying qualifier selectivities and plan costs as such.
- * These are just plain "double"s, but declaring a variable as Selectivity
- * or Cost makes the intent more obvious.
- *
- * These could have gone into plannodes.h or some such, but many files
- * depend on them...
- */
- typedef double Selectivity; /* fraction of tuples a qualifier will pass */
- typedef double Cost; /* execution cost (in page-access units) */
-
-
- /*
* CmdType -
* enums for type of operation represented by a Query or PlannedStmt
*
--- 547,552 ----
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
new file mode 100644
index 9a0dd28..03f87bb
*** a/src/include/nodes/relation.h
--- b/src/include/nodes/relation.h
***************
*** 18,24 ****
--- 18,26 ----
#include "lib/stringinfo.h"
#include "nodes/params.h"
#include "nodes/parsenodes.h"
+ #include "nodes/reldecls.h"
#include "storage/block.h"
+ #include "utils/relcache.h"
/*
*************** typedef struct PlannerGlobal
*** 125,131 ****
* the passed-in Query data structure; someday that should stop.
*----------
*/
! typedef struct PlannerInfo
{
NodeTag type;
--- 127,133 ----
* the passed-in Query data structure; someday that should stop.
*----------
*/
! struct PlannerInfo
{
NodeTag type;
*************** typedef struct PlannerInfo
*** 276,282 ****
/* for GroupingFunc fixup in setrefs */
AttrNumber *grouping_map;
! } PlannerInfo;
/*
--- 278,284 ----
/* for GroupingFunc fixup in setrefs */
AttrNumber *grouping_map;
! };
/*
*************** typedef struct IndexOptInfo
*** 549,556 ****
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 */
--- 551,557 ----
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
*** 561,572 ****
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;
--- 562,573 ----
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
*** 821,827 ****
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! typedef struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
--- 822,828 ----
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
*************** typedef struct IndexPath
*** 833,839 ****
ScanDirection indexscandir;
Cost indextotalcost;
Selectivity indexselectivity;
! } IndexPath;
/*
* BitmapHeapPath represents one or more indexscans that generate TID bitmaps
--- 834,840 ----
ScanDirection indexscandir;
Cost indextotalcost;
Selectivity indexselectivity;
! };
/*
* BitmapHeapPath represents one or more indexscans that generate TID bitmaps
diff --git a/src/include/nodes/reldecls.h b/src/include/nodes/reldecls.h
new file mode 100644
index ...cd97808
*** a/src/include/nodes/reldecls.h
--- b/src/include/nodes/reldecls.h
***************
*** 0 ****
--- 1,34 ----
+ /*-------------------------------------------------------------------------
+ *
+ * reldecls.h
+ * Declarations of some planner's data structures.
+ *
+ *
+ * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/nodes/reldecls.h
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef RELDECLS_H
+ #define RELDECLS_H
+
+ /*
+ * Typedefs for identifying qualifier selectivities and plan costs as such.
+ * These are just plain "double"s, but declaring a variable as Selectivity
+ * or Cost makes the intent more obvious.
+ *
+ * These could have gone into plannodes.h or some such, but many files
+ * depend on them...
+ */
+ typedef double Selectivity; /* fraction of tuples a qualifier will pass */
+ typedef double Cost; /* execution cost (in page-access units) */
+
+ /* Declarations for some data structures of src/include/nodes/relation.h */
+ typedef struct IndexAmRoutine IndexAmRoutine;
+ typedef struct PlannerInfo PlannerInfo;
+ typedef struct IndexPath IndexPath;
+ typedef struct IndexInfo IndexInfo;
+
+ #endif /* RELDECLS_H */
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
new file mode 100644
index e610bf3..ca55370
*** 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..825fed1
*** a/src/include/utils/relcache.h
--- b/src/include/utils/relcache.h
***************
*** 16,21 ****
--- 16,22 ----
#include "access/tupdesc.h"
#include "nodes/bitmapset.h"
+ #include "nodes/reldecls.h"
typedef struct RelationData *Relation;
*************** typedef struct RelationData *Relation;
*** 29,34 ****
--- 30,42 ----
typedef Relation *RelationPtr;
/*
+ * Routines to retreive IndexAmRoutine
+ */
+ extern IndexAmRoutine *GetIndexAmRoutine(Oid amhandler);
+ extern IndexAmRoutine *GetIndexAmRoutineByAmId(Oid amoid);
+ extern void InitIndexAmRoutine(Relation relation);
+
+ /*
* Routines to open (lookup) and close a relcache entry
*/
extern Relation RelationIdGetRelation(Oid relationId);
diff --git a/src/include/utils/selfuncs.h b/src/include/utils/selfuncs.h
new file mode 100644
index a7433d9..3745d1c
*** a/src/include/utils/selfuncs.h
--- b/src/include/utils/selfuncs.h
*************** extern double estimate_num_groups(Planne
*** 191,202 ****
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 */
--- 191,226 ----
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..d1a322d
*** a/src/test/regress/expected/oidjoins.out
--- b/src/test/regress/expected/oidjoins.out
*************** WHERE aggmtranstype != 0 AND
*** 73,206 ****
------+---------------
(0 rows)
- SELECT ctid, amkeytype
- FROM pg_catalog.pg_am fk
- WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
- ctid | amkeytype
- ------+-----------
- (0 rows)
-
- SELECT ctid, aminsert
- FROM pg_catalog.pg_am fk
- WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
- ctid | aminsert
- ------+----------
- (0 rows)
-
- SELECT ctid, ambeginscan
- FROM pg_catalog.pg_am fk
- WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
- ctid | ambeginscan
- ------+-------------
- (0 rows)
-
- SELECT ctid, amgettuple
- FROM pg_catalog.pg_am fk
- WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- ctid | amgettuple
- ------+------------
- (0 rows)
-
- SELECT ctid, amgetbitmap
- FROM pg_catalog.pg_am fk
- WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
- ctid | amgetbitmap
- ------+-------------
- (0 rows)
-
- SELECT ctid, amrescan
- FROM pg_catalog.pg_am fk
- WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
- ctid | amrescan
- ------+----------
- (0 rows)
-
- SELECT ctid, amendscan
- FROM pg_catalog.pg_am fk
- WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
- ctid | amendscan
- ------+-----------
- (0 rows)
-
- SELECT ctid, ammarkpos
- FROM pg_catalog.pg_am fk
- WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
- ctid | ammarkpos
- ------+-----------
- (0 rows)
-
- SELECT ctid, amrestrpos
- FROM pg_catalog.pg_am fk
- WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
- ctid | amrestrpos
- ------+------------
- (0 rows)
-
- SELECT ctid, ambuild
- FROM pg_catalog.pg_am fk
- WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
- ctid | ambuild
- ------+---------
- (0 rows)
-
- SELECT ctid, ambuildempty
- FROM pg_catalog.pg_am fk
- WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
- ctid | ambuildempty
- ------+--------------
- (0 rows)
-
- SELECT ctid, ambulkdelete
- FROM pg_catalog.pg_am fk
- WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
- ctid | ambulkdelete
- ------+--------------
- (0 rows)
-
- SELECT ctid, amvacuumcleanup
- FROM pg_catalog.pg_am fk
- WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
- ctid | amvacuumcleanup
- ------+-----------------
- (0 rows)
-
- SELECT ctid, amcanreturn
- FROM pg_catalog.pg_am fk
- WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
- ctid | amcanreturn
- ------+-------------
- (0 rows)
-
- SELECT ctid, amcostestimate
- FROM pg_catalog.pg_am fk
- WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
- ctid | amcostestimate
- ------+----------------
- (0 rows)
-
- SELECT ctid, amoptions
- FROM pg_catalog.pg_am fk
- WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
- ctid | amoptions
- ------+-----------
- (0 rows)
-
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 73,78 ----
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
new file mode 100644
index 7c93b3b..ef66a08
*** a/src/test/regress/expected/opr_sanity.out
--- b/src/test/regress/expected/opr_sanity.out
*************** WHERE p1.oid != p2.oid AND
*** 1481,1486 ****
--- 1481,1492 ----
-----+-----
(0 rows)
+ -- Ask access methods to validate opclasses
+ SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid);
+ oid
+ -----
+ (0 rows)
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
SELECT p1.amopfamily, p1.amopstrategy
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 1526,1574 ****
------------+--------------
(0 rows)
- -- check for ordering operators not supported by parent AM
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
- amopfamily | amopopr | oid | amname
- ------------+---------+-----+--------
- (0 rows)
-
- -- Cross-check amopstrategy index against parent AM
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
- amopfamily | amopopr | oid | amname
- ------------+---------+-----+--------
- (0 rows)
-
- -- Detect missing pg_amop entries: should have as many strategy operators
- -- as AM expects for each datatype combination supported by the opfamily.
- -- We can't check this for AMs with variable strategy sets.
- SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
- amname | amoplefttype | amoprighttype
- --------+--------------+---------------
- (0 rows)
-
- -- Currently, none of the AMs with fixed strategy sets support ordering ops.
- SELECT p1.amname, p2.amopfamily, p2.amopstrategy
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
- amname | amopfamily | amopstrategy
- --------+------------+--------------
- (0 rows)
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
--- 1532,1537 ----
*************** WHERE p1.amprocfamily = 0 OR p1.amprocle
*** 1851,1865 ****
--------------+-----------
(0 rows)
- -- Cross-check amprocnum index against parent AM
- SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
- FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
- WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
- amprocfamily | amprocnum | oid | amname
- --------------+-----------+-----+--------
- (0 rows)
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
SELECT * FROM (
--- 1814,1819 ----
diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql
new file mode 100644
index 2fa628d..ca419fd
*** a/src/test/regress/sql/oidjoins.sql
--- b/src/test/regress/sql/oidjoins.sql
*************** SELECT ctid, aggmtranstype
*** 37,106 ****
FROM pg_catalog.pg_aggregate fk
WHERE aggmtranstype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
- SELECT ctid, amkeytype
- FROM pg_catalog.pg_am fk
- WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
- SELECT ctid, aminsert
- FROM pg_catalog.pg_am fk
- WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
- SELECT ctid, ambeginscan
- FROM pg_catalog.pg_am fk
- WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
- SELECT ctid, amgettuple
- FROM pg_catalog.pg_am fk
- WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- SELECT ctid, amgetbitmap
- FROM pg_catalog.pg_am fk
- WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
- SELECT ctid, amrescan
- FROM pg_catalog.pg_am fk
- WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
- SELECT ctid, amendscan
- FROM pg_catalog.pg_am fk
- WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
- SELECT ctid, ammarkpos
- FROM pg_catalog.pg_am fk
- WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
- SELECT ctid, amrestrpos
- FROM pg_catalog.pg_am fk
- WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
- SELECT ctid, ambuild
- FROM pg_catalog.pg_am fk
- WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
- SELECT ctid, ambuildempty
- FROM pg_catalog.pg_am fk
- WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
- SELECT ctid, ambulkdelete
- FROM pg_catalog.pg_am fk
- WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
- SELECT ctid, amvacuumcleanup
- FROM pg_catalog.pg_am fk
- WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
- SELECT ctid, amcanreturn
- FROM pg_catalog.pg_am fk
- WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
- SELECT ctid, amcostestimate
- FROM pg_catalog.pg_am fk
- WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
- SELECT ctid, amoptions
- FROM pg_catalog.pg_am fk
- WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 37,42 ----
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
new file mode 100644
index c9bdd77..0e0506e
*** a/src/test/regress/sql/opr_sanity.sql
--- b/src/test/regress/sql/opr_sanity.sql
*************** WHERE p1.oid != p2.oid AND
*** 960,965 ****
--- 960,969 ----
p1.opcmethod = p2.opcmethod AND p1.opcintype = p2.opcintype AND
p1.opcdefault AND p2.opcdefault;
+ -- Ask access methods to validate opclasses
+
+ SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid);
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 995,1035 ****
(SELECT 1 from pg_opfamily op WHERE op.oid = p1.amopsortfamily
AND op.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree'));
- -- check for ordering operators not supported by parent AM
-
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
-
- -- Cross-check amopstrategy index against parent AM
-
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
-
- -- Detect missing pg_amop entries: should have as many strategy operators
- -- as AM expects for each datatype combination supported by the opfamily.
- -- We can't check this for AMs with variable strategy sets.
-
- SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
-
- -- Currently, none of the AMs with fixed strategy sets support ordering ops.
-
- SELECT p1.amname, p2.amopfamily, p2.amopstrategy
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
--- 999,1004 ----
*************** FROM pg_amproc as p1
*** 1176,1188 ****
WHERE p1.amprocfamily = 0 OR p1.amproclefttype = 0 OR p1.amprocrighttype = 0
OR p1.amprocnum < 1 OR p1.amproc = 0;
- -- Cross-check amprocnum index against parent AM
-
- SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
- FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
- WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
--- 1145,1150 ----
On Thu, Nov 12, 2015 at 2:49 PM, Alexander Korotkov <
a.korotkov@postgrespro.ru> wrote:
On Tue, Nov 3, 2015 at 3:16 PM, Alexander Korotkov <
a.korotkov@postgrespro.ru> wrote:On Tue, Nov 3, 2015 at 2:36 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
Tom Lane wrote:
I'm kind of inclined to just let the verifiers read the catalogs for
themselves. AFAICS, a loop around the results of SearchSysCacheList
is not going to be significantly more code than what this patch does,
and it avoids presuming that we know what the verifiers will wish to
look at.Hmm, so this amounts to saying the verifier can only run after the
catalog rows are written. Is that okay?Why not? Surely we are not interested in performance-optimizing for
the case of a detectably incorrect CREATE OP CLASS command.I don't actually care that much about running the verifiers during
CREATE/etc OP CLASS at all. It's at least as important to be able
to run them across the built-in opclasses, considering all the chances
for human error in constructing those things. Even in the ALTER OP CLASS
case, the verifier would likely need to look at existing catalog rows as
well as the new ones. So basically, I see zero value in exposing CREATE/
ALTER OP CLASS's internal working representation to the verifiers.I'm OK with validating opclass directly by system catalog, i.e. looping
over SearchSysCacheList results. Teodor was telling me something similar
personally.
I'll also try to rearrange header according to the comments upthread.The next revision of patch is attached.
The changes are following:1. Definitions of Selectivity, Cost and declarations
of IndexAmRoutine, PlannerInfo, IndexPath, IndexInfo are moved into
separate header reldecls.h. That allows to get rid of #include
"nodes/relation.h" in amapi.h.
2. amvalidate method now gets opclass oid as parameter. Internally,
amvalidate implementations do catalog lookups. opfam_internal.h isn't
included from inappropriate places anymore.
3. I removed amvalidate calls from opclasscmds.c. Validating
user-defined opclasses is behavior change which can have issues with
backward compatibility. I think if we want to introduce this, it should be
considered separately of API rework.Patch was rebased against current master.
Any notes about current version of patch?
It would be nice to commit it and continue work on other parts of am
extendability.
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Attachments:
aminterface-11.patchapplication/octet-stream; name=aminterface-11.patchDownload
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
new file mode 100644
index 99337b0..0442bd4
*** 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 931dceb..b52846f
*** a/src/backend/access/common/reloptions.c
--- b/src/backend/access/common/reloptions.c
*************** untransformRelOptions(Datum options)
*** 891,897 ****
* 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;
--- 891,897 ----
* 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
*** 1379,1412 ****
* 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);
}
/*
--- 1379,1393 ----
* 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 49e9185..92701b9
*** 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 323cfb0..5b38607
*** 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, true, stats);
}
! PG_RETURN_POINTER(stats);
}
/*
--- 656,662 ----
initGinState(&ginstate, index);
ginInsertCleanup(&ginstate, true, 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 53bccf6..6e15049
*** 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 void gistfinishsplit(GISTInsertSt
*** 38,43 ****
--- 40,87 ----
GISTSTATE *giststate, List *splitinfo, bool releasebuf);
static void gistvacuumpage(Relation rel, Page page, Buffer buffer);
+ /*
+ * 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)
*** 70,79 ****
/*
* 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 */
--- 114,122 ----
/*
* gistbuildempty() -- build an empty gist index in the initialization fork
*/
! void
! gistbuildempty(Relation index)
{
Buffer buffer;
/* Initialize the root page */
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 89,96 ****
/* Unlock and release the buffer */
UnlockReleaseBuffer(buffer);
-
- PG_RETURN_VOID();
}
/*
--- 132,137 ----
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 99,116 ****
* 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;
--- 140,150 ----
* 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)
*** 136,142 ****
MemoryContextSwitchTo(oldCxt);
freeGISTstate(giststate);
! PG_RETURN_BOOL(false);
}
--- 170,176 ----
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 ce8e582..1adf92f
*** a/src/backend/access/gist/gistget.c
--- b/src/backend/access/gist/gistget.c
*************** getNextNearest(IndexScanDesc scan)
*** 618,628 ****
/*
* 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)
--- 618,626 ----
/*
* 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)
*** 651,657 ****
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! PG_RETURN_BOOL(getNextNearest(scan));
}
else
{
--- 649,655 ----
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! return getNextNearest(scan);
}
else
{
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 688,694 ****
so->curPageData++;
! PG_RETURN_BOOL(true);
}
/*
--- 686,692 ----
so->curPageData++;
! return true;
}
/*
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 726,732 ****
item = getNextGISTSearchItem(so);
if (!item)
! PG_RETURN_BOOL(false);
CHECK_FOR_INTERRUPTS();
--- 724,730 ----
item = getNextGISTSearchItem(so);
if (!item)
! return false;
CHECK_FOR_INTERRUPTS();
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 750,766 ****
/*
* 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);
--- 748,762 ----
/*
* 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)
*** 791,797 ****
pfree(item);
}
! PG_RETURN_INT64(ntids);
}
/*
--- 787,793 ----
pfree(item);
}
! return ntids;
}
/*
*************** gistgetbitmap(PG_FUNCTION_ARGS)
*** 799,812 ****
*
* 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);
}
--- 795,805 ----
*
* 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 a17c5bc..22f0c68
*** 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)
*** 107,121 ****
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;
--- 104,116 ----
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)
*** 314,341 ****
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;
/*
--- 309,331 ----
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)
*** 343,348 ****
* as well as the queueCxt if there is a separate context for it.
*/
freeGISTstate(so->giststate);
-
- PG_RETURN_VOID();
}
--- 333,336 ----
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 a0b0eeb..e0ce620
*** 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)
*** 276,280 ****
vacuum_delay_point();
}
! PG_RETURN_POINTER(stats);
}
--- 271,275 ----
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/genam.c b/src/backend/access/index/genam.c
new file mode 100644
index aa5b28c..1ec5631
*** a/src/backend/access/index/genam.c
--- b/src/backend/access/index/genam.c
*************** systable_endscan_ordered(SysScanDesc sys
*** 613,615 ****
--- 613,713 ----
UnregisterSnapshot(sysscan->snapshot);
pfree(sysscan);
}
+
+ /*
+ * Get oid parameter of access method.
+ */
+ Datum
+ get_am_param_oid(PG_FUNCTION_ARGS)
+ {
+ Oid amoid = PG_GETARG_OID(0);
+ text *param = PG_GETARG_TEXT_PP(1);
+ char *param_name;
+ IndexAmRoutine *routine;
+
+ routine = GetIndexAmRoutine(amoid);
+ param_name = text_to_cstring(param);
+
+ if (!strcmp(param_name, "amkeytype"))
+ PG_RETURN_OID(routine->amkeytype);
+
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid index access method oid parameter: \"%s\"",
+ param_name)));
+
+ pg_unreachable();
+ }
+
+ /*
+ * Get integer parameter of access method.
+ */
+ Datum
+ get_am_param_int(PG_FUNCTION_ARGS)
+ {
+ Oid amoid = PG_GETARG_OID(0);
+ text *param = PG_GETARG_TEXT_PP(1);
+ char *param_name;
+ IndexAmRoutine *routine;
+
+ routine = GetIndexAmRoutine(amoid);
+ param_name = text_to_cstring(param);
+
+ if (!strcmp(param_name, "amstrategies"))
+ PG_RETURN_OID(routine->amstrategies);
+ else if (!strcmp(param_name, "amsupport"))
+ PG_RETURN_OID(routine->amsupport);
+
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid index access method integer parameter: \"%s\"",
+ param_name)));
+
+ pg_unreachable();
+ }
+
+
+ /*
+ * Get boolean parameter of access method.
+ */
+ Datum
+ get_am_param_bool(PG_FUNCTION_ARGS)
+ {
+ Oid amoid = PG_GETARG_OID(0);
+ text *param = PG_GETARG_TEXT_PP(1);
+ char *param_name;
+ IndexAmRoutine *routine;
+
+ routine = GetIndexAmRoutine(amoid);
+ param_name = text_to_cstring(param);
+
+ if (!strcmp(param_name, "amcanorder"))
+ PG_RETURN_OID(routine->amcanorder);
+ else if (!strcmp(param_name, "amcanorderbyop"))
+ PG_RETURN_OID(routine->amcanorderbyop);
+ else if (!strcmp(param_name, "amcanbackward"))
+ PG_RETURN_OID(routine->amcanbackward);
+ else if (!strcmp(param_name, "amcanunique"))
+ PG_RETURN_OID(routine->amcanunique);
+ else if (!strcmp(param_name, "amcanmulticol"))
+ PG_RETURN_OID(routine->amcanmulticol);
+ else if (!strcmp(param_name, "amoptionalkey"))
+ PG_RETURN_OID(routine->amoptionalkey);
+ else if (!strcmp(param_name, "amsearcharray"))
+ PG_RETURN_OID(routine->amsearcharray);
+ else if (!strcmp(param_name, "amsearchnulls"))
+ PG_RETURN_OID(routine->amsearchnulls);
+ else if (!strcmp(param_name, "amstorage"))
+ PG_RETURN_OID(routine->amstorage);
+ else if (!strcmp(param_name, "amclusterable"))
+ PG_RETURN_OID(routine->amclusterable);
+ else if (!strcmp(param_name, "ampredlocks"))
+ PG_RETURN_OID(routine->ampredlocks);
+
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid index access method boolean parameter: \"%s\"",
+ param_name)));
+
+ pg_unreachable();
+ }
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..80ab3b1
*** 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"
+
+
+ /*
+ * 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 <unistd.h>
+ #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/opclasscmds.c b/src/backend/commands/opclasscmds.c
new file mode 100644
index 3375f10..a8208b3
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 334,346 ****
ListCell *l;
Relation rel;
HeapTuple tup;
- Form_pg_am pg_am;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
--- 334,346 ----
ListCell *l;
Relation rel;
HeapTuple tup;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
+ IndexAmRoutine *amroutine;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 361,373 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
! amstorage = pg_am->amstorage;
/* XXX Should we make any privilege check against the AM? */
--- 361,373 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! amroutine = GetIndexAmRoutine(amoid);
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
! amstorage = amroutine->amstorage;
/* XXX Should we make any privilege check against the AM? */
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 776,782 ****
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! Form_pg_am pg_am;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
--- 776,782 ----
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! IndexAmRoutine *amroutine;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 787,798 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
/* XXX Should we make any privilege check against the AM? */
--- 787,798 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! amroutine = GetIndexAmRoutine(amoid);
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
/* XXX Should we make any privilege check against the AM? */
*************** assignOperTypes(OpFamilyMember *member,
*** 1099,1119 ****
* the family has been created but not yet populated with the required
* operators.)
*/
! HeapTuple amtup;
! Form_pg_am pg_am;
! amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
! if (amtup == NULL)
! elog(ERROR, "cache lookup failed for access method %u", amoid);
! pg_am = (Form_pg_am) GETSTRUCT(amtup);
! if (!pg_am->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! NameStr(pg_am->amname))));
!
! ReleaseSysCache(amtup);
}
else
{
--- 1099,1113 ----
* the family has been created but not yet populated with the required
* operators.)
*/
! IndexAmRoutine *amroutine;
! amroutine = GetIndexAmRoutine(amoid);
! if (!amroutine->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! get_am_name(amoid))));
}
else
{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
new file mode 100644
index 0ddde72..cc01166
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
*************** ATExecSetRelOptions(Relation rel, List *
*** 9397,9403 ****
(void) view_reloptions(newOptions, true);
break;
case RELKIND_INDEX:
! (void) index_reloptions(rel->rd_am->amoptions, newOptions, true);
break;
default:
ereport(ERROR,
--- 9397,9403 ----
(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
*** 10988,10994 ****
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",
--- 10988,10994 ----
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 b969fc0..0c339c3
*** 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)
*** 545,550 ****
--- 546,552 ----
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)
*** 558,566 ****
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);
--- 560,570 ----
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 990486c..1310613
*** a/src/backend/optimizer/path/costsize.c
--- b/src/backend/optimizer/path/costsize.c
*************** cost_index(IndexPath *path, PlannerInfo
*** 419,432 ****
* 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.
--- 419,426 ----
* 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 344a40c..f11c236
*** 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
*** 1292,1298 ****
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
--- 1293,1299 ----
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 0ab839d..8ffb18c
*** a/src/backend/utils/adt/ruleutils.c
--- b/src/backend/utils/adt/ruleutils.c
***************
*** 19,24 ****
--- 19,25 ----
#include <unistd.h>
#include <fcntl.h>
+ #include "access/amapi.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "catalog/dependency.h"
*************** pg_get_indexdef_worker(Oid indexrelid, i
*** 1179,1184 ****
--- 1180,1186 ----
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
*** 1189,1196 ****
/* 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)
--- 1191,1201 ----
/* 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 15121bc..a882796
*** a/src/backend/utils/adt/selfuncs.c
--- b/src/backend/utils/adt/selfuncs.c
*************** add_predicate_to_quals(IndexOptInfo *ind
*** 6443,6458 ****
}
! 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;
--- 6443,6453 ----
}
! 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)
*** 6741,6760 ****
*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;
--- 6736,6748 ----
*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)
*** 6794,6813 ****
*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;
--- 6782,6794 ----
*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)
*** 6860,6879 ****
*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;
--- 6841,6853 ----
*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)
*** 6926,6933 ****
*indexTotalCost = costs.indexTotalCost;
*indexSelectivity = costs.indexSelectivity;
*indexCorrelation = costs.indexCorrelation;
-
- PG_RETURN_VOID();
}
--- 6900,6905 ----
*************** gincost_scalararrayopexpr(PlannerInfo *r
*** 7222,7237 ****
/*
* 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;
--- 7194,7204 ----
/*
* 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)
*** 7400,7406 ****
*indexStartupCost = 0;
*indexTotalCost = 0;
*indexSelectivity = 0;
! PG_RETURN_VOID();
}
if (counts.haveFullScan || indexQuals == NIL)
--- 7367,7373 ----
*indexStartupCost = 0;
*indexTotalCost = 0;
*indexSelectivity = 0;
! return;
}
if (counts.haveFullScan || indexQuals == NIL)
*************** gincostestimate(PG_FUNCTION_ARGS)
*** 7522,7544 ****
*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;
--- 7489,7504 ----
*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)
*** 7591,7596 ****
*indexTotalCost += (numTuples * *indexSelectivity) * (cpu_index_tuple_cost + qual_op_cost);
/* XXX what about pages_per_range? */
-
- PG_RETURN_VOID();
}
--- 7551,7554 ----
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
new file mode 100644
index 6b0c0b7..3327f39
*** a/src/backend/utils/cache/relcache.c
--- b/src/backend/utils/cache/relcache.c
*************** 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
--- 445,451 ----
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
*** 1160,1172 ****
}
/*
* 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;
--- 1160,1217 ----
}
/*
+ * Get IndexAmRoutine structure from access method oid.
+ */
+ IndexAmRoutine *
+ GetIndexAmRoutine(Oid amoid)
+ {
+ IndexAmRoutine *result;
+ HeapTuple tuple;
+ regproc amhandler;
+
+ tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for access method %u",
+ amoid);
+ amhandler = ((Form_pg_am)GETSTRUCT(tuple))->amhandler;
+
+ if (!RegProcedureIsValid(amhandler))
+ elog(ERROR, "invalid %u regproc", amhandler);
+
+ result = (IndexAmRoutine *)DatumGetPointer(OidFunctionCall0(amhandler));
+
+ if (result == NULL || !IsA(result, IndexAmRoutine))
+ elog(ERROR, "index access method handler function %u did not return an IndexAmRoutine struct",
+ amhandler);
+
+ ReleaseSysCache(tuple);
+
+ return result;
+ }
+
+ /*
+ * Initialize IndexAmRoutine for relation.
+ */
+ void
+ InitIndexAmRoutine(Relation relation)
+ {
+ IndexAmRoutine *result, *tmp;
+
+ result = (IndexAmRoutine *)MemoryContextAlloc(CacheMemoryContext,
+ sizeof(IndexAmRoutine));
+ tmp = (IndexAmRoutine *)DatumGetPointer(
+ OidFunctionCall0(relation->rd_am->amhandler));
+ memcpy(result, tmp, sizeof(IndexAmRoutine));
+ relation->amroutine = result;
+ }
+
+ /*
* Initialize index-access-method support data for an index relation
*/
void
RelationInitIndexAccessInfo(Relation relation)
{
HeapTuple tuple;
Datum indcollDatum;
Datum indclassDatum;
Datum indoptionDatum;
*************** RelationInitIndexAccessInfo(Relation rel
*** 1178,1183 ****
--- 1223,1229 ----
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
*** 1202,1217 ****
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
--- 1248,1265 ----
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)
*** 4743,4749 ****
Oid *opfamily;
Oid *opcintype;
RegProcedure *support;
- int nsupport;
int16 *indoption;
Oid *indcollation;
--- 4791,4796 ----
*************** load_relcache_init_file(bool shared)
*** 4771,4776 ****
--- 4818,4824 ----
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)
*** 4832,4843 ****
rel->rd_indoption = indoption;
/* 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
{
--- 4880,4892 ----
rel->rd_indoption = indoption;
+ InitIndexAmRoutine(rel);
+
/* set up zeroed fmgr-info vectors */
rel->rd_aminfo = (RelationAmInfo *)
MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
rel->rd_supportinfo = (FmgrInfo *)
! MemoryContextAllocZero(indexcxt, relform->relnatts * rel->amroutine->amsupport * sizeof(FmgrInfo));
}
else
{
*************** write_relcache_init_file(bool shared)
*** 5116,5122 ****
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
--- 5165,5171 ----
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (rel->amroutine->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h
new file mode 100644
index ...4b6dda2
*** a/src/include/access/amapi.h
--- b/src/include/access/amapi.h
***************
*** 0 ****
--- 1,164 ----
+ /*-------------------------------------------------------------------------
+ *
+ * amapi.h
+ * API for access methods
+ *
+ * Copyright (c) 2015, PostgreSQL Global Development Group
+ *
+ * src/include/access/amapi.h
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef AMAPI_H
+ #define AMAPI_H
+
+ #include "access/genam.h"
+ #include "catalog/opfam_internal.h"
+ #include "nodes/relation.h"
+
+ /*
+ * Callback function signatures --- see indexam.sgml for more info.
+ */
+
+ /* "insert this tuple" function */
+ typedef bool
+ (*aminsert_function) (Relation indexRelation,
+ Datum *values,
+ bool *isnull,
+ ItemPointer heap_tid,
+ Relation heapRelation,
+ IndexUniqueCheck checkUnique);
+
+ /* "prepare for index scan" function */
+ typedef IndexScanDesc
+ (*ambeginscan_function) (Relation indexRelation,
+ int nkeys,
+ int norderbys);
+
+ /* "next valid tuple" function, or NULL */
+ typedef bool
+ (*amgettuple_function) (IndexScanDesc scan,
+ ScanDirection direction);
+
+ /* "fetch all valid tuples" function, or NULL */
+ typedef int64
+ (*amgetbitmap_function) (IndexScanDesc scan,
+ TIDBitmap *tbm);
+
+ /* "(re)start index scan" function */
+ typedef void
+ (*amrescan_function) (IndexScanDesc scan,
+ ScanKey keys,
+ int nkeys,
+ ScanKey orderbys,
+ int norderbys);
+
+ /* "end index scan" function */
+ typedef void
+ (*amendscan_function) (IndexScanDesc scan);
+
+ /* "mark current scan position" function */
+ typedef void
+ (*ammarkpos_function) (IndexScanDesc scan);
+
+ /* "restore marked scan position" function */
+ typedef void
+ (*amrestrpos_function) (IndexScanDesc scan);
+
+ /* "build new index" function */
+ typedef IndexBuildResult *
+ (*ambuild_function) (Relation heapRelation,
+ Relation indexRelation,
+ IndexInfo *indexInfo);
+
+ /* "build empty index" function */
+ typedef void
+ (*ambuildempty_function) (Relation indexRelation);
+
+ /* bulk-delete function */
+ typedef IndexBulkDeleteResult *
+ (*ambulkdelete_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+
+ /* post-VACUUM cleanup function */
+ typedef IndexBulkDeleteResult *
+ (*amvacuumcleanup_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
+
+ /* can indexscan return IndexTuples? */
+ typedef bool
+ (*amcanreturn_function) (Relation indexRelation, int attno);
+
+ /* estimate cost of an indexscan */
+ typedef void
+ (*amcostestimate_function) (PlannerInfo *root,
+ IndexPath *path,
+ double loop_count,
+ Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+
+ /* parse AM-specific parameters */
+ typedef bytea *
+ (*amoptions_function) (Datum reloptions,
+ bool validate);
+
+
+ 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..5ae5722
*** 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,51 ----
/*
* prototypes for functions in brin.c (external entry points for BRIN)
*/
! extern Datum brinhandler(PG_FUNCTION_ARGS);
! extern void brinvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *brinbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void brinbuildempty(Relation index);
! extern bool brininsert(Relation idxRel, Datum *values, bool *nulls,
! ItemPointer heaptid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys);
! extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
! ScanKey orderbys, int norderbys);
! extern void brinendscan(IndexScanDesc scan);
! extern void brinmarkpos(IndexScanDesc scan);
! extern void brinrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *brinbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *brinvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern void brincostestimate(PlannerInfo *root, IndexPath *path,
! double loop_count, Cost *indexStartupCost,
! Cost *indexTotalCost,
! Selectivity *indexSelectivity,
! double *indexCorrelation);
! extern bytea *brinoptions(Datum reloptions, bool validate);
/*
* Storage type for BRIN's reloptions
diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h
new file mode 100644
index 6be199e..2f8fe17
*** a/src/include/access/brin_internal.h
--- b/src/include/access/brin_internal.h
*************** typedef struct BrinDesc
*** 72,77 ****
--- 72,78 ----
#define BRIN_PROCNUM_CONSISTENT 3
#define BRIN_PROCNUM_UNION 4
/* procedure numbers up to 10 are reserved for BRIN future expansion */
+ #define BRIN_NPROC 15
#undef BRIN_DEBUG
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
new file mode 100644
index d9d05a0..15170b2
*** 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 ----
*************** extern HeapTuple systable_getnext_ordere
*** 190,193 ****
--- 189,199 ----
ScanDirection direction);
extern void systable_endscan_ordered(SysScanDesc sysscan);
+ /*
+ * get attributes of access methods (in genam.c)
+ */
+ extern Datum get_am_param_oid(PG_FUNCTION_ARGS);
+ extern Datum get_am_param_int(PG_FUNCTION_ARGS);
+ extern Datum get_am_param_bool(PG_FUNCTION_ARGS);
+
#endif /* GENAM_H */
diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h
new file mode 100644
index 5021887..a77d43f
*** 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,601 ----
/* ginutil.c */
! extern Datum ginhandler(PG_FUNCTION_ARGS);
! extern void ginvalidate(OpClassInfo *opclass);
! extern bytea *ginoptions(Datum reloptions, bool validate);
extern void initGinState(GinState *state, Relation index);
extern Buffer GinNewBuffer(Relation index);
extern void GinInitBuffer(Buffer b, uint32 f);
*************** 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,
--- 616,627 ----
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);
--- 872,899 ----
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 1a77982..35fb34a
*** 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
*** 426,434 ****
} 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);
--- 427,439 ----
} GiSTOptions;
/* gist.c */
! extern Datum gisthandler(PG_FUNCTION_ARGS);
! extern void gistvalidate(OpClassInfo *opclass);
! extern void gistbuildempty(Relation index);
! extern bool gistinsert(Relation r, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern bool gistcanreturn(Relation index, int attno);
extern MemoryContext createTempGistContext(void);
extern GISTSTATE *initGISTstate(Relation index);
extern void freeGISTstate(GISTSTATE *giststate);
*************** extern XLogRecPtr gistXLogSplit(RelFileN
*** 474,481 ****
Buffer leftchild, bool markfollowright);
/* gistget.c */
! extern Datum gistgettuple(PG_FUNCTION_ARGS);
! extern Datum gistgetbitmap(PG_FUNCTION_ARGS);
/* gistutil.c */
--- 479,486 ----
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
*** 485,491 ****
#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);
--- 490,496 ----
#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 *
*** 534,541 ****
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,
--- 539,550 ----
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
*** 544,550 ****
int attno);
/* gistbuild.c */
! extern Datum gistbuild(PG_FUNCTION_ARGS);
extern void gistValidateBufferingOption(char *value);
/* gistbuildbuffers.c */
--- 553,560 ----
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..9595c6b
*** 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,271 ----
/* public routines */
! extern Datum hashhandler(PG_FUNCTION_ARGS);
! extern void hashvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *hashbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void hashbuildempty(Relation index);
! extern bool hashinsert(Relation rel, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc hashbeginscan(Relation rel, int nkeys, int norderbys);
! extern bool hashgettuple(IndexScanDesc scan, ScanDirection dir);
! extern int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void hashrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
! ScanKey orderbys, int norderbys);
! extern void hashendscan(IndexScanDesc scan);
! extern void hashmarkpos(IndexScanDesc scan);
! extern void hashrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *hashbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *hashvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern bytea *hashoptions(Datum reloptions, bool validate);
/*
* Datatype-specific hash functions in hashfunc.c.
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
new file mode 100644
index 9e48efd..4fab0a3
*** 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,683 ----
/*
* prototypes for functions in nbtree.c (external entry points for btree)
*/
! extern Datum bthandler(PG_FUNCTION_ARGS);
! extern void btvalidate(OpClassInfo *opclass);
! extern IndexBuildResult *btbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void btbuildempty(Relation index);
! extern bool btinsert(Relation rel, Datum *values, bool *isnull,
! ItemPointer ht_ctid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc btbeginscan(Relation indexRelation,
! int nkeys, int norderbys);
! extern bool btgettuple(IndexScanDesc scan, ScanDirection dir);
! extern int64 btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void btrescan(IndexScanDesc scan, ScanKey keys, int nkeys,
! ScanKey orderbys, int norderbys);
! extern void btendscan(IndexScanDesc scan);
! extern void btmarkpos(IndexScanDesc scan);
! extern void btrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *btbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *btvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern bool btcanreturn(Relation index, int attno);
! extern bytea *btoptions(Datum reloptions, bool validate);
/*
* prototypes for functions in nbtinsert.c
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
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..ba2c1c1
*** 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,212 ----
} spgLeafConsistentOut;
+ /* spgutils.c */
+ extern Datum spghandler(PG_FUNCTION_ARGS);
+ extern void spgvalidate(OpClassInfo *opclass);
+
/* 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/opfam_internal.h b/src/include/catalog/opfam_internal.h
new file mode 100644
index 32195a7..5cc0208
*** a/src/include/catalog/opfam_internal.h
--- b/src/include/catalog/opfam_internal.h
*************** typedef struct
*** 25,28 ****
--- 25,40 ----
Oid sortfamily; /* ordering operator's sort opfamily, or 0 */
} OpFamilyMember;
+ /*
+ * Opclass data for validation by access method.
+ */
+ typedef struct
+ {
+ Oid intype; /* input datatype */
+ Oid keytype; /* key datatype */
+ List *procedures; /* list of OpFamilyMember */
+ List *operators; /* list of OpFamilyMember */
+ } OpClassInfo;
+
+
#endif /* OPFAM_INTERNAL_H */
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
new file mode 100644
index 8a28b8e..f19a873
*** 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,40 ----
CATALOG(pg_am,2601)
{
NameData amname; /* access method name */
! regproc amhandler; /* handler function */
} 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
--- 48,78 ----
* compiler constants for pg_am
* ----------------
*/
! #define Natts_pg_am 2
#define Anum_pg_am_amname 1
! #define Anum_pg_am_amhandler 2
/* ----------------
* initial contents of pg_am
* ----------------
*/
! DATA(insert OID = 403 ( btree bthandler ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
! DATA(insert OID = 405 ( hash hashhandler ));
DESCR("hash index access method");
#define HASH_AM_OID 405
! DATA(insert OID = 783 ( gist gisthandler ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
! DATA(insert OID = 2742 ( gin ginhandler ));
DESCR("GIN index access method");
#define GIN_AM_OID 2742
! DATA(insert OID = 4000 ( spgist spghandler ));
DESCR("SP-GiST index access method");
#define SPGIST_AM_OID 4000
! DATA(insert OID = 3580 ( brin brinhandler ));
DESCR("block range index (BRIN) access method");
#define BRIN_AM_OID 3580
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index d8640db..cc9f441
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DESCR("convert int4 to float4");
*** 548,610 ****
DATA(insert OID = 319 ( int4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "700" _null_ _null_ _null_ _null_ _null_ ftoi4 _null_ _null_ _null_ ));
DESCR("convert float4 to int4");
- DATA(insert OID = 330 ( btgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgettuple _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 636 ( btgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgetbitmap _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 331 ( btinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btinsert _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 333 ( btbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbeginscan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 334 ( btrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btrescan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 335 ( btendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btendscan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 336 ( btmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btmarkpos _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 337 ( btrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btrestrpos _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 338 ( btbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbuild _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 328 ( btbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btbuildempty _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 332 ( btbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbulkdelete _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ btvacuumcleanup _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 276 ( btcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ btcanreturn _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 1268 ( btcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btcostestimate _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 2785 ( btoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ btoptions _null_ _null_ _null_ ));
- DESCR("btree(internal)");
-
- DATA(insert OID = 3789 ( bringetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ bringetbitmap _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3790 ( brininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brininsert _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3791 ( brinbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbeginscan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3792 ( brinrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinrescan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3793 ( brinendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinendscan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3794 ( brinmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinmarkpos _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3795 ( brinrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinrestrpos _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3796 ( brinbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbuild _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3797 ( brinbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinbuildempty _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3798 ( brinbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbulkdelete _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3799 ( brinvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ brinvacuumcleanup _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3800 ( brincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brincostestimate _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3801 ( brinoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ brinoptions _null_ _null_ _null_ ));
- DESCR("brin(internal)");
DATA(insert OID = 3952 ( brin_summarize_new_values PGNSP PGUID 12 1 0 0 0 f f f f f f v s 1 0 23 "2205" _null_ _null_ _null_ _null_ _null_ brin_summarize_new_values _null_ _null_ _null_ ));
DESCR("brin: standalone scan new table pages");
--- 548,553 ----
*************** DESCR("convert name to char(n)");
*** 695,729 ****
DATA(insert OID = 409 ( name PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 19 "1042" _null_ _null_ _null_ _null_ _null_ bpchar_name _null_ _null_ _null_ ));
DESCR("convert char(n) to name");
- DATA(insert OID = 440 ( hashgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgettuple _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 637 ( hashgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgetbitmap _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 441 ( hashinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashinsert _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 443 ( hashbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbeginscan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 444 ( hashrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashrescan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 445 ( hashendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashendscan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 446 ( hashmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashmarkpos _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 447 ( hashrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashrestrpos _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 448 ( hashbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbuild _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 327 ( hashbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashbuildempty _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 442 ( hashbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbulkdelete _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashvacuumcleanup _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 438 ( hashcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashcostestimate _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 2786 ( hashoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ hashoptions _null_ _null_ _null_ ));
- DESCR("hash(internal)");
-
DATA(insert OID = 449 ( hashint2 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "21" _null_ _null_ _null_ _null_ _null_ hashint2 _null_ _null_ _null_ ));
DESCR("hash");
DATA(insert OID = 450 ( hashint4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ hashint4 _null_ _null_ _null_ ));
--- 638,643 ----
*************** DESCR("larger of two");
*** 979,1015 ****
DATA(insert OID = 771 ( int2smaller PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2smaller _null_ _null_ _null_ ));
DESCR("smaller of two");
- DATA(insert OID = 774 ( gistgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgettuple _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 638 ( gistgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgetbitmap _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 775 ( gistinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistinsert _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 777 ( gistbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbeginscan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 778 ( gistrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistrescan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 779 ( gistendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistendscan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 780 ( gistmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistmarkpos _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 781 ( gistrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistrestrpos _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 782 ( gistbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbuild _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 326 ( gistbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistbuildempty _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 776 ( gistbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbulkdelete _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistvacuumcleanup _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 3280 ( gistcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ gistcanreturn _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 772 ( gistcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistcostestimate _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 2787 ( gistoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ gistoptions _null_ _null_ _null_ ));
- DESCR("gist(internal)");
-
DATA(insert OID = 784 ( tintervaleq PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervaleq _null_ _null_ _null_ ));
DATA(insert OID = 785 ( tintervalne PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervalne _null_ _null_ _null_ ));
DATA(insert OID = 786 ( tintervallt PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervallt _null_ _null_ _null_ ));
--- 893,898 ----
*************** DATA(insert OID = 3311 ( tsm_handler_in
*** 3742,3747 ****
--- 3625,3634 ----
DESCR("I/O");
DATA(insert OID = 3312 ( tsm_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "3310" _null_ _null_ _null_ _null_ _null_ tsm_handler_out _null_ _null_ _null_ ));
DESCR("I/O");
+ DATA(insert OID = 326 ( index_am_handler_in PGNSP PGUID 12 1 0 0 0 f f f f f f i s 1 0 325 "2275" _null_ _null_ _null_ _null_ _null_ index_am_handler_in _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 327 ( index_am_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "325" _null_ _null_ _null_ _null_ _null_ index_am_handler_out _null_ _null_ _null_ ));
+ DESCR("I/O");
/* tablesample method handlers */
DATA(insert OID = 3313 ( bernoulli PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 3310 "2281" _null_ _null_ _null_ _null_ _null_ tsm_bernoulli_handler _null_ _null_ _null_ ));
*************** DESCR("GiST support");
*** 4198,4231 ****
DATA(insert OID = 3288 ( gist_bbox_distance PGNSP PGUID 12 1 0 0 0 f f f f t f i s 4 0 701 "2281 600 23 26" _null_ _null_ _null_ _null_ _null_ gist_bbox_distance _null_ _null_ _null_ ));
DESCR("GiST support");
- /* GIN */
- DATA(insert OID = 2731 ( gingetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gingetbitmap _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2732 ( gininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gininsert _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2733 ( ginbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbeginscan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2734 ( ginrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginrescan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2735 ( ginendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginendscan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2736 ( ginmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginmarkpos _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2737 ( ginrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginrestrpos _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2738 ( ginbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbuild _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 325 ( ginbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginbuildempty _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2739 ( ginbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbulkdelete _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ ginvacuumcleanup _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2741 ( gincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gincostestimate _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2788 ( ginoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ ginoptions _null_ _null_ _null_ ));
- DESCR("gin(internal)");
-
/* GIN array support */
DATA(insert OID = 2743 ( ginarrayextract PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 2281 "2277 2281 2281" _null_ _null_ _null_ _null_ _null_ ginarrayextract _null_ _null_ _null_ ));
DESCR("GIN array support");
--- 4085,4090 ----
*************** DESCR("construct timestamp with time zon
*** 5123,5160 ****
DATA(insert OID = 3464 ( make_interval PGNSP PGUID 12 1 0 0 0 f f f f t f i s 7 0 1186 "23 23 23 23 23 23 701" _null_ _null_ "{years,months,weeks,days,hours,mins,secs}" _null_ _null_ make_interval _null_ _null_ _null_ ));
DESCR("construct interval");
- /* spgist support functions */
- DATA(insert OID = 4001 ( spggettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggettuple _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4002 ( spggetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggetbitmap _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4003 ( spginsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spginsert _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4004 ( spgbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbeginscan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4005 ( spgrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgrescan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4006 ( spgendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgendscan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4007 ( spgmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgmarkpos _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4008 ( spgrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgrestrpos _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4009 ( spgbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbuild _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4010 ( spgbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgbuildempty _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4011 ( spgbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbulkdelete _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4012 ( spgvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ spgvacuumcleanup _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4032 ( spgcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ spgcanreturn _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4013 ( spgcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgcostestimate _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4014 ( spgoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ spgoptions _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
-
/* spgist opclasses */
DATA(insert OID = 4018 ( spg_quad_config PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_quad_config _null_ _null_ _null_ ));
DESCR("SP-GiST support for quad tree over point");
--- 4982,4987 ----
*************** DESCR("get an individual replication ori
*** 5337,5342 ****
--- 5164,5192 ----
DATA(insert OID = 6014 ( pg_show_replication_origin_status PGNSP PGUID 12 1 100 0 0 f f f f f t v r 0 0 2249 "" "{26,25,3220,3220}" "{o,o,o,o}" "{local_id, external_id, remote_lsn, local_lsn}" _null_ _null_ pg_show_replication_origin_status _null_ _null_ _null_ ));
DESCR("get progress for all replication origins");
+ /* access methods handlers */
+ DATA(insert OID = 330 ( bthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ bthandler _null_ _null_ _null_ ));
+ DESCR("btree handler");
+ DATA(insert OID = 331 ( hashhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ hashhandler _null_ _null_ _null_ ));
+ DESCR("hash handler");
+ DATA(insert OID = 332 ( gisthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ gisthandler _null_ _null_ _null_ ));
+ DESCR("gist handler");
+ DATA(insert OID = 333 ( ginhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ ginhandler _null_ _null_ _null_ ));
+ DESCR("gin handler");
+ DATA(insert OID = 334 ( spghandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ spghandler _null_ _null_ _null_ ));
+ DESCR("spgist handler");
+ DATA(insert OID = 335 ( brinhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ brinhandler _null_ _null_ _null_ ));
+ DESCR("brin handler");
+
+ /* functions to get access methods parameters */
+ DATA(insert OID = 336 ( get_am_param_oid PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 26 "26 25" _null_ _null_ _null_ _null_ _null_ get_am_param_oid _null_ _null_ _null_ ));
+ DESCR("get am parameter as oid");
+ DATA(insert OID = 337 ( get_am_param_int PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "26 25" _null_ _null_ _null_ _null_ _null_ get_am_param_int _null_ _null_ _null_ ));
+ DESCR("get am parameter as integer");
+ DATA(insert OID = 338 ( get_am_param_bool PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 16 "26 25" _null_ _null_ _null_ _null_ _null_ get_am_param_bool _null_ _null_ _null_ ));
+ DESCR("get am parameter as boolean");
+
+
/*
* 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/commands/defrem.h b/src/include/commands/defrem.h
new file mode 100644
index adae296..d8b9649
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
*************** extern Oid get_am_oid(const char *amname
*** 95,100 ****
--- 95,101 ----
extern char *get_am_name(Oid amOid);
extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+ extern Datum amvalidate(PG_FUNCTION_ARGS);
/* commands/tsearchcmds.c */
extern ObjectAddress DefineTSParser(List *names, List *parameters);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
new file mode 100644
index eb3591a..419d5d2
*** 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 94bdb7c..84e4a36
*** a/src/include/nodes/nodes.h
--- b/src/include/nodes/nodes.h
*************** typedef enum NodeTag
*** 455,461 ****
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;
/*
--- 455,462 ----
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 3232123..a4e1514
*** 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
*** 551,558 ****
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 */
--- 552,558 ----
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
*** 563,574 ****
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;
--- 563,574 ----
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
*** 823,829 ****
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! typedef struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
--- 823,829 ----
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
*************** typedef struct IndexPath
*** 835,841 ****
ScanDirection indexscandir;
Cost indextotalcost;
Selectivity indexselectivity;
! } IndexPath;
/*
* BitmapHeapPath represents one or more indexscans that generate TID bitmaps
--- 835,841 ----
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 e610bf3..ca55370
*** 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 a7433d9..3745d1c
*** a/src/include/utils/selfuncs.h
--- b/src/include/utils/selfuncs.h
*************** extern double estimate_num_groups(Planne
*** 191,202 ****
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 */
--- 191,226 ----
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..c200068
*** a/src/test/regress/expected/oidjoins.out
--- b/src/test/regress/expected/oidjoins.out
*************** WHERE aggmtranstype != 0 AND
*** 73,204 ****
------+---------------
(0 rows)
! SELECT ctid, amkeytype
! FROM pg_catalog.pg_am fk
! WHERE amkeytype != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
! ctid | amkeytype
! ------+-----------
! (0 rows)
!
! SELECT ctid, aminsert
! FROM pg_catalog.pg_am fk
! WHERE aminsert != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
! ctid | aminsert
! ------+----------
! (0 rows)
!
! SELECT ctid, ambeginscan
! FROM pg_catalog.pg_am fk
! WHERE ambeginscan != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
! ctid | ambeginscan
! ------+-------------
! (0 rows)
!
! SELECT ctid, amgettuple
! FROM pg_catalog.pg_am fk
! WHERE amgettuple != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
! ctid | amgettuple
! ------+------------
! (0 rows)
!
! SELECT ctid, amgetbitmap
! FROM pg_catalog.pg_am fk
! WHERE amgetbitmap != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
! ctid | amgetbitmap
! ------+-------------
! (0 rows)
!
! SELECT ctid, amrescan
! FROM pg_catalog.pg_am fk
! WHERE amrescan != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
! ctid | amrescan
! ------+----------
! (0 rows)
!
! SELECT ctid, amendscan
! FROM pg_catalog.pg_am fk
! WHERE amendscan != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
! ctid | amendscan
! ------+-----------
! (0 rows)
!
! SELECT ctid, ammarkpos
! FROM pg_catalog.pg_am fk
! WHERE ammarkpos != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
! ctid | ammarkpos
! ------+-----------
! (0 rows)
!
! SELECT ctid, amrestrpos
! FROM pg_catalog.pg_am fk
! WHERE amrestrpos != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
! ctid | amrestrpos
! ------+------------
! (0 rows)
!
! SELECT ctid, ambuild
! FROM pg_catalog.pg_am fk
! WHERE ambuild != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
! ctid | ambuild
! ------+---------
! (0 rows)
!
! SELECT ctid, ambuildempty
! FROM pg_catalog.pg_am fk
! WHERE ambuildempty != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
! ctid | ambuildempty
! ------+--------------
! (0 rows)
!
! SELECT ctid, ambulkdelete
! FROM pg_catalog.pg_am fk
! WHERE ambulkdelete != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
! ctid | ambulkdelete
! ------+--------------
! (0 rows)
!
! SELECT ctid, amvacuumcleanup
! FROM pg_catalog.pg_am fk
! WHERE amvacuumcleanup != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
! ctid | amvacuumcleanup
! ------+-----------------
! (0 rows)
!
! SELECT ctid, amcanreturn
! FROM pg_catalog.pg_am fk
! WHERE amcanreturn != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
! ctid | amcanreturn
! ------+-------------
! (0 rows)
!
! SELECT ctid, amcostestimate
! FROM pg_catalog.pg_am fk
! WHERE amcostestimate != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
! ctid | amcostestimate
! ------+----------------
! (0 rows)
!
! SELECT ctid, amoptions
! FROM pg_catalog.pg_am fk
! WHERE amoptions != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
! ctid | amoptions
! ------+-----------
(0 rows)
SELECT ctid, amopfamily
--- 73,84 ----
------+---------------
(0 rows)
! SELECT ctid, proc
! FROM (SELECT ctid, get_am_param_oid(oid, 'amkeytype') proc FROM pg_catalog.pg_am) fk
! WHERE fk.proc != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.proc);
! ctid | proc
! ------+------
(0 rows)
SELECT ctid, amopfamily
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
new file mode 100644
index 7c93b3b..01f5973
*** a/src/test/regress/expected/opr_sanity.out
--- b/src/test/regress/expected/opr_sanity.out
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 1530,1536 ****
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
! p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
amopfamily | amopopr | oid | amname
------------+---------+-----+--------
(0 rows)
--- 1530,1536 ----
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
! p1.amoppurpose = 'o' AND NOT get_am_param_bool(p2.oid, 'amcanorderbyop');
amopfamily | amopopr | oid | amname
------------+---------+-----+--------
(0 rows)
*************** WHERE p1.amopmethod = p2.oid AND
*** 1539,1545 ****
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
! p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
amopfamily | amopopr | oid | amname
------------+---------+-----+--------
(0 rows)
--- 1539,1546 ----
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
! p1.amopstrategy > get_am_param_int(p2.oid, 'amstrategies') AND
! get_am_param_int(p2.oid, 'amstrategies') <> 0;
amopfamily | amopopr | oid | amname
------------+---------+-----+--------
(0 rows)
*************** WHERE p1.amopmethod = p2.oid AND
*** 1550,1557 ****
SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
! p1.amstrategies <> 0 AND
! p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
WHERE p3.amopfamily = p2.amopfamily AND
p3.amoplefttype = p2.amoplefttype AND
p3.amoprighttype = p2.amoprighttype AND
--- 1551,1559 ----
SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
! get_am_param_int(p1.oid, 'amstrategies') <> 0 AND
! get_am_param_int(p1.oid, 'amstrategies') !=
! (SELECT count(*) FROM pg_amop AS p3
WHERE p3.amopfamily = p2.amopfamily AND
p3.amoplefttype = p2.amoplefttype AND
p3.amoprighttype = p2.amoprighttype AND
*************** WHERE p2.amopmethod = p1.oid AND
*** 1564,1570 ****
SELECT p1.amname, p2.amopfamily, p2.amopstrategy
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
! p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
amname | amopfamily | amopstrategy
--------+------------+--------------
(0 rows)
--- 1566,1572 ----
SELECT p1.amname, p2.amopfamily, p2.amopstrategy
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
! get_am_param_int(p1.oid, 'amstrategies') <> 0 AND p2.amoppurpose <> 's';
amname | amopfamily | amopstrategy
--------+------------+--------------
(0 rows)
*************** WHERE p1.amprocfamily = 0 OR p1.amprocle
*** 1855,1861 ****
SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
! p1.amprocnum > p2.amsupport;
amprocfamily | amprocnum | oid | amname
--------------+-----------+-----+--------
(0 rows)
--- 1857,1863 ----
SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
! p1.amprocnum > get_am_param_int(p2.oid, 'amsupport');
amprocfamily | amprocnum | oid | amname
--------------+-----------+-----+--------
(0 rows)
diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql
new file mode 100644
index 2fa628d..8e62f76
*** a/src/test/regress/sql/oidjoins.sql
--- b/src/test/regress/sql/oidjoins.sql
*************** SELECT ctid, aggmtranstype
*** 37,106 ****
FROM pg_catalog.pg_aggregate fk
WHERE aggmtranstype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
! SELECT ctid, amkeytype
! FROM pg_catalog.pg_am fk
! WHERE amkeytype != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
! SELECT ctid, aminsert
! FROM pg_catalog.pg_am fk
! WHERE aminsert != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
! SELECT ctid, ambeginscan
! FROM pg_catalog.pg_am fk
! WHERE ambeginscan != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
! SELECT ctid, amgettuple
! FROM pg_catalog.pg_am fk
! WHERE amgettuple != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
! SELECT ctid, amgetbitmap
! FROM pg_catalog.pg_am fk
! WHERE amgetbitmap != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
! SELECT ctid, amrescan
! FROM pg_catalog.pg_am fk
! WHERE amrescan != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
! SELECT ctid, amendscan
! FROM pg_catalog.pg_am fk
! WHERE amendscan != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
! SELECT ctid, ammarkpos
! FROM pg_catalog.pg_am fk
! WHERE ammarkpos != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
! SELECT ctid, amrestrpos
! FROM pg_catalog.pg_am fk
! WHERE amrestrpos != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
! SELECT ctid, ambuild
! FROM pg_catalog.pg_am fk
! WHERE ambuild != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
! SELECT ctid, ambuildempty
! FROM pg_catalog.pg_am fk
! WHERE ambuildempty != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
! SELECT ctid, ambulkdelete
! FROM pg_catalog.pg_am fk
! WHERE ambulkdelete != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
! SELECT ctid, amvacuumcleanup
! FROM pg_catalog.pg_am fk
! WHERE amvacuumcleanup != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
! SELECT ctid, amcanreturn
! FROM pg_catalog.pg_am fk
! WHERE amcanreturn != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
! SELECT ctid, amcostestimate
! FROM pg_catalog.pg_am fk
! WHERE amcostestimate != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
! SELECT ctid, amoptions
! FROM pg_catalog.pg_am fk
! WHERE amoptions != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 37,46 ----
FROM pg_catalog.pg_aggregate fk
WHERE aggmtranstype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
! SELECT ctid, proc
! FROM (SELECT ctid, get_am_param_oid(oid, 'amkeytype') proc FROM pg_catalog.pg_am) fk
! WHERE fk.proc != 0 AND
! NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.proc);
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
new file mode 100644
index c9bdd77..90e10e0
*** a/src/test/regress/sql/opr_sanity.sql
--- b/src/test/regress/sql/opr_sanity.sql
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 1000,1013 ****
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
! p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
-- Cross-check amopstrategy index against parent AM
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
! p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
-- Detect missing pg_amop entries: should have as many strategy operators
-- as AM expects for each datatype combination supported by the opfamily.
--- 1000,1014 ----
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
! p1.amoppurpose = 'o' AND NOT get_am_param_bool(p2.oid, 'amcanorderbyop');
-- Cross-check amopstrategy index against parent AM
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
! p1.amopstrategy > get_am_param_int(p2.oid, 'amstrategies') AND
! get_am_param_int(p2.oid, 'amstrategies') <> 0;
-- Detect missing pg_amop entries: should have as many strategy operators
-- as AM expects for each datatype combination supported by the opfamily.
*************** WHERE p1.amopmethod = p2.oid AND
*** 1016,1023 ****
SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
! p1.amstrategies <> 0 AND
! p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
WHERE p3.amopfamily = p2.amopfamily AND
p3.amoplefttype = p2.amoplefttype AND
p3.amoprighttype = p2.amoprighttype AND
--- 1017,1025 ----
SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
! get_am_param_int(p1.oid, 'amstrategies') <> 0 AND
! get_am_param_int(p1.oid, 'amstrategies') !=
! (SELECT count(*) FROM pg_amop AS p3
WHERE p3.amopfamily = p2.amopfamily AND
p3.amoplefttype = p2.amoplefttype AND
p3.amoprighttype = p2.amoprighttype AND
*************** WHERE p2.amopmethod = p1.oid AND
*** 1028,1034 ****
SELECT p1.amname, p2.amopfamily, p2.amopstrategy
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
! p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
--- 1030,1036 ----
SELECT p1.amname, p2.amopfamily, p2.amopstrategy
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
! get_am_param_int(p1.oid, 'amstrategies') <> 0 AND p2.amoppurpose <> 's';
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
*************** WHERE p1.amprocfamily = 0 OR p1.amprocle
*** 1181,1187 ****
SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
! p1.amprocnum > p2.amsupport;
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
--- 1183,1189 ----
SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
! p1.amprocnum > get_am_param_int(p2.oid, 'amsupport');
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
On 2015-12-09 15:09, Alexander Korotkov wrote:
Patch was rebased against current master.
Any notes about current version of patch?
It would be nice to commit it and continue work on other parts of am
extendability.
The rebase seems broken, there are things missing in this version of the
patch (for example the validation functions).
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sat, Dec 12, 2015 at 9:21 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
On 2015-12-09 15:09, Alexander Korotkov wrote:
Patch was rebased against current master.
Any notes about current version of patch?
It would be nice to commit it and continue work on other parts of am
extendability.The rebase seems broken, there are things missing in this version of the
patch (for example the validation functions).
Ooops, sorry. Correct version is attached.
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Attachments:
aminterface-12.patchapplication/octet-stream; name=aminterface-12.patchDownload
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
new file mode 100644
index 97ef618..48f208a
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 549,762 ****
</row>
<row>
! <entry><structfield>amstrategies</structfield></entry>
! <entry><type>int2</type></entry>
! <entry></entry>
! <entry>Number of operator strategies for this access method,
! or zero if access method does not have a fixed set of operator
! strategies</entry>
! </row>
!
! <row>
! <entry><structfield>amsupport</structfield></entry>
! <entry><type>int2</type></entry>
! <entry></entry>
! <entry>Number of support routines for this access method</entry>
! </row>
!
! <row>
! <entry><structfield>amcanorder</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support ordered scans sorted by the
! indexed column's value?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanorderbyop</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support ordered scans sorted by the result
! of an operator on the indexed column?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanbackward</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support backward scanning?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanunique</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support unique indexes?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanmulticol</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support multicolumn indexes?</entry>
! </row>
!
! <row>
! <entry><structfield>amoptionalkey</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support a scan without any constraint
! for the first index column?</entry>
! </row>
!
! <row>
! <entry><structfield>amsearcharray</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support <literal>ScalarArrayOpExpr</> searches?</entry>
! </row>
!
! <row>
! <entry><structfield>amsearchnulls</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support <literal>IS NULL</>/<literal>NOT NULL</> searches?</entry>
! </row>
!
! <row>
! <entry><structfield>amstorage</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Can index storage data type differ from column data type?</entry>
! </row>
!
! <row>
! <entry><structfield>amclusterable</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Can an index of this type be clustered on?</entry>
! </row>
!
! <row>
! <entry><structfield>ampredlocks</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does an index of this type manage fine-grained predicate locks?</entry>
! </row>
!
! <row>
! <entry><structfield>amkeytype</structfield></entry>
<entry><type>oid</type></entry>
- <entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
- <entry>Type of data stored in index, or zero if not a fixed type</entry>
- </row>
-
- <row>
- <entry><structfield>aminsert</structfield></entry>
- <entry><type>regproc</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Insert this tuple</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambeginscan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Prepare for index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amgettuple</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Next valid tuple</quote> function, or zero if none</entry>
! </row>
!
! <row>
! <entry><structfield>amgetbitmap</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Fetch all valid tuples</quote> function, or zero if none</entry>
! </row>
!
! <row>
! <entry><structfield>amrescan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>(Re)start index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amendscan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Clean up after index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ammarkpos</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Mark current scan position</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amrestrpos</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Restore marked scan position</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambuild</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Build new index</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambuildempty</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Build empty index</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambulkdelete</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Bulk-delete function</entry>
! </row>
!
! <row>
! <entry><structfield>amvacuumcleanup</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Post-<command>VACUUM</command> cleanup function</entry>
! </row>
!
! <row>
! <entry><structfield>amcanreturn</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to check whether an index column supports index-only
! scans. Can be zero if index-only scans are never supported.</entry>
! </row>
!
! <row>
! <entry><structfield>amcostestimate</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to estimate cost of an index scan</entry>
! </row>
!
! <row>
! <entry><structfield>amoptions</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to parse and validate <structfield>reloptions</> for an index</entry>
</row>
-
</tbody>
</tgroup>
</table>
--- 549,562 ----
</row>
<row>
! <entry><structfield>amhandler</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>
! References a handler function that is responsible for
! supplying execution routines for the access method.
! </entry>
</row>
</tbody>
</tgroup>
</table>
diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml
new file mode 100644
index 1c09bae..3ff3651
*** a/doc/src/sgml/indexam.sgml
--- b/doc/src/sgml/indexam.sgml
***************
*** 49,61 ****
<para>
Each index access method is described by a row in the
<structname>pg_am</structname> system catalog (see
! <xref linkend="catalog-pg-am">). The principal contents of a
! <structname>pg_am</structname> row are references to
! <link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>
! entries that identify the index access
! functions supplied by the access method. The APIs for these functions
! are defined later in this chapter. In addition, the
! <structname>pg_am</structname> row specifies a few fixed properties of
the access method, such as whether it can support multicolumn indexes.
There is not currently any special support
for creating or deleting <structname>pg_am</structname> entries;
--- 49,63 ----
<para>
Each index access method is described by a row in the
<structname>pg_am</structname> system catalog (see
! <xref linkend="catalog-pg-am">). In the <structname>pg_am</structname> row
! the handler function is specified by the reference to
! <link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.
! Handler function must be written in a compiled language such as C, using
! the version-1 interface. The handler function simply returns a
! <structname>IndexAmRoutine</structname> struct which contains function
! pointers to callback functions that will be called by the planner, executor,
! and various maintenance commands. In addition, the
! <structname>IndexAmRoutine</structname> contains a few fixed properties of
the access method, such as whether it can support multicolumn indexes.
There is not currently any special support
for creating or deleting <structname>pg_am</structname> entries;
***************
*** 96,126 ****
</para>
<para>
! Some of the flag columns of <structname>pg_am</structname> have nonobvious
! implications. The requirements of <structfield>amcanunique</structfield>
! are discussed in <xref linkend="index-unique-checks">.
! The <structfield>amcanmulticol</structfield> flag asserts that the
! access method supports multicolumn indexes, while
! <structfield>amoptionalkey</structfield> asserts that it allows scans
where no indexable restriction clause is given for the first index column.
! When <structfield>amcanmulticol</structfield> is false,
! <structfield>amoptionalkey</structfield> essentially says whether the
access method supports full-index scans without any restriction clause.
Access methods that support multiple index columns <emphasis>must</>
support scans that omit restrictions on any or all of the columns after
the first; however they are permitted to require some restriction to
appear for the first index column, and this is signaled by setting
! <structfield>amoptionalkey</structfield> false.
! One reason that an index AM might set
! <structfield>amoptionalkey</structfield> false is if it doesn't index
! null values. Since most indexable operators are
strict and hence cannot return true for null inputs,
it is at first sight attractive to not store index entries for null values:
they could never be returned by an index scan anyway. However, this
argument fails when an index scan has no restriction clause for a given
index column. In practice this means that
! indexes that have <structfield>amoptionalkey</structfield> true must
! index nulls, since the planner might decide to use such an index
with no scan keys at all. A related restriction is that an index
access method that supports multiple index columns <emphasis>must</>
support indexing null values in columns after the first, because the planner
--- 98,133 ----
</para>
<para>
! Some of the flag fields of <structname>IndexAmRoutine</structname> have nonobvious
! implications. The requirements of
! <structname>IndexAmRoutine</structname>.<structfield>amcanunique</structfield>
! are discussed in <xref linkend="index-unique-checks">. The
! <structname>IndexAmRoutine</structname>.<structfield>amcanmulticol</structfield>
! flag asserts that the access method supports multicolumn indexes, while
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! asserts that it allows scans
where no indexable restriction clause is given for the first index column.
! When <structname>IndexAmRoutine</structname>.<structfield>amcanmulticol</structfield>
! is false,
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! essentially says whether the
access method supports full-index scans without any restriction clause.
Access methods that support multiple index columns <emphasis>must</>
support scans that omit restrictions on any or all of the columns after
the first; however they are permitted to require some restriction to
appear for the first index column, and this is signaled by setting
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! false. One reason that an index AM might set
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! false is if it doesn't index null values. Since most indexable operators are
strict and hence cannot return true for null inputs,
it is at first sight attractive to not store index entries for null values:
they could never be returned by an index scan anyway. However, this
argument fails when an index scan has no restriction clause for a given
index column. In practice this means that
! indexes that have
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! true must index nulls, since the planner might decide to use such an index
with no scan keys at all. A related restriction is that an index
access method that supports multiple index columns <emphasis>must</>
support indexing null values in columns after the first, because the planner
***************
*** 131,139 ****
index omits rows where <literal>b</> is null.
It is, however, OK to omit rows where the first indexed column is null.
An index access method that does index nulls may also set
! <structfield>amsearchnulls</structfield>, indicating that it supports
! <literal>IS NULL</> and <literal>IS NOT NULL</> clauses as search
! conditions.
</para>
</sect1>
--- 138,146 ----
index omits rows where <literal>b</> is null.
It is, however, OK to omit rows where the first indexed column is null.
An index access method that does index nulls may also set
! <structname>IndexAmRoutine</structname>.<structfield>amsearchnulls</structfield>,
! indicating that it supports <literal>IS NULL</> and <literal>IS NOT NULL</>
! clauses as search conditions.
</para>
</sect1>
***************
*** 143,149 ****
<para>
The index construction and maintenance functions that an index access
! method must provide are:
</para>
<para>
--- 150,156 ----
<para>
The index construction and maintenance functions that an index access
! method must provide in <structname>IndexAmRoutine</structname> are:
</para>
<para>
*************** aminsert (Relation indexRelation,
*** 188,194 ****
<literal>isnull</> arrays give the key values to be indexed, and
<literal>heap_tid</> is the TID to be indexed.
If the access method supports unique indexes (its
! <structname>pg_am</>.<structfield>amcanunique</> flag is true) then
<literal>checkUnique</> indicates the type of uniqueness check to
perform. This varies depending on whether the unique constraint is
deferrable; see <xref linkend="index-unique-checks"> for details.
--- 195,201 ----
<literal>isnull</> arrays give the key values to be indexed, and
<literal>heap_tid</> is the TID to be indexed.
If the access method supports unique indexes (its
! <structfield>amcanunique</> flag is true) then
<literal>checkUnique</> indicates the type of uniqueness check to
perform. This varies depending on whether the unique constraint is
deferrable; see <xref linkend="index-unique-checks"> for details.
*************** amcanreturn (Relation indexRelation, int
*** 281,288 ****
the form of an <structname>IndexTuple</structname>. The attribute number
is 1-based, i.e. the first columns attno is 1. Returns TRUE if supported,
else FALSE. If the access method does not support index-only scans at all,
! the <structfield>amcanreturn</> field in its <structname>pg_am</> row can
! be set to zero.
</para>
<para>
--- 288,295 ----
the form of an <structname>IndexTuple</structname>. The attribute number
is 1-based, i.e. the first columns attno is 1. Returns TRUE if supported,
else FALSE. If the access method does not support index-only scans at all,
! the <structfield>amcanreturn</> field in its <structname>IndexAmRoutine</>
! struct can be set to NULL.
</para>
<para>
*************** amgettuple (IndexScanDesc scan,
*** 414,421 ****
<para>
The <function>amgettuple</> function need only be provided if the access
method supports <quote>plain</> index scans. If it doesn't, the
! <structfield>amgettuple</> field in its <structname>pg_am</> row must
! be set to zero.
</para>
<para>
--- 421,428 ----
<para>
The <function>amgettuple</> function need only be provided if the access
method supports <quote>plain</> index scans. If it doesn't, the
! <structfield>amgettuple</> field in its <structname>IndexAmRoutine</>
! struct must be set to NULL.
</para>
<para>
*************** amgetbitmap (IndexScanDesc scan,
*** 445,452 ****
<para>
The <function>amgetbitmap</> function need only be provided if the access
method supports <quote>bitmap</> index scans. If it doesn't, the
! <structfield>amgetbitmap</> field in its <structname>pg_am</> row must
! be set to zero.
</para>
<para>
--- 452,459 ----
<para>
The <function>amgetbitmap</> function need only be provided if the access
method supports <quote>bitmap</> index scans. If it doesn't, the
! <structfield>amgetbitmap</> field in its <structname>IndexAmRoutine</>
! struct must be set to NULL.
</para>
<para>
*************** amrestrpos (IndexScanDesc scan);
*** 477,494 ****
</para>
<para>
! By convention, the <literal>pg_proc</literal> entry for an index
! access method function should show the correct number of arguments,
! but declare them all as type <type>internal</> (since most of the arguments
! have types that are not known to SQL, and we don't want users calling
! the functions directly anyway). The return type is declared as
! <type>void</>, <type>internal</>, or <type>boolean</> as appropriate.
! The only exception is <function>amoptions</>, which should be correctly
! declared as taking <type>text[]</> and <type>bool</> and returning
! <type>bytea</>. This provision allows client code to execute
! <function>amoptions</> to test validity of options settings.
</para>
-
</sect1>
<sect1 id="index-scanning">
--- 484,496 ----
</para>
<para>
! <programlisting>
! void
! amvalidate (OpClassInfo *opclass);
! </programlisting>
! Validates given operator class by access method. The <function>amvalidate</>
! must throw an error if opclass is invalid.
</para>
</sect1>
<sect1 id="index-scanning">
*************** amrestrpos (IndexScanDesc scan);
*** 548,554 ****
<para>
Access methods that always return entries in the natural ordering
of their data (such as btree) should set
! <structname>pg_am</>.<structfield>amcanorder</> to true.
Currently, such access methods must use btree-compatible strategy
numbers for their equality and ordering operators.
</para>
--- 550,556 ----
<para>
Access methods that always return entries in the natural ordering
of their data (such as btree) should set
! <structfield>amcanorder</> to true.
Currently, such access methods must use btree-compatible strategy
numbers for their equality and ordering operators.
</para>
*************** amrestrpos (IndexScanDesc scan);
*** 556,562 ****
<listitem>
<para>
Access methods that support ordering operators should set
! <structname>pg_am</>.<structfield>amcanorderbyop</> to true.
This indicates that the index is capable of returning entries in
an order satisfying <literal>ORDER BY</> <replaceable>index_key</>
<replaceable>operator</> <replaceable>constant</>. Scan modifiers
--- 558,564 ----
<listitem>
<para>
Access methods that support ordering operators should set
! <structfield>amcanorderbyop</> to true.
This indicates that the index is capable of returning entries in
an order satisfying <literal>ORDER BY</> <replaceable>index_key</>
<replaceable>operator</> <replaceable>constant</>. Scan modifiers
*************** amrestrpos (IndexScanDesc scan);
*** 579,585 ****
methods that set <structfield>amcanorder</> to true.) After the
first call, <function>amgettuple</> must be prepared to advance the scan in
either direction from the most recently returned entry. (But if
! <structname>pg_am</>.<structfield>amcanbackward</> is false, all subsequent
calls will have the same direction as the first one.)
</para>
--- 581,587 ----
methods that set <structfield>amcanorder</> to true.) After the
first call, <function>amgettuple</> must be prepared to advance the scan in
either direction from the most recently returned entry. (But if
! <structfield>amcanbackward</> is false, all subsequent
calls will have the same direction as the first one.)
</para>
*************** amrestrpos (IndexScanDesc scan);
*** 590,597 ****
be remembered per scan; a new <function>ammarkpos</> call overrides the
previously marked position. An access method that does not support
ordered scans should still provide mark and restore functions in
! <structname>pg_am</>, but it is sufficient to have them throw errors if
! called.
</para>
<para>
--- 592,599 ----
be remembered per scan; a new <function>ammarkpos</> call overrides the
previously marked position. An access method that does not support
ordered scans should still provide mark and restore functions in
! <structname>IndexAmRoutine</>, but it is sufficient to have them throw
! errors if called.
</para>
<para>
*************** amrestrpos (IndexScanDesc scan);
*** 766,772 ****
<productname>PostgreSQL</productname> enforces SQL uniqueness constraints
using <firstterm>unique indexes</>, which are indexes that disallow
multiple entries with identical keys. An access method that supports this
! feature sets <structname>pg_am</>.<structfield>amcanunique</> true.
(At present, only b-tree supports it.)
</para>
--- 768,774 ----
<productname>PostgreSQL</productname> enforces SQL uniqueness constraints
using <firstterm>unique indexes</>, which are indexes that disallow
multiple entries with identical keys. An access method that supports this
! feature sets <structfield>amcanunique</> true.
(At present, only b-tree supports it.)
</para>
diff --git a/doc/src/sgml/xindex.sgml b/doc/src/sgml/xindex.sgml
new file mode 100644
index 1782782..a16f478
*** a/doc/src/sgml/xindex.sgml
--- b/doc/src/sgml/xindex.sgml
***************
*** 34,40 ****
regular access to tables is built into
<productname>PostgreSQL</productname>, but all index methods are
described in <classname>pg_am</classname>. It is possible to add a
! new index method by defining the required interface routines and
then creating a row in <classname>pg_am</classname> — but that is
beyond the scope of this chapter (see <xref linkend="indexam">).
</para>
--- 34,41 ----
regular access to tables is built into
<productname>PostgreSQL</productname>, but all index methods are
described in <classname>pg_am</classname>. It is possible to add a
! new index access method by defining the handler function, which returns
! C-struct with required interface routines and parameters, and
then creating a row in <classname>pg_am</classname> — but that is
beyond the scope of this chapter (see <xref linkend="indexam">).
</para>
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
new file mode 100644
index 99337b0..00e7538
*** a/src/backend/access/brin/brin.c
--- b/src/backend/access/brin/brin.c
***************
*** 25,38 ****
--- 25,176 ----
#include "access/xact.h"
#include "access/xloginsert.h"
#include "catalog/index.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
+ #include "catalog/pg_opclass.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "storage/bufmgr.h"
#include "storage/freespace.h"
+ #include "utils/catcache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
+ #include "utils/syscache.h"
+
+
+ /*
+ * BRIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ brinhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 15;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = brininsert;
+ amroutine->ambeginscan = brinbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = bringetbitmap;
+ amroutine->amrescan = brinrescan;
+ amroutine->amendscan = brinendscan;
+ amroutine->ammarkpos = brinmarkpos;
+ amroutine->amrestrpos = brinrestrpos;
+ amroutine->ambuild = brinbuild;
+ amroutine->ambuildempty = brinbuildempty;
+ amroutine->ambulkdelete = brinbulkdelete;
+ amroutine->amvacuumcleanup = brinvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = brincostestimate;
+ amroutine->amoptions = brinoptions;
+ amroutine->amvalidate = brinvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ brinvalidate(Oid opclassoid)
+ {
+ bool procsPresent[BRIN_MANDATORY_NPROCS];
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid,
+ intype,
+ keytype;
+ CatCList *proclist,
+ *oprlist;
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ /* Fetch opclass information */
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ intype = classform->opcintype;
+ keytype = classform->opckeytype;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+
+ /* Fetch opfamily information: operators and functions */
+ oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+
+ /* Check required procedure numbers exist */
+ for (i = 0; i < proclist->n_members; i++)
+ {
+ HeapTuple proctup = &proclist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype != intype ||
+ procform->amprocrighttype != intype)
+ continue;
+
+ if (procform->amprocnum < 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for BRIN: %u",
+ procform->amprocnum)));
+
+ /* BRIN opclasses could contain any number of non-mandatory procedures */
+ if (procform->amprocnum > BRIN_MANDATORY_NPROCS)
+ continue;
+
+ if (procsPresent[procform->amprocnum - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u was defined more than once",
+ procform->amprocnum)));
+
+ procsPresent[procform->amprocnum - 1] = true;
+ }
+
+ /*
+ * Don't use BRIN_NPROC because some procnumbers
+ * are reserved for future use
+ */
+ for (i = 0; i < BRIN_MANDATORY_NPROCS; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u is required", i + 1)));
+ }
+ /* Check operators: ORDER BY operators are not supported */
+ for (i = 0; i < oprlist->n_members; i++)
+ {
+ HeapTuple oprtup = &oprlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+
+ if (OidIsValid(oprform->amopsortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN doesn't support ORDER BY operators")));
+ }
+
+ ReleaseCatCacheList(proclist);
+ ReleaseCatCacheList(oprlist);
+ }
/*
* We use a BrinBuildState during initial construction of a BRIN index.
*************** 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;
--- 218,228 ----
* 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);
}
/*
--- 360,366 ----
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;
--- 370,378 ----
* 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);
}
/*
--- 383,389 ----
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;
--- 398,406 ----
* 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
--- 580,595 ----
* 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();
}
/*
--- 601,631 ----
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;
--- 697,705 ----
/*
* 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. */
--- 778,789 ----
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();
}
/*
--- 800,805 ----
*************** 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));
--- 811,839 ----
* 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;
--- 850,864 ----
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);
--- 871,877 ----
/* 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);
}
/*
--- 880,886 ----
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 931dceb..b52846f
*** a/src/backend/access/common/reloptions.c
--- b/src/backend/access/common/reloptions.c
*************** untransformRelOptions(Datum options)
*** 891,897 ****
* 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;
--- 891,897 ----
* 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
*** 1379,1412 ****
* 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);
}
/*
--- 1379,1393 ----
* 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 49e9185..92701b9
*** 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..08642e1
*** a/src/backend/access/gin/ginutil.c
--- b/src/backend/access/gin/ginutil.c
***************
*** 15,28 ****
--- 15,176 ----
#include "postgres.h"
#include "access/gin_private.h"
+ #include "access/htup_details.h"
#include "access/reloptions.h"
#include "access/xloginsert.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
#include "catalog/pg_collation.h"
+ #include "catalog/pg_opclass.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
+ #include "utils/catcache.h"
+ #include "utils/selfuncs.h"
+ #include "utils/syscache.h"
+
+
+ /*
+ * GIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ ginhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 6;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = gininsert;
+ amroutine->ambeginscan = ginbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = gingetbitmap;
+ amroutine->amrescan = ginrescan;
+ amroutine->amendscan = ginendscan;
+ amroutine->ammarkpos = ginmarkpos;
+ amroutine->amrestrpos = ginrestrpos;
+ amroutine->ambuild = ginbuild;
+ amroutine->ambuildempty = ginbuildempty;
+ amroutine->ambulkdelete = ginbulkdelete;
+ amroutine->amvacuumcleanup = ginvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = gincostestimate;
+ amroutine->amoptions = ginoptions;
+ amroutine->amvalidate = ginvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ ginvalidate(Oid opclassoid)
+ {
+ bool procsPresent[GINNProcs];
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid,
+ intype,
+ keytype;
+ CatCList *proclist,
+ *oprlist;
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ /* Fetch opclass information */
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ intype = classform->opcintype;
+ keytype = classform->opckeytype;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+
+ /* Fetch opfamily information: operators and functions */
+ oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+
+ /* Check required procedure numbers exist */
+ for (i = 0; i < proclist->n_members; i++)
+ {
+ HeapTuple proctup = &proclist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype != intype ||
+ procform->amprocrighttype != intype)
+ continue;
+
+ if (procform->amprocnum < 1 || procform->amprocnum > GINNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for GIN: %u",
+ procform->amprocnum)));
+
+ if (procsPresent[procform->amprocnum - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u was defined more than once",
+ procform->amprocnum)));
+
+ procsPresent[procform->amprocnum - 1] = true;
+ }
+ for (i = 0; i < GINNProcs; i++)
+ {
+ if (i+1 == GIN_COMPARE_PARTIAL_PROC)
+ continue; /* optional method */
+ if (i+1 == GIN_CONSISTENT_PROC || i+1 == GIN_TRICONSISTENT_PROC)
+ continue; /* don't need to have both, see check below loop */
+
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u is required", i + 1)));
+ }
+
+ if (!procsPresent[GIN_CONSISTENT_PROC - 1]
+ && !procsPresent[GIN_TRICONSISTENT_PROC - 1])
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("at least one of consistent support (number %u) "
+ "and triconsistent support (number %u) is "
+ "is required",
+ GIN_CONSISTENT_PROC, GIN_TRICONSISTENT_PROC)));
+ }
+
+ /* Check operators: ORDER BY operators are not supported */
+ for (i = 0; i < oprlist->n_members; i++)
+ {
+ HeapTuple oprtup = &oprlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+
+ if (OidIsValid(oprform->amopsortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN doesn't support ORDER BY operators")));
+ }
+
+ ReleaseCatCacheList(proclist);
+ ReleaseCatCacheList(oprlist);
+ }
/*
* 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;
--- 664,672 ----
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);
--- 681,687 ----
/* 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);
}
/*
--- 690,696 ----
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 323cfb0..5b38607
*** 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, true, stats);
}
! PG_RETURN_POINTER(stats);
}
/*
--- 656,662 ----
initGinState(&ginstate, index);
ginInsertCleanup(&ginstate, true, 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 53bccf6..bf031b9
*** a/src/backend/access/gist/gist.c
--- b/src/backend/access/gist/gist.c
***************
*** 16,29 ****
--- 16,37 ----
#include "access/genam.h"
#include "access/gist_private.h"
+ #include "access/gistscan.h"
+ #include "access/htup_details.h"
#include "access/xloginsert.h"
#include "catalog/index.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
#include "catalog/pg_collation.h"
+ #include "catalog/pg_opclass.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "storage/indexfsm.h"
#include "utils/memutils.h"
#include "utils/rel.h"
+ #include "utils/catcache.h"
+ #include "utils/selfuncs.h"
+ #include "utils/syscache.h"
/* non-export function prototypes */
static void gistfixsplit(GISTInsertState *state, GISTSTATE *giststate);
*************** static void gistfinishsplit(GISTInsertSt
*** 38,43 ****
--- 46,182 ----
GISTSTATE *giststate, List *splitinfo, bool releasebuf);
static void gistvacuumpage(Relation rel, Page page, Buffer buffer);
+ /*
+ * GiST handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ gisthandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 9;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = true;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = true;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = gistinsert;
+ amroutine->ambeginscan = gistbeginscan;
+ amroutine->amgettuple = gistgettuple;
+ amroutine->amgetbitmap = gistgetbitmap;
+ amroutine->amrescan = gistrescan;
+ amroutine->amendscan = gistendscan;
+ amroutine->ammarkpos = gistmarkpos;
+ amroutine->amrestrpos = gistrestrpos;
+ amroutine->ambuild = gistbuild;
+ amroutine->ambuildempty = gistbuildempty;
+ amroutine->ambulkdelete = gistbulkdelete;
+ amroutine->amvacuumcleanup = gistvacuumcleanup;
+ amroutine->amcanreturn = gistcanreturn;
+ amroutine->amcostestimate = gistcostestimate;
+ amroutine->amoptions = gistoptions;
+ amroutine->amvalidate = gistvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ gistvalidate(Oid opclassoid)
+ {
+ bool procsPresent[GISTNProcs];
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid,
+ intype,
+ keytype;
+ CatCList *proclist,
+ *oprlist;
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ /* Fetch opclass information */
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ intype = classform->opcintype;
+ keytype = classform->opckeytype;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+
+ /* Fetch opfamily information: operators and functions */
+ oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+
+ /* Check required procedure numbers exist */
+ for (i = 0; i < proclist->n_members; i++)
+ {
+ HeapTuple proctup = &proclist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype != intype ||
+ procform->amprocrighttype != intype)
+ continue;
+
+ if (procform->amprocnum < 1 || procform->amprocnum > GISTNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for GiST: %u",
+ procform->amprocnum)));
+
+ if (procsPresent[procform->amprocnum - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u was defined more than once",
+ procform->amprocnum)));
+
+ procsPresent[procform->amprocnum - 1] = true;
+ }
+
+ for (i = 0; i < GISTNProcs; i++)
+ {
+ if (i+1 == GIST_DISTANCE_PROC || i+1 == GIST_FETCH_PROC)
+ continue; /* optional methods */
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u is required", i+1)));
+ }
+
+ /*
+ * Check operators: ORDER BY operators are supported only if distance
+ * procedure is specified.
+ */
+ for (i = 0; i < oprlist->n_members; i++)
+ {
+ HeapTuple oprtup = &oprlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+
+ if (OidIsValid(oprform->amopsortfamily) &&
+ !procsPresent[GIST_DISTANCE_PROC - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST distance support function %u is required "
+ "for ORDER BY operators", GIST_DISTANCE_PROC)));
+ }
+
+ ReleaseCatCacheList(proclist);
+ ReleaseCatCacheList(oprlist);
+ }
#define ROTATEDIST(d) do { \
SplitedPageLayout *tmp=(SplitedPageLayout*)palloc(sizeof(SplitedPageLayout)); \
*************** createTempGistContext(void)
*** 70,79 ****
/*
* 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 */
--- 209,217 ----
/*
* gistbuildempty() -- build an empty gist index in the initialization fork
*/
! void
! gistbuildempty(Relation index)
{
Buffer buffer;
/* Initialize the root page */
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 89,96 ****
/* Unlock and release the buffer */
UnlockReleaseBuffer(buffer);
-
- PG_RETURN_VOID();
}
/*
--- 227,232 ----
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 99,116 ****
* 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;
--- 235,245 ----
* 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)
*** 136,142 ****
MemoryContextSwitchTo(oldCxt);
freeGISTstate(giststate);
! PG_RETURN_BOOL(false);
}
--- 265,271 ----
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 ce8e582..1adf92f
*** a/src/backend/access/gist/gistget.c
--- b/src/backend/access/gist/gistget.c
*************** getNextNearest(IndexScanDesc scan)
*** 618,628 ****
/*
* 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)
--- 618,626 ----
/*
* 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)
*** 651,657 ****
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! PG_RETURN_BOOL(getNextNearest(scan));
}
else
{
--- 649,655 ----
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! return getNextNearest(scan);
}
else
{
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 688,694 ****
so->curPageData++;
! PG_RETURN_BOOL(true);
}
/*
--- 686,692 ----
so->curPageData++;
! return true;
}
/*
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 726,732 ****
item = getNextGISTSearchItem(so);
if (!item)
! PG_RETURN_BOOL(false);
CHECK_FOR_INTERRUPTS();
--- 724,730 ----
item = getNextGISTSearchItem(so);
if (!item)
! return false;
CHECK_FOR_INTERRUPTS();
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 750,766 ****
/*
* 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);
--- 748,762 ----
/*
* 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)
*** 791,797 ****
pfree(item);
}
! PG_RETURN_INT64(ntids);
}
/*
--- 787,793 ----
pfree(item);
}
! return ntids;
}
/*
*************** gistgetbitmap(PG_FUNCTION_ARGS)
*** 799,812 ****
*
* 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);
}
--- 795,805 ----
*
* 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 a17c5bc..22f0c68
*** 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)
*** 107,121 ****
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;
--- 104,116 ----
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)
*** 314,341 ****
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;
/*
--- 309,331 ----
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)
*** 343,348 ****
* as well as the queueCxt if there is a separate context for it.
*/
freeGISTstate(so->giststate);
-
- PG_RETURN_VOID();
}
--- 333,336 ----
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 a0b0eeb..e0ce620
*** 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)
*** 276,280 ****
vacuum_delay_point();
}
! PG_RETURN_POINTER(stats);
}
--- 271,275 ----
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..109f8f1
*** a/src/backend/access/hash/hash.c
--- b/src/backend/access/hash/hash.c
***************
*** 18,31 ****
--- 18,38 ----
#include "postgres.h"
+ #include "access/amapi.h"
#include "access/hash.h"
#include "access/relscan.h"
#include "catalog/index.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
+ #include "catalog/pg_opclass.h"
#include "commands/vacuum.h"
#include "optimizer/cost.h"
#include "optimizer/plancat.h"
#include "storage/bufmgr.h"
+ #include "utils/catcache.h"
#include "utils/rel.h"
+ #include "utils/selfuncs.h"
+ #include "utils/syscache.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;
--- 49,196 ----
bool tupleIsAlive,
void *state);
+ /*
+ * Hash handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ hashhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 1;
+ amroutine->amsupport = 1;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = true;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = false;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = INT4OID;
+
+ amroutine->aminsert = hashinsert;
+ amroutine->ambeginscan = hashbeginscan;
+ amroutine->amgettuple = hashgettuple;
+ amroutine->amgetbitmap = hashgetbitmap;
+ amroutine->amrescan = hashrescan;
+ amroutine->amendscan = hashendscan;
+ amroutine->ammarkpos = hashmarkpos;
+ amroutine->amrestrpos = hashrestrpos;
+ amroutine->ambuild = hashbuild;
+ amroutine->ambuildempty = hashbuildempty;
+ amroutine->ambulkdelete = hashbulkdelete;
+ amroutine->amvacuumcleanup = hashvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = hashcostestimate;
+ amroutine->amoptions = hashoptions;
+ amroutine->amvalidate = hashvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ hashvalidate(Oid opclassoid)
+ {
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid,
+ intype,
+ keytype;
+ CatCList *proclist,
+ *oprlist;
+ int i,
+ j;
+
+ /* Fetch opclass information */
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ intype = classform->opcintype;
+ keytype = classform->opckeytype;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+
+ /* Fetch opfamily information: operators and functions */
+ oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+
+ /* Check hash procedure exists */
+ for (i = 0; i < proclist->n_members; i++)
+ {
+ HeapTuple proctup = &proclist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype != intype ||
+ procform->amprocrighttype != intype)
+ continue;
+
+ if (procform->amprocnum != HASHPROC)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for hash: %u",
+ procform->amprocnum)));
+ }
+
+ /* Check operators */
+ for (i = 0; i < oprlist->n_members; i++)
+ {
+ HeapTuple oprtup = &oprlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+ bool leftFound = false,
+ rightFound = false;
+
+ /* ORDER BY operators are not supported */
+ if (OidIsValid(oprform->amopsortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("hash doesn't support ORDER BY operators")));
+
+ /* Check strategy number */
+ if (oprform->amopstrategy < 1 ||
+ oprform->amopstrategy > HTMaxStrategyNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid strategy number for hash: %u",
+ oprform->amopstrategy)));
+
+ /* There should be relevant hash procedure for operator */
+ for (j = 0; j < proclist->n_members; j++)
+ {
+ HeapTuple proctup = &proclist->members[j]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype == oprform->amoplefttype)
+ leftFound = true;
+ if (procform->amproclefttype == oprform->amoprighttype)
+ rightFound = true;
+ }
+
+ if (!leftFound || !rightFound)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("no hash procedure found for operator: %u",
+ oprform->amopopr)));
+ }
+
+ ReleaseCatCacheList(proclist);
+ ReleaseCatCacheList(oprlist);
+ }
/*
* 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();
}
/*
--- 251,266 ----
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;
/*
--- 302,312 ----
* 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);
--- 319,325 ----
* 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;
--- 329,344 ----
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;
--- 440,455 ----
/* 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;
--- 486,501 ----
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;
--- 517,532 ----
/* 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;
--- 552,565 ----
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();
}
/*
--- 578,601 ----
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;
--- 605,614 ----
*
* 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);
}
/*
--- 778,784 ----
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);
}
--- 786,807 ----
*
* 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..ea8ae00
*** a/src/backend/access/nbtree/nbtree.c
--- b/src/backend/access/nbtree/nbtree.c
***************
*** 22,34 ****
--- 22,39 ----
#include "access/relscan.h"
#include "access/xlog.h"
#include "catalog/index.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
+ #include "catalog/pg_opclass.h"
#include "commands/vacuum.h"
#include "storage/indexfsm.h"
#include "storage/ipc.h"
#include "storage/lmgr.h"
#include "storage/smgr.h"
#include "tcop/tcopprot.h"
+ #include "utils/catcache.h"
#include "utils/memutils.h"
+ #include "utils/syscache.h"
/* Working state for btbuild and its callback */
*************** 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;
--- 81,221 ----
/*
! * 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;
! amroutine->amvalidate = btvalidate;
!
! PG_RETURN_POINTER(amroutine);
! }
!
! void
! btvalidate(Oid opclassoid)
! {
! HeapTuple classtup;
! Form_pg_opclass classform;
! Oid opfamilyoid,
! intype,
! keytype;
! CatCList *proclist,
! *oprlist;
! int i,
! j;
!
! /* Fetch opclass information */
! classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
!
! if (!HeapTupleIsValid(classtup))
! elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
!
! classform = (Form_pg_opclass) GETSTRUCT(classtup);
! intype = classform->opcintype;
! keytype = classform->opckeytype;
! opfamilyoid = classform->opcfamily;
!
! ReleaseSysCache(classtup);
!
! /* Fetch opfamily information: operators and functions */
! oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
! proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
!
! /* Check that only allowed procedure numbers exist */
! for (i = 0; i < proclist->n_members; i++)
! {
! HeapTuple proctup = &proclist->members[i]->tuple;
! Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
!
! if (procform->amprocnum != BTORDER_PROC &&
! procform->amprocnum != BTSORTSUPPORT_PROC)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("invalid support number for btree: %u",
! procform->amprocnum)));
!
! }
!
! /* Check operators */
! for (i = 0; i < oprlist->n_members; i++)
! {
! HeapTuple oprtup = &oprlist->members[i]->tuple;
! Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
! bool found = false;
!
! if (OidIsValid(oprform->amopsortfamily))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("btree doesn't support ORDER BY operators")));
!
! if (oprform->amopstrategy < 1 || oprform->amopstrategy > BTMaxStrategyNumber)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("invalid strategy number for btree: %u",
! oprform->amopstrategy)));
!
! /* There should be relevant support function for operator */
! for (j = 0; j < proclist->n_members; j++)
! {
! HeapTuple proctup = &proclist->members[j]->tuple;
! Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
!
! if (procform->amprocnum == BTORDER_PROC &&
! procform->amproclefttype == oprform->amoplefttype &&
! procform->amprocrighttype == oprform->amoprighttype)
! found = true;
! }
!
! if (!found)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("no ordering procedure found for operator: %u",
! oprform->amopopr)));
! }
!
! ReleaseCatCacheList(proclist);
! ReleaseCatCacheList(oprlist);
! }
!
! /*
! * 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);
}
/*
--- 287,293 ----
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);
--- 322,331 ----
/*
* 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();
}
/*
--- 345,350 ----
*************** 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;
--- 353,363 ----
* 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;
--- 369,383 ----
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);
}
--- 393,399 ----
{
/* 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;
--- 443,457 ----
/* ... 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);
}
--- 463,469 ----
{
/* 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;
--- 501,515 ----
/* 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 */
--- 547,562 ----
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 */
--- 607,620 ----
/* 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). */
--- 643,656 ----
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 */
--- 673,686 ----
/* 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();
}
/*
--- 748,753 ----
*************** 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;
--- 757,766 ----
*
* 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);
}
/*
--- 779,785 ----
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
--- 787,798 ----
*
* 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);
}
/*
--- 824,830 ----
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);
}
--- 1225,1232 ----
*
* 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..63e4537
*** a/src/backend/access/spgist/spgutils.c
--- b/src/backend/access/spgist/spgutils.c
***************
*** 16,30 ****
--- 16,162 ----
#include "postgres.h"
#include "access/genam.h"
+ #include "access/htup_details.h"
#include "access/reloptions.h"
#include "access/spgist_private.h"
#include "access/transam.h"
#include "access/xact.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
+ #include "catalog/pg_opclass.h"
#include "storage/bufmgr.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "utils/lsyscache.h"
+ #include "utils/catcache.h"
+ #include "utils/selfuncs.h"
+ #include "utils/syscache.h"
+
+
+ /*
+ * SP-GiST handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ spghandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 5;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = spginsert;
+ amroutine->ambeginscan = spgbeginscan;
+ amroutine->amgettuple = spggettuple;
+ amroutine->amgetbitmap = spggetbitmap;
+ amroutine->amrescan = spgrescan;
+ amroutine->amendscan = spgendscan;
+ amroutine->ammarkpos = spgmarkpos;
+ amroutine->amrestrpos = spgrestrpos;
+ amroutine->ambuild = spgbuild;
+ amroutine->ambuildempty = spgbuildempty;
+ amroutine->ambulkdelete = spgbulkdelete;
+ amroutine->amvacuumcleanup = spgvacuumcleanup;
+ amroutine->amcanreturn = spgcanreturn;
+ amroutine->amcostestimate = spgcostestimate;
+ amroutine->amoptions = spgoptions;
+ amroutine->amvalidate = spgvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ spgvalidate(Oid opclassoid)
+ {
+ bool procsPresent[SPGISTNProc];
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid,
+ intype,
+ keytype;
+ CatCList *proclist,
+ *oprlist;
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ /* Fetch opclass information */
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ intype = classform->opcintype;
+ keytype = classform->opckeytype;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+
+ /* Fetch opfamily information: operators and functions */
+ oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+
+ /* Check required procedure numbers exist */
+ for (i = 0; i < proclist->n_members; i++)
+ {
+ HeapTuple proctup = &proclist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype != intype ||
+ procform->amprocrighttype != intype)
+ continue;
+
+ if (procform->amprocnum < 1 || procform->amprocnum > SPGISTNProc)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for SP-GiST: %u",
+ procform->amprocnum)));
+ if (procsPresent[procform->amprocnum - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u was defined more than once",
+ procform->amprocnum)));
+
+ procsPresent[procform->amprocnum - 1] = true;
+ }
+
+ for (i = 0; i < SPGISTNProc; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u is required", i + 1)));
+ }
+
+ /* Check operators: ORDER BY operators are not supported */
+ for (i = 0; i < oprlist->n_members; i++)
+ {
+ HeapTuple oprtup = &oprlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+
+ if (OidIsValid(oprform->amopsortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST doesn't support ORDER BY operators")));
+ }
+
+ ReleaseCatCacheList(proclist);
+ ReleaseCatCacheList(oprlist);
+ }
/* 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();
}
/*
--- 621,636 ----
/*
* 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..4e21304
*** a/src/backend/catalog/index.c
--- b/src/backend/catalog/index.c
***************
*** 23,28 ****
--- 23,29 ----
#include <unistd.h>
+ #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 = GetIndexAmRoutineByAmId(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..b794d59
*** 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,169 ----
accessMethodName)));
accessMethodId = HeapTupleGetOid(tuple);
accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
! amRoutine = GetIndexAmRoutine(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;
--- 318,326 ----
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);
--- 493,523 ----
}
accessMethodId = HeapTupleGetOid(tuple);
accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
+ amRoutine = GetIndexAmRoutine(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/opclasscmds.c b/src/backend/commands/opclasscmds.c
new file mode 100644
index 3375f10..7a50b6a
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 334,346 ****
ListCell *l;
Relation rel;
HeapTuple tup;
- Form_pg_am pg_am;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
--- 334,346 ----
ListCell *l;
Relation rel;
HeapTuple tup;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
+ IndexAmRoutine *amroutine;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 361,373 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
! amstorage = pg_am->amstorage;
/* XXX Should we make any privilege check against the AM? */
--- 361,375 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
!
! amroutine = GetIndexAmRoutineByAmId(amoid);
!
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
! amstorage = amroutine->amstorage;
/* XXX Should we make any privilege check against the AM? */
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 720,725 ****
--- 722,757 ----
/*
+ * Ask access method to validate given opclass.
+ */
+ Datum
+ amvalidate(PG_FUNCTION_ARGS)
+ {
+ Oid opclassoid = PG_GETARG_OID(0),
+ amoid;
+ IndexAmRoutine *amroutine;
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ amoid = classform->opcmethod;
+
+ ReleaseSysCache(classtup);
+
+ amroutine = GetIndexAmRoutineByAmId(amoid);
+
+ amroutine->amvalidate(opclassoid);
+
+ PG_RETURN_BOOL(true);
+ }
+
+
+ /*
* DefineOpFamily
* Define a new index operator family.
*/
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 776,782 ****
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! Form_pg_am pg_am;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
--- 808,814 ----
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! IndexAmRoutine *amroutine;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 787,802 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
/* XXX Should we make any privilege check against the AM? */
- ReleaseSysCache(tup);
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
--- 819,834 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! amroutine = GetIndexAmRoutineByAmId(amoid);
! ReleaseSysCache(tup);
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
/* XXX Should we make any privilege check against the AM? */
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
*************** assignOperTypes(OpFamilyMember *member,
*** 1099,1119 ****
* the family has been created but not yet populated with the required
* operators.)
*/
! HeapTuple amtup;
! Form_pg_am pg_am;
! amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
! if (amtup == NULL)
! elog(ERROR, "cache lookup failed for access method %u", amoid);
! pg_am = (Form_pg_am) GETSTRUCT(amtup);
! if (!pg_am->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! NameStr(pg_am->amname))));
!
! ReleaseSysCache(amtup);
}
else
{
--- 1131,1145 ----
* the family has been created but not yet populated with the required
* operators.)
*/
! IndexAmRoutine *amroutine;
! amroutine = GetIndexAmRoutineByAmId(amoid);
! if (!amroutine->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! get_am_name(amoid))));
}
else
{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
new file mode 100644
index 6df4939..d37eec5
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
*************** ATExecSetRelOptions(Relation rel, List *
*** 9398,9404 ****
(void) view_reloptions(newOptions, true);
break;
case RELKIND_INDEX:
! (void) index_reloptions(rel->rd_am->amoptions, newOptions, true);
break;
default:
ereport(ERROR,
--- 9398,9404 ----
(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
*** 11008,11014 ****
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",
--- 11008,11014 ----
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 b969fc0..587b6e9
*** 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)
*** 545,550 ****
--- 546,552 ----
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)
*** 558,566 ****
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);
--- 560,570 ----
elog(ERROR, "cache lookup failed for access method %u",
idxrelrec->relam);
amrec = (Form_pg_am) GETSTRUCT(ht_am);
+ amroutine = GetIndexAmRoutine(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 990486c..1310613
*** a/src/backend/optimizer/path/costsize.c
--- b/src/backend/optimizer/path/costsize.c
*************** cost_index(IndexPath *path, PlannerInfo
*** 419,432 ****
* 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.
--- 419,426 ----
* 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 344a40c..f11c236
*** 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
*** 1292,1298 ****
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
--- 1293,1299 ----
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 0ab839d..e191f35
*** a/src/backend/utils/adt/ruleutils.c
--- b/src/backend/utils/adt/ruleutils.c
***************
*** 19,24 ****
--- 19,25 ----
#include <unistd.h>
#include <fcntl.h>
+ #include "access/amapi.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "catalog/dependency.h"
*************** pg_get_indexdef_worker(Oid indexrelid, i
*** 1179,1184 ****
--- 1180,1186 ----
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
*** 1189,1196 ****
/* 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)
--- 1191,1200 ----
/* Add the operator class name, if not default */
get_opclass_name(indclass->values[keyno], keycoltype, &buf);
+ amroutine = GetIndexAmRoutine(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 15121bc..a882796
*** a/src/backend/utils/adt/selfuncs.c
--- b/src/backend/utils/adt/selfuncs.c
*************** add_predicate_to_quals(IndexOptInfo *ind
*** 6443,6458 ****
}
! 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;
--- 6443,6453 ----
}
! 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)
*** 6741,6760 ****
*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;
--- 6736,6748 ----
*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)
*** 6794,6813 ****
*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;
--- 6782,6794 ----
*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)
*** 6860,6879 ****
*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;
--- 6841,6853 ----
*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)
*** 6926,6933 ****
*indexTotalCost = costs.indexTotalCost;
*indexSelectivity = costs.indexSelectivity;
*indexCorrelation = costs.indexCorrelation;
-
- PG_RETURN_VOID();
}
--- 6900,6905 ----
*************** gincost_scalararrayopexpr(PlannerInfo *r
*** 7222,7237 ****
/*
* 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;
--- 7194,7204 ----
/*
* 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)
*** 7400,7406 ****
*indexStartupCost = 0;
*indexTotalCost = 0;
*indexSelectivity = 0;
! PG_RETURN_VOID();
}
if (counts.haveFullScan || indexQuals == NIL)
--- 7367,7373 ----
*indexStartupCost = 0;
*indexTotalCost = 0;
*indexSelectivity = 0;
! return;
}
if (counts.haveFullScan || indexQuals == NIL)
*************** gincostestimate(PG_FUNCTION_ARGS)
*** 7522,7544 ****
*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;
--- 7489,7504 ----
*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)
*** 7591,7596 ****
*indexTotalCost += (numTuples * *indexSelectivity) * (cpu_index_tuple_cost + qual_op_cost);
/* XXX what about pages_per_range? */
-
- PG_RETURN_VOID();
}
--- 7551,7554 ----
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
new file mode 100644
index 6b0c0b7..7d19b45
*** a/src/backend/utils/cache/relcache.c
--- b/src/backend/utils/cache/relcache.c
*************** 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
--- 445,451 ----
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
*** 1160,1165 ****
--- 1160,1231 ----
}
/*
+ * GetIndexAmRoutine - call the specified access method handler routine
+ * to get its IndexAmRoutine struct.
+ */
+ IndexAmRoutine *
+ GetIndexAmRoutine(Oid amhandler)
+ {
+ Datum datum;
+ IndexAmRoutine *routine;
+
+ datum = OidFunctionCall0(amhandler);
+ routine = (IndexAmRoutine *) DatumGetPointer(datum);
+
+ if (routine == NULL || !IsA(routine, IndexAmRoutine))
+ elog(ERROR, "index access method handler function %u did not return an IndexAmRoutine struct",
+ amhandler);
+
+ return routine;
+ }
+
+ /*
+ * GetIndexAmRoutine - look up the handler of the access method
+ * for the given OID, and retrieve its IndexAmRoutine struct.
+ */
+ IndexAmRoutine *
+ GetIndexAmRoutineByAmId(Oid amoid)
+ {
+ HeapTuple tuple;
+ regproc amhandler;
+ Form_pg_am amform;
+
+ /* Get handler function OID for the access method */
+ tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for access method %u",
+ amoid);
+ amform = (Form_pg_am) GETSTRUCT(tuple);
+ amhandler = amform->amhandler;
+
+ /* Complain if handler OID is invalid */
+ if (!RegProcedureIsValid(amhandler))
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("index access method \"%s\" does not have a handler",
+ NameStr(amform->amname))));
+ ReleaseSysCache(tuple);
+
+ /* And finally, call the handler function. */
+ return GetIndexAmRoutine(amhandler);
+ }
+
+ /*
+ * Initialize IndexAmRoutine for relation.
+ */
+ void
+ InitIndexAmRoutine(Relation relation)
+ {
+ IndexAmRoutine *result, *tmp;
+
+ result = (IndexAmRoutine *) MemoryContextAlloc(relation->rd_indexcxt,
+ sizeof(IndexAmRoutine));
+ tmp = GetIndexAmRoutine(relation->rd_am->amhandler);
+ memcpy(result, tmp, sizeof(IndexAmRoutine));
+ relation->amroutine = result;
+ }
+
+ /*
* Initialize index-access-method support data for an index relation
*/
void
*************** RelationInitIndexAccessInfo(Relation rel
*** 1211,1217 ****
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
--- 1277,1282 ----
*************** RelationInitIndexAccessInfo(Relation rel
*** 1228,1233 ****
--- 1293,1303 ----
ALLOCSET_SMALL_MAXSIZE);
relation->rd_indexcxt = indexcxt;
+ /* Initialize index AM routine */
+ InitIndexAmRoutine(relation);
+
+ amsupport = relation->amroutine->amsupport;
+
/*
* Allocate arrays to hold data
*/
*************** load_relcache_init_file(bool shared)
*** 4743,4749 ****
Oid *opfamily;
Oid *opcintype;
RegProcedure *support;
- int nsupport;
int16 *indoption;
Oid *indcollation;
--- 4813,4818 ----
*************** load_relcache_init_file(bool shared)
*** 4771,4776 ****
--- 4840,4846 ----
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)
*** 4832,4843 ****
rel->rd_indoption = indoption;
/* 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
{
--- 4902,4914 ----
rel->rd_indoption = indoption;
+ InitIndexAmRoutine(rel);
+
/* set up zeroed fmgr-info vectors */
rel->rd_aminfo = (RelationAmInfo *)
MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
rel->rd_supportinfo = (FmgrInfo *)
! MemoryContextAllocZero(indexcxt, relform->relnatts * rel->amroutine->amsupport * sizeof(FmgrInfo));
}
else
{
*************** write_relcache_init_file(bool shared)
*** 5116,5122 ****
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
--- 5187,5193 ----
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (rel->amroutine->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h
new file mode 100644
index ...71d62d3
*** a/src/include/access/amapi.h
--- b/src/include/access/amapi.h
***************
*** 0 ****
--- 1,168 ----
+ /*-------------------------------------------------------------------------
+ *
+ * amapi.h
+ * API for generalized index access methods definition.
+ *
+ * Copyright (c) 2015, PostgreSQL Global Development Group
+ *
+ * src/include/access/amapi.h
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef AMAPI_H
+ #define AMAPI_H
+
+ #include "access/genam.h"
+ #include "nodes/reldecls.h"
+
+ /*
+ * Callback function signatures --- see indexam.sgml for more info.
+ */
+
+ /* "insert this tuple" function */
+ typedef bool
+ (*aminsert_function) (Relation indexRelation,
+ Datum *values,
+ bool *isnull,
+ ItemPointer heap_tid,
+ Relation heapRelation,
+ IndexUniqueCheck checkUnique);
+
+ /* "prepare for index scan" function */
+ typedef IndexScanDesc
+ (*ambeginscan_function) (Relation indexRelation,
+ int nkeys,
+ int norderbys);
+
+ /* "next valid tuple" function, or NULL */
+ typedef bool
+ (*amgettuple_function) (IndexScanDesc scan,
+ ScanDirection direction);
+
+ /* "fetch all valid tuples" function, or NULL */
+ typedef int64
+ (*amgetbitmap_function) (IndexScanDesc scan,
+ TIDBitmap *tbm);
+
+ /* "(re)start index scan" function */
+ typedef void
+ (*amrescan_function) (IndexScanDesc scan,
+ ScanKey keys,
+ int nkeys,
+ ScanKey orderbys,
+ int norderbys);
+
+ /* "end index scan" function */
+ typedef void
+ (*amendscan_function) (IndexScanDesc scan);
+
+ /* "mark current scan position" function */
+ typedef void
+ (*ammarkpos_function) (IndexScanDesc scan);
+
+ /* "restore marked scan position" function */
+ typedef void
+ (*amrestrpos_function) (IndexScanDesc scan);
+
+ /* "build new index" function */
+ typedef IndexBuildResult *
+ (*ambuild_function) (Relation heapRelation,
+ Relation indexRelation,
+ IndexInfo *indexInfo);
+
+ /* "build empty index" function */
+ typedef void
+ (*ambuildempty_function) (Relation indexRelation);
+
+ /* bulk-delete function */
+ typedef IndexBulkDeleteResult *
+ (*ambulkdelete_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+
+ /* post-VACUUM cleanup function */
+ typedef IndexBulkDeleteResult *
+ (*amvacuumcleanup_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
+
+ /* can indexscan return IndexTuples? */
+ typedef bool
+ (*amcanreturn_function) (Relation indexRelation, int attno);
+
+ /* estimate cost of an indexscan */
+ typedef void
+ (*amcostestimate_function) (PlannerInfo *root,
+ IndexPath *path,
+ double loop_count,
+ Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+
+ /* parse AM-specific parameters */
+ typedef bytea *
+ (*amoptions_function) (Datum reloptions,
+ bool validate);
+
+ /* validate oplass */
+ typedef void
+ (*amvalidate_function) (Oid opclassoid);
+
+
+ struct IndexAmRoutine
+ {
+ NodeTag type;
+
+ /*
+ * Total number of strategies (operators) by which we can traverse/search
+ * this AM. Zero if AM does not have a fixed set of strategy assignments.
+ */
+ int16 amstrategies;
+ /* total number of support functions that this AM uses */
+ int16 amsupport;
+ /* does AM support order by column value? */
+ bool amcanorder;
+ /* does AM support order by operator result? */
+ bool amcanorderbyop;
+ /* does AM support backward scan? */
+ bool amcanbackward;
+ /* does AM support UNIQUE indexes? */
+ bool amcanunique;
+ /* does AM support multi-column indexes? */
+ bool amcanmulticol;
+ /* can query omit key for the first column? */
+ bool amoptionalkey;
+ /* can AM handle ScalarArrayOpExpr quals? */
+ bool amsearcharray;
+ /* can AM search for NULL/NOT NULL entries? */
+ bool amsearchnulls;
+ /* can storage type differ from column type? */
+ bool amstorage;
+ /* does AM support cluster command? */
+ bool amclusterable;
+ /* does AM handle predicate locks? */
+ bool ampredlocks;
+ /* type of data in index, or InvalidOid */
+ Oid amkeytype;
+
+ /* interface functions */
+ aminsert_function aminsert;
+ ambeginscan_function ambeginscan;
+ amgettuple_function amgettuple;
+ amgetbitmap_function amgetbitmap;
+ amrescan_function amrescan;
+ amendscan_function amendscan;
+ ammarkpos_function ammarkpos;
+ amrestrpos_function amrestrpos;
+ ambuild_function ambuild;
+ ambuildempty_function ambuildempty;
+ ambulkdelete_function ambulkdelete;
+ amvacuumcleanup_function amvacuumcleanup;
+ amcanreturn_function amcanreturn;
+ amcostestimate_function amcostestimate;
+ amoptions_function amoptions;
+ amvalidate_function amvalidate;
+ };
+
+ #endif /* AMAPI_H */
diff --git a/src/include/access/brin.h b/src/include/access/brin.h
new file mode 100644
index e72fb2d..b9024fd
*** a/src/include/access/brin.h
--- b/src/include/access/brin.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
--- 18,50 ----
/*
* prototypes for functions in brin.c (external entry points for BRIN)
*/
! extern Datum brinhandler(PG_FUNCTION_ARGS);
! extern void brinvalidate(Oid opclassoid);
! extern IndexBuildResult *brinbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void brinbuildempty(Relation index);
! extern bool brininsert(Relation idxRel, Datum *values, bool *nulls,
! ItemPointer heaptid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys);
! extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
! ScanKey orderbys, int norderbys);
! extern void brinendscan(IndexScanDesc scan);
! extern void brinmarkpos(IndexScanDesc scan);
! extern void brinrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *brinbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *brinvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern void brincostestimate(PlannerInfo *root, IndexPath *path,
! double loop_count, Cost *indexStartupCost,
! Cost *indexTotalCost,
! Selectivity *indexSelectivity,
! double *indexCorrelation);
! extern bytea *brinoptions(Datum reloptions, bool validate);
/*
* Storage type for BRIN's reloptions
diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h
new file mode 100644
index 6be199e..3273fa7
*** a/src/include/access/brin_internal.h
--- b/src/include/access/brin_internal.h
***************
*** 11,16 ****
--- 11,17 ----
#ifndef BRIN_INTERNAL_H
#define BRIN_INTERNAL_H
+ #include "access/amapi.h"
#include "fmgr.h"
#include "storage/buf.h"
#include "storage/bufpage.h"
*************** typedef struct BrinDesc
*** 71,76 ****
--- 72,78 ----
#define BRIN_PROCNUM_ADDVALUE 2
#define BRIN_PROCNUM_CONSISTENT 3
#define BRIN_PROCNUM_UNION 4
+ #define BRIN_MANDATORY_NPROCS 4
/* procedure numbers up to 10 are reserved for BRIN future expansion */
#undef BRIN_DEBUG
*************** typedef struct BrinDesc
*** 85,89 ****
--- 87,117 ----
extern BrinDesc *brin_build_desc(Relation rel);
extern void brin_free_desc(BrinDesc *bdesc);
extern Datum brin_summarize_new_values(PG_FUNCTION_ARGS);
+ extern void brinvalidate(Oid opclassoid);
+ 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);
#endif /* BRIN_INTERNAL_H */
diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h
new file mode 100644
index 5021887..40c2fa0
*** 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,601 ----
/* ginutil.c */
! extern Datum ginhandler(PG_FUNCTION_ARGS);
! extern void ginvalidate(Oid opclassoid);
! 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,
--- 616,627 ----
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);
--- 872,899 ----
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 1a77982..c00b578
*** 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
*** 426,434 ****
} 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);
--- 427,439 ----
} GiSTOptions;
/* gist.c */
! extern Datum gisthandler(PG_FUNCTION_ARGS);
! extern void gistvalidate(Oid opclassoid);
! 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
*** 474,481 ****
Buffer leftchild, bool markfollowright);
/* gistget.c */
! extern Datum gistgettuple(PG_FUNCTION_ARGS);
! extern Datum gistgetbitmap(PG_FUNCTION_ARGS);
/* gistutil.c */
--- 479,486 ----
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
*** 485,491 ****
#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);
--- 490,496 ----
#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 *
*** 534,541 ****
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,
--- 539,550 ----
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
*** 544,550 ****
int attno);
/* gistbuild.c */
! extern Datum gistbuild(PG_FUNCTION_ARGS);
extern void gistValidateBufferingOption(char *value);
/* gistbuildbuffers.c */
--- 553,560 ----
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..866ad6b
*** 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,271 ----
/* public routines */
! extern Datum hashhandler(PG_FUNCTION_ARGS);
! extern void hashvalidate(Oid opclassoid);
! 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..50c66ee
*** 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,683 ----
/*
* prototypes for functions in nbtree.c (external entry points for btree)
*/
! extern Datum bthandler(PG_FUNCTION_ARGS);
! extern void btvalidate(Oid opclassoid);
! 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..d17aebd
*** 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,212 ----
} spgLeafConsistentOut;
+ /* spgutils.c */
+ extern Datum spghandler(PG_FUNCTION_ARGS);
+ extern void spgvalidate(Oid opclassoid);
+
/* 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..f19a873
*** 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,40 ----
CATALOG(pg_am,2601)
{
NameData amname; /* access method name */
! regproc amhandler; /* handler function */
} 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
--- 48,78 ----
* compiler constants for pg_am
* ----------------
*/
! #define Natts_pg_am 2
#define Anum_pg_am_amname 1
! #define Anum_pg_am_amhandler 2
/* ----------------
* initial contents of pg_am
* ----------------
*/
! DATA(insert OID = 403 ( btree bthandler ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
! DATA(insert OID = 405 ( hash hashhandler ));
DESCR("hash index access method");
#define HASH_AM_OID 405
! DATA(insert OID = 783 ( gist gisthandler ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
! DATA(insert OID = 2742 ( gin ginhandler ));
DESCR("GIN index access method");
#define GIN_AM_OID 2742
! DATA(insert OID = 4000 ( spgist spghandler ));
DESCR("SP-GiST index access method");
#define SPGIST_AM_OID 4000
! DATA(insert OID = 3580 ( brin brinhandler ));
DESCR("block range index (BRIN) access method");
#define BRIN_AM_OID 3580
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index d8640db..b3c6915
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DESCR("convert int4 to float4");
*** 548,610 ****
DATA(insert OID = 319 ( int4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "700" _null_ _null_ _null_ _null_ _null_ ftoi4 _null_ _null_ _null_ ));
DESCR("convert float4 to int4");
- DATA(insert OID = 330 ( btgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgettuple _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 636 ( btgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgetbitmap _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 331 ( btinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btinsert _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 333 ( btbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbeginscan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 334 ( btrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btrescan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 335 ( btendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btendscan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 336 ( btmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btmarkpos _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 337 ( btrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btrestrpos _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 338 ( btbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbuild _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 328 ( btbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btbuildempty _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 332 ( btbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbulkdelete _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ btvacuumcleanup _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 276 ( btcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ btcanreturn _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 1268 ( btcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btcostestimate _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 2785 ( btoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ btoptions _null_ _null_ _null_ ));
- DESCR("btree(internal)");
-
- DATA(insert OID = 3789 ( bringetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ bringetbitmap _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3790 ( brininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brininsert _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3791 ( brinbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbeginscan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3792 ( brinrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinrescan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3793 ( brinendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinendscan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3794 ( brinmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinmarkpos _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3795 ( brinrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinrestrpos _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3796 ( brinbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbuild _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3797 ( brinbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinbuildempty _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3798 ( brinbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbulkdelete _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3799 ( brinvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ brinvacuumcleanup _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3800 ( brincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brincostestimate _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3801 ( brinoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ brinoptions _null_ _null_ _null_ ));
- DESCR("brin(internal)");
DATA(insert OID = 3952 ( brin_summarize_new_values PGNSP PGUID 12 1 0 0 0 f f f f f f v s 1 0 23 "2205" _null_ _null_ _null_ _null_ _null_ brin_summarize_new_values _null_ _null_ _null_ ));
DESCR("brin: standalone scan new table pages");
--- 548,553 ----
*************** DESCR("convert name to char(n)");
*** 695,729 ****
DATA(insert OID = 409 ( name PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 19 "1042" _null_ _null_ _null_ _null_ _null_ bpchar_name _null_ _null_ _null_ ));
DESCR("convert char(n) to name");
- DATA(insert OID = 440 ( hashgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgettuple _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 637 ( hashgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgetbitmap _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 441 ( hashinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashinsert _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 443 ( hashbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbeginscan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 444 ( hashrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashrescan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 445 ( hashendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashendscan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 446 ( hashmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashmarkpos _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 447 ( hashrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashrestrpos _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 448 ( hashbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbuild _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 327 ( hashbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashbuildempty _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 442 ( hashbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbulkdelete _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashvacuumcleanup _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 438 ( hashcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashcostestimate _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 2786 ( hashoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ hashoptions _null_ _null_ _null_ ));
- DESCR("hash(internal)");
-
DATA(insert OID = 449 ( hashint2 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "21" _null_ _null_ _null_ _null_ _null_ hashint2 _null_ _null_ _null_ ));
DESCR("hash");
DATA(insert OID = 450 ( hashint4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ hashint4 _null_ _null_ _null_ ));
--- 638,643 ----
*************** DESCR("larger of two");
*** 979,1015 ****
DATA(insert OID = 771 ( int2smaller PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2smaller _null_ _null_ _null_ ));
DESCR("smaller of two");
- DATA(insert OID = 774 ( gistgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgettuple _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 638 ( gistgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgetbitmap _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 775 ( gistinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistinsert _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 777 ( gistbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbeginscan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 778 ( gistrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistrescan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 779 ( gistendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistendscan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 780 ( gistmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistmarkpos _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 781 ( gistrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistrestrpos _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 782 ( gistbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbuild _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 326 ( gistbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistbuildempty _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 776 ( gistbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbulkdelete _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistvacuumcleanup _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 3280 ( gistcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ gistcanreturn _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 772 ( gistcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistcostestimate _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 2787 ( gistoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ gistoptions _null_ _null_ _null_ ));
- DESCR("gist(internal)");
-
DATA(insert OID = 784 ( tintervaleq PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervaleq _null_ _null_ _null_ ));
DATA(insert OID = 785 ( tintervalne PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervalne _null_ _null_ _null_ ));
DATA(insert OID = 786 ( tintervallt PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervallt _null_ _null_ _null_ ));
--- 893,898 ----
*************** DATA(insert OID = 3311 ( tsm_handler_in
*** 3742,3747 ****
--- 3625,3634 ----
DESCR("I/O");
DATA(insert OID = 3312 ( tsm_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "3310" _null_ _null_ _null_ _null_ _null_ tsm_handler_out _null_ _null_ _null_ ));
DESCR("I/O");
+ DATA(insert OID = 326 ( index_am_handler_in PGNSP PGUID 12 1 0 0 0 f f f f f f i s 1 0 325 "2275" _null_ _null_ _null_ _null_ _null_ index_am_handler_in _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 327 ( index_am_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "325" _null_ _null_ _null_ _null_ _null_ index_am_handler_out _null_ _null_ _null_ ));
+ DESCR("I/O");
/* tablesample method handlers */
DATA(insert OID = 3313 ( bernoulli PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 3310 "2281" _null_ _null_ _null_ _null_ _null_ tsm_bernoulli_handler _null_ _null_ _null_ ));
*************** DESCR("GiST support");
*** 4198,4231 ****
DATA(insert OID = 3288 ( gist_bbox_distance PGNSP PGUID 12 1 0 0 0 f f f f t f i s 4 0 701 "2281 600 23 26" _null_ _null_ _null_ _null_ _null_ gist_bbox_distance _null_ _null_ _null_ ));
DESCR("GiST support");
- /* GIN */
- DATA(insert OID = 2731 ( gingetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gingetbitmap _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2732 ( gininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gininsert _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2733 ( ginbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbeginscan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2734 ( ginrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginrescan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2735 ( ginendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginendscan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2736 ( ginmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginmarkpos _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2737 ( ginrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginrestrpos _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2738 ( ginbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbuild _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 325 ( ginbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginbuildempty _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2739 ( ginbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbulkdelete _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ ginvacuumcleanup _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2741 ( gincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gincostestimate _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2788 ( ginoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ ginoptions _null_ _null_ _null_ ));
- DESCR("gin(internal)");
-
/* GIN array support */
DATA(insert OID = 2743 ( ginarrayextract PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 2281 "2277 2281 2281" _null_ _null_ _null_ _null_ _null_ ginarrayextract _null_ _null_ _null_ ));
DESCR("GIN array support");
--- 4085,4090 ----
*************** DESCR("construct timestamp with time zon
*** 5123,5160 ****
DATA(insert OID = 3464 ( make_interval PGNSP PGUID 12 1 0 0 0 f f f f t f i s 7 0 1186 "23 23 23 23 23 23 701" _null_ _null_ "{years,months,weeks,days,hours,mins,secs}" _null_ _null_ make_interval _null_ _null_ _null_ ));
DESCR("construct interval");
- /* spgist support functions */
- DATA(insert OID = 4001 ( spggettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggettuple _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4002 ( spggetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggetbitmap _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4003 ( spginsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spginsert _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4004 ( spgbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbeginscan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4005 ( spgrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgrescan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4006 ( spgendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgendscan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4007 ( spgmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgmarkpos _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4008 ( spgrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgrestrpos _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4009 ( spgbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbuild _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4010 ( spgbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgbuildempty _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4011 ( spgbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbulkdelete _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4012 ( spgvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ spgvacuumcleanup _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4032 ( spgcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ spgcanreturn _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4013 ( spgcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgcostestimate _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4014 ( spgoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ spgoptions _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
-
/* spgist opclasses */
DATA(insert OID = 4018 ( spg_quad_config PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_quad_config _null_ _null_ _null_ ));
DESCR("SP-GiST support for quad tree over point");
--- 4982,4987 ----
*************** DESCR("get an individual replication ori
*** 5337,5342 ****
--- 5164,5188 ----
DATA(insert OID = 6014 ( pg_show_replication_origin_status PGNSP PGUID 12 1 100 0 0 f f f f f t v r 0 0 2249 "" "{26,25,3220,3220}" "{o,o,o,o}" "{local_id, external_id, remote_lsn, local_lsn}" _null_ _null_ pg_show_replication_origin_status _null_ _null_ _null_ ));
DESCR("get progress for all replication origins");
+ /* Access methods handlers */
+ DATA(insert OID = 330 ( bthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ bthandler _null_ _null_ _null_ ));
+ DESCR("btree handler");
+ DATA(insert OID = 331 ( hashhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ hashhandler _null_ _null_ _null_ ));
+ DESCR("hash handler");
+ DATA(insert OID = 332 ( gisthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ gisthandler _null_ _null_ _null_ ));
+ DESCR("gist handler");
+ DATA(insert OID = 333 ( ginhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ ginhandler _null_ _null_ _null_ ));
+ DESCR("gin handler");
+ DATA(insert OID = 334 ( spghandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ spghandler _null_ _null_ _null_ ));
+ DESCR("spgist handler");
+ DATA(insert OID = 335 ( brinhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ brinhandler _null_ _null_ _null_ ));
+ DESCR("brin handler");
+
+ DATA(insert OID = 336 ( amvalidate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 16 "26" _null_ _null_ _null_ _null_ _null_ amvalidate _null_ _null_ _null_ ));
+ DESCR("ask access method to validate opclass");
+
+
+
/*
* Symbolic values for provolatile column: these indicate whether the result
* of a function is dependent *only* on the values of its explicit arguments,
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
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/commands/defrem.h b/src/include/commands/defrem.h
new file mode 100644
index adae296..112f9dc
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
*************** extern Oid get_am_oid(const char *amname
*** 95,100 ****
--- 95,101 ----
extern char *get_am_name(Oid amOid);
extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+ extern Datum amvalidate(PG_FUNCTION_ARGS);
/* commands/tsearchcmds.c */
extern ObjectAddress DefineTSParser(List *names, List *parameters);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
new file mode 100644
index 5ccf470..98a8bd6
*** 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 603edd3..0ad9ee9
*** a/src/include/nodes/nodes.h
--- b/src/include/nodes/nodes.h
***************
*** 14,19 ****
--- 14,21 ----
#ifndef NODES_H
#define NODES_H
+ #include "nodes/reldecls.h"
+
/*
* The first field of every node is NodeTag. Each node created (with makeNode)
* will have one of the following tags as the value of its first field.
*************** typedef enum NodeTag
*** 454,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 */
} NodeTag;
/*
--- 456,463 ----
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;
/*
*************** extern bool equal(const void *a, const v
*** 543,560 ****
/*
- * Typedefs for identifying qualifier selectivities and plan costs as such.
- * These are just plain "double"s, but declaring a variable as Selectivity
- * or Cost makes the intent more obvious.
- *
- * These could have gone into plannodes.h or some such, but many files
- * depend on them...
- */
- typedef double Selectivity; /* fraction of tuples a qualifier will pass */
- typedef double Cost; /* execution cost (in page-access units) */
-
-
- /*
* CmdType -
* enums for type of operation represented by a Query or PlannedStmt
*
--- 546,551 ----
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
new file mode 100644
index 5393005..2245895
*** a/src/include/nodes/relation.h
--- b/src/include/nodes/relation.h
***************
*** 18,24 ****
--- 18,26 ----
#include "lib/stringinfo.h"
#include "nodes/params.h"
#include "nodes/parsenodes.h"
+ #include "nodes/reldecls.h"
#include "storage/block.h"
+ #include "utils/relcache.h"
/*
*************** typedef struct PlannerGlobal
*** 125,131 ****
* the passed-in Query data structure; someday that should stop.
*----------
*/
! typedef struct PlannerInfo
{
NodeTag type;
--- 127,133 ----
* the passed-in Query data structure; someday that should stop.
*----------
*/
! struct PlannerInfo
{
NodeTag type;
*************** typedef struct PlannerInfo
*** 274,280 ****
/* for GroupingFunc fixup in setrefs */
AttrNumber *grouping_map;
! } PlannerInfo;
/*
--- 276,282 ----
/* for GroupingFunc fixup in setrefs */
AttrNumber *grouping_map;
! };
/*
*************** typedef struct IndexOptInfo
*** 553,560 ****
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 */
--- 555,561 ----
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
*** 565,576 ****
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;
--- 566,577 ----
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
*** 825,831 ****
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! typedef struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
--- 826,832 ----
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
*************** typedef struct IndexPath
*** 837,843 ****
ScanDirection indexscandir;
Cost indextotalcost;
Selectivity indexselectivity;
! } IndexPath;
/*
* BitmapHeapPath represents one or more indexscans that generate TID bitmaps
--- 838,844 ----
ScanDirection indexscandir;
Cost indextotalcost;
Selectivity indexselectivity;
! };
/*
* BitmapHeapPath represents one or more indexscans that generate TID bitmaps
diff --git a/src/include/nodes/reldecls.h b/src/include/nodes/reldecls.h
new file mode 100644
index ...cd97808
*** a/src/include/nodes/reldecls.h
--- b/src/include/nodes/reldecls.h
***************
*** 0 ****
--- 1,34 ----
+ /*-------------------------------------------------------------------------
+ *
+ * reldecls.h
+ * Declarations of some planner's data structures.
+ *
+ *
+ * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/nodes/reldecls.h
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef RELDECLS_H
+ #define RELDECLS_H
+
+ /*
+ * Typedefs for identifying qualifier selectivities and plan costs as such.
+ * These are just plain "double"s, but declaring a variable as Selectivity
+ * or Cost makes the intent more obvious.
+ *
+ * These could have gone into plannodes.h or some such, but many files
+ * depend on them...
+ */
+ typedef double Selectivity; /* fraction of tuples a qualifier will pass */
+ typedef double Cost; /* execution cost (in page-access units) */
+
+ /* Declarations for some data structures of src/include/nodes/relation.h */
+ typedef struct IndexAmRoutine IndexAmRoutine;
+ typedef struct PlannerInfo PlannerInfo;
+ typedef struct IndexPath IndexPath;
+ typedef struct IndexInfo IndexInfo;
+
+ #endif /* RELDECLS_H */
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
new file mode 100644
index e610bf3..ca55370
*** 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..825fed1
*** a/src/include/utils/relcache.h
--- b/src/include/utils/relcache.h
***************
*** 16,21 ****
--- 16,22 ----
#include "access/tupdesc.h"
#include "nodes/bitmapset.h"
+ #include "nodes/reldecls.h"
typedef struct RelationData *Relation;
*************** typedef struct RelationData *Relation;
*** 29,34 ****
--- 30,42 ----
typedef Relation *RelationPtr;
/*
+ * Routines to retreive IndexAmRoutine
+ */
+ extern IndexAmRoutine *GetIndexAmRoutine(Oid amhandler);
+ extern IndexAmRoutine *GetIndexAmRoutineByAmId(Oid amoid);
+ extern void InitIndexAmRoutine(Relation relation);
+
+ /*
* Routines to open (lookup) and close a relcache entry
*/
extern Relation RelationIdGetRelation(Oid relationId);
diff --git a/src/include/utils/selfuncs.h b/src/include/utils/selfuncs.h
new file mode 100644
index a7433d9..3745d1c
*** a/src/include/utils/selfuncs.h
--- b/src/include/utils/selfuncs.h
*************** extern double estimate_num_groups(Planne
*** 191,202 ****
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 */
--- 191,226 ----
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..d1a322d
*** a/src/test/regress/expected/oidjoins.out
--- b/src/test/regress/expected/oidjoins.out
*************** WHERE aggmtranstype != 0 AND
*** 73,206 ****
------+---------------
(0 rows)
- SELECT ctid, amkeytype
- FROM pg_catalog.pg_am fk
- WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
- ctid | amkeytype
- ------+-----------
- (0 rows)
-
- SELECT ctid, aminsert
- FROM pg_catalog.pg_am fk
- WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
- ctid | aminsert
- ------+----------
- (0 rows)
-
- SELECT ctid, ambeginscan
- FROM pg_catalog.pg_am fk
- WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
- ctid | ambeginscan
- ------+-------------
- (0 rows)
-
- SELECT ctid, amgettuple
- FROM pg_catalog.pg_am fk
- WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- ctid | amgettuple
- ------+------------
- (0 rows)
-
- SELECT ctid, amgetbitmap
- FROM pg_catalog.pg_am fk
- WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
- ctid | amgetbitmap
- ------+-------------
- (0 rows)
-
- SELECT ctid, amrescan
- FROM pg_catalog.pg_am fk
- WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
- ctid | amrescan
- ------+----------
- (0 rows)
-
- SELECT ctid, amendscan
- FROM pg_catalog.pg_am fk
- WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
- ctid | amendscan
- ------+-----------
- (0 rows)
-
- SELECT ctid, ammarkpos
- FROM pg_catalog.pg_am fk
- WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
- ctid | ammarkpos
- ------+-----------
- (0 rows)
-
- SELECT ctid, amrestrpos
- FROM pg_catalog.pg_am fk
- WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
- ctid | amrestrpos
- ------+------------
- (0 rows)
-
- SELECT ctid, ambuild
- FROM pg_catalog.pg_am fk
- WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
- ctid | ambuild
- ------+---------
- (0 rows)
-
- SELECT ctid, ambuildempty
- FROM pg_catalog.pg_am fk
- WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
- ctid | ambuildempty
- ------+--------------
- (0 rows)
-
- SELECT ctid, ambulkdelete
- FROM pg_catalog.pg_am fk
- WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
- ctid | ambulkdelete
- ------+--------------
- (0 rows)
-
- SELECT ctid, amvacuumcleanup
- FROM pg_catalog.pg_am fk
- WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
- ctid | amvacuumcleanup
- ------+-----------------
- (0 rows)
-
- SELECT ctid, amcanreturn
- FROM pg_catalog.pg_am fk
- WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
- ctid | amcanreturn
- ------+-------------
- (0 rows)
-
- SELECT ctid, amcostestimate
- FROM pg_catalog.pg_am fk
- WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
- ctid | amcostestimate
- ------+----------------
- (0 rows)
-
- SELECT ctid, amoptions
- FROM pg_catalog.pg_am fk
- WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
- ctid | amoptions
- ------+-----------
- (0 rows)
-
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 73,78 ----
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
new file mode 100644
index 7c93b3b..ef66a08
*** a/src/test/regress/expected/opr_sanity.out
--- b/src/test/regress/expected/opr_sanity.out
*************** WHERE p1.oid != p2.oid AND
*** 1481,1486 ****
--- 1481,1492 ----
-----+-----
(0 rows)
+ -- Ask access methods to validate opclasses
+ SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid);
+ oid
+ -----
+ (0 rows)
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
SELECT p1.amopfamily, p1.amopstrategy
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 1526,1574 ****
------------+--------------
(0 rows)
- -- check for ordering operators not supported by parent AM
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
- amopfamily | amopopr | oid | amname
- ------------+---------+-----+--------
- (0 rows)
-
- -- Cross-check amopstrategy index against parent AM
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
- amopfamily | amopopr | oid | amname
- ------------+---------+-----+--------
- (0 rows)
-
- -- Detect missing pg_amop entries: should have as many strategy operators
- -- as AM expects for each datatype combination supported by the opfamily.
- -- We can't check this for AMs with variable strategy sets.
- SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
- amname | amoplefttype | amoprighttype
- --------+--------------+---------------
- (0 rows)
-
- -- Currently, none of the AMs with fixed strategy sets support ordering ops.
- SELECT p1.amname, p2.amopfamily, p2.amopstrategy
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
- amname | amopfamily | amopstrategy
- --------+------------+--------------
- (0 rows)
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
--- 1532,1537 ----
*************** WHERE p1.amprocfamily = 0 OR p1.amprocle
*** 1851,1865 ****
--------------+-----------
(0 rows)
- -- Cross-check amprocnum index against parent AM
- SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
- FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
- WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
- amprocfamily | amprocnum | oid | amname
- --------------+-----------+-----+--------
- (0 rows)
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
SELECT * FROM (
--- 1814,1819 ----
diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql
new file mode 100644
index 2fa628d..ca419fd
*** a/src/test/regress/sql/oidjoins.sql
--- b/src/test/regress/sql/oidjoins.sql
*************** SELECT ctid, aggmtranstype
*** 37,106 ****
FROM pg_catalog.pg_aggregate fk
WHERE aggmtranstype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
- SELECT ctid, amkeytype
- FROM pg_catalog.pg_am fk
- WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
- SELECT ctid, aminsert
- FROM pg_catalog.pg_am fk
- WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
- SELECT ctid, ambeginscan
- FROM pg_catalog.pg_am fk
- WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
- SELECT ctid, amgettuple
- FROM pg_catalog.pg_am fk
- WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- SELECT ctid, amgetbitmap
- FROM pg_catalog.pg_am fk
- WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
- SELECT ctid, amrescan
- FROM pg_catalog.pg_am fk
- WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
- SELECT ctid, amendscan
- FROM pg_catalog.pg_am fk
- WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
- SELECT ctid, ammarkpos
- FROM pg_catalog.pg_am fk
- WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
- SELECT ctid, amrestrpos
- FROM pg_catalog.pg_am fk
- WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
- SELECT ctid, ambuild
- FROM pg_catalog.pg_am fk
- WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
- SELECT ctid, ambuildempty
- FROM pg_catalog.pg_am fk
- WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
- SELECT ctid, ambulkdelete
- FROM pg_catalog.pg_am fk
- WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
- SELECT ctid, amvacuumcleanup
- FROM pg_catalog.pg_am fk
- WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
- SELECT ctid, amcanreturn
- FROM pg_catalog.pg_am fk
- WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
- SELECT ctid, amcostestimate
- FROM pg_catalog.pg_am fk
- WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
- SELECT ctid, amoptions
- FROM pg_catalog.pg_am fk
- WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 37,42 ----
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
new file mode 100644
index c9bdd77..0e0506e
*** a/src/test/regress/sql/opr_sanity.sql
--- b/src/test/regress/sql/opr_sanity.sql
*************** WHERE p1.oid != p2.oid AND
*** 960,965 ****
--- 960,969 ----
p1.opcmethod = p2.opcmethod AND p1.opcintype = p2.opcintype AND
p1.opcdefault AND p2.opcdefault;
+ -- Ask access methods to validate opclasses
+
+ SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid);
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 995,1035 ****
(SELECT 1 from pg_opfamily op WHERE op.oid = p1.amopsortfamily
AND op.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree'));
- -- check for ordering operators not supported by parent AM
-
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
-
- -- Cross-check amopstrategy index against parent AM
-
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
-
- -- Detect missing pg_amop entries: should have as many strategy operators
- -- as AM expects for each datatype combination supported by the opfamily.
- -- We can't check this for AMs with variable strategy sets.
-
- SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
-
- -- Currently, none of the AMs with fixed strategy sets support ordering ops.
-
- SELECT p1.amname, p2.amopfamily, p2.amopstrategy
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
--- 999,1004 ----
*************** FROM pg_amproc as p1
*** 1176,1188 ****
WHERE p1.amprocfamily = 0 OR p1.amproclefttype = 0 OR p1.amprocrighttype = 0
OR p1.amprocnum < 1 OR p1.amproc = 0;
- -- Cross-check amprocnum index against parent AM
-
- SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
- FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
- WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
--- 1145,1150 ----
On 2015-12-12 23:17, Alexander Korotkov wrote:
On Sat, Dec 12, 2015 at 9:21 PM, Petr Jelinek <petr@2ndquadrant.com
<mailto:petr@2ndquadrant.com>> wrote:On 2015-12-09 15:09, Alexander Korotkov wrote:
Patch was rebased against current master.
Any notes about current version of patch?
It would be nice to commit it and continue work on other parts of am
extendability.The rebase seems broken, there are things missing in this version of
the patch (for example the validation functions).Ooops, sorry. Correct version is attached.
Hi,
I went over this.
I get these compiler warning about unused variables in the validation
functions:
brin.c: In function ‘brinvalidate’:
brin.c:94:6: warning: variable ‘keytype’ set but not used
[-Wunused-but-set-variable]
keytype;
^
ginutil.c: In function ‘ginvalidate’:
ginutil.c:86:6: warning: variable ‘keytype’ set but not used
[-Wunused-but-set-variable]
keytype;
^
gist.c: In function ‘gistvalidate’:
gist.c:101:6: warning: variable ‘keytype’ set but not used
[-Wunused-but-set-variable]
keytype;
^
hash.c: In function ‘hashvalidate’:
hash.c:103:6: warning: variable ‘keytype’ set but not used
[-Wunused-but-set-variable]
keytype;
^
nbtree.c: In function ‘btvalidate’:
nbtree.c:134:6: warning: variable ‘keytype’ set but not used
[-Wunused-but-set-variable]
keytype;
^
nbtree.c:133:6: warning: variable ‘intype’ set but not used
[-Wunused-but-set-variable]
intype,
^
spgutils.c: In function ‘spgvalidate’:
spgutils.c:88:6: warning: variable ‘keytype’ set but not used
[-Wunused-but-set-variable]
keytype;
^
These look like copy-pastos of boilerplate.
Another note is that amvalidate SQL interface is not documented
anywhere. I know it's mainly meant for regression tests and we for
example don't document hashing functions but it's something to think
about/discuss maybe.
Other than that I am happy with the patch.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Dec 14, 2015 at 11:26 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
These look like copy-pastos of boilerplate.
Another note is that amvalidate SQL interface is not documented anywhere. I
know it's mainly meant for regression tests and we for example don't
document hashing functions but it's something to think about/discuss maybe.Other than that I am happy with the patch.
I have moved this patch to the next CF with the same status.
Alexander, could you address the warnings reported by Petr?
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi!
On Mon, Dec 14, 2015 at 5:26 PM, Petr Jelinek <petr@2ndquadrant.com> wrote:
I went over this.
I get these compiler warning about unused variables in the validation
functions:
brin.c: In function ‘brinvalidate’:
brin.c:94:6: warning: variable ‘keytype’ set but not used
[-Wunused-but-set-variable]
keytype;
^
ginutil.c: In function ‘ginvalidate’:
ginutil.c:86:6: warning: variable ‘keytype’ set but not used
[-Wunused-but-set-variable]
keytype;
^
gist.c: In function ‘gistvalidate’:
gist.c:101:6: warning: variable ‘keytype’ set but not used
[-Wunused-but-set-variable]
keytype;
^
hash.c: In function ‘hashvalidate’:
hash.c:103:6: warning: variable ‘keytype’ set but not used
[-Wunused-but-set-variable]
keytype;
^
nbtree.c: In function ‘btvalidate’:
nbtree.c:134:6: warning: variable ‘keytype’ set but not used
[-Wunused-but-set-variable]
keytype;
^
nbtree.c:133:6: warning: variable ‘intype’ set but not used
[-Wunused-but-set-variable]
intype,
^
spgutils.c: In function ‘spgvalidate’:
spgutils.c:88:6: warning: variable ‘keytype’ set but not used
[-Wunused-but-set-variable]
keytype;
^These look like copy-pastos of boilerplate.
Fixed in the attached version of patch.
Another note is that amvalidate SQL interface is not documented anywhere. I
know it's mainly meant for regression tests and we for example don't
document hashing functions but it's something to think about/discuss maybe.
What do you think about
"
System Administration Functions
" chapter?
http://www.postgresql.org/docs/devel/static/functions-admin.html
Other than that I am happy with the patch.
Great!
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Attachments:
aminterface-13.patchapplication/octet-stream; name=aminterface-13.patchDownload
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
new file mode 100644
index 97ef618..48f208a
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 549,762 ****
</row>
<row>
! <entry><structfield>amstrategies</structfield></entry>
! <entry><type>int2</type></entry>
! <entry></entry>
! <entry>Number of operator strategies for this access method,
! or zero if access method does not have a fixed set of operator
! strategies</entry>
! </row>
!
! <row>
! <entry><structfield>amsupport</structfield></entry>
! <entry><type>int2</type></entry>
! <entry></entry>
! <entry>Number of support routines for this access method</entry>
! </row>
!
! <row>
! <entry><structfield>amcanorder</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support ordered scans sorted by the
! indexed column's value?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanorderbyop</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support ordered scans sorted by the result
! of an operator on the indexed column?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanbackward</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support backward scanning?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanunique</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support unique indexes?</entry>
! </row>
!
! <row>
! <entry><structfield>amcanmulticol</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support multicolumn indexes?</entry>
! </row>
!
! <row>
! <entry><structfield>amoptionalkey</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support a scan without any constraint
! for the first index column?</entry>
! </row>
!
! <row>
! <entry><structfield>amsearcharray</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support <literal>ScalarArrayOpExpr</> searches?</entry>
! </row>
!
! <row>
! <entry><structfield>amsearchnulls</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does the access method support <literal>IS NULL</>/<literal>NOT NULL</> searches?</entry>
! </row>
!
! <row>
! <entry><structfield>amstorage</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Can index storage data type differ from column data type?</entry>
! </row>
!
! <row>
! <entry><structfield>amclusterable</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Can an index of this type be clustered on?</entry>
! </row>
!
! <row>
! <entry><structfield>ampredlocks</structfield></entry>
! <entry><type>bool</type></entry>
! <entry></entry>
! <entry>Does an index of this type manage fine-grained predicate locks?</entry>
! </row>
!
! <row>
! <entry><structfield>amkeytype</structfield></entry>
<entry><type>oid</type></entry>
- <entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
- <entry>Type of data stored in index, or zero if not a fixed type</entry>
- </row>
-
- <row>
- <entry><structfield>aminsert</structfield></entry>
- <entry><type>regproc</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Insert this tuple</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambeginscan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Prepare for index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amgettuple</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Next valid tuple</quote> function, or zero if none</entry>
! </row>
!
! <row>
! <entry><structfield>amgetbitmap</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Fetch all valid tuples</quote> function, or zero if none</entry>
! </row>
!
! <row>
! <entry><structfield>amrescan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>(Re)start index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amendscan</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Clean up after index scan</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ammarkpos</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Mark current scan position</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>amrestrpos</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Restore marked scan position</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambuild</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Build new index</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambuildempty</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry><quote>Build empty index</quote> function</entry>
! </row>
!
! <row>
! <entry><structfield>ambulkdelete</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Bulk-delete function</entry>
! </row>
!
! <row>
! <entry><structfield>amvacuumcleanup</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Post-<command>VACUUM</command> cleanup function</entry>
! </row>
!
! <row>
! <entry><structfield>amcanreturn</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to check whether an index column supports index-only
! scans. Can be zero if index-only scans are never supported.</entry>
! </row>
!
! <row>
! <entry><structfield>amcostestimate</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to estimate cost of an index scan</entry>
! </row>
!
! <row>
! <entry><structfield>amoptions</structfield></entry>
! <entry><type>regproc</type></entry>
! <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>Function to parse and validate <structfield>reloptions</> for an index</entry>
</row>
-
</tbody>
</tgroup>
</table>
--- 549,562 ----
</row>
<row>
! <entry><structfield>amhandler</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
! <entry>
! References a handler function that is responsible for
! supplying execution routines for the access method.
! </entry>
</row>
</tbody>
</tgroup>
</table>
diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml
new file mode 100644
index 1c09bae..3ff3651
*** a/doc/src/sgml/indexam.sgml
--- b/doc/src/sgml/indexam.sgml
***************
*** 49,61 ****
<para>
Each index access method is described by a row in the
<structname>pg_am</structname> system catalog (see
! <xref linkend="catalog-pg-am">). The principal contents of a
! <structname>pg_am</structname> row are references to
! <link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>
! entries that identify the index access
! functions supplied by the access method. The APIs for these functions
! are defined later in this chapter. In addition, the
! <structname>pg_am</structname> row specifies a few fixed properties of
the access method, such as whether it can support multicolumn indexes.
There is not currently any special support
for creating or deleting <structname>pg_am</structname> entries;
--- 49,63 ----
<para>
Each index access method is described by a row in the
<structname>pg_am</structname> system catalog (see
! <xref linkend="catalog-pg-am">). In the <structname>pg_am</structname> row
! the handler function is specified by the reference to
! <link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.
! Handler function must be written in a compiled language such as C, using
! the version-1 interface. The handler function simply returns a
! <structname>IndexAmRoutine</structname> struct which contains function
! pointers to callback functions that will be called by the planner, executor,
! and various maintenance commands. In addition, the
! <structname>IndexAmRoutine</structname> contains a few fixed properties of
the access method, such as whether it can support multicolumn indexes.
There is not currently any special support
for creating or deleting <structname>pg_am</structname> entries;
***************
*** 96,126 ****
</para>
<para>
! Some of the flag columns of <structname>pg_am</structname> have nonobvious
! implications. The requirements of <structfield>amcanunique</structfield>
! are discussed in <xref linkend="index-unique-checks">.
! The <structfield>amcanmulticol</structfield> flag asserts that the
! access method supports multicolumn indexes, while
! <structfield>amoptionalkey</structfield> asserts that it allows scans
where no indexable restriction clause is given for the first index column.
! When <structfield>amcanmulticol</structfield> is false,
! <structfield>amoptionalkey</structfield> essentially says whether the
access method supports full-index scans without any restriction clause.
Access methods that support multiple index columns <emphasis>must</>
support scans that omit restrictions on any or all of the columns after
the first; however they are permitted to require some restriction to
appear for the first index column, and this is signaled by setting
! <structfield>amoptionalkey</structfield> false.
! One reason that an index AM might set
! <structfield>amoptionalkey</structfield> false is if it doesn't index
! null values. Since most indexable operators are
strict and hence cannot return true for null inputs,
it is at first sight attractive to not store index entries for null values:
they could never be returned by an index scan anyway. However, this
argument fails when an index scan has no restriction clause for a given
index column. In practice this means that
! indexes that have <structfield>amoptionalkey</structfield> true must
! index nulls, since the planner might decide to use such an index
with no scan keys at all. A related restriction is that an index
access method that supports multiple index columns <emphasis>must</>
support indexing null values in columns after the first, because the planner
--- 98,133 ----
</para>
<para>
! Some of the flag fields of <structname>IndexAmRoutine</structname> have nonobvious
! implications. The requirements of
! <structname>IndexAmRoutine</structname>.<structfield>amcanunique</structfield>
! are discussed in <xref linkend="index-unique-checks">. The
! <structname>IndexAmRoutine</structname>.<structfield>amcanmulticol</structfield>
! flag asserts that the access method supports multicolumn indexes, while
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! asserts that it allows scans
where no indexable restriction clause is given for the first index column.
! When <structname>IndexAmRoutine</structname>.<structfield>amcanmulticol</structfield>
! is false,
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! essentially says whether the
access method supports full-index scans without any restriction clause.
Access methods that support multiple index columns <emphasis>must</>
support scans that omit restrictions on any or all of the columns after
the first; however they are permitted to require some restriction to
appear for the first index column, and this is signaled by setting
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! false. One reason that an index AM might set
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! false is if it doesn't index null values. Since most indexable operators are
strict and hence cannot return true for null inputs,
it is at first sight attractive to not store index entries for null values:
they could never be returned by an index scan anyway. However, this
argument fails when an index scan has no restriction clause for a given
index column. In practice this means that
! indexes that have
! <structname>IndexAmRoutine</structname>.<structfield>amoptionalkey</structfield>
! true must index nulls, since the planner might decide to use such an index
with no scan keys at all. A related restriction is that an index
access method that supports multiple index columns <emphasis>must</>
support indexing null values in columns after the first, because the planner
***************
*** 131,139 ****
index omits rows where <literal>b</> is null.
It is, however, OK to omit rows where the first indexed column is null.
An index access method that does index nulls may also set
! <structfield>amsearchnulls</structfield>, indicating that it supports
! <literal>IS NULL</> and <literal>IS NOT NULL</> clauses as search
! conditions.
</para>
</sect1>
--- 138,146 ----
index omits rows where <literal>b</> is null.
It is, however, OK to omit rows where the first indexed column is null.
An index access method that does index nulls may also set
! <structname>IndexAmRoutine</structname>.<structfield>amsearchnulls</structfield>,
! indicating that it supports <literal>IS NULL</> and <literal>IS NOT NULL</>
! clauses as search conditions.
</para>
</sect1>
***************
*** 143,149 ****
<para>
The index construction and maintenance functions that an index access
! method must provide are:
</para>
<para>
--- 150,156 ----
<para>
The index construction and maintenance functions that an index access
! method must provide in <structname>IndexAmRoutine</structname> are:
</para>
<para>
*************** aminsert (Relation indexRelation,
*** 188,194 ****
<literal>isnull</> arrays give the key values to be indexed, and
<literal>heap_tid</> is the TID to be indexed.
If the access method supports unique indexes (its
! <structname>pg_am</>.<structfield>amcanunique</> flag is true) then
<literal>checkUnique</> indicates the type of uniqueness check to
perform. This varies depending on whether the unique constraint is
deferrable; see <xref linkend="index-unique-checks"> for details.
--- 195,201 ----
<literal>isnull</> arrays give the key values to be indexed, and
<literal>heap_tid</> is the TID to be indexed.
If the access method supports unique indexes (its
! <structfield>amcanunique</> flag is true) then
<literal>checkUnique</> indicates the type of uniqueness check to
perform. This varies depending on whether the unique constraint is
deferrable; see <xref linkend="index-unique-checks"> for details.
*************** amcanreturn (Relation indexRelation, int
*** 281,288 ****
the form of an <structname>IndexTuple</structname>. The attribute number
is 1-based, i.e. the first columns attno is 1. Returns TRUE if supported,
else FALSE. If the access method does not support index-only scans at all,
! the <structfield>amcanreturn</> field in its <structname>pg_am</> row can
! be set to zero.
</para>
<para>
--- 288,295 ----
the form of an <structname>IndexTuple</structname>. The attribute number
is 1-based, i.e. the first columns attno is 1. Returns TRUE if supported,
else FALSE. If the access method does not support index-only scans at all,
! the <structfield>amcanreturn</> field in its <structname>IndexAmRoutine</>
! struct can be set to NULL.
</para>
<para>
*************** amgettuple (IndexScanDesc scan,
*** 414,421 ****
<para>
The <function>amgettuple</> function need only be provided if the access
method supports <quote>plain</> index scans. If it doesn't, the
! <structfield>amgettuple</> field in its <structname>pg_am</> row must
! be set to zero.
</para>
<para>
--- 421,428 ----
<para>
The <function>amgettuple</> function need only be provided if the access
method supports <quote>plain</> index scans. If it doesn't, the
! <structfield>amgettuple</> field in its <structname>IndexAmRoutine</>
! struct must be set to NULL.
</para>
<para>
*************** amgetbitmap (IndexScanDesc scan,
*** 445,452 ****
<para>
The <function>amgetbitmap</> function need only be provided if the access
method supports <quote>bitmap</> index scans. If it doesn't, the
! <structfield>amgetbitmap</> field in its <structname>pg_am</> row must
! be set to zero.
</para>
<para>
--- 452,459 ----
<para>
The <function>amgetbitmap</> function need only be provided if the access
method supports <quote>bitmap</> index scans. If it doesn't, the
! <structfield>amgetbitmap</> field in its <structname>IndexAmRoutine</>
! struct must be set to NULL.
</para>
<para>
*************** amrestrpos (IndexScanDesc scan);
*** 477,494 ****
</para>
<para>
! By convention, the <literal>pg_proc</literal> entry for an index
! access method function should show the correct number of arguments,
! but declare them all as type <type>internal</> (since most of the arguments
! have types that are not known to SQL, and we don't want users calling
! the functions directly anyway). The return type is declared as
! <type>void</>, <type>internal</>, or <type>boolean</> as appropriate.
! The only exception is <function>amoptions</>, which should be correctly
! declared as taking <type>text[]</> and <type>bool</> and returning
! <type>bytea</>. This provision allows client code to execute
! <function>amoptions</> to test validity of options settings.
</para>
-
</sect1>
<sect1 id="index-scanning">
--- 484,496 ----
</para>
<para>
! <programlisting>
! void
! amvalidate (OpClassInfo *opclass);
! </programlisting>
! Validates given operator class by access method. The <function>amvalidate</>
! must throw an error if opclass is invalid.
</para>
</sect1>
<sect1 id="index-scanning">
*************** amrestrpos (IndexScanDesc scan);
*** 548,554 ****
<para>
Access methods that always return entries in the natural ordering
of their data (such as btree) should set
! <structname>pg_am</>.<structfield>amcanorder</> to true.
Currently, such access methods must use btree-compatible strategy
numbers for their equality and ordering operators.
</para>
--- 550,556 ----
<para>
Access methods that always return entries in the natural ordering
of their data (such as btree) should set
! <structfield>amcanorder</> to true.
Currently, such access methods must use btree-compatible strategy
numbers for their equality and ordering operators.
</para>
*************** amrestrpos (IndexScanDesc scan);
*** 556,562 ****
<listitem>
<para>
Access methods that support ordering operators should set
! <structname>pg_am</>.<structfield>amcanorderbyop</> to true.
This indicates that the index is capable of returning entries in
an order satisfying <literal>ORDER BY</> <replaceable>index_key</>
<replaceable>operator</> <replaceable>constant</>. Scan modifiers
--- 558,564 ----
<listitem>
<para>
Access methods that support ordering operators should set
! <structfield>amcanorderbyop</> to true.
This indicates that the index is capable of returning entries in
an order satisfying <literal>ORDER BY</> <replaceable>index_key</>
<replaceable>operator</> <replaceable>constant</>. Scan modifiers
*************** amrestrpos (IndexScanDesc scan);
*** 579,585 ****
methods that set <structfield>amcanorder</> to true.) After the
first call, <function>amgettuple</> must be prepared to advance the scan in
either direction from the most recently returned entry. (But if
! <structname>pg_am</>.<structfield>amcanbackward</> is false, all subsequent
calls will have the same direction as the first one.)
</para>
--- 581,587 ----
methods that set <structfield>amcanorder</> to true.) After the
first call, <function>amgettuple</> must be prepared to advance the scan in
either direction from the most recently returned entry. (But if
! <structfield>amcanbackward</> is false, all subsequent
calls will have the same direction as the first one.)
</para>
*************** amrestrpos (IndexScanDesc scan);
*** 590,597 ****
be remembered per scan; a new <function>ammarkpos</> call overrides the
previously marked position. An access method that does not support
ordered scans should still provide mark and restore functions in
! <structname>pg_am</>, but it is sufficient to have them throw errors if
! called.
</para>
<para>
--- 592,599 ----
be remembered per scan; a new <function>ammarkpos</> call overrides the
previously marked position. An access method that does not support
ordered scans should still provide mark and restore functions in
! <structname>IndexAmRoutine</>, but it is sufficient to have them throw
! errors if called.
</para>
<para>
*************** amrestrpos (IndexScanDesc scan);
*** 766,772 ****
<productname>PostgreSQL</productname> enforces SQL uniqueness constraints
using <firstterm>unique indexes</>, which are indexes that disallow
multiple entries with identical keys. An access method that supports this
! feature sets <structname>pg_am</>.<structfield>amcanunique</> true.
(At present, only b-tree supports it.)
</para>
--- 768,774 ----
<productname>PostgreSQL</productname> enforces SQL uniqueness constraints
using <firstterm>unique indexes</>, which are indexes that disallow
multiple entries with identical keys. An access method that supports this
! feature sets <structfield>amcanunique</> true.
(At present, only b-tree supports it.)
</para>
diff --git a/doc/src/sgml/xindex.sgml b/doc/src/sgml/xindex.sgml
new file mode 100644
index 1782782..a16f478
*** a/doc/src/sgml/xindex.sgml
--- b/doc/src/sgml/xindex.sgml
***************
*** 34,40 ****
regular access to tables is built into
<productname>PostgreSQL</productname>, but all index methods are
described in <classname>pg_am</classname>. It is possible to add a
! new index method by defining the required interface routines and
then creating a row in <classname>pg_am</classname> — but that is
beyond the scope of this chapter (see <xref linkend="indexam">).
</para>
--- 34,41 ----
regular access to tables is built into
<productname>PostgreSQL</productname>, but all index methods are
described in <classname>pg_am</classname>. It is possible to add a
! new index access method by defining the handler function, which returns
! C-struct with required interface routines and parameters, and
then creating a row in <classname>pg_am</classname> — but that is
beyond the scope of this chapter (see <xref linkend="indexam">).
</para>
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
new file mode 100644
index 99337b0..81d576b
*** a/src/backend/access/brin/brin.c
--- b/src/backend/access/brin/brin.c
***************
*** 25,38 ****
--- 25,174 ----
#include "access/xact.h"
#include "access/xloginsert.h"
#include "catalog/index.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
+ #include "catalog/pg_opclass.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "storage/bufmgr.h"
#include "storage/freespace.h"
+ #include "utils/catcache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
+ #include "utils/syscache.h"
+
+
+ /*
+ * BRIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ brinhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 15;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = brininsert;
+ amroutine->ambeginscan = brinbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = bringetbitmap;
+ amroutine->amrescan = brinrescan;
+ amroutine->amendscan = brinendscan;
+ amroutine->ammarkpos = brinmarkpos;
+ amroutine->amrestrpos = brinrestrpos;
+ amroutine->ambuild = brinbuild;
+ amroutine->ambuildempty = brinbuildempty;
+ amroutine->ambulkdelete = brinbulkdelete;
+ amroutine->amvacuumcleanup = brinvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = brincostestimate;
+ amroutine->amoptions = brinoptions;
+ amroutine->amvalidate = brinvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ brinvalidate(Oid opclassoid)
+ {
+ bool procsPresent[BRIN_MANDATORY_NPROCS];
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid,
+ intype;
+ CatCList *proclist,
+ *oprlist;
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ /* Fetch opclass information */
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ intype = classform->opcintype;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+
+ /* Fetch opfamily information: operators and functions */
+ oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+
+ /* Check required procedure numbers exist */
+ for (i = 0; i < proclist->n_members; i++)
+ {
+ HeapTuple proctup = &proclist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype != intype ||
+ procform->amprocrighttype != intype)
+ continue;
+
+ if (procform->amprocnum < 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for BRIN: %u",
+ procform->amprocnum)));
+
+ /* BRIN opclasses could contain any number of non-mandatory procedures */
+ if (procform->amprocnum > BRIN_MANDATORY_NPROCS)
+ continue;
+
+ if (procsPresent[procform->amprocnum - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u was defined more than once",
+ procform->amprocnum)));
+
+ procsPresent[procform->amprocnum - 1] = true;
+ }
+
+ /*
+ * Don't use BRIN_NPROC because some procnumbers
+ * are reserved for future use
+ */
+ for (i = 0; i < BRIN_MANDATORY_NPROCS; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN support number %u is required", i + 1)));
+ }
+
+ /* Check operators: ORDER BY operators are not supported */
+ for (i = 0; i < oprlist->n_members; i++)
+ {
+ HeapTuple oprtup = &oprlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+
+ if (OidIsValid(oprform->amopsortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("BRIN doesn't support ORDER BY operators")));
+ }
+ ReleaseCatCacheList(proclist);
+ ReleaseCatCacheList(oprlist);
+ }
/*
* We use a BrinBuildState during initial construction of a BRIN index.
*************** 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;
--- 216,226 ----
* 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);
}
/*
--- 358,364 ----
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;
--- 368,376 ----
* 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);
}
/*
--- 381,387 ----
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;
--- 396,404 ----
* 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
--- 578,593 ----
* 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();
}
/*
--- 599,629 ----
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;
--- 695,703 ----
/*
* 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. */
--- 776,787 ----
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();
}
/*
--- 798,803 ----
*************** 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));
--- 809,837 ----
* 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;
--- 848,862 ----
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);
--- 869,875 ----
/* 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);
}
/*
--- 878,884 ----
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 931dceb..b52846f
*** a/src/backend/access/common/reloptions.c
--- b/src/backend/access/common/reloptions.c
*************** untransformRelOptions(Datum options)
*** 891,897 ****
* 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;
--- 891,897 ----
* 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
*** 1379,1412 ****
* 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);
}
/*
--- 1379,1393 ----
* 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 49e9185..92701b9
*** 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..7156b1c
*** a/src/backend/access/gin/ginutil.c
--- b/src/backend/access/gin/ginutil.c
***************
*** 15,28 ****
--- 15,174 ----
#include "postgres.h"
#include "access/gin_private.h"
+ #include "access/htup_details.h"
#include "access/reloptions.h"
#include "access/xloginsert.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
#include "catalog/pg_collation.h"
+ #include "catalog/pg_opclass.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
+ #include "utils/catcache.h"
+ #include "utils/selfuncs.h"
+ #include "utils/syscache.h"
+
+
+ /*
+ * GIN handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ ginhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 6;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = gininsert;
+ amroutine->ambeginscan = ginbeginscan;
+ amroutine->amgettuple = NULL;
+ amroutine->amgetbitmap = gingetbitmap;
+ amroutine->amrescan = ginrescan;
+ amroutine->amendscan = ginendscan;
+ amroutine->ammarkpos = ginmarkpos;
+ amroutine->amrestrpos = ginrestrpos;
+ amroutine->ambuild = ginbuild;
+ amroutine->ambuildempty = ginbuildempty;
+ amroutine->ambulkdelete = ginbulkdelete;
+ amroutine->amvacuumcleanup = ginvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = gincostestimate;
+ amroutine->amoptions = ginoptions;
+ amroutine->amvalidate = ginvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ ginvalidate(Oid opclassoid)
+ {
+ bool procsPresent[GINNProcs];
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid,
+ intype;
+ CatCList *proclist,
+ *oprlist;
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ /* Fetch opclass information */
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ intype = classform->opcintype;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+ /* Fetch opfamily information: operators and functions */
+ oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+
+ /* Check required procedure numbers exist */
+ for (i = 0; i < proclist->n_members; i++)
+ {
+ HeapTuple proctup = &proclist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype != intype ||
+ procform->amprocrighttype != intype)
+ continue;
+
+ if (procform->amprocnum < 1 || procform->amprocnum > GINNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for GIN: %u",
+ procform->amprocnum)));
+
+ if (procsPresent[procform->amprocnum - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u was defined more than once",
+ procform->amprocnum)));
+
+ procsPresent[procform->amprocnum - 1] = true;
+ }
+
+ for (i = 0; i < GINNProcs; i++)
+ {
+ if (i+1 == GIN_COMPARE_PARTIAL_PROC)
+ continue; /* optional method */
+ if (i+1 == GIN_CONSISTENT_PROC || i+1 == GIN_TRICONSISTENT_PROC)
+ continue; /* don't need to have both, see check below loop */
+
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN support number %u is required", i + 1)));
+ }
+
+ if (!procsPresent[GIN_CONSISTENT_PROC - 1]
+ && !procsPresent[GIN_TRICONSISTENT_PROC - 1])
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("at least one of consistent support (number %u) "
+ "and triconsistent support (number %u) is "
+ "is required",
+ GIN_CONSISTENT_PROC, GIN_TRICONSISTENT_PROC)));
+ }
+
+ /* Check operators: ORDER BY operators are not supported */
+ for (i = 0; i < oprlist->n_members; i++)
+ {
+ HeapTuple oprtup = &oprlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+
+ if (OidIsValid(oprform->amopsortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GIN doesn't support ORDER BY operators")));
+ }
+
+ ReleaseCatCacheList(proclist);
+ ReleaseCatCacheList(oprlist);
+ }
/*
* 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;
--- 662,670 ----
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);
--- 679,685 ----
/* 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);
}
/*
--- 688,694 ----
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 323cfb0..5b38607
*** 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, true, stats);
}
! PG_RETURN_POINTER(stats);
}
/*
--- 656,662 ----
initGinState(&ginstate, index);
ginInsertCleanup(&ginstate, true, 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 53bccf6..47dc698
*** a/src/backend/access/gist/gist.c
--- b/src/backend/access/gist/gist.c
***************
*** 16,29 ****
--- 16,37 ----
#include "access/genam.h"
#include "access/gist_private.h"
+ #include "access/gistscan.h"
+ #include "access/htup_details.h"
#include "access/xloginsert.h"
#include "catalog/index.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
#include "catalog/pg_collation.h"
+ #include "catalog/pg_opclass.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "storage/indexfsm.h"
#include "utils/memutils.h"
#include "utils/rel.h"
+ #include "utils/catcache.h"
+ #include "utils/selfuncs.h"
+ #include "utils/syscache.h"
/* non-export function prototypes */
static void gistfixsplit(GISTInsertState *state, GISTSTATE *giststate);
*************** static void gistfinishsplit(GISTInsertSt
*** 38,43 ****
--- 46,180 ----
GISTSTATE *giststate, List *splitinfo, bool releasebuf);
static void gistvacuumpage(Relation rel, Page page, Buffer buffer);
+ /*
+ * GiST handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ gisthandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 9;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = true;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = true;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = true;
+ amroutine->amclusterable = true;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = gistinsert;
+ amroutine->ambeginscan = gistbeginscan;
+ amroutine->amgettuple = gistgettuple;
+ amroutine->amgetbitmap = gistgetbitmap;
+ amroutine->amrescan = gistrescan;
+ amroutine->amendscan = gistendscan;
+ amroutine->ammarkpos = gistmarkpos;
+ amroutine->amrestrpos = gistrestrpos;
+ amroutine->ambuild = gistbuild;
+ amroutine->ambuildempty = gistbuildempty;
+ amroutine->ambulkdelete = gistbulkdelete;
+ amroutine->amvacuumcleanup = gistvacuumcleanup;
+ amroutine->amcanreturn = gistcanreturn;
+ amroutine->amcostestimate = gistcostestimate;
+ amroutine->amoptions = gistoptions;
+ amroutine->amvalidate = gistvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ gistvalidate(Oid opclassoid)
+ {
+ bool procsPresent[GISTNProcs];
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid,
+ intype;
+ CatCList *proclist,
+ *oprlist;
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ /* Fetch opclass information */
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ intype = classform->opcintype;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+
+ /* Fetch opfamily information: operators and functions */
+ oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+
+ /* Check required procedure numbers exist */
+ for (i = 0; i < proclist->n_members; i++)
+ {
+ HeapTuple proctup = &proclist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype != intype ||
+ procform->amprocrighttype != intype)
+ continue;
+
+ if (procform->amprocnum < 1 || procform->amprocnum > GISTNProcs)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for GiST: %u",
+ procform->amprocnum)));
+
+ if (procsPresent[procform->amprocnum - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u was defined more than once",
+ procform->amprocnum)));
+
+ procsPresent[procform->amprocnum - 1] = true;
+ }
+
+ for (i = 0; i < GISTNProcs; i++)
+ {
+ if (i+1 == GIST_DISTANCE_PROC || i+1 == GIST_FETCH_PROC)
+ continue; /* optional methods */
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST support number %u is required", i+1)));
+ }
+
+ /*
+ * Check operators: ORDER BY operators are supported only if distance
+ * procedure is specified.
+ */
+ for (i = 0; i < oprlist->n_members; i++)
+ {
+ HeapTuple oprtup = &oprlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+
+ if (OidIsValid(oprform->amopsortfamily) &&
+ !procsPresent[GIST_DISTANCE_PROC - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("GiST distance support function %u is required "
+ "for ORDER BY operators", GIST_DISTANCE_PROC)));
+ }
+
+ ReleaseCatCacheList(proclist);
+ ReleaseCatCacheList(oprlist);
+ }
#define ROTATEDIST(d) do { \
SplitedPageLayout *tmp=(SplitedPageLayout*)palloc(sizeof(SplitedPageLayout)); \
*************** createTempGistContext(void)
*** 70,79 ****
/*
* 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 */
--- 207,215 ----
/*
* gistbuildempty() -- build an empty gist index in the initialization fork
*/
! void
! gistbuildempty(Relation index)
{
Buffer buffer;
/* Initialize the root page */
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 89,96 ****
/* Unlock and release the buffer */
UnlockReleaseBuffer(buffer);
-
- PG_RETURN_VOID();
}
/*
--- 225,230 ----
*************** gistbuildempty(PG_FUNCTION_ARGS)
*** 99,116 ****
* 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;
--- 233,243 ----
* 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)
*** 136,142 ****
MemoryContextSwitchTo(oldCxt);
freeGISTstate(giststate);
! PG_RETURN_BOOL(false);
}
--- 263,269 ----
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 ce8e582..1adf92f
*** a/src/backend/access/gist/gistget.c
--- b/src/backend/access/gist/gistget.c
*************** getNextNearest(IndexScanDesc scan)
*** 618,628 ****
/*
* 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)
--- 618,626 ----
/*
* 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)
*** 651,657 ****
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! PG_RETURN_BOOL(getNextNearest(scan));
}
else
{
--- 649,655 ----
if (scan->numberOfOrderBys > 0)
{
/* Must fetch tuples in strict distance order */
! return getNextNearest(scan);
}
else
{
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 688,694 ****
so->curPageData++;
! PG_RETURN_BOOL(true);
}
/*
--- 686,692 ----
so->curPageData++;
! return true;
}
/*
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 726,732 ****
item = getNextGISTSearchItem(so);
if (!item)
! PG_RETURN_BOOL(false);
CHECK_FOR_INTERRUPTS();
--- 724,730 ----
item = getNextGISTSearchItem(so);
if (!item)
! return false;
CHECK_FOR_INTERRUPTS();
*************** gistgettuple(PG_FUNCTION_ARGS)
*** 750,766 ****
/*
* 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);
--- 748,762 ----
/*
* 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)
*** 791,797 ****
pfree(item);
}
! PG_RETURN_INT64(ntids);
}
/*
--- 787,793 ----
pfree(item);
}
! return ntids;
}
/*
*************** gistgetbitmap(PG_FUNCTION_ARGS)
*** 799,812 ****
*
* 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);
}
--- 795,805 ----
*
* 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 a17c5bc..22f0c68
*** 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)
*** 107,121 ****
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;
--- 104,116 ----
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)
*** 314,341 ****
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;
/*
--- 309,331 ----
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)
*** 343,348 ****
* as well as the queueCxt if there is a separate context for it.
*/
freeGISTstate(so->giststate);
-
- PG_RETURN_VOID();
}
--- 333,336 ----
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 a0b0eeb..e0ce620
*** 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)
*** 276,280 ****
vacuum_delay_point();
}
! PG_RETURN_POINTER(stats);
}
--- 271,275 ----
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..86cc393
*** a/src/backend/access/hash/hash.c
--- b/src/backend/access/hash/hash.c
***************
*** 18,31 ****
--- 18,38 ----
#include "postgres.h"
+ #include "access/amapi.h"
#include "access/hash.h"
#include "access/relscan.h"
#include "catalog/index.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
+ #include "catalog/pg_opclass.h"
#include "commands/vacuum.h"
#include "optimizer/cost.h"
#include "optimizer/plancat.h"
#include "storage/bufmgr.h"
+ #include "utils/catcache.h"
#include "utils/rel.h"
+ #include "utils/selfuncs.h"
+ #include "utils/syscache.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;
--- 49,194 ----
bool tupleIsAlive,
void *state);
+ /*
+ * Hash handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ hashhandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 1;
+ amroutine->amsupport = 1;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = true;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = false;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = false;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = INT4OID;
+
+ amroutine->aminsert = hashinsert;
+ amroutine->ambeginscan = hashbeginscan;
+ amroutine->amgettuple = hashgettuple;
+ amroutine->amgetbitmap = hashgetbitmap;
+ amroutine->amrescan = hashrescan;
+ amroutine->amendscan = hashendscan;
+ amroutine->ammarkpos = hashmarkpos;
+ amroutine->amrestrpos = hashrestrpos;
+ amroutine->ambuild = hashbuild;
+ amroutine->ambuildempty = hashbuildempty;
+ amroutine->ambulkdelete = hashbulkdelete;
+ amroutine->amvacuumcleanup = hashvacuumcleanup;
+ amroutine->amcanreturn = NULL;
+ amroutine->amcostestimate = hashcostestimate;
+ amroutine->amoptions = hashoptions;
+ amroutine->amvalidate = hashvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ hashvalidate(Oid opclassoid)
+ {
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid,
+ intype;
+ CatCList *proclist,
+ *oprlist;
+ int i,
+ j;
+
+ /* Fetch opclass information */
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ intype = classform->opcintype;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+
+ /* Fetch opfamily information: operators and functions */
+ oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+
+ /* Check hash procedure exists */
+ for (i = 0; i < proclist->n_members; i++)
+ {
+ HeapTuple proctup = &proclist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype != intype ||
+ procform->amprocrighttype != intype)
+ continue;
+
+ if (procform->amprocnum != HASHPROC)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for hash: %u",
+ procform->amprocnum)));
+ }
+
+ /* Check operators */
+ for (i = 0; i < oprlist->n_members; i++)
+ {
+ HeapTuple oprtup = &oprlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+ bool leftFound = false,
+ rightFound = false;
+
+ /* ORDER BY operators are not supported */
+ if (OidIsValid(oprform->amopsortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("hash doesn't support ORDER BY operators")));
+
+ /* Check strategy number */
+ if (oprform->amopstrategy < 1 ||
+ oprform->amopstrategy > HTMaxStrategyNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid strategy number for hash: %u",
+ oprform->amopstrategy)));
+
+ /* There should be relevant hash procedure for operator */
+ for (j = 0; j < proclist->n_members; j++)
+ {
+ HeapTuple proctup = &proclist->members[j]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype == oprform->amoplefttype)
+ leftFound = true;
+ if (procform->amproclefttype == oprform->amoprighttype)
+ rightFound = true;
+ }
+
+ if (!leftFound || !rightFound)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("no hash procedure found for operator: %u",
+ oprform->amopopr)));
+ }
+
+ ReleaseCatCacheList(proclist);
+ ReleaseCatCacheList(oprlist);
+ }
/*
* 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();
}
/*
--- 249,264 ----
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;
/*
--- 300,310 ----
* 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);
--- 317,323 ----
* 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;
--- 327,342 ----
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;
--- 438,453 ----
/* 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;
--- 484,499 ----
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;
--- 515,530 ----
/* 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;
--- 550,563 ----
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();
}
/*
--- 576,599 ----
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;
--- 603,612 ----
*
* 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);
}
/*
--- 776,782 ----
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);
}
--- 784,805 ----
*
* 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..8d74414
*** a/src/backend/access/nbtree/nbtree.c
--- b/src/backend/access/nbtree/nbtree.c
***************
*** 22,34 ****
--- 22,39 ----
#include "access/relscan.h"
#include "access/xlog.h"
#include "catalog/index.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
+ #include "catalog/pg_opclass.h"
#include "commands/vacuum.h"
#include "storage/indexfsm.h"
#include "storage/ipc.h"
#include "storage/lmgr.h"
#include "storage/smgr.h"
#include "tcop/tcopprot.h"
+ #include "utils/catcache.h"
#include "utils/memutils.h"
+ #include "utils/syscache.h"
/* Working state for btbuild and its callback */
*************** 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;
--- 81,217 ----
/*
! * 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;
! amroutine->amvalidate = btvalidate;
!
! PG_RETURN_POINTER(amroutine);
! }
!
! void
! btvalidate(Oid opclassoid)
! {
! HeapTuple classtup;
! Form_pg_opclass classform;
! Oid opfamilyoid;
! CatCList *proclist,
! *oprlist;
! int i,
! j;
!
! /* Fetch opclass information */
! classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
!
! if (!HeapTupleIsValid(classtup))
! elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
!
! classform = (Form_pg_opclass) GETSTRUCT(classtup);
! opfamilyoid = classform->opcfamily;
!
! ReleaseSysCache(classtup);
!
! /* Fetch opfamily information: operators and functions */
! oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
! proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
!
! /* Check that only allowed procedure numbers exist */
! for (i = 0; i < proclist->n_members; i++)
! {
! HeapTuple proctup = &proclist->members[i]->tuple;
! Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
!
! if (procform->amprocnum != BTORDER_PROC &&
! procform->amprocnum != BTSORTSUPPORT_PROC)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("invalid support number for btree: %u",
! procform->amprocnum)));
!
! }
!
! /* Check operators */
! for (i = 0; i < oprlist->n_members; i++)
! {
! HeapTuple oprtup = &oprlist->members[i]->tuple;
! Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
! bool found = false;
!
! if (OidIsValid(oprform->amopsortfamily))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("btree doesn't support ORDER BY operators")));
!
! if (oprform->amopstrategy < 1 || oprform->amopstrategy > BTMaxStrategyNumber)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("invalid strategy number for btree: %u",
! oprform->amopstrategy)));
!
! /* There should be relevant support function for operator */
! for (j = 0; j < proclist->n_members; j++)
! {
! HeapTuple proctup = &proclist->members[j]->tuple;
! Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
!
! if (procform->amprocnum == BTORDER_PROC &&
! procform->amproclefttype == oprform->amoplefttype &&
! procform->amprocrighttype == oprform->amoprighttype)
! found = true;
! }
!
! if (!found)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! errmsg("no ordering procedure found for operator: %u",
! oprform->amopopr)));
! }
!
! ReleaseCatCacheList(proclist);
! ReleaseCatCacheList(oprlist);
! }
!
! /*
! * 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);
}
/*
--- 283,289 ----
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);
--- 318,327 ----
/*
* 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();
}
/*
--- 341,346 ----
*************** 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;
--- 349,359 ----
* 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;
--- 365,379 ----
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);
}
--- 389,395 ----
{
/* 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;
--- 439,453 ----
/* ... 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);
}
--- 459,465 ----
{
/* 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;
--- 497,511 ----
/* 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 */
--- 543,558 ----
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 */
--- 603,616 ----
/* 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). */
--- 639,652 ----
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 */
--- 669,682 ----
/* 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();
}
/*
--- 744,749 ----
*************** 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;
--- 753,762 ----
*
* 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);
}
/*
--- 775,781 ----
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
--- 783,794 ----
*
* 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);
}
/*
--- 820,826 ----
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);
}
--- 1221,1228 ----
*
* 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..141aee5
*** a/src/backend/access/spgist/spgutils.c
--- b/src/backend/access/spgist/spgutils.c
***************
*** 16,30 ****
--- 16,160 ----
#include "postgres.h"
#include "access/genam.h"
+ #include "access/htup_details.h"
#include "access/reloptions.h"
#include "access/spgist_private.h"
#include "access/transam.h"
#include "access/xact.h"
+ #include "catalog/pg_amop.h"
+ #include "catalog/pg_amproc.h"
+ #include "catalog/pg_opclass.h"
#include "storage/bufmgr.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "utils/lsyscache.h"
+ #include "utils/catcache.h"
+ #include "utils/selfuncs.h"
+ #include "utils/syscache.h"
+
+
+ /*
+ * SP-GiST handler function: return IndexAmRoutine with access method parameters
+ * and callbacks.
+ */
+ Datum
+ spghandler(PG_FUNCTION_ARGS)
+ {
+ IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
+
+ amroutine->amstrategies = 0;
+ amroutine->amsupport = 5;
+ amroutine->amcanorder = false;
+ amroutine->amcanorderbyop = false;
+ amroutine->amcanbackward = false;
+ amroutine->amcanunique = false;
+ amroutine->amcanmulticol = false;
+ amroutine->amoptionalkey = true;
+ amroutine->amsearcharray = false;
+ amroutine->amsearchnulls = true;
+ amroutine->amstorage = false;
+ amroutine->amclusterable = false;
+ amroutine->ampredlocks = false;
+ amroutine->amkeytype = 0;
+
+ amroutine->aminsert = spginsert;
+ amroutine->ambeginscan = spgbeginscan;
+ amroutine->amgettuple = spggettuple;
+ amroutine->amgetbitmap = spggetbitmap;
+ amroutine->amrescan = spgrescan;
+ amroutine->amendscan = spgendscan;
+ amroutine->ammarkpos = spgmarkpos;
+ amroutine->amrestrpos = spgrestrpos;
+ amroutine->ambuild = spgbuild;
+ amroutine->ambuildempty = spgbuildempty;
+ amroutine->ambulkdelete = spgbulkdelete;
+ amroutine->amvacuumcleanup = spgvacuumcleanup;
+ amroutine->amcanreturn = spgcanreturn;
+ amroutine->amcostestimate = spgcostestimate;
+ amroutine->amoptions = spgoptions;
+ amroutine->amvalidate = spgvalidate;
+
+ PG_RETURN_POINTER(amroutine);
+ }
+
+ void
+ spgvalidate(Oid opclassoid)
+ {
+ bool procsPresent[SPGISTNProc];
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+ Oid opfamilyoid,
+ intype;
+ CatCList *proclist,
+ *oprlist;
+ int i;
+
+ memset(procsPresent, 0, sizeof(procsPresent));
+
+ /* Fetch opclass information */
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ intype = classform->opcintype;
+ opfamilyoid = classform->opcfamily;
+
+ ReleaseSysCache(classtup);
+
+ /* Fetch opfamily information: operators and functions */
+ oprlist = SearchSysCacheList1(AMOPSTRATEGY, opfamilyoid);
+ proclist = SearchSysCacheList1(AMPROCNUM, opfamilyoid);
+
+ /* Check required procedure numbers exist */
+ for (i = 0; i < proclist->n_members; i++)
+ {
+ HeapTuple proctup = &proclist->members[i]->tuple;
+ Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
+
+ if (procform->amproclefttype != intype ||
+ procform->amprocrighttype != intype)
+ continue;
+
+ if (procform->amprocnum < 1 || procform->amprocnum > SPGISTNProc)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid support number for SP-GiST: %u",
+ procform->amprocnum)));
+
+ if (procsPresent[procform->amprocnum - 1])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u was defined more than once",
+ procform->amprocnum)));
+
+ procsPresent[procform->amprocnum - 1] = true;
+ }
+
+ for (i = 0; i < SPGISTNProc; i++)
+ {
+ if (!procsPresent[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST support number %u is required", i + 1)));
+ }
+ /* Check operators: ORDER BY operators are not supported */
+ for (i = 0; i < oprlist->n_members; i++)
+ {
+ HeapTuple oprtup = &oprlist->members[i]->tuple;
+ Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
+
+ if (OidIsValid(oprform->amopsortfamily))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("SP-GiST doesn't support ORDER BY operators")));
+ }
+
+ ReleaseCatCacheList(proclist);
+ ReleaseCatCacheList(oprlist);
+ }
/* 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();
}
/*
--- 619,634 ----
/*
* 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 c10be3d..3e0085a
*** a/src/backend/catalog/index.c
--- b/src/backend/catalog/index.c
***************
*** 23,28 ****
--- 23,29 ----
#include <unistd.h>
+ #include "access/amapi.h"
#include "access/multixact.h"
#include "access/relscan.h"
#include "access/sysattr.h"
*************** ConstructTupleDescriptor(Relation heapRe
*** 279,298 ****
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);
--- 280,293 ----
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 = GetIndexAmRoutineByAmId(accessMethodObjectId);
/* ... and to the table's tuple descriptor */
heapTupDesc = RelationGetDescr(heapRelation);
*************** ConstructTupleDescriptor(Relation heapRe
*** 439,445 ****
if (OidIsValid(opclassTup->opckeytype))
keyType = opclassTup->opckeytype;
else
! keyType = amform->amkeytype;
ReleaseSysCache(tuple);
if (OidIsValid(keyType) && keyType != to->atttypid)
--- 434,440 ----
if (OidIsValid(opclassTup->opckeytype))
keyType = opclassTup->opckeytype;
else
! keyType = amroutine->amkeytype;
ReleaseSysCache(tuple);
if (OidIsValid(keyType) && keyType != to->atttypid)
*************** ConstructTupleDescriptor(Relation heapRe
*** 461,468 ****
}
}
- ReleaseSysCache(amtuple);
-
return indexTupDesc;
}
--- 456,461 ----
*************** index_build(Relation heapRelation,
*** 1990,1996 ****
bool isprimary,
bool isreindex)
{
- RegProcedure procedure;
IndexBuildResult *stats;
Oid save_userid;
int save_sec_context;
--- 1983,1988 ----
*************** index_build(Relation heapRelation,
*** 2000,2009 ****
* 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\"",
--- 1992,1999 ----
* 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,
*** 2023,2033 ****
/*
* Call the access method's build procedure
*/
! stats = (IndexBuildResult *)
! DatumGetPointer(OidFunctionCall3(procedure,
! PointerGetDatum(heapRelation),
! PointerGetDatum(indexRelation),
! PointerGetDatum(indexInfo)));
Assert(PointerIsValid(stats));
/*
--- 2013,2020 ----
/*
* Call the access method's build procedure
*/
! stats = indexRelation->amroutine->ambuild(heapRelation, indexRelation,
! indexInfo);
Assert(PointerIsValid(stats));
/*
*************** index_build(Relation heapRelation,
*** 2040,2050 ****
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));
}
/*
--- 2027,2035 ----
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..b794d59
*** 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,169 ----
accessMethodName)));
accessMethodId = HeapTupleGetOid(tuple);
accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
! amRoutine = GetIndexAmRoutine(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;
--- 318,326 ----
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);
--- 493,523 ----
}
accessMethodId = HeapTupleGetOid(tuple);
accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
+ amRoutine = GetIndexAmRoutine(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/opclasscmds.c b/src/backend/commands/opclasscmds.c
new file mode 100644
index 3375f10..7a50b6a
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 334,346 ****
ListCell *l;
Relation rel;
HeapTuple tup;
- Form_pg_am pg_am;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
--- 334,346 ----
ListCell *l;
Relation rel;
HeapTuple tup;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
+ IndexAmRoutine *amroutine;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 361,373 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
! amstorage = pg_am->amstorage;
/* XXX Should we make any privilege check against the AM? */
--- 361,375 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
!
! amroutine = GetIndexAmRoutineByAmId(amoid);
!
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
! amstorage = amroutine->amstorage;
/* XXX Should we make any privilege check against the AM? */
*************** DefineOpClass(CreateOpClassStmt *stmt)
*** 720,725 ****
--- 722,757 ----
/*
+ * Ask access method to validate given opclass.
+ */
+ Datum
+ amvalidate(PG_FUNCTION_ARGS)
+ {
+ Oid opclassoid = PG_GETARG_OID(0),
+ amoid;
+ IndexAmRoutine *amroutine;
+ HeapTuple classtup;
+ Form_pg_opclass classform;
+
+ classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
+
+ if (!HeapTupleIsValid(classtup))
+ elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
+
+ classform = (Form_pg_opclass) GETSTRUCT(classtup);
+ amoid = classform->opcmethod;
+
+ ReleaseSysCache(classtup);
+
+ amroutine = GetIndexAmRoutineByAmId(amoid);
+
+ amroutine->amvalidate(opclassoid);
+
+ PG_RETURN_BOOL(true);
+ }
+
+
+ /*
* DefineOpFamily
* Define a new index operator family.
*/
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 776,782 ****
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! Form_pg_am pg_am;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
--- 808,814 ----
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
! IndexAmRoutine *amroutine;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
*************** AlterOpFamily(AlterOpFamilyStmt *stmt)
*** 787,802 ****
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! pg_am = (Form_pg_am) GETSTRUCT(tup);
! maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = pg_am->amsupport;
/* XXX Should we make any privilege check against the AM? */
- ReleaseSysCache(tup);
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
--- 819,834 ----
stmt->amname)));
amoid = HeapTupleGetOid(tup);
! amroutine = GetIndexAmRoutineByAmId(amoid);
! ReleaseSysCache(tup);
! maxOpNumber = amroutine->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
! maxProcNumber = amroutine->amsupport;
/* XXX Should we make any privilege check against the AM? */
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
*************** assignOperTypes(OpFamilyMember *member,
*** 1099,1119 ****
* the family has been created but not yet populated with the required
* operators.)
*/
! HeapTuple amtup;
! Form_pg_am pg_am;
! amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
! if (amtup == NULL)
! elog(ERROR, "cache lookup failed for access method %u", amoid);
! pg_am = (Form_pg_am) GETSTRUCT(amtup);
! if (!pg_am->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! NameStr(pg_am->amname))));
!
! ReleaseSysCache(amtup);
}
else
{
--- 1131,1145 ----
* the family has been created but not yet populated with the required
* operators.)
*/
! IndexAmRoutine *amroutine;
! amroutine = GetIndexAmRoutineByAmId(amoid);
! if (!amroutine->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
! get_am_name(amoid))));
}
else
{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
new file mode 100644
index 56fed4d..d6cba4a
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
*************** ATExecSetRelOptions(Relation rel, List *
*** 9397,9403 ****
(void) view_reloptions(newOptions, true);
break;
case RELKIND_INDEX:
! (void) index_reloptions(rel->rd_am->amoptions, newOptions, true);
break;
default:
ereport(ERROR,
--- 9397,9403 ----
(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
*** 11007,11013 ****
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",
--- 11007,11013 ----
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 b969fc0..587b6e9
*** 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)
*** 545,550 ****
--- 546,552 ----
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)
*** 558,566 ****
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);
--- 560,570 ----
elog(ERROR, "cache lookup failed for access method %u",
idxrelrec->relam);
amrec = (Form_pg_am) GETSTRUCT(ht_am);
+ amroutine = GetIndexAmRoutine(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 990486c..1310613
*** a/src/backend/optimizer/path/costsize.c
--- b/src/backend/optimizer/path/costsize.c
*************** cost_index(IndexPath *path, PlannerInfo
*** 419,432 ****
* 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.
--- 419,426 ----
* 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 4c24c13..7f1c28f
*** 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
*** 1299,1305 ****
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
--- 1300,1306 ----
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 280808a..d01f926
*** a/src/backend/utils/adt/ruleutils.c
--- b/src/backend/utils/adt/ruleutils.c
***************
*** 19,24 ****
--- 19,25 ----
#include <unistd.h>
#include <fcntl.h>
+ #include "access/amapi.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "catalog/dependency.h"
*************** pg_get_indexdef_worker(Oid indexrelid, i
*** 1179,1184 ****
--- 1180,1186 ----
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
*** 1189,1196 ****
/* 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)
--- 1191,1200 ----
/* Add the operator class name, if not default */
get_opclass_name(indclass->values[keyno], keycoltype, &buf);
+ amroutine = GetIndexAmRoutine(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 15121bc..a882796
*** a/src/backend/utils/adt/selfuncs.c
--- b/src/backend/utils/adt/selfuncs.c
*************** add_predicate_to_quals(IndexOptInfo *ind
*** 6443,6458 ****
}
! 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;
--- 6443,6453 ----
}
! 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)
*** 6741,6760 ****
*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;
--- 6736,6748 ----
*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)
*** 6794,6813 ****
*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;
--- 6782,6794 ----
*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)
*** 6860,6879 ****
*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;
--- 6841,6853 ----
*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)
*** 6926,6933 ****
*indexTotalCost = costs.indexTotalCost;
*indexSelectivity = costs.indexSelectivity;
*indexCorrelation = costs.indexCorrelation;
-
- PG_RETURN_VOID();
}
--- 6900,6905 ----
*************** gincost_scalararrayopexpr(PlannerInfo *r
*** 7222,7237 ****
/*
* 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;
--- 7194,7204 ----
/*
* 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)
*** 7400,7406 ****
*indexStartupCost = 0;
*indexTotalCost = 0;
*indexSelectivity = 0;
! PG_RETURN_VOID();
}
if (counts.haveFullScan || indexQuals == NIL)
--- 7367,7373 ----
*indexStartupCost = 0;
*indexTotalCost = 0;
*indexSelectivity = 0;
! return;
}
if (counts.haveFullScan || indexQuals == NIL)
*************** gincostestimate(PG_FUNCTION_ARGS)
*** 7522,7544 ****
*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;
--- 7489,7504 ----
*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)
*** 7591,7596 ****
*indexTotalCost += (numTuples * *indexSelectivity) * (cpu_index_tuple_cost + qual_op_cost);
/* XXX what about pages_per_range? */
-
- PG_RETURN_VOID();
}
--- 7551,7554 ----
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
new file mode 100644
index 6b0c0b7..7d19b45
*** a/src/backend/utils/cache/relcache.c
--- b/src/backend/utils/cache/relcache.c
*************** 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
--- 445,451 ----
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
*** 1160,1165 ****
--- 1160,1231 ----
}
/*
+ * GetIndexAmRoutine - call the specified access method handler routine
+ * to get its IndexAmRoutine struct.
+ */
+ IndexAmRoutine *
+ GetIndexAmRoutine(Oid amhandler)
+ {
+ Datum datum;
+ IndexAmRoutine *routine;
+
+ datum = OidFunctionCall0(amhandler);
+ routine = (IndexAmRoutine *) DatumGetPointer(datum);
+
+ if (routine == NULL || !IsA(routine, IndexAmRoutine))
+ elog(ERROR, "index access method handler function %u did not return an IndexAmRoutine struct",
+ amhandler);
+
+ return routine;
+ }
+
+ /*
+ * GetIndexAmRoutine - look up the handler of the access method
+ * for the given OID, and retrieve its IndexAmRoutine struct.
+ */
+ IndexAmRoutine *
+ GetIndexAmRoutineByAmId(Oid amoid)
+ {
+ HeapTuple tuple;
+ regproc amhandler;
+ Form_pg_am amform;
+
+ /* Get handler function OID for the access method */
+ tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for access method %u",
+ amoid);
+ amform = (Form_pg_am) GETSTRUCT(tuple);
+ amhandler = amform->amhandler;
+
+ /* Complain if handler OID is invalid */
+ if (!RegProcedureIsValid(amhandler))
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("index access method \"%s\" does not have a handler",
+ NameStr(amform->amname))));
+ ReleaseSysCache(tuple);
+
+ /* And finally, call the handler function. */
+ return GetIndexAmRoutine(amhandler);
+ }
+
+ /*
+ * Initialize IndexAmRoutine for relation.
+ */
+ void
+ InitIndexAmRoutine(Relation relation)
+ {
+ IndexAmRoutine *result, *tmp;
+
+ result = (IndexAmRoutine *) MemoryContextAlloc(relation->rd_indexcxt,
+ sizeof(IndexAmRoutine));
+ tmp = GetIndexAmRoutine(relation->rd_am->amhandler);
+ memcpy(result, tmp, sizeof(IndexAmRoutine));
+ relation->amroutine = result;
+ }
+
+ /*
* Initialize index-access-method support data for an index relation
*/
void
*************** RelationInitIndexAccessInfo(Relation rel
*** 1211,1217 ****
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
--- 1277,1282 ----
*************** RelationInitIndexAccessInfo(Relation rel
*** 1228,1233 ****
--- 1293,1303 ----
ALLOCSET_SMALL_MAXSIZE);
relation->rd_indexcxt = indexcxt;
+ /* Initialize index AM routine */
+ InitIndexAmRoutine(relation);
+
+ amsupport = relation->amroutine->amsupport;
+
/*
* Allocate arrays to hold data
*/
*************** load_relcache_init_file(bool shared)
*** 4743,4749 ****
Oid *opfamily;
Oid *opcintype;
RegProcedure *support;
- int nsupport;
int16 *indoption;
Oid *indcollation;
--- 4813,4818 ----
*************** load_relcache_init_file(bool shared)
*** 4771,4776 ****
--- 4840,4846 ----
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)
*** 4832,4843 ****
rel->rd_indoption = indoption;
/* 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
{
--- 4902,4914 ----
rel->rd_indoption = indoption;
+ InitIndexAmRoutine(rel);
+
/* set up zeroed fmgr-info vectors */
rel->rd_aminfo = (RelationAmInfo *)
MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
rel->rd_supportinfo = (FmgrInfo *)
! MemoryContextAllocZero(indexcxt, relform->relnatts * rel->amroutine->amsupport * sizeof(FmgrInfo));
}
else
{
*************** write_relcache_init_file(bool shared)
*** 5116,5122 ****
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
--- 5187,5193 ----
/* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
! relform->relnatts * (rel->amroutine->amsupport * sizeof(RegProcedure)),
fp);
/* next, write the vector of collation OIDs */
diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h
new file mode 100644
index ...71d62d3
*** a/src/include/access/amapi.h
--- b/src/include/access/amapi.h
***************
*** 0 ****
--- 1,168 ----
+ /*-------------------------------------------------------------------------
+ *
+ * amapi.h
+ * API for generalized index access methods definition.
+ *
+ * Copyright (c) 2015, PostgreSQL Global Development Group
+ *
+ * src/include/access/amapi.h
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef AMAPI_H
+ #define AMAPI_H
+
+ #include "access/genam.h"
+ #include "nodes/reldecls.h"
+
+ /*
+ * Callback function signatures --- see indexam.sgml for more info.
+ */
+
+ /* "insert this tuple" function */
+ typedef bool
+ (*aminsert_function) (Relation indexRelation,
+ Datum *values,
+ bool *isnull,
+ ItemPointer heap_tid,
+ Relation heapRelation,
+ IndexUniqueCheck checkUnique);
+
+ /* "prepare for index scan" function */
+ typedef IndexScanDesc
+ (*ambeginscan_function) (Relation indexRelation,
+ int nkeys,
+ int norderbys);
+
+ /* "next valid tuple" function, or NULL */
+ typedef bool
+ (*amgettuple_function) (IndexScanDesc scan,
+ ScanDirection direction);
+
+ /* "fetch all valid tuples" function, or NULL */
+ typedef int64
+ (*amgetbitmap_function) (IndexScanDesc scan,
+ TIDBitmap *tbm);
+
+ /* "(re)start index scan" function */
+ typedef void
+ (*amrescan_function) (IndexScanDesc scan,
+ ScanKey keys,
+ int nkeys,
+ ScanKey orderbys,
+ int norderbys);
+
+ /* "end index scan" function */
+ typedef void
+ (*amendscan_function) (IndexScanDesc scan);
+
+ /* "mark current scan position" function */
+ typedef void
+ (*ammarkpos_function) (IndexScanDesc scan);
+
+ /* "restore marked scan position" function */
+ typedef void
+ (*amrestrpos_function) (IndexScanDesc scan);
+
+ /* "build new index" function */
+ typedef IndexBuildResult *
+ (*ambuild_function) (Relation heapRelation,
+ Relation indexRelation,
+ IndexInfo *indexInfo);
+
+ /* "build empty index" function */
+ typedef void
+ (*ambuildempty_function) (Relation indexRelation);
+
+ /* bulk-delete function */
+ typedef IndexBulkDeleteResult *
+ (*ambulkdelete_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
+ IndexBulkDeleteCallback callback,
+ void *callback_state);
+
+ /* post-VACUUM cleanup function */
+ typedef IndexBulkDeleteResult *
+ (*amvacuumcleanup_function) (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats);
+
+ /* can indexscan return IndexTuples? */
+ typedef bool
+ (*amcanreturn_function) (Relation indexRelation, int attno);
+
+ /* estimate cost of an indexscan */
+ typedef void
+ (*amcostestimate_function) (PlannerInfo *root,
+ IndexPath *path,
+ double loop_count,
+ Cost *indexStartupCost,
+ Cost *indexTotalCost,
+ Selectivity *indexSelectivity,
+ double *indexCorrelation);
+
+ /* parse AM-specific parameters */
+ typedef bytea *
+ (*amoptions_function) (Datum reloptions,
+ bool validate);
+
+ /* validate oplass */
+ typedef void
+ (*amvalidate_function) (Oid opclassoid);
+
+
+ struct IndexAmRoutine
+ {
+ NodeTag type;
+
+ /*
+ * Total number of strategies (operators) by which we can traverse/search
+ * this AM. Zero if AM does not have a fixed set of strategy assignments.
+ */
+ int16 amstrategies;
+ /* total number of support functions that this AM uses */
+ int16 amsupport;
+ /* does AM support order by column value? */
+ bool amcanorder;
+ /* does AM support order by operator result? */
+ bool amcanorderbyop;
+ /* does AM support backward scan? */
+ bool amcanbackward;
+ /* does AM support UNIQUE indexes? */
+ bool amcanunique;
+ /* does AM support multi-column indexes? */
+ bool amcanmulticol;
+ /* can query omit key for the first column? */
+ bool amoptionalkey;
+ /* can AM handle ScalarArrayOpExpr quals? */
+ bool amsearcharray;
+ /* can AM search for NULL/NOT NULL entries? */
+ bool amsearchnulls;
+ /* can storage type differ from column type? */
+ bool amstorage;
+ /* does AM support cluster command? */
+ bool amclusterable;
+ /* does AM handle predicate locks? */
+ bool ampredlocks;
+ /* type of data in index, or InvalidOid */
+ Oid amkeytype;
+
+ /* interface functions */
+ aminsert_function aminsert;
+ ambeginscan_function ambeginscan;
+ amgettuple_function amgettuple;
+ amgetbitmap_function amgetbitmap;
+ amrescan_function amrescan;
+ amendscan_function amendscan;
+ ammarkpos_function ammarkpos;
+ amrestrpos_function amrestrpos;
+ ambuild_function ambuild;
+ ambuildempty_function ambuildempty;
+ ambulkdelete_function ambulkdelete;
+ amvacuumcleanup_function amvacuumcleanup;
+ amcanreturn_function amcanreturn;
+ amcostestimate_function amcostestimate;
+ amoptions_function amoptions;
+ amvalidate_function amvalidate;
+ };
+
+ #endif /* AMAPI_H */
diff --git a/src/include/access/brin.h b/src/include/access/brin.h
new file mode 100644
index e72fb2d..b9024fd
*** a/src/include/access/brin.h
--- b/src/include/access/brin.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
--- 18,50 ----
/*
* prototypes for functions in brin.c (external entry points for BRIN)
*/
! extern Datum brinhandler(PG_FUNCTION_ARGS);
! extern void brinvalidate(Oid opclassoid);
! extern IndexBuildResult *brinbuild(Relation heap, Relation index,
! IndexInfo *indexInfo);
! extern void brinbuildempty(Relation index);
! extern bool brininsert(Relation idxRel, Datum *values, bool *nulls,
! ItemPointer heaptid, Relation heapRel,
! IndexUniqueCheck checkUnique);
! extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys);
! extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
! extern void brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
! ScanKey orderbys, int norderbys);
! extern void brinendscan(IndexScanDesc scan);
! extern void brinmarkpos(IndexScanDesc scan);
! extern void brinrestrpos(IndexScanDesc scan);
! extern IndexBulkDeleteResult *brinbulkdelete(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats,
! IndexBulkDeleteCallback callback,
! void *callback_state);
! extern IndexBulkDeleteResult *brinvacuumcleanup(IndexVacuumInfo *info,
! IndexBulkDeleteResult *stats);
! extern void brincostestimate(PlannerInfo *root, IndexPath *path,
! double loop_count, Cost *indexStartupCost,
! Cost *indexTotalCost,
! Selectivity *indexSelectivity,
! double *indexCorrelation);
! extern bytea *brinoptions(Datum reloptions, bool validate);
/*
* Storage type for BRIN's reloptions
diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h
new file mode 100644
index 6be199e..3273fa7
*** a/src/include/access/brin_internal.h
--- b/src/include/access/brin_internal.h
***************
*** 11,16 ****
--- 11,17 ----
#ifndef BRIN_INTERNAL_H
#define BRIN_INTERNAL_H
+ #include "access/amapi.h"
#include "fmgr.h"
#include "storage/buf.h"
#include "storage/bufpage.h"
*************** typedef struct BrinDesc
*** 71,76 ****
--- 72,78 ----
#define BRIN_PROCNUM_ADDVALUE 2
#define BRIN_PROCNUM_CONSISTENT 3
#define BRIN_PROCNUM_UNION 4
+ #define BRIN_MANDATORY_NPROCS 4
/* procedure numbers up to 10 are reserved for BRIN future expansion */
#undef BRIN_DEBUG
*************** typedef struct BrinDesc
*** 85,89 ****
--- 87,117 ----
extern BrinDesc *brin_build_desc(Relation rel);
extern void brin_free_desc(BrinDesc *bdesc);
extern Datum brin_summarize_new_values(PG_FUNCTION_ARGS);
+ extern void brinvalidate(Oid opclassoid);
+ 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);
#endif /* BRIN_INTERNAL_H */
diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h
new file mode 100644
index 5021887..40c2fa0
*** 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,601 ----
/* ginutil.c */
! extern Datum ginhandler(PG_FUNCTION_ARGS);
! extern void ginvalidate(Oid opclassoid);
! 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,
--- 616,627 ----
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);
--- 872,899 ----
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 1a77982..c00b578
*** 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
*** 426,434 ****
} 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);
--- 427,439 ----
} GiSTOptions;
/* gist.c */
! extern Datum gisthandler(PG_FUNCTION_ARGS);
! extern void gistvalidate(Oid opclassoid);
! 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
*** 474,481 ****
Buffer leftchild, bool markfollowright);
/* gistget.c */
! extern Datum gistgettuple(PG_FUNCTION_ARGS);
! extern Datum gistgetbitmap(PG_FUNCTION_ARGS);
/* gistutil.c */
--- 479,486 ----
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
*** 485,491 ****
#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);
--- 490,496 ----
#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 *
*** 534,541 ****
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,
--- 539,550 ----
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
*** 544,550 ****
int attno);
/* gistbuild.c */
! extern Datum gistbuild(PG_FUNCTION_ARGS);
extern void gistValidateBufferingOption(char *value);
/* gistbuildbuffers.c */
--- 553,560 ----
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..866ad6b
*** 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,271 ----
/* public routines */
! extern Datum hashhandler(PG_FUNCTION_ARGS);
! extern void hashvalidate(Oid opclassoid);
! 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..50c66ee
*** 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,683 ----
/*
* prototypes for functions in nbtree.c (external entry points for btree)
*/
! extern Datum bthandler(PG_FUNCTION_ARGS);
! extern void btvalidate(Oid opclassoid);
! 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..d17aebd
*** 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,212 ----
} spgLeafConsistentOut;
+ /* spgutils.c */
+ extern Datum spghandler(PG_FUNCTION_ARGS);
+ extern void spgvalidate(Oid opclassoid);
+
/* 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..f19a873
*** 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,40 ----
CATALOG(pg_am,2601)
{
NameData amname; /* access method name */
! regproc amhandler; /* handler function */
} 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
--- 48,78 ----
* compiler constants for pg_am
* ----------------
*/
! #define Natts_pg_am 2
#define Anum_pg_am_amname 1
! #define Anum_pg_am_amhandler 2
/* ----------------
* initial contents of pg_am
* ----------------
*/
! DATA(insert OID = 403 ( btree bthandler ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
! DATA(insert OID = 405 ( hash hashhandler ));
DESCR("hash index access method");
#define HASH_AM_OID 405
! DATA(insert OID = 783 ( gist gisthandler ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
! DATA(insert OID = 2742 ( gin ginhandler ));
DESCR("GIN index access method");
#define GIN_AM_OID 2742
! DATA(insert OID = 4000 ( spgist spghandler ));
DESCR("SP-GiST index access method");
#define SPGIST_AM_OID 4000
! DATA(insert OID = 3580 ( brin brinhandler ));
DESCR("block range index (BRIN) access method");
#define BRIN_AM_OID 3580
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index d8640db..b3c6915
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DESCR("convert int4 to float4");
*** 548,610 ****
DATA(insert OID = 319 ( int4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "700" _null_ _null_ _null_ _null_ _null_ ftoi4 _null_ _null_ _null_ ));
DESCR("convert float4 to int4");
- DATA(insert OID = 330 ( btgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgettuple _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 636 ( btgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ btgetbitmap _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 331 ( btinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btinsert _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 333 ( btbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbeginscan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 334 ( btrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btrescan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 335 ( btendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btendscan _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 336 ( btmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btmarkpos _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 337 ( btrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btrestrpos _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 338 ( btbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbuild _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 328 ( btbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ btbuildempty _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 332 ( btbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btbulkdelete _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ btvacuumcleanup _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 276 ( btcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ btcanreturn _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 1268 ( btcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ btcostestimate _null_ _null_ _null_ ));
- DESCR("btree(internal)");
- DATA(insert OID = 2785 ( btoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ btoptions _null_ _null_ _null_ ));
- DESCR("btree(internal)");
-
- DATA(insert OID = 3789 ( bringetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ bringetbitmap _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3790 ( brininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brininsert _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3791 ( brinbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbeginscan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3792 ( brinrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinrescan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3793 ( brinendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinendscan _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3794 ( brinmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinmarkpos _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3795 ( brinrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinrestrpos _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3796 ( brinbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbuild _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3797 ( brinbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ brinbuildempty _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3798 ( brinbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brinbulkdelete _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3799 ( brinvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ brinvacuumcleanup _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3800 ( brincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brincostestimate _null_ _null_ _null_ ));
- DESCR("brin(internal)");
- DATA(insert OID = 3801 ( brinoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ brinoptions _null_ _null_ _null_ ));
- DESCR("brin(internal)");
DATA(insert OID = 3952 ( brin_summarize_new_values PGNSP PGUID 12 1 0 0 0 f f f f f f v s 1 0 23 "2205" _null_ _null_ _null_ _null_ _null_ brin_summarize_new_values _null_ _null_ _null_ ));
DESCR("brin: standalone scan new table pages");
--- 548,553 ----
*************** DESCR("convert name to char(n)");
*** 695,729 ****
DATA(insert OID = 409 ( name PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 19 "1042" _null_ _null_ _null_ _null_ _null_ bpchar_name _null_ _null_ _null_ ));
DESCR("convert char(n) to name");
- DATA(insert OID = 440 ( hashgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgettuple _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 637 ( hashgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashgetbitmap _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 441 ( hashinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashinsert _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 443 ( hashbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbeginscan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 444 ( hashrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashrescan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 445 ( hashendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashendscan _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 446 ( hashmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashmarkpos _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 447 ( hashrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashrestrpos _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 448 ( hashbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbuild _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 327 ( hashbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ hashbuildempty _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 442 ( hashbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashbulkdelete _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ hashvacuumcleanup _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 438 ( hashcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ hashcostestimate _null_ _null_ _null_ ));
- DESCR("hash(internal)");
- DATA(insert OID = 2786 ( hashoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ hashoptions _null_ _null_ _null_ ));
- DESCR("hash(internal)");
-
DATA(insert OID = 449 ( hashint2 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "21" _null_ _null_ _null_ _null_ _null_ hashint2 _null_ _null_ _null_ ));
DESCR("hash");
DATA(insert OID = 450 ( hashint4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ hashint4 _null_ _null_ _null_ ));
--- 638,643 ----
*************** DESCR("larger of two");
*** 979,1015 ****
DATA(insert OID = 771 ( int2smaller PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2smaller _null_ _null_ _null_ ));
DESCR("smaller of two");
- DATA(insert OID = 774 ( gistgettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgettuple _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 638 ( gistgetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistgetbitmap _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 775 ( gistinsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistinsert _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 777 ( gistbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbeginscan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 778 ( gistrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistrescan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 779 ( gistendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistendscan _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 780 ( gistmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistmarkpos _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 781 ( gistrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistrestrpos _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 782 ( gistbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbuild _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 326 ( gistbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ gistbuildempty _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 776 ( gistbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistbulkdelete _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ gistvacuumcleanup _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 3280 ( gistcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ gistcanreturn _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 772 ( gistcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gistcostestimate _null_ _null_ _null_ ));
- DESCR("gist(internal)");
- DATA(insert OID = 2787 ( gistoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ gistoptions _null_ _null_ _null_ ));
- DESCR("gist(internal)");
-
DATA(insert OID = 784 ( tintervaleq PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervaleq _null_ _null_ _null_ ));
DATA(insert OID = 785 ( tintervalne PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervalne _null_ _null_ _null_ ));
DATA(insert OID = 786 ( tintervallt PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "704 704" _null_ _null_ _null_ _null_ _null_ tintervallt _null_ _null_ _null_ ));
--- 893,898 ----
*************** DATA(insert OID = 3311 ( tsm_handler_in
*** 3742,3747 ****
--- 3625,3634 ----
DESCR("I/O");
DATA(insert OID = 3312 ( tsm_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "3310" _null_ _null_ _null_ _null_ _null_ tsm_handler_out _null_ _null_ _null_ ));
DESCR("I/O");
+ DATA(insert OID = 326 ( index_am_handler_in PGNSP PGUID 12 1 0 0 0 f f f f f f i s 1 0 325 "2275" _null_ _null_ _null_ _null_ _null_ index_am_handler_in _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 327 ( index_am_handler_out PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "325" _null_ _null_ _null_ _null_ _null_ index_am_handler_out _null_ _null_ _null_ ));
+ DESCR("I/O");
/* tablesample method handlers */
DATA(insert OID = 3313 ( bernoulli PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 3310 "2281" _null_ _null_ _null_ _null_ _null_ tsm_bernoulli_handler _null_ _null_ _null_ ));
*************** DESCR("GiST support");
*** 4198,4231 ****
DATA(insert OID = 3288 ( gist_bbox_distance PGNSP PGUID 12 1 0 0 0 f f f f t f i s 4 0 701 "2281 600 23 26" _null_ _null_ _null_ _null_ _null_ gist_bbox_distance _null_ _null_ _null_ ));
DESCR("GiST support");
- /* GIN */
- DATA(insert OID = 2731 ( gingetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gingetbitmap _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2732 ( gininsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gininsert _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2733 ( ginbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbeginscan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2734 ( ginrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginrescan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2735 ( ginendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginendscan _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2736 ( ginmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginmarkpos _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2737 ( ginrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginrestrpos _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2738 ( ginbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbuild _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 325 ( ginbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ ginbuildempty _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2739 ( ginbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginbulkdelete _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ ginvacuumcleanup _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2741 ( gincostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gincostestimate _null_ _null_ _null_ ));
- DESCR("gin(internal)");
- DATA(insert OID = 2788 ( ginoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ ginoptions _null_ _null_ _null_ ));
- DESCR("gin(internal)");
-
/* GIN array support */
DATA(insert OID = 2743 ( ginarrayextract PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 2281 "2277 2281 2281" _null_ _null_ _null_ _null_ _null_ ginarrayextract _null_ _null_ _null_ ));
DESCR("GIN array support");
--- 4085,4090 ----
*************** DESCR("construct timestamp with time zon
*** 5123,5160 ****
DATA(insert OID = 3464 ( make_interval PGNSP PGUID 12 1 0 0 0 f f f f t f i s 7 0 1186 "23 23 23 23 23 23 701" _null_ _null_ "{years,months,weeks,days,hours,mins,secs}" _null_ _null_ make_interval _null_ _null_ _null_ ));
DESCR("construct interval");
- /* spgist support functions */
- DATA(insert OID = 4001 ( spggettuple PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggettuple _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4002 ( spggetbitmap PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ spggetbitmap _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4003 ( spginsert PGNSP PGUID 12 1 0 0 0 f f f f t f v s 6 0 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spginsert _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4004 ( spgbeginscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbeginscan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4005 ( spgrescan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 5 0 2278 "2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgrescan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4006 ( spgendscan PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgendscan _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4007 ( spgmarkpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgmarkpos _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4008 ( spgrestrpos PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgrestrpos _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4009 ( spgbuild PGNSP PGUID 12 1 0 0 0 f f f f t f v s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbuild _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4010 ( spgbuildempty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 2278 "2281" _null_ _null_ _null_ _null_ _null_ spgbuildempty _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4011 ( spgbulkdelete PGNSP PGUID 12 1 0 0 0 f f f f t f v s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgbulkdelete _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4012 ( spgvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ spgvacuumcleanup _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4032 ( spgcanreturn PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "2281 23" _null_ _null_ _null_ _null_ _null_ spgcanreturn _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4013 ( spgcostestimate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ spgcostestimate _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
- DATA(insert OID = 4014 ( spgoptions PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ _null_ spgoptions _null_ _null_ _null_ ));
- DESCR("spgist(internal)");
-
/* spgist opclasses */
DATA(insert OID = 4018 ( spg_quad_config PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_quad_config _null_ _null_ _null_ ));
DESCR("SP-GiST support for quad tree over point");
--- 4982,4987 ----
*************** DESCR("get an individual replication ori
*** 5337,5342 ****
--- 5164,5188 ----
DATA(insert OID = 6014 ( pg_show_replication_origin_status PGNSP PGUID 12 1 100 0 0 f f f f f t v r 0 0 2249 "" "{26,25,3220,3220}" "{o,o,o,o}" "{local_id, external_id, remote_lsn, local_lsn}" _null_ _null_ pg_show_replication_origin_status _null_ _null_ _null_ ));
DESCR("get progress for all replication origins");
+ /* Access methods handlers */
+ DATA(insert OID = 330 ( bthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ bthandler _null_ _null_ _null_ ));
+ DESCR("btree handler");
+ DATA(insert OID = 331 ( hashhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ hashhandler _null_ _null_ _null_ ));
+ DESCR("hash handler");
+ DATA(insert OID = 332 ( gisthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ gisthandler _null_ _null_ _null_ ));
+ DESCR("gist handler");
+ DATA(insert OID = 333 ( ginhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ ginhandler _null_ _null_ _null_ ));
+ DESCR("gin handler");
+ DATA(insert OID = 334 ( spghandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ spghandler _null_ _null_ _null_ ));
+ DESCR("spgist handler");
+ DATA(insert OID = 335 ( brinhandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 325 "" _null_ _null_ _null_ _null_ _null_ brinhandler _null_ _null_ _null_ ));
+ DESCR("brin handler");
+
+ DATA(insert OID = 336 ( amvalidate PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 16 "26" _null_ _null_ _null_ _null_ _null_ amvalidate _null_ _null_ _null_ ));
+ DESCR("ask access method to validate opclass");
+
+
+
/*
* Symbolic values for provolatile column: these indicate whether the result
* of a function is dependent *only* on the values of its explicit arguments,
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
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/commands/defrem.h b/src/include/commands/defrem.h
new file mode 100644
index adae296..112f9dc
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
*************** extern Oid get_am_oid(const char *amname
*** 95,100 ****
--- 95,101 ----
extern char *get_am_name(Oid amOid);
extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+ extern Datum amvalidate(PG_FUNCTION_ARGS);
/* commands/tsearchcmds.c */
extern ObjectAddress DefineTSParser(List *names, List *parameters);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
new file mode 100644
index 5ccf470..98a8bd6
*** 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 603edd3..0ad9ee9
*** a/src/include/nodes/nodes.h
--- b/src/include/nodes/nodes.h
***************
*** 14,19 ****
--- 14,21 ----
#ifndef NODES_H
#define NODES_H
+ #include "nodes/reldecls.h"
+
/*
* The first field of every node is NodeTag. Each node created (with makeNode)
* will have one of the following tags as the value of its first field.
*************** typedef enum NodeTag
*** 454,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 */
} NodeTag;
/*
--- 456,463 ----
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;
/*
*************** extern bool equal(const void *a, const v
*** 543,560 ****
/*
- * Typedefs for identifying qualifier selectivities and plan costs as such.
- * These are just plain "double"s, but declaring a variable as Selectivity
- * or Cost makes the intent more obvious.
- *
- * These could have gone into plannodes.h or some such, but many files
- * depend on them...
- */
- typedef double Selectivity; /* fraction of tuples a qualifier will pass */
- typedef double Cost; /* execution cost (in page-access units) */
-
-
- /*
* CmdType -
* enums for type of operation represented by a Query or PlannedStmt
*
--- 546,551 ----
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
new file mode 100644
index 5393005..2245895
*** a/src/include/nodes/relation.h
--- b/src/include/nodes/relation.h
***************
*** 18,24 ****
--- 18,26 ----
#include "lib/stringinfo.h"
#include "nodes/params.h"
#include "nodes/parsenodes.h"
+ #include "nodes/reldecls.h"
#include "storage/block.h"
+ #include "utils/relcache.h"
/*
*************** typedef struct PlannerGlobal
*** 125,131 ****
* the passed-in Query data structure; someday that should stop.
*----------
*/
! typedef struct PlannerInfo
{
NodeTag type;
--- 127,133 ----
* the passed-in Query data structure; someday that should stop.
*----------
*/
! struct PlannerInfo
{
NodeTag type;
*************** typedef struct PlannerInfo
*** 274,280 ****
/* for GroupingFunc fixup in setrefs */
AttrNumber *grouping_map;
! } PlannerInfo;
/*
--- 276,282 ----
/* for GroupingFunc fixup in setrefs */
AttrNumber *grouping_map;
! };
/*
*************** typedef struct IndexOptInfo
*** 553,560 ****
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 */
--- 555,561 ----
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
*** 565,576 ****
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;
--- 566,577 ----
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
*** 825,831 ****
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! typedef struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
--- 826,832 ----
* itself represent the costs of an IndexScan or IndexOnlyScan plan type.
*----------
*/
! struct IndexPath
{
Path path;
IndexOptInfo *indexinfo;
*************** typedef struct IndexPath
*** 837,843 ****
ScanDirection indexscandir;
Cost indextotalcost;
Selectivity indexselectivity;
! } IndexPath;
/*
* BitmapHeapPath represents one or more indexscans that generate TID bitmaps
--- 838,844 ----
ScanDirection indexscandir;
Cost indextotalcost;
Selectivity indexselectivity;
! };
/*
* BitmapHeapPath represents one or more indexscans that generate TID bitmaps
diff --git a/src/include/nodes/reldecls.h b/src/include/nodes/reldecls.h
new file mode 100644
index ...cd97808
*** a/src/include/nodes/reldecls.h
--- b/src/include/nodes/reldecls.h
***************
*** 0 ****
--- 1,34 ----
+ /*-------------------------------------------------------------------------
+ *
+ * reldecls.h
+ * Declarations of some planner's data structures.
+ *
+ *
+ * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/nodes/reldecls.h
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef RELDECLS_H
+ #define RELDECLS_H
+
+ /*
+ * Typedefs for identifying qualifier selectivities and plan costs as such.
+ * These are just plain "double"s, but declaring a variable as Selectivity
+ * or Cost makes the intent more obvious.
+ *
+ * These could have gone into plannodes.h or some such, but many files
+ * depend on them...
+ */
+ typedef double Selectivity; /* fraction of tuples a qualifier will pass */
+ typedef double Cost; /* execution cost (in page-access units) */
+
+ /* Declarations for some data structures of src/include/nodes/relation.h */
+ typedef struct IndexAmRoutine IndexAmRoutine;
+ typedef struct PlannerInfo PlannerInfo;
+ typedef struct IndexPath IndexPath;
+ typedef struct IndexInfo IndexInfo;
+
+ #endif /* RELDECLS_H */
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
new file mode 100644
index e610bf3..ca55370
*** 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..825fed1
*** a/src/include/utils/relcache.h
--- b/src/include/utils/relcache.h
***************
*** 16,21 ****
--- 16,22 ----
#include "access/tupdesc.h"
#include "nodes/bitmapset.h"
+ #include "nodes/reldecls.h"
typedef struct RelationData *Relation;
*************** typedef struct RelationData *Relation;
*** 29,34 ****
--- 30,42 ----
typedef Relation *RelationPtr;
/*
+ * Routines to retreive IndexAmRoutine
+ */
+ extern IndexAmRoutine *GetIndexAmRoutine(Oid amhandler);
+ extern IndexAmRoutine *GetIndexAmRoutineByAmId(Oid amoid);
+ extern void InitIndexAmRoutine(Relation relation);
+
+ /*
* Routines to open (lookup) and close a relcache entry
*/
extern Relation RelationIdGetRelation(Oid relationId);
diff --git a/src/include/utils/selfuncs.h b/src/include/utils/selfuncs.h
new file mode 100644
index a7433d9..3745d1c
*** a/src/include/utils/selfuncs.h
--- b/src/include/utils/selfuncs.h
*************** extern double estimate_num_groups(Planne
*** 191,202 ****
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 */
--- 191,226 ----
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..d1a322d
*** a/src/test/regress/expected/oidjoins.out
--- b/src/test/regress/expected/oidjoins.out
*************** WHERE aggmtranstype != 0 AND
*** 73,206 ****
------+---------------
(0 rows)
- SELECT ctid, amkeytype
- FROM pg_catalog.pg_am fk
- WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
- ctid | amkeytype
- ------+-----------
- (0 rows)
-
- SELECT ctid, aminsert
- FROM pg_catalog.pg_am fk
- WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
- ctid | aminsert
- ------+----------
- (0 rows)
-
- SELECT ctid, ambeginscan
- FROM pg_catalog.pg_am fk
- WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
- ctid | ambeginscan
- ------+-------------
- (0 rows)
-
- SELECT ctid, amgettuple
- FROM pg_catalog.pg_am fk
- WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- ctid | amgettuple
- ------+------------
- (0 rows)
-
- SELECT ctid, amgetbitmap
- FROM pg_catalog.pg_am fk
- WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
- ctid | amgetbitmap
- ------+-------------
- (0 rows)
-
- SELECT ctid, amrescan
- FROM pg_catalog.pg_am fk
- WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
- ctid | amrescan
- ------+----------
- (0 rows)
-
- SELECT ctid, amendscan
- FROM pg_catalog.pg_am fk
- WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
- ctid | amendscan
- ------+-----------
- (0 rows)
-
- SELECT ctid, ammarkpos
- FROM pg_catalog.pg_am fk
- WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
- ctid | ammarkpos
- ------+-----------
- (0 rows)
-
- SELECT ctid, amrestrpos
- FROM pg_catalog.pg_am fk
- WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
- ctid | amrestrpos
- ------+------------
- (0 rows)
-
- SELECT ctid, ambuild
- FROM pg_catalog.pg_am fk
- WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
- ctid | ambuild
- ------+---------
- (0 rows)
-
- SELECT ctid, ambuildempty
- FROM pg_catalog.pg_am fk
- WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
- ctid | ambuildempty
- ------+--------------
- (0 rows)
-
- SELECT ctid, ambulkdelete
- FROM pg_catalog.pg_am fk
- WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
- ctid | ambulkdelete
- ------+--------------
- (0 rows)
-
- SELECT ctid, amvacuumcleanup
- FROM pg_catalog.pg_am fk
- WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
- ctid | amvacuumcleanup
- ------+-----------------
- (0 rows)
-
- SELECT ctid, amcanreturn
- FROM pg_catalog.pg_am fk
- WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
- ctid | amcanreturn
- ------+-------------
- (0 rows)
-
- SELECT ctid, amcostestimate
- FROM pg_catalog.pg_am fk
- WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
- ctid | amcostestimate
- ------+----------------
- (0 rows)
-
- SELECT ctid, amoptions
- FROM pg_catalog.pg_am fk
- WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
- ctid | amoptions
- ------+-----------
- (0 rows)
-
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 73,78 ----
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
new file mode 100644
index 7c93b3b..ef66a08
*** a/src/test/regress/expected/opr_sanity.out
--- b/src/test/regress/expected/opr_sanity.out
*************** WHERE p1.oid != p2.oid AND
*** 1481,1486 ****
--- 1481,1492 ----
-----+-----
(0 rows)
+ -- Ask access methods to validate opclasses
+ SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid);
+ oid
+ -----
+ (0 rows)
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
SELECT p1.amopfamily, p1.amopstrategy
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 1526,1574 ****
------------+--------------
(0 rows)
- -- check for ordering operators not supported by parent AM
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
- amopfamily | amopopr | oid | amname
- ------------+---------+-----+--------
- (0 rows)
-
- -- Cross-check amopstrategy index against parent AM
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
- amopfamily | amopopr | oid | amname
- ------------+---------+-----+--------
- (0 rows)
-
- -- Detect missing pg_amop entries: should have as many strategy operators
- -- as AM expects for each datatype combination supported by the opfamily.
- -- We can't check this for AMs with variable strategy sets.
- SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
- amname | amoplefttype | amoprighttype
- --------+--------------+---------------
- (0 rows)
-
- -- Currently, none of the AMs with fixed strategy sets support ordering ops.
- SELECT p1.amname, p2.amopfamily, p2.amopstrategy
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
- amname | amopfamily | amopstrategy
- --------+------------+--------------
- (0 rows)
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
--- 1532,1537 ----
*************** WHERE p1.amprocfamily = 0 OR p1.amprocle
*** 1851,1865 ****
--------------+-----------
(0 rows)
- -- Cross-check amprocnum index against parent AM
- SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
- FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
- WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
- amprocfamily | amprocnum | oid | amname
- --------------+-----------+-----+--------
- (0 rows)
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
SELECT * FROM (
--- 1814,1819 ----
diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql
new file mode 100644
index 2fa628d..ca419fd
*** a/src/test/regress/sql/oidjoins.sql
--- b/src/test/regress/sql/oidjoins.sql
*************** SELECT ctid, aggmtranstype
*** 37,106 ****
FROM pg_catalog.pg_aggregate fk
WHERE aggmtranstype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
- SELECT ctid, amkeytype
- FROM pg_catalog.pg_am fk
- WHERE amkeytype != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
- SELECT ctid, aminsert
- FROM pg_catalog.pg_am fk
- WHERE aminsert != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
- SELECT ctid, ambeginscan
- FROM pg_catalog.pg_am fk
- WHERE ambeginscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
- SELECT ctid, amgettuple
- FROM pg_catalog.pg_am fk
- WHERE amgettuple != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- SELECT ctid, amgetbitmap
- FROM pg_catalog.pg_am fk
- WHERE amgetbitmap != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
- SELECT ctid, amrescan
- FROM pg_catalog.pg_am fk
- WHERE amrescan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
- SELECT ctid, amendscan
- FROM pg_catalog.pg_am fk
- WHERE amendscan != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
- SELECT ctid, ammarkpos
- FROM pg_catalog.pg_am fk
- WHERE ammarkpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
- SELECT ctid, amrestrpos
- FROM pg_catalog.pg_am fk
- WHERE amrestrpos != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
- SELECT ctid, ambuild
- FROM pg_catalog.pg_am fk
- WHERE ambuild != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
- SELECT ctid, ambuildempty
- FROM pg_catalog.pg_am fk
- WHERE ambuildempty != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
- SELECT ctid, ambulkdelete
- FROM pg_catalog.pg_am fk
- WHERE ambulkdelete != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
- SELECT ctid, amvacuumcleanup
- FROM pg_catalog.pg_am fk
- WHERE amvacuumcleanup != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
- SELECT ctid, amcanreturn
- FROM pg_catalog.pg_am fk
- WHERE amcanreturn != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
- SELECT ctid, amcostestimate
- FROM pg_catalog.pg_am fk
- WHERE amcostestimate != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
- SELECT ctid, amoptions
- FROM pg_catalog.pg_am fk
- WHERE amoptions != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopfamily != 0 AND
--- 37,42 ----
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
new file mode 100644
index c9bdd77..0e0506e
*** a/src/test/regress/sql/opr_sanity.sql
--- b/src/test/regress/sql/opr_sanity.sql
*************** WHERE p1.oid != p2.oid AND
*** 960,965 ****
--- 960,969 ----
p1.opcmethod = p2.opcmethod AND p1.opcintype = p2.opcintype AND
p1.opcdefault AND p2.opcdefault;
+ -- Ask access methods to validate opclasses
+
+ SELECT oid FROM pg_opclass WHERE NOT amvalidate(oid);
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
*************** WHERE p1.amopsortfamily <> 0 AND NOT EXI
*** 995,1035 ****
(SELECT 1 from pg_opfamily op WHERE op.oid = p1.amopsortfamily
AND op.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree'));
- -- check for ordering operators not supported by parent AM
-
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
-
- -- Cross-check amopstrategy index against parent AM
-
- SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
- FROM pg_amop AS p1, pg_am AS p2
- WHERE p1.amopmethod = p2.oid AND
- p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
-
- -- Detect missing pg_amop entries: should have as many strategy operators
- -- as AM expects for each datatype combination supported by the opfamily.
- -- We can't check this for AMs with variable strategy sets.
-
- SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND
- p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
- WHERE p3.amopfamily = p2.amopfamily AND
- p3.amoplefttype = p2.amoplefttype AND
- p3.amoprighttype = p2.amoprighttype AND
- p3.amoppurpose = 's');
-
- -- Currently, none of the AMs with fixed strategy sets support ordering ops.
-
- SELECT p1.amname, p2.amopfamily, p2.amopstrategy
- FROM pg_am AS p1, pg_amop AS p2
- WHERE p2.amopmethod = p1.oid AND
- p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
-
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator. If it's a search operator it had better yield boolean,
-- otherwise an input type of its sort opfamily.
--- 999,1004 ----
*************** FROM pg_amproc as p1
*** 1176,1188 ****
WHERE p1.amprocfamily = 0 OR p1.amproclefttype = 0 OR p1.amprocrighttype = 0
OR p1.amprocnum < 1 OR p1.amproc = 0;
- -- Cross-check amprocnum index against parent AM
-
- SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
- FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
- WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
- p1.amprocnum > p2.amsupport;
-
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
--- 1145,1150 ----
On 2015-12-24 14:57, Alexander Korotkov wrote:
What do you think about
"
System Administration Functions
" chapter?
http://www.postgresql.org/docs/devel/static/functions-admin.htmlOther than that I am happy with the patch.
Sounds good to me.
One last tiny gripe, I think the amroutine in RelationData should be
named rd_amroutine for consistency.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
I just noticed that this patch had remained in Waiting-for-author status
after Alexander had already submitted the updated version of the patch.
I marked it as ready-for-committer, because Petr stated so in the
thread.
Tom, you're registered as committer for this patch. Do you have time in
the near future to review this patch?
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
I just noticed that this patch had remained in Waiting-for-author status
after Alexander had already submitted the updated version of the patch.
I marked it as ready-for-committer, because Petr stated so in the
thread.
Tom, you're registered as committer for this patch. Do you have time in
the near future to review this patch?
Yeah, I will look at it soon.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Alexander Korotkov <a.korotkov@postgrespro.ru> writes:
[ aminterface-13.patch ]
I've started to review this. There are a bunch of cosmetic things I don't
like, notably the include-file nesting you've chosen, but they're fixable.
One item that I think could use some discussion is where to put the new
amvalidate functions. I don't especially like your choice to drop them
into nbtree.c, gist.c, etc, for a couple of reasons:
1. These aren't really at the same semantic level as functions like
btinsert or btgettuple; they're not part of the implementation of an
index, and indeed are *users* of indexes (at least of the catalog
indexes).
2. This approach substantially bloats the #include lists for the
relevant files, which again is a token of the validate functions not
belonging where they were put.
3. There's probably room to share code across the different validators;
but this design isn't very amenable to that.
A comparison point worth noting is that the amcostestimate functions
are in more or less the same boat: they aren't part of the index
implementation in any meaningful way, but are really part of the
planner instead. Those are all in selfuncs.c, not under backend/access
at all.
There are a couple of things we could do instead:
* Put each amvalidate function into its own file (but probably keep it
in the same directory as now). This is a reasonable response to
points #1 and #2 but isn't very much help for #3.
* Collect the amvalidate functions into one file, which then leaves
us wondering where to put that; surely not under any one AM's directory.
A new file in src/backend/access/index/ is one plausible solution.
This file would also be a reasonable place to put the amvalidate()
dispatch function itself.
I'm somewhat leaning to the second choice, but perhaps someone has
a better idea, or an argument against doing that.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Jan 16, 2016, at 11:13 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Alexander Korotkov <a.korotkov@postgrespro.ru> writes:
[ aminterface-13.patch ]
I've started to review this. There are a bunch of cosmetic things I don't
like, notably the include-file nesting you've chosen, but they're fixable.
One item that I think could use some discussion is where to put the new
amvalidate functions. I don't especially like your choice to drop them
into nbtree.c, gist.c, etc, for a couple of reasons:1. These aren't really at the same semantic level as functions like
btinsert or btgettuple; they're not part of the implementation of an
index, and indeed are *users* of indexes (at least of the catalog
indexes).2. This approach substantially bloats the #include lists for the
relevant files, which again is a token of the validate functions not
belonging where they were put.3. There's probably room to share code across the different validators;
but this design isn't very amenable to that.A comparison point worth noting is that the amcostestimate functions
are in more or less the same boat: they aren't part of the index
implementation in any meaningful way, but are really part of the
planner instead. Those are all in selfuncs.c, not under backend/access
at all.There are a couple of things we could do instead:
* Put each amvalidate function into its own file (but probably keep it
in the same directory as now). This is a reasonable response to
points #1 and #2 but isn't very much help for #3.* Collect the amvalidate functions into one file, which then leaves
us wondering where to put that; surely not under any one AM's directory.
A new file in src/backend/access/index/ is one plausible solution.
This file would also be a reasonable place to put the amvalidate()
dispatch function itself.I'm somewhat leaning to the second choice, but perhaps someone has
a better idea, or an argument against doing that.
Doesn't seem very modular. How about putting common code there but AM-specific code in each AM's directory? It would be nice if adding a new AM meant mostly adding a new directory, not much touching the common code.
...Robert
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Robert Haas <robertmhaas@gmail.com> writes:
On Jan 16, 2016, at 11:13 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
There are a couple of things we could do instead:
* Put each amvalidate function into its own file (but probably keep it
in the same directory as now). This is a reasonable response to
points #1 and #2 but isn't very much help for #3.* Collect the amvalidate functions into one file, which then leaves
us wondering where to put that; surely not under any one AM's directory.
A new file in src/backend/access/index/ is one plausible solution.
This file would also be a reasonable place to put the amvalidate()
dispatch function itself.I'm somewhat leaning to the second choice, but perhaps someone has
a better idea, or an argument against doing that.
Doesn't seem very modular. How about putting common code there but AM-specific code in each AM's directory? It would be nice if adding a new AM meant mostly adding a new directory, not much touching the common code.
Then we're going to end up with option A; and I suspect that we'll never
bother with factoring out any common code, because it won't be worth the
notational trouble if it involves common code that's in a different file
in a different directory.
As for modularity, nobody's moaned particularly about the amcostestimate
functions all being in selfuncs.c. It all depends on what you think is
"modular".
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On January 16, 2016 6:32:47 PM GMT+01:00, Tom Lane <tgl@sss.pgh.pa.us> wrote:
As for modularity, nobody's moaned particularly about the
amcostestimate
functions all being in selfuncs.c. It all depends on what you think is
"modular".
Well, back then you couldn't really have a production grade indeed as an extension. With this were getting pretty close to being able to do that for a bunch of useful indexes.
Andres
---
Please excuse brevity and formatting - I am writing this on my mobile phone.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sat, Jan 16, 2016 at 9:43 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Alexander Korotkov <a.korotkov@postgrespro.ru> writes:
[ aminterface-13.patch ]
I've started to review this. There are a bunch of cosmetic things I don't
like, notably the include-file nesting you've chosen, but they're fixable.
One item that I think could use some discussion is where to put the new
amvalidate functions. I don't especially like your choice to drop them
into nbtree.c, gist.c, etc, for a couple of reasons:1. These aren't really at the same semantic level as functions like
btinsert or btgettuple; they're not part of the implementation of an
index, and indeed are *users* of indexes (at least of the catalog
indexes).2. This approach substantially bloats the #include lists for the
relevant files, which again is a token of the validate functions not
belonging where they were put.3. There's probably room to share code across the different validators;
but this design isn't very amenable to that.A comparison point worth noting is that the amcostestimate functions
are in more or less the same boat: they aren't part of the index
implementation in any meaningful way, but are really part of the
planner instead. Those are all in selfuncs.c, not under backend/access
at all.There are a couple of things we could do instead:
* Put each amvalidate function into its own file (but probably keep it
in the same directory as now). This is a reasonable response to
points #1 and #2 but isn't very much help for #3.
Shouldn't we try to move amhandler function as well along with
amvalidate? I think moving each am's handler and validate into
am specific new file can make this arrangement closer to what
we have for PL's (ex. we have plpgsql_validator and plpgsql_call_
handler in pl_handler.c and similar handler and validator functions
for other languages in their corresponding modules).
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com
Amit Kapila <amit.kapila16@gmail.com> writes:
Shouldn't we try to move amhandler function as well along with
amvalidate? I think moving each am's handler and validate into
am specific new file can make this arrangement closer to what
we have for PL's (ex. we have plpgsql_validator and plpgsql_call_
handler in pl_handler.c and similar handler and validator functions
for other languages in their corresponding modules).
I feel no great need to move the amhandler functions, and if we did,
I would not want to put them into the same files as the amvalidate
functions. As I said before, the latter are appendages to the AMs
that really don't have anything to do with the core index access code.
They require very different sets of #include files, for instance.
So I see the AMs as containing three separate subsets of code:
core index access/maintenance, amcostestimate, and amvalidate.
The second and third really need to be in separate files because of
#include footprint considerations, but the amhandler function can
perfectly well go in with the first group.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Alexander Korotkov <a.korotkov@postgrespro.ru> writes:
[ aminterface-13.patch ]
I've committed this after some rather significant rework, not all of
it cosmetic in nature. For example, the patch fell over under
CLOBBER_CACHE_ALWAYS (planner failing to copy data out of relcache
entries that might not survive long) and on 32-bit machines (failure
to fix index_getbitmap API properly). I might've missed some other
portability issues; we'll see what the buildfarm says.
The amvalidate functions could do with quite a bit more work in the
long run. For now, they more or less replace the queries we had to
remove from opr_sanity, but I'd like to see almost all of what
opr_sanity does with opclasses get pushed down, so that these functions
can provide a test facility for extensions' opclasses. That does not
need to hold up adoption of the patch, though.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sat, Jan 16, 2016 at 12:32 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Then we're going to end up with option A; and I suspect that we'll never
bother with factoring out any common code, because it won't be worth the
notational trouble if it involves common code that's in a different file
in a different directory.
Since when is sharing code across files in different directories even
an iota more difficult than sharing code across files in the same
directory?
Sharing code across multiple files is only slightly more difficult
than sharing it within a file. You just have to create a header file
in the appropriate place and stick the necessary declarations in
there. I'll admit that's some work, but it's not usually very much.
After that, where the header gets included from really makes no
difference.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers