summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Eisentraut2025-02-27 16:03:31 +0000
committerPeter Eisentraut2025-02-27 16:03:31 +0000
commitce62f2f2a0a48d021f250ba84dfcab5d45ddc914 (patch)
treedd73a4a521f961961ce8c991363b3425e9e4741d
parent6eb8a1a4f90c542d7ce9dcc381528fcb81390ab9 (diff)
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 <[email protected]> Discussion: https://www.postgresql.org/message-id/flat/[email protected]
-rw-r--r--contrib/bloom/blutils.c2
-rw-r--r--doc/src/sgml/indexam.sgml4
-rw-r--r--src/backend/access/brin/brin.c2
-rw-r--r--src/backend/access/gin/ginutil.c2
-rw-r--r--src/backend/access/gist/gist.c2
-rw-r--r--src/backend/access/hash/hash.c2
-rw-r--r--src/backend/access/nbtree/nbtree.c2
-rw-r--r--src/backend/access/spgist/spgutils.c2
-rw-r--r--src/backend/commands/opclasscmds.c34
-rw-r--r--src/backend/executor/nodeIndexscan.c4
-rw-r--r--src/backend/utils/cache/lsyscache.c8
-rw-r--r--src/include/access/amapi.h4
-rw-r--r--src/test/modules/dummy_index_am/dummy_index_am.c2
-rw-r--r--src/test/regress/expected/alter_generic.out6
14 files changed, 50 insertions, 26 deletions
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;