And another small patch set extracted from the bigger one, to keep things moving along:

0001: Add get_opfamily_method() in lsyscache.c, from your patch set.

0002: Add get_opfamily_member_for_cmptype(). This was called get_opmethod_member() in your patch set, but I think that name wasn't quite right. I also removed the opmethod argument, which was rarely used and is somewhat redundant.

0003 and 0004 are enabling non-btree unique indexes for partition keys and materialized views. These were v21-0011 and v21-0012, except that I'm combining the switch from strategies to compare types (which was in v21-0006 or so) with the removal of the btree requirements.
From bca4cfd1b8837ced9b74a04267861cac8003fbc6 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Wed, 12 Mar 2025 13:45:39 +0100
Subject: [PATCH v21.2 1/4] Add get_opfamily_method()

---
 src/backend/utils/cache/lsyscache.c | 22 ++++++++++++++++++++++
 src/include/utils/lsyscache.h       |  1 +
 2 files changed, 23 insertions(+)

diff --git a/src/backend/utils/cache/lsyscache.c 
b/src/backend/utils/cache/lsyscache.c
index 80c5a3fcfb7..9f7c0315052 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -1288,6 +1288,28 @@ get_opclass_method(Oid opclass)
 
 /*                             ---------- OPFAMILY CACHE ----------            
                         */
 
