From 4e6542739a08589b154271d7d7da3890d664fd34 Mon Sep 17 00:00:00 2001
From: reshke <reshke@double.cloud>
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

