From 1f83c2983d58a3141112d8f09ab8a90448d01ac2 Mon Sep 17 00:00:00 2001 From: shihao zhong Date: Mon, 5 Oct 2026 11:41:30 -0400 Subject: [PATCH v1 1/2] Remove equalimage support from bpchar_ops and bpchar_pattern_ops bpchar equality ignores trailing spaces, so equal values in a column with no length can have different images. Deduplication could make an index-only scan return the wrong value, and eager aggregation could merge such rows below a join. Drop support function 4 from both opclasses, like interval_ops. Existing indexes need a REINDEX. Bug: #19749 Reported-by: Ke Discussion: https://postgr.es/m/19749-d46adf7c7d910b07@postgresql.org --- contrib/amcheck/verify_nbtree.c | 15 ++++++--- doc/src/sgml/btree.sgml | 9 +++++- src/include/catalog/pg_amproc.dat | 5 --- src/test/regress/expected/opr_sanity.out | 39 ++++++++++++------------ 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c index 455eb90f38c..aa367e5133e 100644 --- a/contrib/amcheck/verify_nbtree.c +++ b/contrib/amcheck/verify_nbtree.c @@ -331,13 +331,18 @@ bt_index_check_callback(Relation indrel, Relation heaprel, void *state, bool rea if (allequalimage && !_bt_allequalimage(indrel, false)) { bool has_interval_ops = false; + bool has_bpchar_ops = false; for (int i = 0; i < IndexRelationGetNumberOfKeyAttributes(indrel); i++) - if (indrel->rd_opfamily[i] == INTERVAL_BTREE_FAM_OID) - { + { + Oid opfamily = indrel->rd_opfamily[i]; + + if (opfamily == INTERVAL_BTREE_FAM_OID) has_interval_ops = true; - break; - } + else if (opfamily == BPCHAR_BTREE_FAM_OID || + opfamily == BPCHAR_PATTERN_BTREE_FAM_OID) + has_bpchar_ops = true; + } ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED), @@ -345,6 +350,8 @@ bt_index_check_callback(Relation indrel, Relation heaprel, void *state, bool rea RelationGetRelationName(indrel)), has_interval_ops ? errhint("This is known of \"interval\" indexes last built on a version predating 2023-11.") + : has_bpchar_ops + ? errhint("This is known of \"character\" indexes last built on a version predating 2026-11.") : 0)); } diff --git a/doc/src/sgml/btree.sgml b/doc/src/sgml/btree.sgml index 027361f20bb..3e5ca7a4430 100644 --- a/doc/src/sgml/btree.sgml +++ b/doc/src/sgml/btree.sgml @@ -875,13 +875,20 @@ options(relopts local_relopts *) returns - text, varchar, and char + 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. + + + numeric cannot use deduplication. Numeric display diff --git a/src/include/catalog/pg_amproc.dat b/src/include/catalog/pg_amproc.dat index 4a1efdbc899..3504d2d135d 100644 --- a/src/include/catalog/pg_amproc.dat +++ b/src/include/catalog/pg_amproc.dat @@ -30,9 +30,6 @@ { amprocfamily => 'btree/bpchar_ops', amproclefttype => 'bpchar', amprocrighttype => 'bpchar', amprocnum => '2', amproc => 'bpchar_sortsupport' }, -{ amprocfamily => 'btree/bpchar_ops', amproclefttype => 'bpchar', - amprocrighttype => 'bpchar', amprocnum => '4', - amproc => 'btvarstrequalimage' }, { amprocfamily => 'btree/bytea_ops', amproclefttype => 'bytea', amprocrighttype => 'bytea', amprocnum => '1', amproc => 'byteacmp' }, { amprocfamily => 'btree/bytea_ops', amproclefttype => 'bytea', @@ -273,8 +270,6 @@ { amprocfamily => 'btree/bpchar_pattern_ops', amproclefttype => 'bpchar', amprocrighttype => 'bpchar', amprocnum => '2', amproc => 'btbpchar_pattern_sortsupport' }, -{ amprocfamily => 'btree/bpchar_pattern_ops', amproclefttype => 'bpchar', - amprocrighttype => 'bpchar', amprocnum => '4', amproc => 'btequalimage' }, { amprocfamily => 'btree/money_ops', amproclefttype => 'money', amprocrighttype => 'money', amprocnum => '1', amproc => 'cash_cmp' }, { amprocfamily => 'btree/money_ops', amproclefttype => 'money', diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index 67cae397861..d703fdce536 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -2225,25 +2225,26 @@ LEFT JOIN pg_amproc AS amp ON amp.amprocfamily = opf.oid AND WHERE am.amname = 'btree' AND amp.amproc IS DISTINCT FROM 'btequalimage'::regproc ORDER BY 1, 2, 3; - proc | opfamily_name | opclass_name | opcintype ---------------------+------------------+------------------+------------------ - btvarstrequalimage | bpchar_ops | bpchar_ops | character - btvarstrequalimage | text_ops | name_ops | name - btvarstrequalimage | text_ops | text_ops | text - btvarstrequalimage | text_ops | varchar_ops | text - | array_ops | array_ops | anyarray - | float_ops | float4_ops | real - | float_ops | float8_ops | double precision - | interval_ops | interval_ops | interval - | jsonb_ops | jsonb_ops | jsonb - | multirange_ops | multirange_ops | anymultirange - | numeric_ops | numeric_ops | numeric - | range_ops | range_ops | anyrange - | record_image_ops | record_image_ops | record - | record_ops | record_ops | record - | tsquery_ops | tsquery_ops | tsquery - | tsvector_ops | tsvector_ops | tsvector -(16 rows) + proc | opfamily_name | opclass_name | opcintype +--------------------+--------------------+--------------------+------------------ + btvarstrequalimage | text_ops | name_ops | name + btvarstrequalimage | text_ops | text_ops | text + btvarstrequalimage | text_ops | varchar_ops | text + | array_ops | array_ops | anyarray + | bpchar_ops | bpchar_ops | character + | bpchar_pattern_ops | bpchar_pattern_ops | character + | float_ops | float4_ops | real + | float_ops | float8_ops | double precision + | interval_ops | interval_ops | interval + | jsonb_ops | jsonb_ops | jsonb + | multirange_ops | multirange_ops | anymultirange + | numeric_ops | numeric_ops | numeric + | range_ops | range_ops | anyrange + | record_image_ops | record_image_ops | record + | record_ops | record_ops | record + | tsquery_ops | tsquery_ops | tsquery + | tsvector_ops | tsvector_ops | tsvector +(17 rows) -- **************** pg_index **************** -- Look for illegal values in pg_index fields. -- 2.37.1 (Apple Git-137.1)