Re: BUG #19633: Unexpected results of IN (subquery) with a non-deterministic collation

From: Andrey Rachitskiy <pl0h0yp1(at)gmail(dot)com>
To: syzhong16(at)gmail(dot)com, pgsql-bugs(at)lists(dot)postgresql(dot)org, Alexander Korotkov <aekorotkov(at)gmail(dot)com>, Tender Wang <tndrwang(at)gmail(dot)com>
Subject: Re: BUG #19633: Unexpected results of IN (subquery) with a non-deterministic collation
Date: 2026-08-20 20:34:49
Message-ID: CAB8bMiuXGnBC3QrjpTK89MjweEP+Znc4MJNc6W-2k94AFv_TMQ@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

чт, 20 авг. 2026 г. в 23:41, PG Bug reporting form <noreply(at)postgresql(dot)org>:

> The following bug has been logged on the website:
>
> Bug reference: 19633
> Logged by: Suyang Zhong
> Email address: syzhong16(at)gmail(dot)com
> PostgreSQL version: 19beta3
> Operating system: Ubuntu 22.04
> Description:
>
> Hi,
>
> Consider the following test case:
>
> ```
> CREATE COLLATION ci (provider = icu, locale = 'und-u-ks-level1',
> deterministic = false);
>
> CREATE TABLE t_lhs(c1 text COLLATE ci);
> CREATE TABLE t_rhs(c0 text);
> INSERT INTO t_lhs VALUES ('a'), ('x'), ('y');
> INSERT INTO t_rhs VALUES ('a'), ('a');
> ANALYZE t_lhs;
> ANALYZE t_rhs;
> INSERT INTO t_rhs VALUES ('A');
>
> SELECT c1, c1 IN (SELECT c0 FROM t_rhs) AS p FROM t_lhs;
> -- a | t
> -- x | f
> -- y | f
>
> SELECT count(*) FROM t_lhs WHERE c1 IN (SELECT c0 FROM t_rhs);
> -- Expected: 1, Actual: 2
> ```
>
> Hi, Suyang!

Thanks for the report.

With enable_hashagg off that looks like:

Aggregate
-> Nested Loop
Join Filter: (t_semi_ci.c1 = ((t_semi_cs.c0)::text))
-> Unique
-> Sort
Sort Key: t_semi_cs.c0
-> Seq Scan on t_semi_cs
-> Seq Scan on t_semi_ci

Under gdb that path is create_unique_paths from the join search:

#0 create_unique_paths at planner.c:8673
#1 populate_joinrel_with_paths at joinrels.c:1189
#2 make_join_rel at joinrels.c:774
#3 make_rels_by_clause_joins at joinrels.c:300
#4 join_search_one_level at joinrels.c:123
#5 standard_join_search at allpaths.c:3987

(gdb) pgprint sjinfo
SpecialJoinInfo [jointype=JOIN_SEMI semi_can_btree=true
semi_can_hash=false]
[semi_operators] OidList: [98]
[semi_rhs_exprs]
Var [varno=3 varattno=1 vartype=25 varcollid=100]

Unique/HashAgg take the collation from the RHS expression. Here that
is the default collation of t_rhs.c0 (varcollid 100), not the join's
input collation (ci). So Sort+Unique keeps both 'a' and 'A'. Under
ci those values are equal, and the inner join emits the outer 'a'
twice (count is 2).

The attached patch labels each semi_rhs_expr with the join operator's
inputcollid via canonicalize_ec_expression (RelabelType when needed),
so unique-ification uses the same equality as the join. Sort then
shows

Sort Key: t_semi_cs.c0 COLLATE case_insensitive

and the count is 1. A regress case is included in collate.icu.utf8.

I am still getting familiar with this part. I am not sure this is the right
place or the right approach.

Thoughts?

--
Regards,
Rachitskiy Andrey

Attachment Content-Type Size
0001-Fix-semijoin-RHS-unique-ification-to-use-join-collation.patch text/x-patch 4.3 KB

In response to

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message Michael Paquier 2026-08-20 22:14:33 Re: BUG #19632: RULE rewriting crashes with XX000 when RETURNING old/new references a system column
Previous Message Ilia Kashintsev 2026-08-20 13:22:52 pg_restore: stack-buffer-overflow(read) in _tarGetHeader() in pg_backup_tar.c