Wrong result: count(DISTINCT x COLLATE "C") with GROUP BY x on a nondeterministic collation

From: Nidal FAKIH <nidal(dot)fakih(at)soptimal(dot)com>
To: pgsql-bugs(at)lists(dot)postgresql(dot)org
Subject: Wrong result: count(DISTINCT x COLLATE "C") with GROUP BY x on a nondeterministic collation
Date: 2026-11-01 09:27:43
Message-ID: c6790a7b-7c10-4baf-9c8f-b404420c63f9@soptimal.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

Hello,

I would like to report what looks like a wrong-result bug with presorted
aggregation when the GROUP BY column uses a nondeterministic collation
and the DISTINCT aggregate uses a different (deterministic) collation.

Version (SELECT version()):
PostgreSQL 18.3 on x86_64-windows, compiled by msvc-19.44.35223, 64-bit

System: Windows 11 x64. ICU collation provider. The script sets
max_parallel_workers_per_gather = 0 only to keep the plan simple; the
result is
the same without it.
_
Self-contained reproduction script:_

    CREATE COLLATION ci_ai (provider = icu, locale = 'und-u-ks-level1',
deterministic = false);

    CREATE TABLE t (x varchar(10) COLLATE ci_ai);
    -- 60 rows: 'a' x20, 'A' x20, 'b' x20
    INSERT INTO t SELECT (ARRAY['a','A','b'])[1 + i % 3] FROM
generate_series(0, 59) i;

    SET max_parallel_workers_per_gather = 0;

    SELECT x COLLATE "C" AS grp, count(DISTINCT x COLLATE "C") AS variants
    FROM t GROUP BY x ORDER BY 1;

    EXPLAIN (COSTS OFF)
    SELECT count(DISTINCT x COLLATE "C") FROM t GROUP BY x;

    SET enable_presorted_aggregate = off;
    SELECT x COLLATE "C" AS grp, count(DISTINCT x COLLATE "C") AS variants
    FROM t GROUP BY x ORDER BY 1;
    RESET enable_presorted_aggregate;

    DROP TABLE t;
    DROP COLLATION ci_ai;

Result obtained:

     grp | variants
    -----+----------
     a   |       40
     b   |        1

Expected result: 'a' and 'A' are equal under ci_ai, so they form one
group, but they are two distinct values under "C":

     grp | variants
    -----+----------
     a   |        2
     b   |        1

Plan:

     GroupAggregate
       Group Key: x
       ->  Sort
             Sort Key: x COLLATE ci_ai, x COLLATE "C"
             ->  Seq Scan on t

With SET enable_presorted_aggregate = off, the same query returns the
expected result (a = 2, b = 1).

The plan looks right: the input is sorted by (x COLLATE ci_ai, x COLLATE
"C").
So I suspect the presorted DISTINCT aggregate compares adjacent values
with the GROUP BY collation, or does not compare them at all, instead of
using theaggregate argument's collation "C". 40 is the number of rows in
the group ('a' and 'A'), so in effect every row is counted as a new
distinct value. With a different distribution of the same three values,
I got 41 in an earlier test, so the wrong count depends on the data.

Workaround: SET enable_presorted_aggregate = off, or compute the
distinct values in a subquery first, for example:

    SELECT g, count(*) FROM (SELECT DISTINCT x AS g, x COLLATE "C" AS v
FROM t) s GROUP BY g;

Thank you for your work on PostgreSQL.

B.Regards
N.Fakih

Browse pgsql-bugs by date

  From Date Subject
Next Message PG Bug reporting form 2026-11-01 14:40:41 BUG #19825: JSON_VALUE(... RETURNING <domain over json/jsonb>) loses the re-quoting of scalar strings and silent
Previous Message PG Bug reporting form 2026-11-01 08:07:24 BUG #19824: OMIT QUOTES breaks non-string results: array / composite / array-domain coercions in JSON_QUERY / JS