mirror of
https://github.com/postgres/postgres.git
synced 2025-06-14 18:42:34 +03:00
Generalize hash and ordering support in amapi
Stop comparing access method OID values against HASH_AM_OID and BTREE_AM_OID, and instead check the IndexAmRoutine for an index to see if it advertises its ability to perform the necessary ordering, hashing, or cross-type comparing functionality. A field amcanorder already existed, this uses it more widely. Fields amcanhash and amcancrosscompare are added for the other purposes. Author: Mark Dilger <mark.dilger@enterprisedb.com> Discussion: https://www.postgresql.org/message-id/flat/E72EAA49-354D-4C2E-8EB9-255197F55330@enterprisedb.com
This commit is contained in:
@ -109,6 +109,8 @@ blhandler(PG_FUNCTION_ARGS)
|
|||||||
amroutine->amoptsprocnum = BLOOM_OPTIONS_PROC;
|
amroutine->amoptsprocnum = BLOOM_OPTIONS_PROC;
|
||||||
amroutine->amcanorder = false;
|
amroutine->amcanorder = false;
|
||||||
amroutine->amcanorderbyop = false;
|
amroutine->amcanorderbyop = false;
|
||||||
|
amroutine->amcanhash = false;
|
||||||
|
amroutine->amcancrosscompare = false;
|
||||||
amroutine->amcanbackward = false;
|
amroutine->amcanbackward = false;
|
||||||
amroutine->amcanunique = false;
|
amroutine->amcanunique = false;
|
||||||
amroutine->amcanmulticol = true;
|
amroutine->amcanmulticol = true;
|
||||||
|
@ -103,6 +103,10 @@ typedef struct IndexAmRoutine
|
|||||||
bool amcanorder;
|
bool amcanorder;
|
||||||
/* does AM support ORDER BY result of an operator on indexed column? */
|
/* does AM support ORDER BY result of an operator on indexed column? */
|
||||||
bool amcanorderbyop;
|
bool amcanorderbyop;
|
||||||
|
/* does AM support hashing using API consistent with the hash AM? */
|
||||||
|
bool amcanhash;
|
||||||
|
/* does AM support cross-type comparisons? */
|
||||||
|
bool amcancrosscompare;
|
||||||
/* does AM support backward scanning? */
|
/* does AM support backward scanning? */
|
||||||
bool amcanbackward;
|
bool amcanbackward;
|
||||||
/* does AM support UNIQUE indexes? */
|
/* does AM support UNIQUE indexes? */
|
||||||
|
@ -256,6 +256,8 @@ brinhandler(PG_FUNCTION_ARGS)
|
|||||||
amroutine->amoptsprocnum = BRIN_PROCNUM_OPTIONS;
|
amroutine->amoptsprocnum = BRIN_PROCNUM_OPTIONS;
|
||||||
amroutine->amcanorder = false;
|
amroutine->amcanorder = false;
|
||||||
amroutine->amcanorderbyop = false;
|
amroutine->amcanorderbyop = false;
|
||||||
|
amroutine->amcanhash = false;
|
||||||
|
amroutine->amcancrosscompare = false;
|
||||||
amroutine->amcanbackward = false;
|
amroutine->amcanbackward = false;
|
||||||
amroutine->amcanunique = false;
|
amroutine->amcanunique = false;
|
||||||
amroutine->amcanmulticol = true;
|
amroutine->amcanmulticol = true;
|
||||||
|
@ -43,6 +43,8 @@ ginhandler(PG_FUNCTION_ARGS)
|
|||||||
amroutine->amoptsprocnum = GIN_OPTIONS_PROC;
|
amroutine->amoptsprocnum = GIN_OPTIONS_PROC;
|
||||||
amroutine->amcanorder = false;
|
amroutine->amcanorder = false;
|
||||||
amroutine->amcanorderbyop = false;
|
amroutine->amcanorderbyop = false;
|
||||||
|
amroutine->amcanhash = false;
|
||||||
|
amroutine->amcancrosscompare = false;
|
||||||
amroutine->amcanbackward = false;
|
amroutine->amcanbackward = false;
|
||||||
amroutine->amcanunique = false;
|
amroutine->amcanunique = false;
|
||||||
amroutine->amcanmulticol = true;
|
amroutine->amcanmulticol = true;
|
||||||
|
@ -65,6 +65,8 @@ gisthandler(PG_FUNCTION_ARGS)
|
|||||||
amroutine->amoptsprocnum = GIST_OPTIONS_PROC;
|
amroutine->amoptsprocnum = GIST_OPTIONS_PROC;
|
||||||
amroutine->amcanorder = false;
|
amroutine->amcanorder = false;
|
||||||
amroutine->amcanorderbyop = true;
|
amroutine->amcanorderbyop = true;
|
||||||
|
amroutine->amcanhash = false;
|
||||||
|
amroutine->amcancrosscompare = false;
|
||||||
amroutine->amcanbackward = false;
|
amroutine->amcanbackward = false;
|
||||||
amroutine->amcanunique = false;
|
amroutine->amcanunique = false;
|
||||||
amroutine->amcanmulticol = true;
|
amroutine->amcanmulticol = true;
|
||||||
|
@ -64,6 +64,8 @@ hashhandler(PG_FUNCTION_ARGS)
|
|||||||
amroutine->amoptsprocnum = HASHOPTIONS_PROC;
|
amroutine->amoptsprocnum = HASHOPTIONS_PROC;
|
||||||
amroutine->amcanorder = false;
|
amroutine->amcanorder = false;
|
||||||
amroutine->amcanorderbyop = false;
|
amroutine->amcanorderbyop = false;
|
||||||
|
amroutine->amcanhash = true;
|
||||||
|
amroutine->amcancrosscompare = false;
|
||||||
amroutine->amcanbackward = true;
|
amroutine->amcanbackward = true;
|
||||||
amroutine->amcanunique = false;
|
amroutine->amcanunique = false;
|
||||||
amroutine->amcanmulticol = false;
|
amroutine->amcanmulticol = false;
|
||||||
|
@ -107,6 +107,8 @@ bthandler(PG_FUNCTION_ARGS)
|
|||||||
amroutine->amoptsprocnum = BTOPTIONS_PROC;
|
amroutine->amoptsprocnum = BTOPTIONS_PROC;
|
||||||
amroutine->amcanorder = true;
|
amroutine->amcanorder = true;
|
||||||
amroutine->amcanorderbyop = false;
|
amroutine->amcanorderbyop = false;
|
||||||
|
amroutine->amcanhash = false;
|
||||||
|
amroutine->amcancrosscompare = true;
|
||||||
amroutine->amcanbackward = true;
|
amroutine->amcanbackward = true;
|
||||||
amroutine->amcanunique = true;
|
amroutine->amcanunique = true;
|
||||||
amroutine->amcanmulticol = true;
|
amroutine->amcanmulticol = true;
|
||||||
|
@ -50,6 +50,8 @@ spghandler(PG_FUNCTION_ARGS)
|
|||||||
amroutine->amoptsprocnum = SPGIST_OPTIONS_PROC;
|
amroutine->amoptsprocnum = SPGIST_OPTIONS_PROC;
|
||||||
amroutine->amcanorder = false;
|
amroutine->amcanorder = false;
|
||||||
amroutine->amcanorderbyop = true;
|
amroutine->amcanorderbyop = true;
|
||||||
|
amroutine->amcanhash = false;
|
||||||
|
amroutine->amcancrosscompare = false;
|
||||||
amroutine->amcanbackward = false;
|
amroutine->amcanbackward = false;
|
||||||
amroutine->amcanunique = false;
|
amroutine->amcanunique = false;
|
||||||
amroutine->amcanmulticol = false;
|
amroutine->amcanmulticol = false;
|
||||||
|
@ -1242,25 +1242,25 @@ assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* btree comparison procs must be 2-arg procs returning int4. btree
|
* Ordering comparison procs must be 2-arg procs returning int4. Ordering
|
||||||
* sortsupport procs must take internal and return void. btree in_range
|
* sortsupport procs must take internal and return void. Ordering
|
||||||
* procs must be 5-arg procs returning bool. btree equalimage procs must
|
* in_range procs must be 5-arg procs returning bool. Ordering equalimage
|
||||||
* take 1 arg and return bool. hash support proc 1 must be a 1-arg proc
|
* procs must take 1 arg and return bool. Hashing support proc 1 must be
|
||||||
* returning int4, while proc 2 must be a 2-arg proc returning int8.
|
* a 1-arg proc returning int4, while proc 2 must be a 2-arg proc
|
||||||
* Otherwise we don't know.
|
* returning int8. Otherwise we don't know.
|
||||||
*/
|
*/
|
||||||
else if (amoid == BTREE_AM_OID)
|
else if (GetIndexAmRoutineByAmId(amoid, false)->amcanorder)
|
||||||
{
|
{
|
||||||
if (member->number == BTORDER_PROC)
|
if (member->number == BTORDER_PROC)
|
||||||
{
|
{
|
||||||
if (procform->pronargs != 2)
|
if (procform->pronargs != 2)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
errmsg("btree comparison functions must have two arguments")));
|
errmsg("ordering comparison functions must have two arguments")));
|
||||||
if (procform->prorettype != INT4OID)
|
if (procform->prorettype != INT4OID)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
errmsg("btree comparison functions must return integer")));
|
errmsg("ordering comparison functions must return integer")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If lefttype/righttype isn't specified, use the proc's input
|
* If lefttype/righttype isn't specified, use the proc's input
|
||||||
@ -1277,11 +1277,11 @@ assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid,
|
|||||||
procform->proargtypes.values[0] != INTERNALOID)
|
procform->proargtypes.values[0] != INTERNALOID)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
errmsg("btree sort support functions must accept type \"internal\"")));
|
errmsg("ordering sort support functions must accept type \"internal\"")));
|
||||||
if (procform->prorettype != VOIDOID)
|
if (procform->prorettype != VOIDOID)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
errmsg("btree sort support functions must return void")));
|
errmsg("ordering sort support functions must return void")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Can't infer lefttype/righttype from proc, so use default rule
|
* Can't infer lefttype/righttype from proc, so use default rule
|
||||||
@ -1292,11 +1292,11 @@ assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid,
|
|||||||
if (procform->pronargs != 5)
|
if (procform->pronargs != 5)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
errmsg("btree in_range functions must have five arguments")));
|
errmsg("ordering in_range functions must have five arguments")));
|
||||||
if (procform->prorettype != BOOLOID)
|
if (procform->prorettype != BOOLOID)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
errmsg("btree in_range functions must return boolean")));
|
errmsg("ordering in_range functions must return boolean")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If lefttype/righttype isn't specified, use the proc's input
|
* If lefttype/righttype isn't specified, use the proc's input
|
||||||
@ -1312,11 +1312,11 @@ assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid,
|
|||||||
if (procform->pronargs != 1)
|
if (procform->pronargs != 1)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
errmsg("btree equal image functions must have one argument")));
|
errmsg("ordering equal image functions must have one argument")));
|
||||||
if (procform->prorettype != BOOLOID)
|
if (procform->prorettype != BOOLOID)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
errmsg("btree equal image functions must return boolean")));
|
errmsg("ordering equal image functions must return boolean")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pg_amproc functions are indexed by (lefttype, righttype), but
|
* pg_amproc functions are indexed by (lefttype, righttype), but
|
||||||
@ -1329,10 +1329,10 @@ assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid,
|
|||||||
if (member->lefttype != member->righttype)
|
if (member->lefttype != member->righttype)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
errmsg("btree equal image functions must not be cross-type")));
|
errmsg("ordering equal image functions must not be cross-type")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (amoid == HASH_AM_OID)
|
else if (GetIndexAmRoutineByAmId(amoid, false)->amcanhash)
|
||||||
{
|
{
|
||||||
if (member->number == HASHSTANDARD_PROC)
|
if (member->number == HASHSTANDARD_PROC)
|
||||||
{
|
{
|
||||||
|
@ -1331,10 +1331,10 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
|
|||||||
varattno = ((Var *) leftop)->varattno;
|
varattno = ((Var *) leftop)->varattno;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have to look up the operator's associated btree support
|
* We have to look up the operator's associated support
|
||||||
* function
|
* function
|
||||||
*/
|
*/
|
||||||
if (index->rd_rel->relam != BTREE_AM_OID ||
|
if (!index->rd_indam->amcanorder ||
|
||||||
varattno < 1 || varattno > indnkeyatts)
|
varattno < 1 || varattno > indnkeyatts)
|
||||||
elog(ERROR, "bogus RowCompare index qualification");
|
elog(ERROR, "bogus RowCompare index qualification");
|
||||||
opfamily = index->rd_opfamily[varattno - 1];
|
opfamily = index->rd_opfamily[varattno - 1];
|
||||||
|
8
src/backend/utils/cache/lsyscache.c
vendored
8
src/backend/utils/cache/lsyscache.c
vendored
@ -716,10 +716,9 @@ equality_ops_are_compatible(Oid opno1, Oid opno2)
|
|||||||
{
|
{
|
||||||
HeapTuple op_tuple = &catlist->members[i]->tuple;
|
HeapTuple op_tuple = &catlist->members[i]->tuple;
|
||||||
Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
|
Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
|
||||||
|
IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false);
|
||||||
|
|
||||||
/* must be btree or hash */
|
if (amroutine->amcancrosscompare)
|
||||||
if (op_form->amopmethod == BTREE_AM_OID ||
|
|
||||||
op_form->amopmethod == HASH_AM_OID)
|
|
||||||
{
|
{
|
||||||
if (op_in_opfamily(opno2, op_form->amopfamily))
|
if (op_in_opfamily(opno2, op_form->amopfamily))
|
||||||
{
|
{
|
||||||
@ -767,8 +766,9 @@ comparison_ops_are_compatible(Oid opno1, Oid opno2)
|
|||||||
{
|
{
|
||||||
HeapTuple op_tuple = &catlist->members[i]->tuple;
|
HeapTuple op_tuple = &catlist->members[i]->tuple;
|
||||||
Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
|
Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
|
||||||
|
IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false);
|
||||||
|
|
||||||
if (op_form->amopmethod == BTREE_AM_OID)
|
if (amroutine->amcanorder && amroutine->amcancrosscompare)
|
||||||
{
|
{
|
||||||
if (op_in_opfamily(opno2, op_form->amopfamily))
|
if (op_in_opfamily(opno2, op_form->amopfamily))
|
||||||
{
|
{
|
||||||
|
@ -243,6 +243,10 @@ typedef struct IndexAmRoutine
|
|||||||
bool amcanorder;
|
bool amcanorder;
|
||||||
/* does AM support ORDER BY result of an operator on indexed column? */
|
/* does AM support ORDER BY result of an operator on indexed column? */
|
||||||
bool amcanorderbyop;
|
bool amcanorderbyop;
|
||||||
|
/* does AM support hashing using API consistent with the hash AM? */
|
||||||
|
bool amcanhash;
|
||||||
|
/* does AM support cross-type comparisons? */
|
||||||
|
bool amcancrosscompare;
|
||||||
/* does AM support backward scanning? */
|
/* does AM support backward scanning? */
|
||||||
bool amcanbackward;
|
bool amcanbackward;
|
||||||
/* does AM support UNIQUE indexes? */
|
/* does AM support UNIQUE indexes? */
|
||||||
|
@ -282,6 +282,8 @@ dihandler(PG_FUNCTION_ARGS)
|
|||||||
amroutine->amsupport = 1;
|
amroutine->amsupport = 1;
|
||||||
amroutine->amcanorder = false;
|
amroutine->amcanorder = false;
|
||||||
amroutine->amcanorderbyop = false;
|
amroutine->amcanorderbyop = false;
|
||||||
|
amroutine->amcanhash = false;
|
||||||
|
amroutine->amcancrosscompare = false;
|
||||||
amroutine->amcanbackward = false;
|
amroutine->amcanbackward = false;
|
||||||
amroutine->amcanunique = false;
|
amroutine->amcanunique = false;
|
||||||
amroutine->amcanmulticol = false;
|
amroutine->amcanmulticol = false;
|
||||||
|
@ -420,7 +420,7 @@ BEGIN TRANSACTION;
|
|||||||
CREATE OPERATOR FAMILY alt_opf12 USING btree;
|
CREATE OPERATOR FAMILY alt_opf12 USING btree;
|
||||||
CREATE FUNCTION fn_opf12 (int4, int2) RETURNS BIGINT AS 'SELECT NULL::BIGINT;' LANGUAGE SQL;
|
CREATE FUNCTION fn_opf12 (int4, int2) RETURNS BIGINT AS 'SELECT NULL::BIGINT;' LANGUAGE SQL;
|
||||||
ALTER OPERATOR FAMILY alt_opf12 USING btree ADD FUNCTION 1 fn_opf12(int4, int2);
|
ALTER OPERATOR FAMILY alt_opf12 USING btree ADD FUNCTION 1 fn_opf12(int4, int2);
|
||||||
ERROR: btree comparison functions must return integer
|
ERROR: ordering comparison functions must return integer
|
||||||
DROP OPERATOR FAMILY alt_opf12 USING btree;
|
DROP OPERATOR FAMILY alt_opf12 USING btree;
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
@ -438,7 +438,7 @@ BEGIN TRANSACTION;
|
|||||||
CREATE OPERATOR FAMILY alt_opf14 USING btree;
|
CREATE OPERATOR FAMILY alt_opf14 USING btree;
|
||||||
CREATE FUNCTION fn_opf14 (int4) RETURNS BIGINT AS 'SELECT NULL::BIGINT;' LANGUAGE SQL;
|
CREATE FUNCTION fn_opf14 (int4) RETURNS BIGINT AS 'SELECT NULL::BIGINT;' LANGUAGE SQL;
|
||||||
ALTER OPERATOR FAMILY alt_opf14 USING btree ADD FUNCTION 1 fn_opf14(int4);
|
ALTER OPERATOR FAMILY alt_opf14 USING btree ADD FUNCTION 1 fn_opf14(int4);
|
||||||
ERROR: btree comparison functions must have two arguments
|
ERROR: ordering comparison functions must have two arguments
|
||||||
DROP OPERATOR FAMILY alt_opf14 USING btree;
|
DROP OPERATOR FAMILY alt_opf14 USING btree;
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
@ -504,7 +504,7 @@ ALTER OPERATOR FAMILY alt_opf18 USING btree ADD
|
|||||||
-- Should fail. Not allowed to have cross-type equalimage function.
|
-- Should fail. Not allowed to have cross-type equalimage function.
|
||||||
ALTER OPERATOR FAMILY alt_opf18 USING btree
|
ALTER OPERATOR FAMILY alt_opf18 USING btree
|
||||||
ADD FUNCTION 4 (int4, int2) btequalimage(oid);
|
ADD FUNCTION 4 (int4, int2) btequalimage(oid);
|
||||||
ERROR: btree equal image functions must not be cross-type
|
ERROR: ordering equal image functions must not be cross-type
|
||||||
ALTER OPERATOR FAMILY alt_opf18 USING btree DROP FUNCTION 2 (int4, int4);
|
ALTER OPERATOR FAMILY alt_opf18 USING btree DROP FUNCTION 2 (int4, int4);
|
||||||
ERROR: function 2(integer,integer) does not exist in operator family "alt_opf18"
|
ERROR: function 2(integer,integer) does not exist in operator family "alt_opf18"
|
||||||
DROP OPERATOR FAMILY alt_opf18 USING btree;
|
DROP OPERATOR FAMILY alt_opf18 USING btree;
|
||||||
|
Reference in New Issue
Block a user