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

From: Florin Irion <irionr(at)gmail(dot)com>
To: Richard Guo <guofenglinux(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 12:10:26
Message-ID: CA+HEvJC2CqrHdR6OcVD0zbrfHw02wtcwLQP1Am9rDQPDK8ExFQ@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Il giorno ven 19 giu 2026 alle ore 08:43 Richard Guo <guofenglinux(at)gmail(dot)com>
ha scritto:

> 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
>

Huh, I'm not able to reproduce it anymore either,
probably while reviewing it, I played a bit with some things and this test
was using some bogus install.
Sorry for the noise.

Cheers,
Florin

--
* Florin Irion *
* https://www.enterprisedb.com <https://www.enterprisedb.com/>*

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Akshay Joshi 2026-06-19 12:19:44 Re: [PATCH] Add pg_get_table_ddl() to reconstruct CREATE TABLE statements
Previous Message Amit Kapila 2026-06-19 12:08:37 Re: Fix race in ReplicationSlotRelease for ephemeral slots