Re: Fix HAVING-to-WHERE pushdown with mismatched operator families

From: Richard Guo <guofenglinux(at)gmail(dot)com>
To: Florin Irion <irionr(at)gmail(dot)com>
Cc: pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Re: Fix HAVING-to-WHERE pushdown with mismatched operator families
Date: 2026-06-19 06:43:44
Message-ID: CAMbWs4-vqYf_MNvROqCoH6GwJh1UhnMTfW1B-1BaJriAevpWOQ@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Fri, Jun 19, 2026 at 12:34 AM Florin Irion <irionr(at)gmail(dot)com> wrote:
> When an outer qual is pushed into a GROUP BY subquery it lands in havingQual (correct), but find_having_conflicts then misses the conflict because the pushed qual carries base-table Vars, not GROUP Vars — so the clause gets silently moved to WHERE, filtering before aggregation.

I don't think so. The pushed qual carries the GROUP Vars, not the
base-table Vars.

> Reproducer:
> ```
> CREATE TYPE t_rec AS (x numeric);
> CREATE TABLE t_grp (a t_rec);
> INSERT INTO t_grp VALUES (ROW(1.0)), (ROW(1.00)), (ROW(2));
>
> -- record_ops (default) considers 1.0 and 1.00 equal; record_image_ops does not.
> -- Expected: one row (1.0), count = 2
> -- Got: one row (1.0), count = 1 (wrong)
> SELECT * FROM (SELECT a, count(*) FROM t_grp GROUP BY a) s
> WHERE a *= ROW(1.0)::t_rec;
> ```

I ran your reproducer, and I got the Expected result:

SELECT * FROM (SELECT a, count(*) FROM t_grp GROUP BY a) s
WHERE a *= ROW(1.0)::t_rec;
a | count
-------+-------
(1.0) | 2
(1 row)

Curious how you got the wrong result with this patch.

> EXPLAIN shows the *= filter pushed inside the aggregate scan rather than sitting above it as a Subquery Scan filter.

Here is the EXPLAIN I got:

EXPLAIN (COSTS OFF)
SELECT * FROM (SELECT a, count(*) FROM t_grp GROUP BY a) s
WHERE a *= ROW(1.0)::t_rec;
QUERY PLAN
---------------------------------------
HashAggregate
Group Key: t_grp.a
Filter: (t_grp.a *= '(1.0)'::t_rec)
-> Seq Scan on t_grp
(4 rows)

So the filter stays in HAVING instead of being pushed to Scan, which
is expected. I wonder how you get a plan with the filter being pushed
to scan. Can you show your output of EXPLAIN?

- Richard

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Antonin Houska 2026-06-19 06:48:51 Re: Adding REPACK [concurrently]
Previous Message jian he 2026-06-19 06:21:24 Re: Row pattern recognition