diff --git a/contrib/bloom/blutils.c b/contrib/bloom/blutils.c index 04b61042a57..c901e942720 100644 --- a/contrib/bloom/blutils.c +++ b/contrib/bloom/blutils.c @@ -109,6 +109,8 @@ blhandler(PG_FUNCTION_ARGS) amroutine->amoptsprocnum = BLOOM_OPTIONS_PROC; amroutine->amcanorder = false; amroutine->amcanorderbyop = false; + amroutine->amcanhash = false; + amroutine->amcancrosscompare = false; amroutine->amcanbackward = false; amroutine->amcanunique = false; amroutine->amcanmulticol = true; diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml index d17fcbd5cec..c50ba60e21c 100644 --- a/doc/src/sgml/indexam.sgml +++ b/doc/src/sgml/indexam.sgml @@ -103,6 +103,10 @@ typedef struct IndexAmRoutine bool amcanorder; /* does AM support ORDER BY result of an operator on indexed column? */ 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? */ bool amcanbackward; /* does AM support UNIQUE indexes? */ diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 60320440fc5..75a65ec9c75 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -256,6 +256,8 @@ brinhandler(PG_FUNCTION_ARGS) amroutine->amoptsprocnum = BRIN_PROCNUM_OPTIONS; amroutine->amcanorder = false; amroutine->amcanorderbyop = false; + amroutine->amcanhash = false; + amroutine->amcancrosscompare = false; amroutine->amcanbackward = false; amroutine->amcanunique = false; amroutine->amcanmulticol = true; diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c index 1f9e58c4f1f..5b643619754 100644 --- a/src/backend/access/gin/ginutil.c +++ b/src/backend/access/gin/ginutil.c @@ -43,6 +43,8 @@ ginhandler(PG_FUNCTION_ARGS) amroutine->amoptsprocnum = GIN_OPTIONS_PROC; amroutine->amcanorder = false; amroutine->amcanorderbyop = false; + amroutine->amcanhash = false; + amroutine->amcancrosscompare = false; amroutine->amcanbackward = false; amroutine->amcanunique = false; amroutine->amcanmulticol = true; diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index 4d858b65e1e..5482925a0f3 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -65,6 +65,8 @@ gisthandler(PG_FUNCTION_ARGS) amroutine->amoptsprocnum = GIST_OPTIONS_PROC; amroutine->amcanorder = false; amroutine->amcanorderbyop = true; + amroutine->amcanhash = false; + amroutine->amcancrosscompare = false; amroutine->amcanbackward = false; amroutine->amcanunique = false; amroutine->amcanmulticol = true; diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c index b24aae415ea..a22845d7068 100644 --- a/src/backend/access/hash/hash.c +++ b/src/backend/access/hash/hash.c @@ -64,6 +64,8 @@ hashhandler(PG_FUNCTION_ARGS) amroutine->amoptsprocnum = HASHOPTIONS_PROC; amroutine->amcanorder = false; amroutine->amcanorderbyop = false; + amroutine->amcanhash = true; + amroutine->amcancrosscompare = false; amroutine->amcanbackward = true; amroutine->amcanunique = false; amroutine->amcanmulticol = false; diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 411d5ac0b5f..45ea6afba1d 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -107,6 +107,8 @@ bthandler(PG_FUNCTION_ARGS) amroutine->amoptsprocnum = BTOPTIONS_PROC; amroutine->amcanorder = true; amroutine->amcanorderbyop = false; + amroutine->amcanhash = false; + amroutine->amcancrosscompare = true; amroutine->amcanbackward = true; amroutine->amcanunique = true; amroutine->amcanmulticol = true; diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c index 367c36ef9af..7e56b1e6b95 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -50,6 +50,8 @@ spghandler(PG_FUNCTION_ARGS) amroutine->amoptsprocnum = SPGIST_OPTIONS_PROC; amroutine->amcanorder = false; amroutine->amcanorderbyop = true; + amroutine->amcanhash = false; + amroutine->amcancrosscompare = false; amroutine->amcanbackward = false; amroutine->amcanunique = false; amroutine->amcanmulticol = false; diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c index 2c325badf94..8546366ee06 100644 --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -1242,25 +1242,25 @@ assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, } /* - * btree comparison procs must be 2-arg procs returning int4. btree - * sortsupport procs must take internal and return void. btree in_range - * procs must be 5-arg procs returning bool. btree equalimage procs must - * take 1 arg and return bool. hash support proc 1 must be a 1-arg proc - * returning int4, while proc 2 must be a 2-arg proc returning int8. - * Otherwise we don't know. + * Ordering comparison procs must be 2-arg procs returning int4. Ordering + * sortsupport procs must take internal and return void. Ordering + * in_range procs must be 5-arg procs returning bool. Ordering equalimage + * procs must take 1 arg and return bool. Hashing support proc 1 must be + * a 1-arg proc returning int4, while proc 2 must be a 2-arg proc + * 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 (procform->pronargs != 2) ereport(ERROR, (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) ereport(ERROR, (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 @@ -1277,11 +1277,11 @@ assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, procform->proargtypes.values[0] != INTERNALOID) ereport(ERROR, (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) ereport(ERROR, (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 @@ -1292,11 +1292,11 @@ assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, if (procform->pronargs != 5) ereport(ERROR, (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) ereport(ERROR, (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 @@ -1312,11 +1312,11 @@ assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, if (procform->pronargs != 1) ereport(ERROR, (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) ereport(ERROR, (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 @@ -1329,10 +1329,10 @@ assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, if (member->lefttype != member->righttype) ereport(ERROR, (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) { diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 3b2275e8fe9..c30b9c2c197 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -1331,10 +1331,10 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, 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 */ - if (index->rd_rel->relam != BTREE_AM_OID || + if (!index->rd_indam->amcanorder || varattno < 1 || varattno > indnkeyatts) elog(ERROR, "bogus RowCompare index qualification"); opfamily = index->rd_opfamily[varattno - 1]; diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index bcfa5cb4add..7bd476f3de7 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -716,10 +716,9 @@ equality_ops_are_compatible(Oid opno1, Oid opno2) { HeapTuple op_tuple = &catlist->members[i]->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 (op_form->amopmethod == BTREE_AM_OID || - op_form->amopmethod == HASH_AM_OID) + if (amroutine->amcancrosscompare) { 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; 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)) { diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h index fbe6b225ec9..bf729a1e4ae 100644 --- a/src/include/access/amapi.h +++ b/src/include/access/amapi.h @@ -243,6 +243,10 @@ typedef struct IndexAmRoutine bool amcanorder; /* does AM support ORDER BY result of an operator on indexed column? */ 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? */ bool amcanbackward; /* does AM support UNIQUE indexes? */ diff --git a/src/test/modules/dummy_index_am/dummy_index_am.c b/src/test/modules/dummy_index_am/dummy_index_am.c index 7586f8ae5e1..c83954ad11d 100644 --- a/src/test/modules/dummy_index_am/dummy_index_am.c +++ b/src/test/modules/dummy_index_am/dummy_index_am.c @@ -282,6 +282,8 @@ dihandler(PG_FUNCTION_ARGS) amroutine->amsupport = 1; amroutine->amcanorder = false; amroutine->amcanorderbyop = false; + amroutine->amcanhash = false; + amroutine->amcancrosscompare = false; amroutine->amcanbackward = false; amroutine->amcanunique = false; amroutine->amcanmulticol = false; diff --git a/src/test/regress/expected/alter_generic.out b/src/test/regress/expected/alter_generic.out index ae54cb254f9..0c274d56a04 100644 --- a/src/test/regress/expected/alter_generic.out +++ b/src/test/regress/expected/alter_generic.out @@ -420,7 +420,7 @@ BEGIN TRANSACTION; CREATE OPERATOR FAMILY alt_opf12 USING btree; 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); -ERROR: btree comparison functions must return integer +ERROR: ordering comparison functions must return integer DROP OPERATOR FAMILY alt_opf12 USING btree; ERROR: current transaction is aborted, commands ignored until end of transaction block ROLLBACK; @@ -438,7 +438,7 @@ BEGIN TRANSACTION; CREATE OPERATOR FAMILY alt_opf14 USING btree; 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); -ERROR: btree comparison functions must have two arguments +ERROR: ordering comparison functions must have two arguments DROP OPERATOR FAMILY alt_opf14 USING btree; ERROR: current transaction is aborted, commands ignored until end of transaction block ROLLBACK; @@ -504,7 +504,7 @@ ALTER OPERATOR FAMILY alt_opf18 USING btree ADD -- Should fail. Not allowed to have cross-type equalimage function. ALTER OPERATOR FAMILY alt_opf18 USING btree 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); ERROR: function 2(integer,integer) does not exist in operator family "alt_opf18" DROP OPERATOR FAMILY alt_opf18 USING btree;