aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPeter Eisentraut <peter@eisentraut.org>2025-02-03 08:14:27 +0100
committerPeter Eisentraut <peter@eisentraut.org>2025-02-03 10:53:18 +0100
commit622f678c10202c8a0b350794d504eeef7b773e90 (patch)
tree7ff9730b065921fa91afe7f3c79243ccf5d478bc /src
parent43a15eb9400dba2b0b97be72d1a3745a6a6f7136 (diff)
downloadpostgresql-622f678c10202c8a0b350794d504eeef7b773e90.tar.gz
postgresql-622f678c10202c8a0b350794d504eeef7b773e90.zip
Integrate GistTranslateCompareType() into IndexAmTranslateCompareType()
This turns GistTranslateCompareType() into a callback function of the gist index AM instead of a standalone function. The existing callers are changed to use IndexAmTranslateCompareType(). This then makes that code not hardcoded toward gist. This means in particular that the temporal keys code is now independent of gist. Also, this generalizes commit 74edabce7a3, so other index access methods other than the previously hardcoded ones could now work as REPLICA IDENTITY in a logical replication subscriber. Author: Mark Dilger <mark.dilger@enterprisedb.com> Co-authored-by: Peter Eisentraut <peter@eisentraut.org> Discussion: https://www.postgresql.org/message-id/flat/E72EAA49-354D-4C2E-8EB9-255197F55330@enterprisedb.com
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/gist/gist.c2
-rw-r--r--src/backend/access/gist/gistutil.c8
-rw-r--r--src/backend/commands/indexcmds.c24
-rw-r--r--src/backend/commands/tablecmds.c28
-rw-r--r--src/backend/executor/execReplication.c34
-rw-r--r--src/backend/replication/logical/relation.c8
-rw-r--r--src/include/access/gist.h2
-rw-r--r--src/include/executor/executor.h1
8 files changed, 25 insertions, 82 deletions
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 70f8086db7b..4d858b65e1e 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -108,7 +108,7 @@ gisthandler(PG_FUNCTION_ARGS)
amroutine->aminitparallelscan = NULL;
amroutine->amparallelrescan = NULL;
amroutine->amtranslatestrategy = NULL;
- amroutine->amtranslatecmptype = NULL;
+ amroutine->amtranslatecmptype = gisttranslatecmptype;
PG_RETURN_POINTER(amroutine);
}
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 4d3b6dfa32b..dbc4ac639a2 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -1095,17 +1095,11 @@ gist_stratnum_common(PG_FUNCTION_ARGS)
* Returns InvalidStrategy if the function is not defined.
*/
StrategyNumber
-GistTranslateCompareType(Oid opclass, CompareType cmptype)
+gisttranslatecmptype(CompareType cmptype, Oid opfamily, Oid opcintype)
{
- Oid opfamily;
- Oid opcintype;
Oid funcid;
Datum result;
- /* Look up the opclass family and input datatype. */
- if (!get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
- return InvalidStrategy;
-
/* Check whether the function is provided. */
funcid = get_opfamily_proc(opfamily, opcintype, opcintype, GIST_STRATNUM_PROC);
if (!OidIsValid(funcid))
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index f788b8f29b8..5b1753d4681 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -2422,38 +2422,30 @@ void
GetOperatorFromCompareType(Oid opclass, Oid rhstype, CompareType cmptype,
Oid *opid, StrategyNumber *strat)
{
+ Oid amid;
Oid opfamily;
Oid opcintype;
Assert(cmptype == COMPARE_EQ || cmptype == COMPARE_OVERLAP || cmptype == COMPARE_CONTAINED_BY);
+ amid = get_opclass_method(opclass);
+
*opid = InvalidOid;
if (get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
{
/*
- * Ask the opclass to translate to its internal stratnum
- *
- * For now we only need GiST support, but this could support other
- * indexams if we wanted.
+ * Ask the index AM to translate to its internal stratnum
*/
- *strat = GistTranslateCompareType(opclass, cmptype);
+ *strat = IndexAmTranslateCompareType(cmptype, amid, opfamily, opcintype, true);
if (*strat == InvalidStrategy)
- {
- HeapTuple tuple;
-
- tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "cache lookup failed for operator class %u", opclass);
-
ereport(ERROR,
errcode(ERRCODE_UNDEFINED_OBJECT),
cmptype = COMPARE_EQ ? errmsg("could not identify an equality operator for type %s", format_type_be(opcintype)) :
cmptype == COMPARE_OVERLAP ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) :
cmptype == COMPARE_CONTAINED_BY ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0,
- errdetail("Could not translate compare type %d for operator class \"%s\" for access method \"%s\".",
- cmptype, NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname), "gist"));
- }
+ errdetail("Could not translate compare type %d for operator family \"%s\", input type %s, access method \"%s\".",
+ cmptype, get_opfamily_name(opfamily, false), format_type_be(opcintype), get_am_name(amid)));
/*
* We parameterize rhstype so foreign keys can ask for a <@ operator
@@ -2472,7 +2464,7 @@ GetOperatorFromCompareType(Oid opclass, Oid rhstype, CompareType cmptype,
cmptype == COMPARE_OVERLAP ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) :
cmptype == COMPARE_CONTAINED_BY ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0,
errdetail("There is no suitable operator in operator family \"%s\" for access method \"%s\".",
- get_opfamily_name(opfamily, false), "gist"));
+ get_opfamily_name(opfamily, false), get_am_name(amid)));
}
/*
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 9827b27af8a..18f64db6e39 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -10002,37 +10002,21 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
CompareType cmptype;
bool for_overlaps = with_period && i == numpks - 1;
- /*
- * GiST indexes are required to support temporal foreign keys
- * because they combine equals and overlaps.
- */
- if (amid != GIST_AM_OID)
- elog(ERROR, "only GiST indexes are supported for temporal foreign keys");
-
cmptype = for_overlaps ? COMPARE_OVERLAP : COMPARE_EQ;
/*
- * An opclass can use whatever strategy numbers it wants, so we
- * ask the opclass what number it actually uses instead of our RT*
- * constants.
+ * An index AM can use whatever strategy numbers it wants, so we
+ * ask it what number it actually uses.
*/
- eqstrategy = GistTranslateCompareType(opclasses[i], cmptype);
+ eqstrategy = IndexAmTranslateCompareType(cmptype, amid, opfamily, opcintype, true);
if (eqstrategy == InvalidStrategy)
- {
- HeapTuple tuple;
-
- tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "cache lookup failed for operator class %u", opclasses[i]);
-
ereport(ERROR,
errcode(ERRCODE_UNDEFINED_OBJECT),
for_overlaps
? errmsg("could not identify an overlaps operator for foreign key")
: errmsg("could not identify an equality operator for foreign key"),
- errdetail("Could not translate compare type %d for operator class \"%s\" for access method \"%s\".",
- cmptype, NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname), "gist"));
- }
+ errdetail("Could not translate compare type %d for operator family \"%s\", input type %s, access method \"%s\".",
+ cmptype, get_opfamily_name(opfamily, false), format_type_be(opcintype), get_am_name(amid)));
}
else
{
@@ -10041,7 +10025,7 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
* other index AMs support unique indexes. If we ever did have
* other types of unique indexes, we'd need a way to determine
* which operator strategy number is equality. (We could use
- * something like GistTranslateCompareType.)
+ * IndexAmTranslateCompareType.)
*/
if (amid != BTREE_AM_OID)
elog(ERROR, "only b-tree indexes are supported for foreign keys");
diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c
index 2dac4bd363b..5f7613cc831 100644
--- a/src/backend/executor/execReplication.c
+++ b/src/backend/executor/execReplication.c
@@ -39,35 +39,6 @@ static bool tuples_equal(TupleTableSlot *slot1, TupleTableSlot *slot2,
TypeCacheEntry **eq);
/*
- * Returns the fixed strategy number, if any, of the equality operator for the
- * given operator class, otherwise, InvalidStrategy.
- */
-StrategyNumber
-get_equal_strategy_number(Oid opclass)
-{
- Oid am = get_opclass_method(opclass);
- int ret;
-
- switch (am)
- {
- case BTREE_AM_OID:
- ret = BTEqualStrategyNumber;
- break;
- case HASH_AM_OID:
- ret = HTEqualStrategyNumber;
- break;
- case GIST_AM_OID:
- ret = GistTranslateCompareType(opclass, COMPARE_EQ);
- break;
- default:
- ret = InvalidStrategy;
- break;
- }
-
- return ret;
-}
-
-/*
* Setup a ScanKey for a search in the relation 'rel' for a tuple 'key' that
* is setup to match 'rel' (*NOT* idxrel!).
*
@@ -120,10 +91,7 @@ build_replindex_scan_key(ScanKey skey, Relation rel, Relation idxrel,
*/
optype = get_opclass_input_type(opclass->values[index_attoff]);
opfamily = get_opclass_family(opclass->values[index_attoff]);
- eq_strategy = get_equal_strategy_number(opclass->values[index_attoff]);
- if (!eq_strategy)
- elog(ERROR, "missing equal strategy for opclass %u", opclass->values[index_attoff]);
-
+ eq_strategy = IndexAmTranslateCompareType(COMPARE_EQ, idxrel->rd_rel->relam, opfamily, optype, false);
operator = get_opfamily_member(opfamily, optype,
optype,
eq_strategy);
diff --git a/src/backend/replication/logical/relation.c b/src/backend/replication/logical/relation.c
index 67aab02ff76..e9ad90d64a5 100644
--- a/src/backend/replication/logical/relation.c
+++ b/src/backend/replication/logical/relation.c
@@ -27,6 +27,7 @@
#include "replication/logicalrelation.h"
#include "replication/worker_internal.h"
#include "utils/inval.h"
+#include "utils/lsyscache.h"
#include "utils/syscache.h"
@@ -835,7 +836,12 @@ IsIndexUsableForReplicaIdentityFull(Relation idxrel, AttrMap *attrmap)
/* Ensure that the index has a valid equal strategy for each key column */
for (int i = 0; i < idxrel->rd_index->indnkeyatts; i++)
{
- if (get_equal_strategy_number(indclass->values[i]) == InvalidStrategy)
+ Oid opfamily;
+ Oid opcintype;
+
+ if (!get_opclass_opfamily_and_input_type(indclass->values[i], &opfamily, &opcintype))
+ return false;
+ if (IndexAmTranslateCompareType(COMPARE_EQ, idxrel->rd_rel->relam, opfamily, opcintype, true) == InvalidStrategy)
return false;
}
diff --git a/src/include/access/gist.h b/src/include/access/gist.h
index eff019f7515..db62a9ac0b4 100644
--- a/src/include/access/gist.h
+++ b/src/include/access/gist.h
@@ -248,6 +248,6 @@ typedef struct
do { (e).key = (k); (e).rel = (r); (e).page = (pg); \
(e).offset = (o); (e).leafkey = (l); } while (0)
-extern StrategyNumber GistTranslateCompareType(Oid opclass, CompareType cmptype);
+extern StrategyNumber gisttranslatecmptype(CompareType cmptype, Oid opfamily, Oid opcintype);
#endif /* GIST_H */
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index c7db6defd3e..45b80e6b98e 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -664,7 +664,6 @@ extern void check_exclusion_constraint(Relation heap, Relation index,
/*
* prototypes from functions in execReplication.c
*/
-extern StrategyNumber get_equal_strategy_number(Oid opclass);
extern bool RelationFindReplTupleByIndex(Relation rel, Oid idxoid,
LockTupleMode lockmode,
TupleTableSlot *searchslot,