+/*
+ * get_opfamily_method
+ *
+ *             Returns the OID of the index access method the opfamily is for.
+ */
+Oid
+get_opfamily_method(Oid opfid)
+{
+       HeapTuple       tp;
+       Form_pg_opfamily opfform;
+       Oid                             result;
+
+       tp = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
+       if (!HeapTupleIsValid(tp))
+               elog(ERROR, "cache lookup failed for operator family %u", 
opfid);
+       opfform = (Form_pg_opfamily) GETSTRUCT(tp);
+
+       result = opfform->opfmethod;
+       ReleaseSysCache(tp);
+       return result;
+}
+
 char *
 get_opfamily_name(Oid opfid, bool missing_ok)
 {
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 6fab7aa6009..271eac2f0e1 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -108,6 +108,7 @@ extern Oid  get_opclass_input_type(Oid opclass);
 extern bool get_opclass_opfamily_and_input_type(Oid opclass,
                                                                                
                Oid *opfamily, Oid *opcintype);
 extern Oid     get_opclass_method(Oid opclass);
+extern Oid     get_opfamily_method(Oid opfid);
 extern char *get_opfamily_name(Oid opfid, bool missing_ok);
 extern RegProcedure get_opcode(Oid opno);
 extern char *get_opname(Oid opno);
-- 
2.48.1

From d6788595aa64dbb8fe55703cfec1b9368fe3c245 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Wed, 12 Mar 2025 14:07:34 +0100
Subject: [PATCH v21.2 2/4] Add get_opfamily_member_for_cmptype()

---
 src/backend/utils/cache/lsyscache.c | 20 ++++++++++++++++++++
 src/include/utils/lsyscache.h       |  3 +++
 2 files changed, 23 insertions(+)

diff --git a/src/backend/utils/cache/lsyscache.c 
b/src/backend/utils/cache/lsyscache.c
index 9f7c0315052..2151d8d0915 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -184,6 +184,26 @@ get_opfamily_member(Oid opfamily, Oid lefttype, Oid 
righttype,
        return result;
 }
 
+/*
+ * get_opfamily_member_for_cmptype
+ *             Get the OID of the operator that implements the specified 
comparison
+ *             type with the specified datatypes for the specified opfamily.
+ *
+ * Returns InvalidOid if there is no pg_amop entry for the given keys.
+ */
+Oid
+get_opfamily_member_for_cmptype(Oid opfamily, Oid lefttype, Oid righttype,
+                                                               CompareType 
cmptype)
+{
+       Oid opmethod;
+       StrategyNumber  strategy;
+
+       opmethod = get_opfamily_method(opfamily);
+       strategy = IndexAmTranslateCompareType(cmptype, opmethod, opfamily, 
false);
+
+       return get_opfamily_member(opfamily, lefttype, righttype, strategy);
+}
+
 /*
  * get_ordering_op_properties
  *             Given the OID of an ordering operator (a btree "<" or ">" 
operator),
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 271eac2f0e1..d42380a0d46 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -14,6 +14,7 @@
 #define LSYSCACHE_H
 
 #include "access/attnum.h"
+#include "access/cmptype.h"
 #include "access/htup.h"
 #include "nodes/pg_list.h"
 
@@ -74,6 +75,8 @@ extern void get_op_opfamily_properties(Oid opno, Oid 
opfamily, bool ordering_op,
                                                                           Oid 
*righttype);
 extern Oid     get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
                                                                int16 strategy);
+extern Oid     get_opfamily_member_for_cmptype(Oid opfamily, Oid lefttype, Oid 
righttype,
+                                                                               
        CompareType cmptype);
 extern bool get_ordering_op_properties(Oid opno,
                                                                           Oid 
*opfamily, Oid *opcintype, int16 *strategy);
 extern Oid     get_equality_op_for_ordering_op(Oid opno, bool *reverse);
-- 
2.48.1

From 568884e11a6ec495b21dc71da458b3447f99156f Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Wed, 12 Mar 2025 14:37:05 +0100
Subject: [PATCH v21.2 3/4] Allow non-btree unique indexes for partition keys

We were rejecting non-btree indexes in some cases owing to the
inability to determine the equality operators for other index AMs;
that problem no longer exists, because we can look up the equality
operator using COMPARE_EQ.  The problem of not knowing the strategy
number for equality in other index AMs is already resolved.

Stop rejecting the indexes upfront, and instead reject any for which
the equality operator lookup fails.

Author: Mark Dilger <mark.dil...@enterprisedb.com>
---
 src/backend/commands/indexcmds.c | 30 ++++++++++++------------------
 1 file changed, 12 insertions(+), 18 deletions(-)

diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 32ff3ca9a28..9f4ab9dc1ee 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -1009,20 +1009,6 @@ DefineIndex(Oid tableId,
                                         eq_strategy, key->partopcintype[i], 
key->partopcintype[i],
                                         key->partopfamily[i]);
 
-                       /*
-                        * We'll need to be able to identify the equality 
operators
-                        * associated with index columns, too.  We know what to 
do with
-                        * btree opclasses; if there are ever any other index 
types that
-                        * support unique indexes, this logic will need 
extension. But if
-                        * we have an exclusion constraint (or a temporal PK), 
it already
-                        * knows the operators, so we don't have to infer them.
-                        */
-                       if (stmt->unique && !stmt->iswithoutoverlaps && 
accessMethodId != BTREE_AM_OID)
-                               ereport(ERROR,
-                                               
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                                errmsg("cannot match partition 
key to an index using access method \"%s\"",
-                                                               
accessMethodName)));
-
                        /*
                         * It may be possible to support UNIQUE constraints 
when partition
                         * keys are expressions, but is it worth it?  Give up 
for now.
@@ -1057,10 +1043,18 @@ DefineIndex(Oid tableId,
                                                Oid                     
idx_eqop = InvalidOid;
 
                                                if (stmt->unique && 
!stmt->iswithoutoverlaps)
-                                                       idx_eqop = 
get_opfamily_member(idx_opfamily,
-                                                                               
                                   idx_opcintype,
-                                                                               
                                   idx_opcintype,
-                                                                               
                                   BTEqualStrategyNumber);
+                                               {
+                                                       idx_eqop = 
get_opfamily_member_for_cmptype(idx_opfamily,
+                                                                               
                                                           idx_opcintype,
+                                                                               
                                                           idx_opcintype,
+                                                                               
                                                           COMPARE_EQ);
+                                                       if (!idx_eqop)
+                                                               ereport(ERROR,
+                                                                               
errcode(ERRCODE_UNDEFINED_OBJECT),
+                                                                               
errmsg("could not identify an equality operator for type %s", 
format_type_be(idx_opcintype)),
+                                                                               
errdetail("There is no suitable operator in operator family \"%s\" for access 
method \"%s\".",
+                                                                               
                  get_opfamily_name(idx_opfamily, false), 
get_am_name(get_opfamily_method(idx_opfamily))));
+                                               }
                                                else if (exclusion)
                                                        idx_eqop = 
indexInfo->ii_ExclusionOps[j];
                                                Assert(idx_eqop);
-- 
2.48.1

From d71eb8ce88b920b374e05fc4def38b39ed50fa6a Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Wed, 12 Mar 2025 14:15:36 +0100
Subject: [PATCH v21.2 4/4] Allow non-btree unique indexes for matviews

We were rejecting non-btree indexes in some cases owing to the
inability to determine the equality operators for other index AMs;
that problem no longer exists, because we can look up the equality
operator using COMPARE_EQ.

Stop rejecting these indexes, but instead rely on all unique indexes
having equality operators.  Unique indexes must have equality
operators.

Author: Mark Dilger <mark.dil...@enterprisedb.com>
---
 src/backend/commands/matview.c | 15 ++++-----------
 1 file changed, 4 insertions(+), 11 deletions(-)

diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
index 0bfbc5ca6dc..e7854add178 100644
--- a/src/backend/commands/matview.c
+++ b/src/backend/commands/matview.c
@@ -774,16 +774,14 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid 
relowner,
                                if (!HeapTupleIsValid(cla_ht))
                                        elog(ERROR, "cache lookup failed for 
opclass %u", opclass);
                                cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
-                               Assert(cla_tup->opcmethod == BTREE_AM_OID);
                                opfamily = cla_tup->opcfamily;
                                opcintype = cla_tup->opcintype;
                                ReleaseSysCache(cla_ht);
 
-                               op = get_opfamily_member(opfamily, opcintype, 
opcintype,
-                                                                               
 BTEqualStrategyNumber);
+                               op = get_opfamily_member_for_cmptype(opfamily, 
opcintype, opcintype, COMPARE_EQ);
                                if (!OidIsValid(op))
-                                       elog(ERROR, "missing operator %d(%u,%u) 
in opfamily %u",
-                                                BTEqualStrategyNumber, 
opcintype, opcintype, opfamily);
+                                       elog(ERROR, "missing equality operator 
for (%u,%u) in opfamily %u",
+                                                opcintype, opcintype, 
opfamily);
 
                                /*
                                 * If we find the same column with the same 
equality semantics
@@ -920,15 +918,10 @@ is_usable_unique_index(Relation indexRel)
 
        /*
         * Must be unique, valid, immediate, non-partial, and be defined over
-        * plain user columns (not expressions).  We also require it to be a
-        * btree.  Even if we had any other unique index kinds, we'd not know 
how
-        * to identify the corresponding equality operator, nor could we be sure
-        * that the planner could implement the required FULL JOIN with 
non-btree
-        * operators.
+        * plain user columns (not expressions).
         */
        if (indexStruct->indisunique &&
                indexStruct->indimmediate &&
-               indexRel->rd_rel->relam == BTREE_AM_OID &&
                indexStruct->indisvalid &&
                RelationGetIndexPredicate(indexRel) == NIL &&
                indexStruct->indnatts > 0)
-- 
2.48.1

Reply via email to