From a1514d1ac58864f13a959d6d763778ef1d6de5f5 Mon Sep 17 00:00:00 2001 From: Richard Guo Date: Mon, 5 Oct 2026 07:44:37 +0900 Subject: [PATCH v1 2/3] Don't pass grouped relations to FDWs build_grouped_rel() makes a flat copy of the input relation, including its FDW fields. As a result, when building a grouped join relation for eager aggregation, add_paths_to_joinrel() called the FDW's GetForeignJoinPaths for it. postgres_fdw then failed with "Aggref found where not expected" on the partial Aggrefs in the target list, and in any case it would have treated a partially aggregated input as a plain foreign scan. FDWs are not prepared to handle grouped relations, so clear serverid, fdwroutine and fdw_private in build_grouped_rel(). Reported-by: Robert Haas Author: Richard Guo Discussion: https://postgr.es/m/CA+Tgmob7iSM9YkRM44VjUDuaCchW-fY54MV5njpTZTL9uNyV4w@mail.gmail.com Backpatch-through: 19 --- .../postgres_fdw/expected/postgres_fdw.out | 26 +++++++++++++++++++ contrib/postgres_fdw/sql/postgres_fdw.sql | 5 ++++ src/backend/optimizer/util/relnode.c | 7 +++++ 3 files changed, 38 insertions(+) diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index 739f43af7bb..7adeffa27f5 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -4632,6 +4632,32 @@ select sum(q.a), count(q.b) from ft4 left join (select 13, avg(ft1.c1), sum(ft2. 650 | 50 (1 row) +-- Eager aggregation: a partially grouped rel must not be joined remotely +explain (verbose, costs off) +select t1.c2, sum(t2.c1) from ft1 t1 inner join ft2 t2 on (t1.c2 = t2.c2) where t1.c1 < 20 group by t1.c2 order by 1; + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan + Output: t1.c2, (sum(t2.c1)) + Relations: Aggregate on ((public.ft1 t1) INNER JOIN (public.ft2 t2)) + Remote SQL: SELECT r1.c2, sum(r2."C 1") FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2.c2 = r1.c2)) AND ((r1."C 1" < 20)))) GROUP BY 1 ORDER BY r1.c2 ASC NULLS LAST +(4 rows) + +select t1.c2, sum(t2.c1) from ft1 t1 inner join ft2 t2 on (t1.c2 = t2.c2) where t1.c1 < 20 group by t1.c2 order by 1; + c2 | sum +----+-------- + 0 | 50500 + 1 | 99200 + 2 | 99400 + 3 | 99600 + 4 | 99800 + 5 | 100000 + 6 | 100200 + 7 | 100400 + 8 | 100600 + 9 | 100800 +(10 rows) + -- Not supported cases -- Grouping sets explain (verbose, costs off) diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index f1ca3204382..3a5de68bbee 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -1440,6 +1440,11 @@ explain (verbose, costs off) select sum(q.a), count(q.b) from ft4 left join (select 13, avg(ft1.c1), sum(ft2.c1) from ft1 right join ft2 on (ft1.c1 = ft2.c1)) q(a, b, c) on (ft4.c1 <= q.b); select sum(q.a), count(q.b) from ft4 left join (select 13, avg(ft1.c1), sum(ft2.c1) from ft1 right join ft2 on (ft1.c1 = ft2.c1)) q(a, b, c) on (ft4.c1 <= q.b); +-- Eager aggregation: a partially grouped rel must not be joined remotely +explain (verbose, costs off) +select t1.c2, sum(t2.c1) from ft1 t1 inner join ft2 t2 on (t1.c2 = t2.c2) where t1.c1 < 20 group by t1.c2 order by 1; +select t1.c2, sum(t2.c1) from ft1 t1 inner join ft2 t2 on (t1.c2 = t2.c2) where t1.c1 < 20 group by t1.c2 order by 1; + -- Not supported cases -- Grouping sets diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 36e7a7a9bd1..34dfb757152 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -531,6 +531,13 @@ build_grouped_rel(PlannerInfo *root, RelOptInfo *rel) grouped_rel->nullable_partexprs = NULL; grouped_rel->consider_partitionwise_join = false; + /* + * clear FDW info; FDWs don't know how to handle grouped relations + */ + grouped_rel->serverid = InvalidOid; + grouped_rel->fdwroutine = NULL; + grouped_rel->fdw_private = NULL; + /* * clear size estimates */ -- 2.37.1 (Apple Git-137.1)