bug: having clause evaluated before group by

From: Jacob Brazeal <jacob(dot)brazeal(at)gmail(dot)com>
To: PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: bug: having clause evaluated before group by
Date: 2026-07-24 20:57:10
Message-ID: CA+COZaA0tnyza0pHx6-UEdM5dcLGP4RJJ0KOHFq+wVQCY2Jyiw@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi all,

A HAVING clause can be evaluated before GROUP BY when it contains an
expression that distinguishes equal numeric values, producing a result that
is not possible under the query's semantics.

For example, on current master:

CREATE TABLE t (c numeric);
INSERT INTO t VALUES (0), (0), (0), (0.0), (0.0);

SELECT c, count(*) FROM t GROUP BY c;
c | count
---+-------
0 | 5

SELECT c, count(*) FROM t
GROUP BY c
HAVING scale(c) = 1;
c | count
-----+-------
0.0 | 2

All five input values are equal according to numeric equality, so they form
one group. Therefore the second query can return either no rows or one row
with a count of 5, depending on the value used to represent the group. A
count of 2 is impossible; it implies three scale-0 rows have been filtered
before grouping.

The planner has two optimizations that can move a qualification across a
grouping boundary:

- transferring a HAVING clause to WHERE before aggregation; and
- pushing an outer restriction into a subquery past DISTINCT, DISTINCT
ON, window partitioning, or set-operation grouping.

Commit 44fb59fc605 added expression_has_grouping_conflict() to prevent such
movement when the expression can distinguish values that the grouping
operation considers equal.

The check appears to be incomplete. For a grouping-column reference that is
not a direct operand of the grouping equality, such as scale(c),
grouping_conflict_walker() rejects the expression for a nondeterministic
collation, but not for a type whose equality does not imply image equality.

That matters for numeric, where 0 and 0.0 compare equal but have different
scales. It also appears relevant to other non-equalimage cases such as
record_image_ops and float positive/negative zero.

I reproduced this on master at 1c9c3589042.

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Tom Lane 2026-07-24 21:18:23 Re: bug: having clause evaluated before group by
Previous Message Haibo Yan 2026-07-24 20:48:26 Re: Fix race in background worker termination for database