postgresql/src/backend/utils
Richard Guo b62f514ac5 Consider collation when proving uniqueness from unique indexes
relation_has_unique_index_for() has long had an XXX noting that it
doesn't check collations when matching a unique index's columns
against equality clauses.  This was benign as long as all collations
in play reduced to the same notion of equality, but has been incorrect
since nondeterministic collations were introduced in PG 12: a unique
index under a deterministic collation does not prove uniqueness under
a nondeterministic collation, nor vice versa.

The consequence is wrong query results for any planner optimization
that consumes the faulty proof, including inner-unique join execution
(which stops the inner search after the first match per outer row),
useless-left-join removal, semijoin-to-innerjoin reduction, and
self-join elimination.

Fix by requiring the index's collation to agree on equality with the
clause's input collation.  Two collations agree on equality if either
is InvalidOid (denoting a non-collation-sensitive operation, which
cannot conflict with the other side), if they have the same OID, or if
both are deterministic: by definition a deterministic collation treats
two strings as equal iff they are byte-wise equal (see CREATE
COLLATION), so any two deterministic collations share the same
equality relation and the uniqueness proof carries over.  Any mismatch
involving a nondeterministic collation is rejected.

Back-patch to all supported branches; the bug has existed since
nondeterministic collations were introduced in PG 12.

Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAMbWs4_XUUSTyzCaRjUeeahWNqi=8ZOA5Q4coi8zUVEDSBkM6A@mail.gmail.com
Backpatch-through: 14
2026-05-05 10:26:17 +09:00
..
activity Honor passed-in database OIDs in pgstat_database.c 2026-04-11 17:03:04 +09:00
adt Guard against overly-long numeric formatting symbols from locale. 2026-04-22 12:41:00 -04:00
cache Consider collation when proving uniqueness from unique indexes 2026-05-05 10:26:17 +09:00
error Fix incorrect message-printing in win32security.c. 2025-10-13 17:56:45 -04:00
fmgr Fix: Don't strip $libdir from nested module_pathnames 2025-08-27 15:50:29 +02:00
hash Fix invalid format string in HASH_DEBUG code 2025-08-15 18:06:13 +12:00
init Fix compilation warning with SerializeClientConnectionInfo() 2025-08-14 16:21:58 +09:00
mb pg_mblen_range, pg_mblen_with_len: Valgrind after encoding ereport. 2026-02-14 12:16:19 -08:00
misc Zero-fill private_data when attaching an injection point 2026-04-10 11:17:30 +09:00
mmgr Detect pfree or repalloc of a previously-freed memory chunk. 2026-03-30 12:02:08 -04:00
resowner aio: Basic subsystem initialization 2025-03-17 18:51:33 -04:00
sort Be more careful to preserve consistency of a tuplestore. 2026-03-30 13:59:54 -04:00
time Revert GetTransactionSnapshot() to return historic snapshot during LR 2025-08-22 13:08:16 +03:00
.gitignore Fix build inconsistency due to the generation of wait-event code 2026-02-02 08:02:59 +09:00
errcodes.txt Update copyright for 2025 2025-01-01 11:21:55 -05:00
Gen_dummy_probes.pl Update copyright for 2025 2025-01-01 11:21:55 -05:00
Gen_fmgrtab.pl Update copyright for 2025 2025-01-01 11:21:55 -05:00
generate-errcodes.pl Update copyright for 2025 2025-01-01 11:21:55 -05:00
Makefile Fix build inconsistency due to the generation of wait-event code 2026-02-02 08:02:59 +09:00
meson.build Update copyright for 2025 2025-01-01 11:21:55 -05:00
postprocess_dtrace.sed Update copyright for 2025 2025-01-01 11:21:55 -05:00
probes.d Update copyright for 2025 2025-01-01 11:21:55 -05:00