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