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