From c449e58c884f835cbdf8fe0ab7b16585bbffadcb Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Tue, 6 Oct 2026 13:32:38 -0400 Subject: [PATCH v2_REL_18_STABLE] Rescind unsafe deduplication support. bpchar equality ignores trailing spaces, so equal values in a column with no length can have different images. Similarly, oidvector equality intentionally pays no attention to the array lower bound field. We nevertheless allowed nbtree deduplication to be used with indexes built with one of these opclass. This could lead to an index-only scan that returns the wrong value following a posting list split. To fix, drop support function 4 from all three affected opclasses on master and 19. It isn't possible to change catalog contents on earlier branches, so handle the problem there by explicitly teaching the relevant support functions to reject the two bpchar opclasses only. We deliberately avoid changing anything about the oidvector opclass on these earlier back branches, though. The oidvector issue is benign in practice, and it doesn't seem worth the trouble that it'd cause users who routinely run pg_amcheck. amcheck would otherwise flag affected system catalog indexes (such as pg_proc_proname_args_nsp_index) as containing a corrupt metapage, even though the underlying issue can't cause any harm with idiomatic usage within system catalogs. Author: Shihao Zhong Co-authored-by: Peter Geoghegan Reported-by: Ke Reported-by: Tom Lane Bug: #19749 Discussion: https://postgr.es/m/19749-d46adf7c7d910b07@postgresql.org Backpatch-through: 14 --- src/backend/utils/adt/datum.c | 14 ++++++-------- src/backend/utils/adt/varlena.c | 9 ++++++++- contrib/amcheck/verify_nbtree.c | 16 +--------------- doc/src/sgml/btree.sgml | 14 ++++++++++---- 4 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/backend/utils/adt/datum.c b/src/backend/utils/adt/datum.c index 5aab1edb7..2e906add9 100644 --- a/src/backend/utils/adt/datum.c +++ b/src/backend/utils/adt/datum.c @@ -43,6 +43,7 @@ #include "postgres.h" #include "access/detoast.h" +#include "catalog/pg_type_d.h" #include "common/hashfn.h" #include "fmgr.h" #include "utils/datum.h" @@ -421,20 +422,17 @@ datum_image_hash(Datum value, bool typByVal, int typLen) * datum_image_eq() in all cases can use this as their "equalimage" support * function. * - * Currently, we unconditionally assume that any B-Tree operator class that - * registers btequalimage as its support function 4 must be able to safely use - * optimizations like deduplication (i.e. we return true unconditionally). If - * it ever proved necessary to rescind support for an operator class, we could - * do that in a targeted fashion by doing something with the opcintype - * argument. + * Earlier minor releases erroneously associated this function with + * bpchar_pattern_ops. Detect that case to rescind deduplication support, + * without requiring initdb. *------------------------------------------------------------------------- */ Datum btequalimage(PG_FUNCTION_ARGS) { - /* Oid opcintype = PG_GETARG_OID(0); */ + Oid opcintype = PG_GETARG_OID(0); - PG_RETURN_BOOL(true); + PG_RETURN_BOOL(opcintype != BPCHAROID); } /*------------------------------------------------------------------------- diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 63662e3f7..51f6ab096 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -2655,16 +2655,23 @@ varstr_abbrev_abort(int memtupcount, SortSupport ssup) /* * Generic equalimage support function for character type's operator classes. * Disables the use of deduplication with nondeterministic collations. + * + * Earlier minor releases erroneously associated this function with + * bpchar_ops. Detect that case to rescind deduplication support, without + * requiring initdb. */ Datum btvarstrequalimage(PG_FUNCTION_ARGS) { - /* Oid opcintype = PG_GETARG_OID(0); */ + Oid opcintype = PG_GETARG_OID(0); Oid collid = PG_GET_COLLATION(); pg_locale_t locale; check_collation_set(collid); + if (opcintype == BPCHAROID) + PG_RETURN_BOOL(false); + locale = pg_newlocale_from_collation(collid); PG_RETURN_BOOL(locale->deterministic); diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c index c7cd8d3f0..3073f39de 100644 --- a/contrib/amcheck/verify_nbtree.c +++ b/contrib/amcheck/verify_nbtree.c @@ -329,24 +329,10 @@ bt_index_check_callback(Relation indrel, Relation heaprel, void *state, bool rea errmsg("index \"%s\" metapage has equalimage field set on unsupported nbtree version", RelationGetRelationName(indrel)))); if (allequalimage && !_bt_allequalimage(indrel, false)) - { - bool has_interval_ops = false; - - for (int i = 0; i < IndexRelationGetNumberOfKeyAttributes(indrel); i++) - if (indrel->rd_opfamily[i] == INTERVAL_BTREE_FAM_OID) - { - has_interval_ops = true; - break; - } - ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("index \"%s\" metapage incorrectly indicates that deduplication is safe", - RelationGetRelationName(indrel)), - has_interval_ops - ? errhint("This is known of \"interval\" indexes last built on a version predating 2023-11.") - : 0)); - } + RelationGetRelationName(indrel)))); /* Check index, possibly against table it is an index on */ bt_check_every_level(indrel, heaprel, heapkeyspace, readonly, diff --git a/doc/src/sgml/btree.sgml b/doc/src/sgml/btree.sgml index 027361f20..78ba106bc 100644 --- a/doc/src/sgml/btree.sgml +++ b/doc/src/sgml/btree.sgml @@ -875,10 +875,16 @@ options(relopts local_relopts *) returns - text, varchar, and char - cannot use deduplication when a - nondeterministic collation is used. Case - and accent differences must be preserved among equal datums. + text and varchar cannot use deduplication when + a nondeterministic collation is used. Case and + accent differences must be preserved among equal datums. + + + + + + char cannot use deduplication. Trailing spaces must be + preserved among equal datums. -- 2.55.0