BUG #19783: Sorted GROUPING SETS return a grouping column's value in a set that leaves it out

From: PG Bug reporting form <noreply(at)postgresql(dot)org>
To: pgsql-bugs(at)lists(dot)postgresql(dot)org
Cc: alpkeles99(at)gmail(dot)com
Subject: BUG #19783: Sorted GROUPING SETS return a grouping column's value in a set that leaves it out
Date: 2026-10-21 19:59:51
Message-ID: 19783-070e4bf0c73c1076@postgresql.org
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

The following bug has been logged on the website:

Bug reference: 19783
Logged by: Alperen Keles
Email address: alpkeles99(at)gmail(dot)com
PostgreSQL version: 19rc1
Operating system: macOS 26 arm64
Description:

Hello,

With a sorted grouping-sets plan (GroupAggregate), a column that is not
in the current grouping set can show its real value instead of NULL,
while GROUPING() for the same row says it is not grouped. It happens
when the row has a NULL somewhere and the target list reads a column
that comes after the grouping columns in the Agg's input:

CREATE TABLE t (id int PRIMARY KEY, a int, b int, c int);
INSERT INTO t VALUES (1, 10, NULL, 100);
SET enable_hashagg = off;
SELECT a, b, c, GROUPING(a, b) AS g
FROM t GROUP BY GROUPING SETS ((id, a), (id, b));

a | b | c | g
----+---+-----+---
10 | | 100 | 1
10 | | 100 | 2
(2 rows)

The second row belongs to the set (id, b), so a should be NULL there
(g = 2 says so). 18.6 and 14.24, and master with enable_hashagg = on,
give

a | b | c | g
----+---+-----+---
10 | | 100 | 1
| | 100 | 2

With b = 20 instead of NULL, or without c in the select list, the
result is right. The plan is

GroupAggregate
Output: a, b, c, GROUPING(a, b), id
Group Key: t.id, t.a
Sort Key: t.id, t.b
Group Key: t.id, t.b
-> Sort
Output: a, b, id, c
Sort Key: t.id, t.a

Reproduced on master dd568b047ac (2026-10-21) and 158b6d5109f,
macOS arm64, and on master a261fc2b722 and 19rc1 (REL_19_STABLE
1212d5d33b1), Ubuntu 24.04 x86_64, all --enable-cassert. Not on 18.6
(REL_18_STABLE a85b5523e67 on macOS, dfbc1507cdb on Ubuntu) or 14.24
(REL_14_STABLE 14904052e65, Ubuntu).

As far as I can tell, prepare_projection_slot() in nodeAgg.c deforms
the input slot up to the last grouping column and then sets
tts_isnull[] to true for the grouping columns not in the current set.
Projecting c then deforms the slot further. Since c456e391138
("Optimize tuple deformation"), slot_deform_heap_tuple() calls
populate_isnull_array() from attribute 0 whenever the tuple has a null
bitmap, so tts_isnull[] for the columns already deformed is rewritten
from the bitmap, and a's forced NULL is lost. The value in
tts_values[] is still a's. This looks like the same overwrite as in
the "Whole row var issue" thread, fixed for missing attributes in
d260d7d003f; master with that commit still gives the result above.

Found with a query fuzzer.

Regards,
Alperen Keles

Browse pgsql-bugs by date

  From Date Subject
Next Message PG Bug reporting form 2026-10-21 21:03:30 BUG #19784: "no relation entry for relid 1" when costing = ANY (<array expr over max(col)>) in a MinMaxAggPath
Previous Message Nitin Motiani 2026-10-21 18:39:31 Re: BUG #19773: pg_dump omits a different generation expression of an inherited column in a child table