Generalize hash and ordering support in amapi
authorPeter Eisentraut <peter@eisentraut.org>
Thu, 27 Feb 2025 16:03:31 +0000 (17:03 +0100)
committerPeter Eisentraut <peter@eisentraut.org>
Thu, 27 Feb 2025 16:03:31 +0000 (17:03 +0100)
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

14 files changed:
contrib/bloom/blutils.c
doc/src/sgml/indexam.sgml
src/backend/access/brin/brin.c
src/backend/access/gin/ginutil.c
src/backend/access/gist/gist.c
src/backend/access/hash/hash.c
src/backend/access/nbtree/nbtree.c
src/backend/access/spgist/spgutils.c
src/backend/commands/opclasscmds.c
src/backend/executor/nodeIndexscan.c
src/backend/utils/cache/lsyscache.c
src/include/access/amapi.h
src/test/modules/dummy_index_am/dummy_index_am.c
src/test/regress/expected/alter_generic.out

index 04b61042a579ae53158249801f3f72dd17bcf29b..c901e9427204515862834de06997bfbfb8b8f714 100644 (file)
@@ -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;
index d17fcbd5cec53b9421bb564bb73aa928d77c9584..c50ba60e21c1c211dae55d5a9ffe356cb508da47 100644 (file)
@@ -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? */
index 60320440fc56cd1650e29c2b0ad2d191ce2239e3..75a65ec9c75a949d8a7fa90304fdabe069334587 100644 (file)
@@ -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;
index 1f9e58c4f1fb8f122446c8fe88eeb199ece61e3b..5b643619754bb5d2007c4811d6f7a8f833cec9a6 100644 (file)
@@ -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;
index 4d858b65e1e9455027c4d4823ebb61a3a6e588af..5482925a0f39db9b5e3ec15e36e47a01eb0b9c90 100644 (file)
@@ -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;
index b24aae415ea0f2d4c0dff0ca89a847a55df91d32..a22845d70680210a02850bd80ed8c60ec6d1b25a 100644 (file)
@@ -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;
index 411d5ac0b5f761b8252b2e6d5fba0d9fe4f03b5e..45ea6afba1db57e845c8de561cb24b25f7b10798 100644 (file)
@@ -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;
index 367c36ef9afe3661b4e4ada001da24bd27f7e3e9..7e56b1e6b95de95d04c36f8737db98dc10a398a7 100644 (file)
@@ -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;
index 2c325badf94336e5fd76eb6368a9cfb6f00358ce..8546366ee06c23f73db3460fce939946742b95e6 100644 (file)
@@ -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)
        {
index 3b2275e8fe9d4a27dcea7cf868618c5dee7169b8..c30b9c2c197700aea981341d8f40586c3d4bcc4e 100644 (file)
@@ -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];
index bcfa5cb4add01e22070bb26a82e5e5daf4f656f9..7bd476f3de70c10395574e6716f2881e117ad37f 100644 (file)
@@ -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))
            {
index fbe6b225ec935f61e8109e1242a620a4accef09e..bf729a1e4ae845a01175f013fff39d76947897f0 100644 (file)
@@ -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? */
index 7586f8ae5e1e2fd6ef864514e355182041aba369..c83954ad11da0abd4cf2ce2dcef6e2ae1d2b559f 100644 (file)
@@ -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;
index ae54cb254f9089a838be1b8bddba929581d42edb..0c274d56a04da3c084dc74f776738bbac5621af4 100644 (file)
@@ -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;