mirror of https://github.com/postgres/postgres
This patch reduces pg_am to just two columns, a name and a handler function. All the data formerly obtained from pg_am is now provided in a C struct returned by the handler function. This is similar to the designs we've adopted for FDWs and tablesample methods. There are multiple advantages. For one, the index AM's support functions are now simple C functions, making them faster to call and much less error-prone, since the C compiler can now check function signatures. For another, this will make it far more practical to define index access methods in installable extensions. A disadvantage is that SQL-level code can no longer see attributes of index AMs; in particular, some of the crosschecks in the opr_sanity regression test are no longer possible from SQL. We've addressed that by adding a facility for the index AM to perform such checks instead. (Much more could be done in that line, but for now we're content if the amvalidate functions more or less replace what opr_sanity used to do.) We might also want to expose some sort of reporting functionality, but this patch doesn't do that. Alexander Korotkov, reviewed by Petr Jelínek, and rather heavily editorialized on by me.pull/10/head
parent
8d290c8ec6
commit
65c5fcd353
@ -0,0 +1,152 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* brin_validate.c |
||||
* Opclass validator for BRIN. |
||||
* |
||||
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* IDENTIFICATION |
||||
* src/backend/access/brin/brin_validate.c |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#include "postgres.h" |
||||
|
||||
#include "access/brin_internal.h" |
||||
#include "access/htup_details.h" |
||||
#include "catalog/pg_amop.h" |
||||
#include "catalog/pg_amproc.h" |
||||
#include "catalog/pg_opclass.h" |
||||
#include "utils/catcache.h" |
||||
#include "utils/syscache.h" |
||||
|
||||
|
||||
/*
|
||||
* Validator for a BRIN opclass. |
||||
*/ |
||||
bool |
||||
brinvalidate(Oid opclassoid) |
||||
{ |
||||
HeapTuple classtup; |
||||
Form_pg_opclass classform; |
||||
Oid opfamilyoid; |
||||
Oid opcintype; |
||||
int numclassops; |
||||
int32 classfuncbits; |
||||
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; |
||||
opcintype = classform->opcintype; |
||||
|
||||
ReleaseSysCache(classtup); |
||||
|
||||
/* Fetch all operators and support functions of the opfamily */ |
||||
oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid)); |
||||
proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid)); |
||||
|
||||
/* We'll track the ops and functions belonging to the named opclass */ |
||||
numclassops = 0; |
||||
classfuncbits = 0; |
||||
|
||||
/* Check support functions */ |
||||
for (i = 0; i < proclist->n_members; i++) |
||||
{ |
||||
HeapTuple proctup = &proclist->members[i]->tuple; |
||||
Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup); |
||||
|
||||
/* Check that only allowed procedure numbers exist */ |
||||
if (procform->amprocnum < 1 || |
||||
procform->amprocnum > BRIN_LAST_OPTIONAL_PROCNUM) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("brin opfamily %u contains invalid support number %d for procedure %u", |
||||
opfamilyoid, |
||||
procform->amprocnum, procform->amproc))); |
||||
|
||||
/* Remember functions that are specifically for the named opclass */ |
||||
if (procform->amproclefttype == opcintype && |
||||
procform->amprocrighttype == opcintype) |
||||
classfuncbits |= (1 << procform->amprocnum); |
||||
} |
||||
|
||||
/* Check operators */ |
||||
for (i = 0; i < oprlist->n_members; i++) |
||||
{ |
||||
HeapTuple oprtup = &oprlist->members[i]->tuple; |
||||
Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup); |
||||
bool found = false; |
||||
|
||||
/* TODO: Check that only allowed strategy numbers exist */ |
||||
if (oprform->amopstrategy < 1) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("brin opfamily %u contains invalid strategy number %d for operator %u", |
||||
opfamilyoid, |
||||
oprform->amopstrategy, oprform->amopopr))); |
||||
|
||||
/* TODO: check more thoroughly for missing support functions */ |
||||
for (j = 0; j < proclist->n_members; j++) |
||||
{ |
||||
HeapTuple proctup = &proclist->members[j]->tuple; |
||||
Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup); |
||||
|
||||
/* note only the operator's lefttype matters */ |
||||
if (procform->amproclefttype == oprform->amoplefttype && |
||||
procform->amprocrighttype == oprform->amoplefttype) |
||||
{ |
||||
found = true; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!found) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("brin opfamily %u lacks support function for operator %u", |
||||
opfamilyoid, oprform->amopopr))); |
||||
|
||||
/* brin doesn't support ORDER BY operators */ |
||||
if (oprform->amoppurpose != AMOP_SEARCH || |
||||
OidIsValid(oprform->amopsortfamily)) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("brin opfamily %u contains invalid ORDER BY specification for operator %u", |
||||
opfamilyoid, oprform->amopopr))); |
||||
|
||||
/* Count operators that are specifically for the named opclass */ |
||||
if (oprform->amoplefttype == opcintype && |
||||
oprform->amoprighttype == opcintype) |
||||
numclassops++; |
||||
} |
||||
|
||||
/* Check that the named opclass is complete */ |
||||
if (numclassops == 0) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("brin opclass %u is missing operator(s)", |
||||
opclassoid))); |
||||
for (i = 1; i <= BRIN_MANDATORY_NPROCS; i++) |
||||
{ |
||||
if ((classfuncbits & (1 << i)) != 0) |
||||
continue; /* got it */ |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("brin opclass %u is missing required support function %d", |
||||
opclassoid, i))); |
||||
} |
||||
|
||||
ReleaseCatCacheList(proclist); |
||||
ReleaseCatCacheList(oprlist); |
||||
|
||||
return true; |
||||
} |
@ -0,0 +1,145 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* ginvalidate.c |
||||
* Opclass validator for GIN. |
||||
* |
||||
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* IDENTIFICATION |
||||
* src/backend/access/gin/ginvalidate.c |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#include "postgres.h" |
||||
|
||||
#include "access/gin_private.h" |
||||
#include "access/htup_details.h" |
||||
#include "catalog/pg_amop.h" |
||||
#include "catalog/pg_amproc.h" |
||||
#include "catalog/pg_opclass.h" |
||||
#include "utils/catcache.h" |
||||
#include "utils/syscache.h" |
||||
|
||||
|
||||
/*
|
||||
* Validator for a GIN opclass. |
||||
*/ |
||||
bool |
||||
ginvalidate(Oid opclassoid) |
||||
{ |
||||
HeapTuple classtup; |
||||
Form_pg_opclass classform; |
||||
Oid opfamilyoid; |
||||
Oid opcintype; |
||||
int numclassops; |
||||
int32 classfuncbits; |
||||
CatCList *proclist, |
||||
*oprlist; |
||||
int i; |
||||
|
||||
/* Fetch opclass information */ |
||||
classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid)); |
||||
if (!HeapTupleIsValid(classtup)) |
||||
elog(ERROR, "cache lookup failed for operator class %u", opclassoid); |
||||
classform = (Form_pg_opclass) GETSTRUCT(classtup); |
||||
|
||||
opfamilyoid = classform->opcfamily; |
||||
opcintype = classform->opcintype; |
||||
|
||||
ReleaseSysCache(classtup); |
||||
|
||||
/* Fetch all operators and support functions of the opfamily */ |
||||
oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid)); |
||||
proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid)); |
||||
|
||||
/* We'll track the ops and functions belonging to the named opclass */ |
||||
numclassops = 0; |
||||
classfuncbits = 0; |
||||
|
||||
/* Check support functions */ |
||||
for (i = 0; i < proclist->n_members; i++) |
||||
{ |
||||
HeapTuple proctup = &proclist->members[i]->tuple; |
||||
Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup); |
||||
|
||||
/* Check that only allowed procedure numbers exist */ |
||||
if (procform->amprocnum < 1 || |
||||
procform->amprocnum > GINNProcs) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("gin opfamily %u contains invalid support number %d for procedure %u", |
||||
opfamilyoid, |
||||
procform->amprocnum, procform->amproc))); |
||||
|
||||
/* Remember functions that are specifically for the named opclass */ |
||||
if (procform->amproclefttype == opcintype && |
||||
procform->amprocrighttype == opcintype) |
||||
classfuncbits |= (1 << procform->amprocnum); |
||||
} |
||||
|
||||
/* Check operators */ |
||||
for (i = 0; i < oprlist->n_members; i++) |
||||
{ |
||||
HeapTuple oprtup = &oprlist->members[i]->tuple; |
||||
Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup); |
||||
|
||||
/* TODO: Check that only allowed strategy numbers exist */ |
||||
if (oprform->amopstrategy < 1) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("gin opfamily %u contains invalid strategy number %d for operator %u", |
||||
opfamilyoid, |
||||
oprform->amopstrategy, oprform->amopopr))); |
||||
|
||||
/* gin doesn't support ORDER BY operators */ |
||||
if (oprform->amoppurpose != AMOP_SEARCH || |
||||
OidIsValid(oprform->amopsortfamily)) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("gin opfamily %u contains invalid ORDER BY specification for operator %u", |
||||
opfamilyoid, oprform->amopopr))); |
||||
|
||||
/* Count operators that are specifically for the named opclass */ |
||||
if (oprform->amoplefttype == opcintype && |
||||
oprform->amoprighttype == opcintype) |
||||
numclassops++; |
||||
} |
||||
|
||||
/* Check that the named opclass is complete */ |
||||
|
||||
/* XXX needs work: we need to detect applicability of ANYARRAY operators */ |
||||
#ifdef NOT_USED |
||||
if (numclassops == 0) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("gin opclass %u is missing operator(s)", |
||||
opclassoid))); |
||||
#endif |
||||
|
||||
for (i = 1; i <= GINNProcs; i++) |
||||
{ |
||||
if ((classfuncbits & (1 << i)) != 0) |
||||
continue; /* got it */ |
||||
if (i == GIN_COMPARE_PARTIAL_PROC) |
||||
continue; /* optional method */ |
||||
if (i == GIN_CONSISTENT_PROC || i == GIN_TRICONSISTENT_PROC) |
||||
continue; /* don't need to have both, see check below
|
||||
* loop */ |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("gin opclass %u is missing required support function %d", |
||||
opclassoid, i))); |
||||
} |
||||
if ((classfuncbits & (1 << GIN_CONSISTENT_PROC)) == 0 && |
||||
(classfuncbits & (1 << GIN_TRICONSISTENT_PROC)) == 0) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("gin opclass %u is missing required support function", |
||||
opclassoid))); |
||||
|
||||
ReleaseCatCacheList(proclist); |
||||
ReleaseCatCacheList(oprlist); |
||||
|
||||
return true; |
||||
} |
@ -0,0 +1,133 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* gistvalidate.c |
||||
* Opclass validator for GiST. |
||||
* |
||||
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* IDENTIFICATION |
||||
* src/backend/access/gist/gistvalidate.c |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#include "postgres.h" |
||||
|
||||
#include "access/gist_private.h" |
||||
#include "access/htup_details.h" |
||||
#include "catalog/pg_amop.h" |
||||
#include "catalog/pg_amproc.h" |
||||
#include "catalog/pg_opclass.h" |
||||
#include "utils/catcache.h" |
||||
#include "utils/syscache.h" |
||||
|
||||
|
||||
/*
|
||||
* Validator for a GiST opclass. |
||||
*/ |
||||
bool |
||||
gistvalidate(Oid opclassoid) |
||||
{ |
||||
HeapTuple classtup; |
||||
Form_pg_opclass classform; |
||||
Oid opfamilyoid; |
||||
Oid opcintype; |
||||
int numclassops; |
||||
int32 classfuncbits; |
||||
CatCList *proclist, |
||||
*oprlist; |
||||
int i; |
||||
|
||||
/* Fetch opclass information */ |
||||
classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid)); |
||||
if (!HeapTupleIsValid(classtup)) |
||||
elog(ERROR, "cache lookup failed for operator class %u", opclassoid); |
||||
classform = (Form_pg_opclass) GETSTRUCT(classtup); |
||||
|
||||
opfamilyoid = classform->opcfamily; |
||||
opcintype = classform->opcintype; |
||||
|
||||
ReleaseSysCache(classtup); |
||||
|
||||
/* Fetch all operators and support functions of the opfamily */ |
||||
oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid)); |
||||
proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid)); |
||||
|
||||
/* We'll track the ops and functions belonging to the named opclass */ |
||||
numclassops = 0; |
||||
classfuncbits = 0; |
||||
|
||||
/* Check support functions */ |
||||
for (i = 0; i < proclist->n_members; i++) |
||||
{ |
||||
HeapTuple proctup = &proclist->members[i]->tuple; |
||||
Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup); |
||||
|
||||
/* Check that only allowed procedure numbers exist */ |
||||
if (procform->amprocnum < 1 || |
||||
procform->amprocnum > GISTNProcs) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("gist opfamily %u contains invalid support number %d for procedure %u", |
||||
opfamilyoid, |
||||
procform->amprocnum, procform->amproc))); |
||||
|
||||
/* Remember functions that are specifically for the named opclass */ |
||||
if (procform->amproclefttype == opcintype && |
||||
procform->amprocrighttype == opcintype) |
||||
classfuncbits |= (1 << procform->amprocnum); |
||||
} |
||||
|
||||
/* Check operators */ |
||||
for (i = 0; i < oprlist->n_members; i++) |
||||
{ |
||||
HeapTuple oprtup = &oprlist->members[i]->tuple; |
||||
Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup); |
||||
|
||||
/* TODO: Check that only allowed strategy numbers exist */ |
||||
if (oprform->amopstrategy < 1) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("gist opfamily %u contains invalid strategy number %d for operator %u", |
||||
opfamilyoid, |
||||
oprform->amopstrategy, oprform->amopopr))); |
||||
|
||||
/* GiST supports ORDER BY operators, but must have distance proc */ |
||||
if (oprform->amoppurpose != AMOP_SEARCH && |
||||
oprform->amoplefttype == opcintype && |
||||
oprform->amoprighttype == opcintype && |
||||
(classfuncbits & (1 << GIST_DISTANCE_PROC)) == 0) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("gist opfamily %u contains unsupported ORDER BY specification for operator %u", |
||||
opfamilyoid, oprform->amopopr))); |
||||
|
||||
/* Count operators that are specifically for the named opclass */ |
||||
/* XXX we consider only lefttype here */ |
||||
if (oprform->amoplefttype == opcintype) |
||||
numclassops++; |
||||
} |
||||
|
||||
/* Check that the named opclass is complete */ |
||||
if (numclassops == 0) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("gist opclass %u is missing operator(s)", |
||||
opclassoid))); |
||||
for (i = 1; i <= GISTNProcs; i++) |
||||
{ |
||||
if ((classfuncbits & (1 << i)) != 0) |
||||
continue; /* got it */ |
||||
if (i == GIST_DISTANCE_PROC || i == GIST_FETCH_PROC) |
||||
continue; /* optional methods */ |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("gist opclass %u is missing required support function %d", |
||||
opclassoid, i))); |
||||
} |
||||
|
||||
ReleaseCatCacheList(proclist); |
||||
ReleaseCatCacheList(oprlist); |
||||
|
||||
return true; |
||||
} |
@ -0,0 +1,157 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* hashvalidate.c |
||||
* Opclass validator for hash. |
||||
* |
||||
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* IDENTIFICATION |
||||
* src/backend/access/hash/hashvalidate.c |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#include "postgres.h" |
||||
|
||||
#include "access/hash.h" |
||||
#include "access/htup_details.h" |
||||
#include "catalog/pg_amop.h" |
||||
#include "catalog/pg_amproc.h" |
||||
#include "catalog/pg_opclass.h" |
||||
#include "utils/builtins.h" |
||||
#include "utils/catcache.h" |
||||
#include "utils/syscache.h" |
||||
|
||||
|
||||
/*
|
||||
* Validator for a hash opclass. |
||||
* |
||||
* Some of the checks done here cover the whole opfamily, and therefore are |
||||
* redundant when checking each opclass in a family. But they don't run long |
||||
* enough to be much of a problem, so we accept the duplication rather than |
||||
* complicate the amvalidate API. |
||||
* |
||||
* Some of the code here relies on the fact that hash has only one operator |
||||
* strategy and support function; we don't have to check for incomplete sets. |
||||
*/ |
||||
bool |
||||
hashvalidate(Oid opclassoid) |
||||
{ |
||||
HeapTuple classtup; |
||||
Form_pg_opclass classform; |
||||
Oid opfamilyoid; |
||||
Oid opcintype; |
||||
int numclassops; |
||||
int32 classfuncbits; |
||||
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; |
||||
opcintype = classform->opcintype; |
||||
|
||||
ReleaseSysCache(classtup); |
||||
|
||||
/* Fetch all operators and support functions of the opfamily */ |
||||
oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid)); |
||||
proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid)); |
||||
|
||||
/* We'll track the ops and functions belonging to the named opclass */ |
||||
numclassops = 0; |
||||
classfuncbits = 0; |
||||
|
||||
/* Check support functions */ |
||||
for (i = 0; i < proclist->n_members; i++) |
||||
{ |
||||
HeapTuple proctup = &proclist->members[i]->tuple; |
||||
Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup); |
||||
|
||||
/* Check that only allowed procedure numbers exist */ |
||||
if (procform->amprocnum != HASHPROC) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("hash opfamily %u contains invalid support number %d for procedure %u", |
||||
opfamilyoid, |
||||
procform->amprocnum, procform->amproc))); |
||||
|
||||
/* Remember functions that are specifically for the named opclass */ |
||||
if (procform->amproclefttype == opcintype && |
||||
procform->amprocrighttype == opcintype) |
||||
classfuncbits |= (1 << procform->amprocnum); |
||||
} |
||||
|
||||
/* Check operators */ |
||||
for (i = 0; i < oprlist->n_members; i++) |
||||
{ |
||||
HeapTuple oprtup = &oprlist->members[i]->tuple; |
||||
Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup); |
||||
bool leftFound = false, |
||||
rightFound = false; |
||||
|
||||
/* Check that only allowed strategy numbers exist */ |
||||
if (oprform->amopstrategy < 1 || |
||||
oprform->amopstrategy > HTMaxStrategyNumber) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("hash opfamily %u contains invalid strategy number %d for operator %u", |
||||
opfamilyoid, |
||||
oprform->amopstrategy, oprform->amopopr))); |
||||
|
||||
/*
|
||||
* There should be relevant hash procedures for each 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("hash opfamily %u lacks support function for operator %u", |
||||
opfamilyoid, oprform->amopopr))); |
||||
|
||||
/* hash doesn't support ORDER BY operators */ |
||||
if (oprform->amoppurpose != AMOP_SEARCH || |
||||
OidIsValid(oprform->amopsortfamily)) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("hash opfamily %u contains invalid ORDER BY specification for operator %u", |
||||
opfamilyoid, oprform->amopopr))); |
||||
|
||||
/* Count operators that are specifically for the named opclass */ |
||||
if (oprform->amoplefttype == opcintype && |
||||
oprform->amoprighttype == opcintype) |
||||
numclassops++; |
||||
} |
||||
|
||||
/* Check that the named opclass is complete */ |
||||
if (numclassops != HTMaxStrategyNumber) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("hash opclass %u is missing operator(s)", |
||||
opclassoid))); |
||||
if ((classfuncbits & (1 << HASHPROC)) == 0) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("hash opclass %u is missing required support function", |
||||
opclassoid))); |
||||
|
||||
ReleaseCatCacheList(proclist); |
||||
ReleaseCatCacheList(oprlist); |
||||
|
||||
return true; |
||||
} |
@ -0,0 +1,114 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* amapi.c |
||||
* Support routines for API for Postgres index access methods. |
||||
* |
||||
* Copyright (c) 2015-2016, PostgreSQL Global Development Group |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* src/backend/access/index/amapi.c |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#include "postgres.h" |
||||
|
||||
#include "access/amapi.h" |
||||
#include "access/htup_details.h" |
||||
#include "catalog/pg_am.h" |
||||
#include "catalog/pg_opclass.h" |
||||
#include "utils/syscache.h" |
||||
|
||||
|
||||
/*
|
||||
* GetIndexAmRoutine - call the specified access method handler routine to get |
||||
* its IndexAmRoutine struct, which will be palloc'd in the caller's context. |
||||
* |
||||
* Note that if the amhandler function is built-in, this will not involve |
||||
* any catalog access. It's therefore safe to use this while bootstrapping |
||||
* indexes for the system catalogs. relcache.c relies on that. |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
/*
|
||||
* GetIndexAmRoutineByAmId - look up the handler of the index access method |
||||
* with the given OID, and get its IndexAmRoutine struct. |
||||
*/ |
||||
IndexAmRoutine * |
||||
GetIndexAmRoutineByAmId(Oid amoid) |
||||
{ |
||||
HeapTuple tuple; |
||||
Form_pg_am amform; |
||||
regproc amhandler; |
||||
|
||||
/* 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 to get the API struct. */ |
||||
return GetIndexAmRoutine(amhandler); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* Ask appropriate access method to validate the specified opclass. |
||||
*/ |
||||
Datum |
||||
amvalidate(PG_FUNCTION_ARGS) |
||||
{ |
||||
Oid opclassoid = PG_GETARG_OID(0); |
||||
bool result; |
||||
HeapTuple classtup; |
||||
Form_pg_opclass classform; |
||||
Oid 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); |
||||
|
||||
amoid = classform->opcmethod; |
||||
|
||||
ReleaseSysCache(classtup); |
||||
|
||||
amroutine = GetIndexAmRoutineByAmId(amoid); |
||||
|
||||
if (amroutine->amvalidate == NULL) |
||||
elog(ERROR, "function amvalidate is not defined for index access method %u", |
||||
amoid); |
||||
|
||||
result = amroutine->amvalidate(opclassoid); |
||||
|
||||
pfree(amroutine); |
||||
|
||||
PG_RETURN_BOOL(result); |
||||
} |
@ -0,0 +1,204 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* nbtvalidate.c |
||||
* Opclass validator for btree. |
||||
* |
||||
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* IDENTIFICATION |
||||
* src/backend/access/nbtree/nbtvalidate.c |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#include "postgres.h" |
||||
|
||||
#include "access/htup_details.h" |
||||
#include "access/nbtree.h" |
||||
#include "catalog/pg_amop.h" |
||||
#include "catalog/pg_amproc.h" |
||||
#include "catalog/pg_opclass.h" |
||||
#include "utils/builtins.h" |
||||
#include "utils/catcache.h" |
||||
#include "utils/syscache.h" |
||||
|
||||
|
||||
/*
|
||||
* Validator for a btree opclass. |
||||
* |
||||
* Some of the checks done here cover the whole opfamily, and therefore are |
||||
* redundant when checking each opclass in a family. But they don't run long |
||||
* enough to be much of a problem, so we accept the duplication rather than |
||||
* complicate the amvalidate API. |
||||
*/ |
||||
bool |
||||
btvalidate(Oid opclassoid) |
||||
{ |
||||
HeapTuple classtup; |
||||
Form_pg_opclass classform; |
||||
Oid opfamilyoid; |
||||
Oid opcintype; |
||||
int numclassops; |
||||
int32 classfuncbits; |
||||
CatCList *proclist, |
||||
*oprlist; |
||||
Oid lastlefttype, |
||||
lastrighttype; |
||||
int numOps; |
||||
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; |
||||
opcintype = classform->opcintype; |
||||
|
||||
ReleaseSysCache(classtup); |
||||
|
||||
/* Fetch all operators and support functions of the opfamily */ |
||||
oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid)); |
||||
proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid)); |
||||
|
||||
/* We rely on the oprlist to be ordered */ |
||||
if (!oprlist->ordered) |
||||
elog(ERROR, "cannot validate btree opclass without ordered data"); |
||||
|
||||
/* We'll track the ops and functions belonging to the named opclass */ |
||||
numclassops = 0; |
||||
classfuncbits = 0; |
||||
|
||||
/* Check support functions */ |
||||
for (i = 0; i < proclist->n_members; i++) |
||||
{ |
||||
HeapTuple proctup = &proclist->members[i]->tuple; |
||||
Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup); |
||||
|
||||
/* Check that only allowed procedure numbers exist */ |
||||
if (procform->amprocnum != BTORDER_PROC && |
||||
procform->amprocnum != BTSORTSUPPORT_PROC) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("btree opfamily %u contains invalid support number %d for procedure %u", |
||||
opfamilyoid, |
||||
procform->amprocnum, procform->amproc))); |
||||
|
||||
/* Remember functions that are specifically for the named opclass */ |
||||
if (procform->amproclefttype == opcintype && |
||||
procform->amprocrighttype == opcintype) |
||||
classfuncbits |= (1 << procform->amprocnum); |
||||
} |
||||
|
||||
/* Check operators */ |
||||
lastlefttype = lastrighttype = InvalidOid; |
||||
numOps = 0; |
||||
for (i = 0; i < oprlist->n_members; i++) |
||||
{ |
||||
HeapTuple oprtup = &oprlist->members[i]->tuple; |
||||
Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup); |
||||
|
||||
/* Check that only allowed strategy numbers exist */ |
||||
if (oprform->amopstrategy < 1 || |
||||
oprform->amopstrategy > BTMaxStrategyNumber) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("btree opfamily %u contains invalid strategy number %d for operator %u", |
||||
opfamilyoid, |
||||
oprform->amopstrategy, oprform->amopopr))); |
||||
|
||||
/*
|
||||
* Check that we have all strategies for each supported datatype |
||||
* combination. This is easy since the list will be sorted in |
||||
* datatype order and there can't be duplicate strategy numbers. |
||||
*/ |
||||
if (oprform->amoplefttype == lastlefttype && |
||||
oprform->amoprighttype == lastrighttype) |
||||
numOps++; |
||||
else |
||||
{ |
||||
/* reached a group boundary, so check ... */ |
||||
if (numOps > 0 && numOps != BTMaxStrategyNumber) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("btree opfamily %u has a partial set of operators for datatypes %s and %s", |
||||
opfamilyoid, |
||||
format_type_be(lastlefttype), |
||||
format_type_be(lastrighttype)))); |
||||
/* ... and reset for new group */ |
||||
lastlefttype = oprform->amoplefttype; |
||||
lastrighttype = oprform->amoprighttype; |
||||
numOps = 1; |
||||
} |
||||
|
||||
/*
|
||||
* There should be a relevant support function for each operator, but |
||||
* we only need to check this once per pair of datatypes. |
||||
*/ |
||||
if (numOps == 1) |
||||
{ |
||||
bool found = false; |
||||
|
||||
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; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!found) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("btree opfamily %u lacks support function for operator %u", |
||||
opfamilyoid, oprform->amopopr))); |
||||
} |
||||
|
||||
/* btree doesn't support ORDER BY operators */ |
||||
if (oprform->amoppurpose != AMOP_SEARCH || |
||||
OidIsValid(oprform->amopsortfamily)) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("btree opfamily %u contains invalid ORDER BY specification for operator %u", |
||||
opfamilyoid, oprform->amopopr))); |
||||
|
||||
/* Count operators that are specifically for the named opclass */ |
||||
if (oprform->amoplefttype == opcintype && |
||||
oprform->amoprighttype == opcintype) |
||||
numclassops++; |
||||
} |
||||
|
||||
/* don't forget to check the last batch of operators for completeness */ |
||||
if (numOps > 0 && numOps != BTMaxStrategyNumber) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("btree opfamily %u has a partial set of operators for datatypes %s and %s", |
||||
opfamilyoid, |
||||
format_type_be(lastlefttype), |
||||
format_type_be(lastrighttype)))); |
||||
|
||||
/* Check that the named opclass is complete */ |
||||
if (numclassops != BTMaxStrategyNumber) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("btree opclass %u is missing operator(s)", |
||||
opclassoid))); |
||||
if ((classfuncbits & (1 << BTORDER_PROC)) == 0) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("btree opclass %u is missing required support function", |
||||
opclassoid))); |
||||
|
||||
ReleaseCatCacheList(proclist); |
||||
ReleaseCatCacheList(oprlist); |
||||
|
||||
return true; |
||||
} |
@ -0,0 +1,129 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* spgvalidate.c |
||||
* Opclass validator for SP-GiST. |
||||
* |
||||
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* IDENTIFICATION |
||||
* src/backend/access/spgist/spgvalidate.c |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#include "postgres.h" |
||||
|
||||
#include "access/htup_details.h" |
||||
#include "access/spgist_private.h" |
||||
#include "catalog/pg_amop.h" |
||||
#include "catalog/pg_amproc.h" |
||||
#include "catalog/pg_opclass.h" |
||||
#include "utils/catcache.h" |
||||
#include "utils/syscache.h" |
||||
|
||||
|
||||
/*
|
||||
* Validator for an SP-GiST opclass. |
||||
*/ |
||||
bool |
||||
spgvalidate(Oid opclassoid) |
||||
{ |
||||
HeapTuple classtup; |
||||
Form_pg_opclass classform; |
||||
Oid opfamilyoid; |
||||
Oid opcintype; |
||||
int numclassops; |
||||
int32 classfuncbits; |
||||
CatCList *proclist, |
||||
*oprlist; |
||||
int i; |
||||
|
||||
/* Fetch opclass information */ |
||||
classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid)); |
||||
if (!HeapTupleIsValid(classtup)) |
||||
elog(ERROR, "cache lookup failed for operator class %u", opclassoid); |
||||
classform = (Form_pg_opclass) GETSTRUCT(classtup); |
||||
|
||||
opfamilyoid = classform->opcfamily; |
||||
opcintype = classform->opcintype; |
||||
|
||||
ReleaseSysCache(classtup); |
||||
|
||||
/* Fetch all operators and support functions of the opfamily */ |
||||
oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid)); |
||||
proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid)); |
||||
|
||||
/* We'll track the ops and functions belonging to the named opclass */ |
||||
numclassops = 0; |
||||
classfuncbits = 0; |
||||
|
||||
/* Check support functions */ |
||||
for (i = 0; i < proclist->n_members; i++) |
||||
{ |
||||
HeapTuple proctup = &proclist->members[i]->tuple; |
||||
Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup); |
||||
|
||||
/* Check that only allowed procedure numbers exist */ |
||||
if (procform->amprocnum < 1 || |
||||
procform->amprocnum > SPGISTNProc) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("spgist opfamily %u contains invalid support number %d for procedure %u", |
||||
opfamilyoid, |
||||
procform->amprocnum, procform->amproc))); |
||||
|
||||
/* Remember functions that are specifically for the named opclass */ |
||||
if (procform->amproclefttype == opcintype && |
||||
procform->amprocrighttype == opcintype) |
||||
classfuncbits |= (1 << procform->amprocnum); |
||||
} |
||||
|
||||
/* Check operators */ |
||||
for (i = 0; i < oprlist->n_members; i++) |
||||
{ |
||||
HeapTuple oprtup = &oprlist->members[i]->tuple; |
||||
Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup); |
||||
|
||||
/* TODO: Check that only allowed strategy numbers exist */ |
||||
if (oprform->amopstrategy < 1) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("spgist opfamily %u contains invalid strategy number %d for operator %u", |
||||
opfamilyoid, |
||||
oprform->amopstrategy, oprform->amopopr))); |
||||
|
||||
/* spgist doesn't support ORDER BY operators */ |
||||
if (oprform->amoppurpose != AMOP_SEARCH || |
||||
OidIsValid(oprform->amopsortfamily)) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("spgist opfamily %u contains invalid ORDER BY specification for operator %u", |
||||
opfamilyoid, oprform->amopopr))); |
||||
|
||||
/* Count operators that are specifically for the named opclass */ |
||||
if (oprform->amoplefttype == opcintype && |
||||
oprform->amoprighttype == opcintype) |
||||
numclassops++; |
||||
} |
||||
|
||||
/* Check that the named opclass is complete */ |
||||
if (numclassops == 0) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("spgist opclass %u is missing operator(s)", |
||||
opclassoid))); |
||||
for (i = 1; i <= SPGISTNProc; i++) |
||||
{ |
||||
if ((classfuncbits & (1 << i)) != 0) |
||||
continue; /* got it */ |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("spgist opclass %u is missing required support function %d", |
||||
opclassoid, i))); |
||||
} |
||||
|
||||
ReleaseCatCacheList(proclist); |
||||
ReleaseCatCacheList(oprlist); |
||||
|
||||
return true; |
||||
} |
@ -0,0 +1,174 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* amapi.h |
||||
* API for Postgres index access methods. |
||||
* |
||||
* Copyright (c) 2015-2016, PostgreSQL Global Development Group |
||||
* |
||||
* src/include/access/amapi.h |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#ifndef AMAPI_H |
||||
#define AMAPI_H |
||||
|
||||
#include "access/genam.h" |
||||
|
||||
/*
|
||||
* We don't wish to include planner header files here, since most of an index |
||||
* AM's implementation isn't concerned with those data structures. To allow |
||||
* declaring amcostestimate_function here, use forward struct references. |
||||
*/ |
||||
struct PlannerInfo; |
||||
struct IndexPath; |
||||
|
||||
/* Likewise, this file shouldn't depend on execnodes.h. */ |
||||
struct IndexInfo; |
||||
|
||||
|
||||
/*
|
||||
* Callback function signatures --- see indexam.sgml for more info. |
||||
*/ |
||||
|
||||
/* build new index */ |
||||
typedef IndexBuildResult *(*ambuild_function) (Relation heapRelation, |
||||
Relation indexRelation, |
||||
struct IndexInfo *indexInfo); |
||||
|
||||
/* build empty index */ |
||||
typedef void (*ambuildempty_function) (Relation indexRelation); |
||||
|
||||
/* insert this tuple */ |
||||
typedef bool (*aminsert_function) (Relation indexRelation, |
||||
Datum *values, |
||||
bool *isnull, |
||||
ItemPointer heap_tid, |
||||
Relation heapRelation, |
||||
IndexUniqueCheck checkUnique); |
||||
|
||||
/* bulk delete */ |
||||
typedef IndexBulkDeleteResult *(*ambulkdelete_function) (IndexVacuumInfo *info, |
||||
IndexBulkDeleteResult *stats, |
||||
IndexBulkDeleteCallback callback, |
||||
void *callback_state); |
||||
|
||||
/* post-VACUUM cleanup */ |
||||
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) (struct PlannerInfo *root, |
||||
struct IndexPath *path, |
||||
double loop_count, |
||||
Cost *indexStartupCost, |
||||
Cost *indexTotalCost, |
||||
Selectivity *indexSelectivity, |
||||
double *indexCorrelation); |
||||
|
||||
/* parse index reloptions */ |
||||
typedef bytea *(*amoptions_function) (Datum reloptions, |
||||
bool validate); |
||||
|
||||
/* validate definition of an opclass for this AM */ |
||||
typedef bool (*amvalidate_function) (Oid opclassoid); |
||||
|
||||
/* prepare for index scan */ |
||||
typedef IndexScanDesc (*ambeginscan_function) (Relation indexRelation, |
||||
int nkeys, |
||||
int norderbys); |
||||
|
||||
/* (re)start index scan */ |
||||
typedef void (*amrescan_function) (IndexScanDesc scan, |
||||
ScanKey keys, |
||||
int nkeys, |
||||
ScanKey orderbys, |
||||
int norderbys); |
||||
|
||||
/* next valid tuple */ |
||||
typedef bool (*amgettuple_function) (IndexScanDesc scan, |
||||
ScanDirection direction); |
||||
|
||||
/* fetch all valid tuples */ |
||||
typedef int64 (*amgetbitmap_function) (IndexScanDesc scan, |
||||
TIDBitmap *tbm); |
||||
|
||||
/* end index scan */ |
||||
typedef void (*amendscan_function) (IndexScanDesc scan); |
||||
|
||||
/* mark current scan position */ |
||||
typedef void (*ammarkpos_function) (IndexScanDesc scan); |
||||
|
||||
/* restore marked scan position */ |
||||
typedef void (*amrestrpos_function) (IndexScanDesc scan); |
||||
|
||||
|
||||
/*
|
||||
* API struct for an index AM. Note this must be stored in a single palloc'd |
||||
* chunk of memory. |
||||
*/ |
||||
typedef 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. |
||||
*/ |
||||
uint16 amstrategies; |
||||
/* total number of support functions that this AM uses */ |
||||
uint16 amsupport; |
||||
/* does AM support ORDER BY indexed column's value? */ |
||||
bool amcanorder; |
||||
/* does AM support ORDER BY result of an operator on indexed column? */ |
||||
bool amcanorderbyop; |
||||
/* does AM support backward scanning? */ |
||||
bool amcanbackward; |
||||
/* does AM support UNIQUE indexes? */ |
||||
bool amcanunique; |
||||
/* does AM support multi-column indexes? */ |
||||
bool amcanmulticol; |
||||
/* does AM require scans to have a constraint on the first index column? */ |
||||
bool amoptionalkey; |
||||
/* does AM handle ScalarArrayOpExpr quals? */ |
||||
bool amsearcharray; |
||||
/* does AM handle IS NULL/IS NOT NULL quals? */ |
||||
bool amsearchnulls; |
||||
/* can index storage data type differ from column data type? */ |
||||
bool amstorage; |
||||
/* can an index of this type be clustered on? */ |
||||
bool amclusterable; |
||||
/* does AM handle predicate locks? */ |
||||
bool ampredlocks; |
||||
/* type of data stored in index, or InvalidOid if variable */ |
||||
Oid amkeytype; |
||||
|
||||
/* interface functions */ |
||||
ambuild_function ambuild; |
||||
ambuildempty_function ambuildempty; |
||||
aminsert_function aminsert; |
||||
ambulkdelete_function ambulkdelete; |
||||
amvacuumcleanup_function amvacuumcleanup; |
||||
amcanreturn_function amcanreturn; /* can be NULL */ |
||||
amcostestimate_function amcostestimate; |
||||
amoptions_function amoptions; |
||||
amvalidate_function amvalidate; |
||||
ambeginscan_function ambeginscan; |
||||
amrescan_function amrescan; |
||||
amgettuple_function amgettuple; /* can be NULL */ |
||||
amgetbitmap_function amgetbitmap; /* can be NULL */ |
||||
amendscan_function amendscan; |
||||
ammarkpos_function ammarkpos; /* can be NULL */ |
||||
amrestrpos_function amrestrpos; /* can be NULL */ |
||||
} IndexAmRoutine; |
||||
|
||||
|
||||
/* Functions in access/index/amapi.c */ |
||||
extern IndexAmRoutine *GetIndexAmRoutine(Oid amhandler); |
||||
extern IndexAmRoutine *GetIndexAmRoutineByAmId(Oid amoid); |
||||
|
||||
extern Datum amvalidate(PG_FUNCTION_ARGS); |
||||
|
||||
#endif /* AMAPI_H */ |
@ -0,0 +1,68 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* index_selfuncs.h |
||||
* Index cost estimation functions for standard index access methods. |
||||
* |
||||
* |
||||
* Note: this is split out of selfuncs.h mainly to avoid importing all of the |
||||
* planner's data structures into the non-planner parts of the index AMs. |
||||
* If you make it depend on anything besides access/amapi.h, that's likely |
||||
* a mistake. |
||||
* |
||||
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* src/include/utils/index_selfuncs.h |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#ifndef INDEX_SELFUNCS_H |
||||
#define INDEX_SELFUNCS_H |
||||
|
||||
#include "access/amapi.h" |
||||
|
||||
/* Functions in selfuncs.c */ |
||||
extern void brincostestimate(struct PlannerInfo *root, |
||||
struct IndexPath *path, |
||||
double loop_count, |
||||
Cost *indexStartupCost, |
||||
Cost *indexTotalCost, |
||||
Selectivity *indexSelectivity, |
||||
double *indexCorrelation); |
||||
extern void btcostestimate(struct PlannerInfo *root, |
||||
struct IndexPath *path, |
||||
double loop_count, |
||||
Cost *indexStartupCost, |
||||
Cost *indexTotalCost, |
||||
Selectivity *indexSelectivity, |
||||
double *indexCorrelation); |
||||
extern void hashcostestimate(struct PlannerInfo *root, |
||||
struct IndexPath *path, |
||||
double loop_count, |
||||
Cost *indexStartupCost, |
||||
Cost *indexTotalCost, |
||||
Selectivity *indexSelectivity, |
||||
double *indexCorrelation); |
||||
extern void gistcostestimate(struct PlannerInfo *root, |
||||
struct IndexPath *path, |
||||
double loop_count, |
||||
Cost *indexStartupCost, |
||||
Cost *indexTotalCost, |
||||
Selectivity *indexSelectivity, |
||||
double *indexCorrelation); |
||||
extern void spgcostestimate(struct PlannerInfo *root, |
||||
struct IndexPath *path, |
||||
double loop_count, |
||||
Cost *indexStartupCost, |
||||
Cost *indexTotalCost, |
||||
Selectivity *indexSelectivity, |
||||
double *indexCorrelation); |
||||
extern void gincostestimate(struct PlannerInfo *root, |
||||
struct IndexPath *path, |
||||
double loop_count, |
||||
Cost *indexStartupCost, |
||||
Cost *indexTotalCost, |
||||
Selectivity *indexSelectivity, |
||||
double *indexCorrelation); |
||||
|
||||
#endif /* INDEX_SELFUNCS_H */ |
Loading…
Reference in new issue