From 4e6542739a08589b154271d7d7da3890d664fd34 Mon Sep 17 00:00:00 2001 From: reshke Date: Fri, 25 Sep 2026 07:46:11 +0300 Subject: [PATCH v1] Guard FDW deparse from relations with partial aggregate targets Eager aggregation builds grouped joinrels whose targets contain partial Aggrefs. PostgreSQL FDW pushdown fails to deparse them, so add a simple guard to skip this case. The fully-aggregated query is still pushed down as usual. --- contrib/postgres_fdw/expected/postgres_fdw.out | 12 ++++++++++++ contrib/postgres_fdw/postgres_fdw.c | 7 +++++++ contrib/postgres_fdw/sql/postgres_fdw.sql | 5 +++++ 3 files changed, 24 insertions(+) diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index a6295674da..8fd701f8c7 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -3583,6 +3583,18 @@ SELECT r.a FROM remote_tbl r Function Call: unnest('{3,6,9}'::integer[]) (12 rows) +-- Aggregation over a foreign table joined with a function RTE: the +-- eagerly-aggregated joinrel must not be pushed down as a foreign join. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(1) FROM remote_tbl, generate_series(1, 1) GROUP BY a; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan + Output: (count(*)), remote_tbl.a + Relations: Aggregate on ((public.remote_tbl) INNER JOIN (pg_catalog.generate_series())) + Remote SQL: SELECT count(*), r1.a FROM (public.base_tbl_fn r1 INNER JOIN generate_series(1, 1) f2(c1) ON (TRUE)) GROUP BY 2 +(4 rows) + DROP FOREIGN TABLE remote_tbl; DROP TABLE base_tbl_fn; -- ==================================================================== diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index adfdb91cc2..838d6ab720 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -7692,6 +7692,13 @@ postgresGetForeignJoinPaths(PlannerInfo *root, if (joinrel->fdw_private) return; + /* + * Grouped relations built by eager aggregation hold partially + * aggregated targets, which we can't deparse, so don't push down. + */ + if (IS_GROUPED_REL(joinrel)) + return; + /* * This code does not work for joins with lateral references, since those * must have parameterized paths, which we don't generate yet. diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index eaeb90485e..3977669a2c 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -1096,6 +1096,11 @@ SELECT r.a FROM remote_tbl r WHERE EXISTS (SELECT 1 FROM unnest(array[3, 6, 9]) AS t(n) WHERE t.n = r.a) ORDER BY r.a; +-- Aggregation over a foreign table joined with a function RTE: the +-- eagerly-aggregated joinrel must not be pushed down as a foreign join. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(1) FROM remote_tbl, generate_series(1, 1) GROUP BY a; + DROP FOREIGN TABLE remote_tbl; DROP TABLE base_tbl_fn; -- 2.43.0