1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-11 20:28:21 +03:00

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 74edabce7a, 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
This commit is contained in:
Peter Eisentraut
2025-02-03 08:14:27 +01:00
parent 43a15eb940
commit 622f678c10
8 changed files with 25 additions and 82 deletions

View File

@ -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);
}

View File

@ -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))

View File

@ -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)));
}
/*

View File

@ -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");

View File

@ -38,35 +38,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);

View File

@ -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;
}

View File

@ -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 */

View File

@ -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,