diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c index 5c35414..92a82a0 100644 --- a/contrib/postgres_fdw/deparse.c +++ b/contrib/postgres_fdw/deparse.c @@ -98,7 +98,9 @@ typedef struct foreign_loc_cxt typedef struct deparse_expr_cxt { PlannerInfo *root; /* global planner state */ + RelOptInfo *foreignrel; /* the foreign relation we are planning for */ + RelOptInfo *scanrel; /* the underlying scan relation. */ StringInfo buf; /* output buffer to append to */ List **params_list; /* exprs that will become remote Params */ } deparse_expr_cxt; @@ -903,6 +905,7 @@ deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel, List **retrieved_attrs, List **params_list) { deparse_expr_cxt context; + PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *)rel->fdw_private; /* We handle all relations other than dead one. */ Assert(rel->reloptkind != RELOPT_DEADREL); @@ -911,6 +914,7 @@ deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel, context.buf = buf; context.root = root; context.foreignrel = rel; + context.scanrel = (rel->reloptkind == RELOPT_UPPER_REL) ? fpinfo->outerrel : rel; context.params_list = params_list; /* Construct SELECT clause */ @@ -991,10 +995,11 @@ deparseSelectSql(List *tlist, List **retrieved_attrs, deparse_expr_cxt *context) } /* - * Construct a FROM clause and WHERE clause, if any. And append it to "buf". - * The final output contains "SELECT ... FROM ... [WHERE ... ]". + * Construct a FROM clause and a WHERE clause, if any, and append those to + * "buf". * - * remote_conds is the list of WHERE clauses, NIL if none. + * remote_conds is the list of clauses to be included in the WHERE clause, + * NIL if none. */ static void deparseFromClause(List *remote_conds, deparse_expr_cxt *context) @@ -1003,26 +1008,23 @@ deparseFromClause(List *remote_conds, deparse_expr_cxt *context) RelOptInfo *foreignrel = context->foreignrel; PlannerInfo *root = context->root; PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private; - RelOptInfo *scan_rel = foreignrel; + RelOptInfo *scan_rel = context->scanrel; /* - * For aggregates the FROM clause will be build from underneath scan rel. - * WHERE clause conditions too taken from there. + * For aggregates the FROM clause will be built from the underneath scan + * relation. Conditions in the WHERE clause are also taken from there. */ if (foreignrel->reloptkind == RELOPT_UPPER_REL) { PgFdwRelationInfo *ofpinfo; ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private; - scan_rel = fpinfo->outerrel; - context->foreignrel = scan_rel; remote_conds = ofpinfo->remote_conds; } /* Construct FROM clause */ appendStringInfoString(buf, " FROM "); deparseFromExprForRel(buf, root, scan_rel, - foreignrel->reloptkind == RELOPT_UPPER_REL ? true : (scan_rel->reloptkind == RELOPT_JOINREL), context->params_list); @@ -1032,10 +1034,6 @@ deparseFromClause(List *remote_conds, deparse_expr_cxt *context) appendStringInfo(buf, " WHERE "); appendConditions(remote_conds, context); } - - /* Restore context's foreignrel */ - if (foreignrel->reloptkind == RELOPT_UPPER_REL) - context->foreignrel = foreignrel; } /* @@ -1138,14 +1136,14 @@ deparseTargetList(StringInfo buf, /* * Deparse the appropriate locking clause (FOR UPDATE or FOR SHARE) for a - * given relation (context->foreignrel). + * given relation (context->scanrel). */ static void deparseLockingClause(deparse_expr_cxt *context) { StringInfo buf = context->buf; PlannerInfo *root = context->root; - RelOptInfo *rel = context->foreignrel; + RelOptInfo *rel = context->scanrel; int relid = -1; while ((relid = bms_next_member(rel->relids, relid)) >= 0) @@ -1366,6 +1364,7 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, context.buf = buf; context.foreignrel = foreignrel; + context.scanrel = foreignrel; context.root = root; context.params_list = params_list; @@ -1534,6 +1533,7 @@ deparseDirectUpdateSql(StringInfo buf, PlannerInfo *root, /* Set up context struct for recursion */ context.root = root; context.foreignrel = baserel; + context.scanrel = baserel; context.buf = buf; context.params_list = params_list; @@ -1618,6 +1618,7 @@ deparseDirectDeleteSql(StringInfo buf, PlannerInfo *root, /* Set up context struct for recursion */ context.root = root; context.foreignrel = baserel; + context.scanrel = baserel; context.buf = buf; context.params_list = params_list; @@ -2044,10 +2045,10 @@ deparseExpr(Expr *node, deparse_expr_cxt *context) static void deparseVar(Var *node, deparse_expr_cxt *context) { - bool qualify_col = (context->foreignrel->reloptkind == RELOPT_JOINREL || - context->foreignrel->reloptkind == RELOPT_UPPER_REL); + bool qualify_col = (context->scanrel->reloptkind == RELOPT_JOINREL || + context->scanrel->reloptkind == RELOPT_UPPER_REL); - if (bms_is_member(node->varno, context->foreignrel->relids) && + if (bms_is_member(node->varno, context->scanrel->relids) && node->varlevelsup == 0) deparseColumnRef(context->buf, node->varno, node->varattno, context->root, qualify_col); @@ -2824,42 +2825,45 @@ appendGroupByClause(List *tlist, deparse_expr_cxt *context) { StringInfo buf = context->buf; Query *query = context->root->parse; + ListCell *lc; + bool first = true; - if (query->groupClause != NULL) - { - appendStringInfo(buf, " GROUP BY "); + /* Nothing to be done, if there's no GROUP BY clause in the query. */ + if (!query->groupClause) + return; - if (query->groupingSets == NIL) - { - ListCell *lc; - bool first = true; + appendStringInfo(buf, " GROUP BY "); - foreach(lc, query->groupClause) - { - SortGroupClause *grp = (SortGroupClause *) lfirst(lc); - Index ref = grp->tleSortGroupRef; - TargetEntry *tle; - Expr *expr; + /* + * Queries with grouping sets are not pushed down, so we don't grouping + * sets here. + */ + Assert(!query->groupingSets); - if (!first) - appendStringInfoString(buf, ", "); - first = false; + foreach(lc, query->groupClause) + { + SortGroupClause *grp = (SortGroupClause *) lfirst(lc); + Index ref = grp->tleSortGroupRef; + TargetEntry *tle; + Expr *expr; + + if (!first) + appendStringInfoString(buf, ", "); + first = false; - tle = get_sortgroupref_tle(ref, tlist); - expr = tle->expr; + tle = get_sortgroupref_tle(ref, tlist); + expr = tle->expr; - if (expr && IsA(expr, Const)) - deparseConst((Const *) expr, context); - else if (!expr || IsA(expr, Var)) - deparseExpr(expr, context); - else - { - /* Must force parens for other expressions */ - appendStringInfoString(buf, "("); - deparseExpr(expr, context); - appendStringInfoString(buf, ")"); - } - } + if (expr && IsA(expr, Const)) + deparseConst((Const *) expr, context); + else if (!expr || IsA(expr, Var)) + deparseExpr(expr, context); + else + { + /* Must force parens for other expressions */ + appendStringInfoString(buf, "("); + deparseExpr(expr, context); + appendStringInfoString(buf, ")"); } } } @@ -2875,7 +2879,7 @@ appendOrderByClause(List *pathkeys, deparse_expr_cxt *context) ListCell *lcell; int nestlevel; char *delim = " "; - RelOptInfo *baserel = context->foreignrel; + RelOptInfo *baserel = context->scanrel; StringInfo buf = context->buf; /* Make sure any constants in the exprs are printed portably */ diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index 6ba1895..8079071 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -861,12 +861,12 @@ CREATE OPERATOR === ( -- built-in operators and functions can be shipped for remote execution EXPLAIN (VERBOSE, COSTS OFF) SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = abs(t1.c2); - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------- Foreign Scan Output: (count(c3)) Relations: Aggregate on (public.ft1 t1) - Remote SQL: SELECT count(r1.c3) FROM "S 1"."T 1" r1 WHERE (("C 1" = abs(c2))) + Remote SQL: SELECT count(c3) FROM "S 1"."T 1" WHERE (("C 1" = abs(c2))) (4 rows) SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = abs(t1.c2); @@ -877,12 +877,12 @@ SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = abs(t1.c2); EXPLAIN (VERBOSE, COSTS OFF) SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = t1.c2; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------- Foreign Scan Output: (count(c3)) Relations: Aggregate on (public.ft1 t1) - Remote SQL: SELECT count(r1.c3) FROM "S 1"."T 1" r1 WHERE (("C 1" = c2)) + Remote SQL: SELECT count(c3) FROM "S 1"."T 1" WHERE (("C 1" = c2)) (4 rows) SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = t1.c2; @@ -935,12 +935,12 @@ ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw'); -- ... now they can be shipped EXPLAIN (VERBOSE, COSTS OFF) SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = postgres_fdw_abs(t1.c2); - QUERY PLAN ------------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------- Foreign Scan Output: (count(c3)) Relations: Aggregate on (public.ft1 t1) - Remote SQL: SELECT count(r1.c3) FROM "S 1"."T 1" r1 WHERE (("C 1" = public.postgres_fdw_abs(c2))) + Remote SQL: SELECT count(c3) FROM "S 1"."T 1" WHERE (("C 1" = public.postgres_fdw_abs(c2))) (4 rows) SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = postgres_fdw_abs(t1.c2); @@ -951,12 +951,12 @@ SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = postgres_fdw_abs(t1.c2); EXPLAIN (VERBOSE, COSTS OFF) SELECT count(c3) FROM ft1 t1 WHERE t1.c1 === t1.c2; - QUERY PLAN ------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------- Foreign Scan Output: (count(c3)) Relations: Aggregate on (public.ft1 t1) - Remote SQL: SELECT count(r1.c3) FROM "S 1"."T 1" r1 WHERE (("C 1" OPERATOR(public.===) c2)) + Remote SQL: SELECT count(c3) FROM "S 1"."T 1" WHERE (("C 1" OPERATOR(public.===) c2)) (4 rows) SELECT count(c3) FROM ft1 t1 WHERE t1.c1 === t1.c2; @@ -4437,12 +4437,12 @@ SELECT * FROM ft1 ORDER BY c6 ASC NULLS FIRST, c1 OFFSET 15 LIMIT 10; -- Consistent check constraints provide consistent results ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c2positive CHECK (c2 >= 0); EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 < 0; - QUERY PLAN --------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------- Foreign Scan Output: (count(*)) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT count(*) FROM "S 1"."T 1" r1 WHERE ((c2 < 0)) + Remote SQL: SELECT count(*) FROM "S 1"."T 1" WHERE ((c2 < 0)) (4 rows) SELECT count(*) FROM ft1 WHERE c2 < 0; @@ -4481,12 +4481,12 @@ ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c2positive; -- But inconsistent check constraints provide inconsistent results ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c2negative CHECK (c2 < 0); EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 >= 0; - QUERY PLAN ---------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------ Foreign Scan Output: (count(*)) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT count(*) FROM "S 1"."T 1" r1 WHERE ((c2 >= 0)) + Remote SQL: SELECT count(*) FROM "S 1"."T 1" WHERE ((c2 >= 0)) (4 rows) SELECT count(*) FROM ft1 WHERE c2 >= 0; @@ -5883,12 +5883,12 @@ ROLLBACK; -- A. Simple aggregates explain (verbose, costs off) select sum(c1), avg(c1), min(c2), max(c1), stddev(c2) from ft1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------- Foreign Scan Output: (sum(c1)), (avg(c1)), (min(c2)), (max(c1)), (stddev(c2)) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT sum(r1."C 1"), avg(r1."C 1"), min(r1.c2), max(r1."C 1"), stddev(r1.c2) FROM "S 1"."T 1" r1 + Remote SQL: SELECT sum("C 1"), avg("C 1"), min(c2), max("C 1"), stddev(c2) FROM "S 1"."T 1" (4 rows) select sum(c1), avg(c1), min(c2), max(c1), stddev(c2) from ft1; @@ -5905,22 +5905,22 @@ select sum("C 1"), avg("C 1"), min(c2), max("C 1"), stddev(c2) from "S 1"."T 1"; explain (verbose, costs off) select sum(c1) * random() from ft1; - QUERY PLAN --------------------------------------------------------- + QUERY PLAN +------------------------------------------------------ Foreign Scan Output: (((sum(c1)))::double precision * random()) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT sum(r1."C 1") FROM "S 1"."T 1" r1 + Remote SQL: SELECT sum("C 1") FROM "S 1"."T 1" (4 rows) explain (verbose, costs off) select count(c6) from ft1; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------------------- Foreign Scan Output: (count(c6)) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT count(r1.c6) FROM "S 1"."T 1" r1 + Remote SQL: SELECT count(c6) FROM "S 1"."T 1" (4 rows) select count(c6) from ft1; @@ -5949,12 +5949,12 @@ select sum(c1 * random()), avg(c1) from ft1; explain (verbose, costs off) select sum(c1) from ft2 where c2 < 5; - QUERY PLAN -------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------- Foreign Scan Output: (sum(c1)) Relations: Aggregate on (public.ft2) - Remote SQL: SELECT sum(r1."C 1") FROM "S 1"."T 1" r1 WHERE ((c2 < 5)) + Remote SQL: SELECT sum("C 1") FROM "S 1"."T 1" WHERE ((c2 < 5)) (4 rows) select sum(c1) from ft2 where c2 < 5; @@ -6035,15 +6035,15 @@ select count(*) from ft1 t1 inner join ft1 t2 on (t1.c2 = t2.c2 * random()); -- B. Aggregates with GROUP BY explain (verbose, costs off) select c2, count(*) from ft1 group by c2 order by 1; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------- Sort Output: c2, (count(*)) Sort Key: ft1.c2 -> Foreign Scan Output: c2, (count(*)) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT r1.c2, count(*) FROM "S 1"."T 1" r1 GROUP BY r1.c2 + Remote SQL: SELECT c2, count(*) FROM "S 1"."T 1" GROUP BY c2 (7 rows) select c2, count(*) from ft1 group by c2 order by 1; @@ -6100,15 +6100,15 @@ select c2, count(*) from "S 1"."T 1" group by c2 order by 1; explain (verbose, costs off) select count(c1), length(c6) from ft2 group by c6 order by 1, 2; - QUERY PLAN ------------------------------------------------------------------------------------------------------ + QUERY PLAN +-------------------------------------------------------------------------------------- Sort Output: (count(c1)), (length((c6)::text)), c6 Sort Key: (count(ft2.c1)), (length((ft2.c6)::text)) -> Foreign Scan Output: (count(c1)), (length((c6)::text)), c6 Relations: Aggregate on (public.ft2) - Remote SQL: SELECT count(r1."C 1"), length(r1.c6), r1.c6 FROM "S 1"."T 1" r1 GROUP BY r1.c6 + Remote SQL: SELECT count("C 1"), length(c6), c6 FROM "S 1"."T 1" GROUP BY c6 (7 rows) select count(c1), length(c6) from ft2 group by c6 order by 1, 2; @@ -6143,15 +6143,15 @@ select count("C 1"), length(c6) from "S 1"."T 1" group by c6 order by 1, 2; explain (verbose, costs off) select c2/2, sum(c2) * (c2/2) from ft1 group by c2/2 order by c2/2; - QUERY PLAN ---------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------ Sort Output: ((c2 / 2)), ((sum(c2) * (c2 / 2))) Sort Key: ((ft1.c2 / 2)) -> Foreign Scan Output: ((c2 / 2)), ((sum(c2) * (c2 / 2))) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT (r1.c2 / 2), (sum(r1.c2) * (r1.c2 / 2)) FROM "S 1"."T 1" r1 GROUP BY ((r1.c2 / 2)) + Remote SQL: SELECT (c2 / 2), (sum(c2) * (c2 / 2)) FROM "S 1"."T 1" GROUP BY ((c2 / 2)) (7 rows) select c2/2, sum(c2) * (c2/2) from ft1 group by c2/2 order by c2/2; @@ -6204,8 +6204,8 @@ select c2/2, sum(c2) * (c2/2) from "S 1"."T 1" group by c2/2 order by c2/2; explain (verbose, costs off) select count(a), sum(a) from (select c2 a, sum(c1) b from ft1 group by c2, sqrt(c1) order by 1, 2) x; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------- Aggregate Output: count(ft1.c2), sum(ft1.c2) -> Sort @@ -6214,7 +6214,7 @@ select count(a), sum(a) from (select c2 a, sum(c1) b from ft1 group by c2, sqrt( -> Foreign Scan Output: ft1.c2, (sum(ft1.c1)), (sqrt((ft1.c1)::double precision)) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT r1.c2, sum(r1."C 1"), sqrt(r1."C 1") FROM "S 1"."T 1" r1 GROUP BY r1.c2, (sqrt(r1."C 1")) + Remote SQL: SELECT c2, sum("C 1"), sqrt("C 1") FROM "S 1"."T 1" GROUP BY c2, (sqrt("C 1")) (9 rows) select count(a), sum(a) from (select c2 a, sum(c1) b from ft1 group by c2, sqrt(c1) order by 1, 2) x; @@ -6232,12 +6232,12 @@ select count(a), sum(a) from (select c2 a, sum("C 1") b from "S 1"."T 1" group b -- Aggregate is still pushed down by taking random() out explain (verbose, costs off) select c1 * random(), sum(c1) * c1 from ft1 group by c1; - QUERY PLAN -------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------- Foreign Scan Output: ((c1)::double precision * random()), ((sum(c1) * c1)), c1 Relations: Aggregate on (public.ft1) - Remote SQL: SELECT (sum(r1."C 1") * r1."C 1"), r1."C 1" FROM "S 1"."T 1" r1 GROUP BY r1."C 1" + Remote SQL: SELECT (sum("C 1") * "C 1"), "C 1" FROM "S 1"."T 1" GROUP BY "C 1" (4 rows) --select c1 * random(), sum(c1) * c1 from ft1 group by c1; @@ -6258,15 +6258,15 @@ select c1 * random() from ft2 group by c1 * random(), c2; -- C. Aggregates with HAVING clause explain (verbose, costs off) select c2, sum(c1) from ft2 group by c2 having avg(c1) < 500 order by 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------- Sort Output: c2, (sum(c1)) Sort Key: ft2.c2 -> Foreign Scan Output: c2, (sum(c1)) Relations: Aggregate on (public.ft2) - Remote SQL: SELECT r1.c2, sum(r1."C 1") FROM "S 1"."T 1" r1 GROUP BY r1.c2 HAVING ((avg(r1."C 1") < 500::numeric)) + Remote SQL: SELECT c2, sum("C 1") FROM "S 1"."T 1" GROUP BY c2 HAVING ((avg("C 1") < 500::numeric)) (7 rows) select c2, sum(c1) from ft2 group by c2 having avg(c1) < 500 order by 1; @@ -6285,15 +6285,15 @@ select c2, sum("C 1") from "S 1"."T 1" group by c2 having avg("C 1") < 500 order explain (verbose, costs off) select c2, sum(c1) from ft1 group by c2 having avg(c1) < 500 and sum(c1) < 200000 order by c2; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------- Sort Output: c2, (sum(c1)) Sort Key: ft1.c2 -> Foreign Scan Output: c2, (sum(c1)) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT r1.c2, sum(r1."C 1") FROM "S 1"."T 1" r1 GROUP BY r1.c2 HAVING ((avg(r1."C 1") < 500::numeric)) AND ((sum(r1."C 1") < 200000)) + Remote SQL: SELECT c2, sum("C 1") FROM "S 1"."T 1" GROUP BY c2 HAVING ((avg("C 1") < 500::numeric)) AND ((sum("C 1") < 200000)) (7 rows) select c2, sum(c1) from ft1 group by c2 having avg(c1) < 500 and sum(c1) < 200000 order by c2; @@ -6312,15 +6312,15 @@ select c2, sum("C 1") from "S 1"."T 1" group by c2 having avg("C 1") < 500 and s explain (verbose, costs off) select c5, count(c2) from ft1 group by c5, sqrt(c2) having sqrt(max(c2)) < 2 order by 1, 2; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------- Sort Output: c5, (count(c2)), (sqrt((c2)::double precision)) Sort Key: ft1.c5, (count(ft1.c2)) -> Foreign Scan Output: c5, (count(c2)), (sqrt((c2)::double precision)) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT r1.c5, count(r1.c2), sqrt(r1.c2) FROM "S 1"."T 1" r1 GROUP BY r1.c5, (sqrt(r1.c2)) HAVING ((sqrt(max(r1.c2)) < 2::double precision)) + Remote SQL: SELECT c5, count(c2), sqrt(c2) FROM "S 1"."T 1" GROUP BY c5, (sqrt(c2)) HAVING ((sqrt(max(c2)) < 2::double precision)) (7 rows) select c5, count(c2) from ft1 group by c5, sqrt(c2) having sqrt(max(c2)) < 2 order by 1, 2; @@ -6369,7 +6369,7 @@ select c2, sum(c1) from ft2 group by c2 having sum(c1) * random() < 500000 order Output: c2, (sum(c1)) Filter: ((((sum(ft2.c1)))::double precision * random()) < '500000'::double precision) Relations: Aggregate on (public.ft2) - Remote SQL: SELECT r1.c2, sum(r1."C 1") FROM "S 1"."T 1" r1 GROUP BY r1.c2 + Remote SQL: SELECT c2, sum("C 1") FROM "S 1"."T 1" GROUP BY c2 (8 rows) select c2, sum(c1) from ft2 group by c2 having sum(c1) * random() < 500000 order by c2; @@ -6427,15 +6427,15 @@ select c2, sum("C 1") from "S 1"."T 1" group by c2 having sum("C 1") * random() -- Having clause with random() will be evaluated locally, and other having qual is pushed explain (verbose, costs off) select count(*) from (select c5, count(c1) from ft1 group by c5, sqrt(c2) having avg(c1) * random() < 500 and avg(c1) < 500) x; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------- Aggregate Output: count(*) -> Foreign Scan Output: ft1.c5, (NULL::bigint), (sqrt((ft1.c2)::double precision)) Filter: ((((avg(ft1.c1)))::double precision * random()) < '500'::double precision) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT r1.c5, NULL::bigint, sqrt(r1.c2), avg(r1."C 1") FROM "S 1"."T 1" r1 GROUP BY r1.c5, (sqrt(r1.c2)) HAVING ((avg(r1."C 1") < 500::numeric)) + Remote SQL: SELECT c5, NULL::bigint, sqrt(c2), avg("C 1") FROM "S 1"."T 1" GROUP BY c5, (sqrt(c2)) HAVING ((avg("C 1") < 500::numeric)) (7 rows) select count(*) from (select c5, count(c1) from ft1 group by c5, sqrt(c2) having avg(c1) * random() < 500 and avg(c1) < 500) x; @@ -6453,12 +6453,12 @@ select count(*) from (select c5, count("C 1") from "S 1"."T 1" group by c5, sqrt -- D. ORDER BY, DISTINCT, FILTER, Ordered-sets and VARIADIC within aggregates explain (verbose, costs off) select array_agg(c1 order by c3) from ft1 where c2 = 6 and c1 < 100; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------- Foreign Scan Output: (array_agg(c1 ORDER BY c3)) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT array_agg(r1."C 1" ORDER BY r1.c3) FROM "S 1"."T 1" r1 WHERE (("C 1" < 100)) AND ((c2 = 6)) + Remote SQL: SELECT array_agg("C 1" ORDER BY c3) FROM "S 1"."T 1" WHERE (("C 1" < 100)) AND ((c2 = 6)) (4 rows) select array_agg(c1 order by c3) from ft1 where c2 = 6 and c1 < 100; @@ -6475,15 +6475,15 @@ select array_agg("C 1" order by c3) from "S 1"."T 1" where c2 = 6 and "C 1" < 10 explain (verbose, costs off) select array_agg(c1 order by c1) from ft2 where c1 < 100 group by c2 order by 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Sort Output: (array_agg(c1 ORDER BY c1)), c2 Sort Key: (array_agg(ft2.c1 ORDER BY ft2.c1)) -> Foreign Scan Output: (array_agg(c1 ORDER BY c1)), c2 Relations: Aggregate on (public.ft2) - Remote SQL: SELECT array_agg(r1."C 1" ORDER BY r1."C 1"), r1.c2 FROM "S 1"."T 1" r1 WHERE (("C 1" < 100)) GROUP BY r1.c2 + Remote SQL: SELECT array_agg("C 1" ORDER BY "C 1"), c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) GROUP BY c2 (7 rows) select array_agg(c1 order by c1) from ft2 where c1 < 100 group by c2 order by 1; @@ -6516,12 +6516,12 @@ select array_agg("C 1" order by "C 1") from "S 1"."T 1" where "C 1" < 100 group explain (verbose, costs off) select array_agg(c1 order by c1 desc) from ft1 where c2 = 6 and c1 < 100 group by c2; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (array_agg(c1 ORDER BY c1 DESC)), c2 Relations: Aggregate on (public.ft1) - Remote SQL: SELECT array_agg(r1."C 1" ORDER BY r1."C 1" DESC), r1.c2 FROM "S 1"."T 1" r1 WHERE (("C 1" < 100)) AND ((c2 = 6)) GROUP BY r1.c2 + Remote SQL: SELECT array_agg("C 1" ORDER BY "C 1" DESC), c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) AND ((c2 = 6)) GROUP BY c2 (4 rows) select array_agg(c1 order by c1 desc) from ft1 where c2 = 6 and c1 < 100 group by c2; @@ -6538,12 +6538,12 @@ select array_agg("C 1" order by "C 1" desc) from "S 1"."T 1" where c2 = 6 and "C explain (verbose, costs off) select array_agg(c5 order by c1 desc) from ft2 where c2 = 6 and c1 < 50; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (array_agg(c5 ORDER BY c1 DESC)) Relations: Aggregate on (public.ft2) - Remote SQL: SELECT array_agg(r1.c5 ORDER BY r1."C 1" DESC) FROM "S 1"."T 1" r1 WHERE (("C 1" < 50)) AND ((c2 = 6)) + Remote SQL: SELECT array_agg(c5 ORDER BY "C 1" DESC) FROM "S 1"."T 1" WHERE (("C 1" < 50)) AND ((c2 = 6)) (4 rows) select array_agg(c5 order by c1 desc) from ft2 where c2 = 6 and c1 < 50; @@ -6668,12 +6668,12 @@ select array_agg(distinct (t1.c1)%5 order by (t1.c1)%5 desc nulls last) from "S explain (verbose, costs off) select sum(c1%3), sum(distinct c1%3) filter (where c1%3 < 2), c2 from ft1 where c2 = 6 group by c2; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (sum((c1 % 3))), (sum(DISTINCT (c1 % 3)) FILTER (WHERE ((c1 % 3) < 2))), c2 Relations: Aggregate on (public.ft1) - Remote SQL: SELECT sum((r1."C 1" % 3)), sum(DISTINCT (r1."C 1" % 3)) FILTER (WHERE ((r1."C 1" % 3) < 2)), r1.c2 FROM "S 1"."T 1" r1 WHERE ((c2 = 6)) GROUP BY r1.c2 + Remote SQL: SELECT sum(("C 1" % 3)), sum(DISTINCT ("C 1" % 3)) FILTER (WHERE (("C 1" % 3) < 2)), c2 FROM "S 1"."T 1" WHERE ((c2 = 6)) GROUP BY c2 (4 rows) select sum(c1%3), sum(distinct c1%3) filter (where c1%3 < 2), c2 from ft1 where c2 = 6 group by c2; @@ -6691,8 +6691,8 @@ select sum("C 1"%3), sum(distinct "C 1"%3) filter (where "C 1"%3 < 2), c2 from " -- DISTINCT itself is not pushed down, whereas underneath aggregate is pushed explain (verbose, costs off) select distinct sum(c1), c2 from ft2 where c2 < 6 group by c2 order by c2; - QUERY PLAN ------------------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------- Unique Output: (sum(c1)), c2 -> Sort @@ -6701,7 +6701,7 @@ select distinct sum(c1), c2 from ft2 where c2 < 6 group by c2 order by c2; -> Foreign Scan Output: (sum(c1)), c2 Relations: Aggregate on (public.ft2) - Remote SQL: SELECT sum(r1."C 1"), r1.c2 FROM "S 1"."T 1" r1 WHERE ((c2 < 6)) GROUP BY r1.c2 + Remote SQL: SELECT sum("C 1"), c2 FROM "S 1"."T 1" WHERE ((c2 < 6)) GROUP BY c2 (9 rows) select distinct sum(c1), c2 from ft2 where c2 < 6 group by c2 order by c2; @@ -6720,15 +6720,15 @@ select distinct sum("C 1"), c2 from "S 1"."T 1" where c2 < 6 group by c2 order b explain (verbose, costs off) select sum(c1) filter (where c1 < 100) from ft1 group by c2 order by 1 nulls last; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------- Sort Output: (sum(c1) FILTER (WHERE (c1 < 100))), c2 Sort Key: (sum(ft1.c1) FILTER (WHERE (ft1.c1 < 100))) -> Foreign Scan Output: (sum(c1) FILTER (WHERE (c1 < 100))), c2 Relations: Aggregate on (public.ft1) - Remote SQL: SELECT sum(r1."C 1") FILTER (WHERE (r1."C 1" < 100)), r1.c2 FROM "S 1"."T 1" r1 GROUP BY r1.c2 + Remote SQL: SELECT sum("C 1") FILTER (WHERE ("C 1" < 100)), c2 FROM "S 1"."T 1" GROUP BY c2 (7 rows) select sum(c1) filter (where c1 < 100) from ft1 group by c2 order by 1 nulls last; @@ -6785,15 +6785,15 @@ select sum("C 1") filter (where "C 1" < 100) from "S 1"."T 1" group by c2 order explain (verbose, costs off) select sum(c1) filter (where c1 < 100 and c2 > 5) from ft1 group by c2 order by 1 nulls last; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Sort Output: (sum(c1) FILTER (WHERE ((c1 < 100) AND (c2 > 5)))), c2 Sort Key: (sum(ft1.c1) FILTER (WHERE ((ft1.c1 < 100) AND (ft1.c2 > 5)))) -> Foreign Scan Output: (sum(c1) FILTER (WHERE ((c1 < 100) AND (c2 > 5)))), c2 Relations: Aggregate on (public.ft1) - Remote SQL: SELECT sum(r1."C 1") FILTER (WHERE ((r1."C 1" < 100) AND (r1.c2 > 5))), r1.c2 FROM "S 1"."T 1" r1 GROUP BY r1.c2 + Remote SQL: SELECT sum("C 1") FILTER (WHERE (("C 1" < 100) AND (c2 > 5))), c2 FROM "S 1"."T 1" GROUP BY c2 (7 rows) select sum(c1) filter (where c1 < 100 and c2 > 5) from ft1 group by c2 order by 1 nulls last; @@ -6851,8 +6851,8 @@ select sum("C 1") filter (where "C 1" < 100 and c2 > 5) from "S 1"."T 1" group b -- Outer query is aggregation query explain (verbose, costs off) select distinct (select count(*) filter (where t2.c2 = 6 and t2.c1 < 10) from ft1 t1 where t1.c1 = 6) from ft1 t2 order by 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------- Unique Output: ((SubPlan 1)) -> Sort @@ -6861,7 +6861,7 @@ select distinct (select count(*) filter (where t2.c2 = 6 and t2.c1 < 10) from ft -> Foreign Scan Output: (SubPlan 1) Relations: Aggregate on (public.ft1 t2) - Remote SQL: SELECT count(*) FILTER (WHERE ((r1.c2 = 6) AND (r1."C 1" < 10))) FROM "S 1"."T 1" r1 + Remote SQL: SELECT count(*) FILTER (WHERE ((c2 = 6) AND ("C 1" < 10))) FROM "S 1"."T 1" SubPlan 1 -> Foreign Scan on public.ft1 t1 Output: (count(*) FILTER (WHERE ((t2.c2 = 6) AND (t2.c1 < 10)))) @@ -6883,8 +6883,8 @@ select distinct (select count(*) filter (where t2.c2 = 6 and t2."C 1" < 10) from -- Inner query is aggregation query explain (verbose, costs off) select distinct (select count(t1.c1) filter (where t2.c2 = 6 and t2.c1 < 10) from ft1 t1 where t1.c1 = 6) from ft1 t2 order by 1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------ Unique Output: ((SubPlan 1)) -> Sort @@ -6897,7 +6897,7 @@ select distinct (select count(t1.c1) filter (where t2.c2 = 6 and t2.c1 < 10) fro -> Foreign Scan Output: (count(t1.c1) FILTER (WHERE ((t2.c2 = 6) AND (t2.c1 < 10)))) Relations: Aggregate on (public.ft1 t1) - Remote SQL: SELECT count(r1."C 1") FILTER (WHERE (($1::integer = 6) AND ($2::integer < 10))) FROM "S 1"."T 1" r1 WHERE (("C 1" = 6)) + Remote SQL: SELECT count("C 1") FILTER (WHERE (($1::integer = 6) AND ($2::integer < 10))) FROM "S 1"."T 1" WHERE (("C 1" = 6)) (13 rows) select distinct (select count(t1.c1) filter (where t2.c2 = 6 and t2.c1 < 10) from ft1 t1 where t1.c1 = 6) from ft1 t2 order by 1; @@ -6944,12 +6944,12 @@ select sum(c2) filter (where c2 in (select c2 from ft1 where c2 < 5)) from ft1; explain (verbose, costs off) select percentile_disc(0.25) within group (order by c2) from ft1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------- Foreign Scan Output: (percentile_disc('0.25'::double precision) WITHIN GROUP (ORDER BY c2)) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT percentile_disc(0.25::double precision) WITHIN GROUP (ORDER BY r1.c2) FROM "S 1"."T 1" r1 + Remote SQL: SELECT percentile_disc(0.25::double precision) WITHIN GROUP (ORDER BY c2) FROM "S 1"."T 1" (4 rows) select percentile_disc(0.25) within group (order by c2) from ft1; @@ -6966,15 +6966,15 @@ select percentile_disc(0.25) within group (order by c2) from "S 1"."T 1"; explain (verbose, costs off) select c2, percentile_cont(0.5) within group (order by c1) from ft1 where c2 < 10 group by c2 order by 1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------ Sort Output: c2, (percentile_cont('0.5'::double precision) WITHIN GROUP (ORDER BY ((c1)::double precision))) Sort Key: ft1.c2 -> Foreign Scan Output: c2, (percentile_cont('0.5'::double precision) WITHIN GROUP (ORDER BY ((c1)::double precision))) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT r1.c2, percentile_cont(0.5::double precision) WITHIN GROUP (ORDER BY (r1."C 1")) FROM "S 1"."T 1" r1 WHERE ((c2 < 10)) GROUP BY r1.c2 + Remote SQL: SELECT c2, percentile_cont(0.5::double precision) WITHIN GROUP (ORDER BY ("C 1")) FROM "S 1"."T 1" WHERE ((c2 < 10)) GROUP BY c2 (7 rows) select c2, percentile_cont(0.5) within group (order by c1) from ft1 where c2 < 10 group by c2 order by 1; @@ -6996,33 +6996,33 @@ select c2, percentile_cont(0.5) within group (order by "C 1") from "S 1"."T 1" w -- Error from remote server explain (verbose, costs off) select c2, percentile_cont(c2) within group (order by c1) from ft1 group by c2 order by c2; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------- Sort Output: c2, (percentile_cont((c2)::double precision) WITHIN GROUP (ORDER BY ((c1)::double precision))) Sort Key: ft1.c2 -> Foreign Scan Output: c2, (percentile_cont((c2)::double precision) WITHIN GROUP (ORDER BY ((c1)::double precision))) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT r1.c2, percentile_cont(r1.c2) WITHIN GROUP (ORDER BY (r1."C 1")) FROM "S 1"."T 1" r1 GROUP BY r1.c2 + Remote SQL: SELECT c2, percentile_cont(c2) WITHIN GROUP (ORDER BY ("C 1")) FROM "S 1"."T 1" GROUP BY c2 (7 rows) select c2, percentile_cont(c2) within group (order by c1) from ft1 group by c2 order by c2; ERROR: percentile value 2 is not between 0 and 1 -CONTEXT: Remote SQL command: SELECT r1.c2, percentile_cont(r1.c2) WITHIN GROUP (ORDER BY (r1."C 1")) FROM "S 1"."T 1" r1 GROUP BY r1.c2 +CONTEXT: Remote SQL command: SELECT c2, percentile_cont(c2) WITHIN GROUP (ORDER BY ("C 1")) FROM "S 1"."T 1" GROUP BY c2 select c2, percentile_cont(c2) within group (order by "C 1") from "S 1"."T 1" group by c2 order by c2; ERROR: percentile value 2 is not between 0 and 1 explain (verbose, costs off) select c2, percentile_cont(c2/10::numeric) within group (order by c1) from ft1 where c2 < 10 group by c2 having percentile_cont(c2/10::numeric) within group (order by c1) < 500 order by c2; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Sort Output: c2, (percentile_cont((((c2)::numeric / '10'::numeric))::double precision) WITHIN GROUP (ORDER BY ((c1)::double precision))) Sort Key: ft1.c2 -> Foreign Scan Output: c2, (percentile_cont((((c2)::numeric / '10'::numeric))::double precision) WITHIN GROUP (ORDER BY ((c1)::double precision))) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT r1.c2, percentile_cont((r1.c2 / 10::numeric)) WITHIN GROUP (ORDER BY (r1."C 1")) FROM "S 1"."T 1" r1 WHERE ((c2 < 10)) GROUP BY r1.c2 HAVING ((percentile_cont((r1.c2 / 10::numeric)) WITHIN GROUP (ORDER BY (r1."C 1")) < 500::double precision)) + Remote SQL: SELECT c2, percentile_cont((c2 / 10::numeric)) WITHIN GROUP (ORDER BY ("C 1")) FROM "S 1"."T 1" WHERE ((c2 < 10)) GROUP BY c2 HAVING ((percentile_cont((c2 / 10::numeric)) WITHIN GROUP (ORDER BY ("C 1")) < 500::double precision)) (7 rows) select c2, percentile_cont(c2/10::numeric) within group (order by c1) from ft1 where c2 < 10 group by c2 having percentile_cont(c2/10::numeric) within group (order by c1) < 500 order by c2; @@ -7041,12 +7041,12 @@ select c2, percentile_cont(c2/10::numeric) within group (order by "C 1") from "S explain (verbose, costs off) select rank('10'::varchar) within group (order by c6) from ft1; - QUERY PLAN ------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------ Foreign Scan Output: (rank('10'::character varying) WITHIN GROUP (ORDER BY c6)) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT rank('10'::character varying) WITHIN GROUP (ORDER BY r1.c6) FROM "S 1"."T 1" r1 + Remote SQL: SELECT rank('10'::character varying) WITHIN GROUP (ORDER BY c6) FROM "S 1"."T 1" (4 rows) select rank('10'::varchar) within group (order by c6) from ft1; @@ -7091,15 +7091,15 @@ ALTER SERVER loopback OPTIONS (SET extensions 'postgres_fdw'); -- Now aggregate with VARIADIC will be pushed explain (verbose, costs off) select c2, least_agg(c1) from ft1 where c2 < 100 group by c2 order by c2; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Sort Output: c2, (least_agg(VARIADIC ARRAY[c1])) Sort Key: ft1.c2 -> Foreign Scan Output: c2, (least_agg(VARIADIC ARRAY[c1])) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT r1.c2, public.least_agg(VARIADIC ARRAY[r1."C 1"]) FROM "S 1"."T 1" r1 WHERE ((c2 < 100)) GROUP BY r1.c2 + Remote SQL: SELECT c2, public.least_agg(VARIADIC ARRAY["C 1"]) FROM "S 1"."T 1" WHERE ((c2 < 100)) GROUP BY c2 (7 rows) select c2, least_agg(c1) from ft1 where c2 < 100 group by c2 order by c2; @@ -7126,15 +7126,15 @@ select c2, least_agg("C 1") from "S 1"."T 1" where c2 < 100 group by c2 order by -- Clauses with random() will be evaluated locally, and other clauses are pushed explain (verbose, costs off) select count(*) from (select c2 * random(), count(c1) from ft2 group by c2 having sum(c1) * random() < 100000 and avg(c1) < 50000) x; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Aggregate Output: count(*) -> Foreign Scan Output: ((ft2.c2)::double precision * random()), (NULL::bigint), ft2.c2 Filter: ((((sum(ft2.c1)))::double precision * random()) < '100000'::double precision) Relations: Aggregate on (public.ft2) - Remote SQL: SELECT NULL::bigint, r1.c2, sum(r1."C 1") FROM "S 1"."T 1" r1 GROUP BY r1.c2 HAVING ((avg(r1."C 1") < 50000::numeric)) + Remote SQL: SELECT NULL::bigint, c2, sum("C 1") FROM "S 1"."T 1" GROUP BY c2 HAVING ((avg("C 1") < 50000::numeric)) (7 rows) select count(*) from (select c2 * random(), count(c1) from ft2 group by c2 having sum(c1) * random() < 100000 and avg(c1) < 50000) x; @@ -7151,15 +7151,15 @@ select count(*) from (select c2 * random(), count("C 1") from "S 1"."T 1" group explain (verbose, costs off) select c2, sum(c2) from ft1 group by c2 having avg(c2) + c2 < 10 order by c2; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------- Sort Output: c2, (sum(c2)) Sort Key: ft1.c2 -> Foreign Scan Output: c2, (sum(c2)) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT r1.c2, sum(r1.c2) FROM "S 1"."T 1" r1 GROUP BY r1.c2 HAVING (((avg(r1.c2) + r1.c2) < 10::numeric)) + Remote SQL: SELECT c2, sum(c2) FROM "S 1"."T 1" GROUP BY c2 HAVING (((avg(c2) + c2) < 10::numeric)) (7 rows) select c2, sum(c2) from ft1 group by c2 having avg(c2) + c2 < 10 order by c2; @@ -7197,8 +7197,8 @@ select count(t1.c3) from ft1 t1, ft1 t2 where t1.c1 = postgres_fdw_abs(t1.c2); -- Subquery in FROM clause having aggregate explain (verbose, costs off) select count(*), x.b from ft1, (select c2 a, sum(c1) b from ft1 group by c2) x where ft1.c2 = x.a group by x.b order by 1, 2; - QUERY PLAN ------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------ Sort Output: (count(*)), x.b Sort Key: (count(*)), x.b @@ -7218,7 +7218,7 @@ select count(*), x.b from ft1, (select c2 a, sum(c1) b from ft1 group by c2) x w -> Foreign Scan Output: ft1_1.c2, (sum(ft1_1.c1)) Relations: Aggregate on (public.ft1) - Remote SQL: SELECT r1.c2, sum(r1."C 1") FROM "S 1"."T 1" r1 GROUP BY r1.c2 + Remote SQL: SELECT c2, sum("C 1") FROM "S 1"."T 1" GROUP BY c2 (20 rows) select count(*), x.b from ft1, (select c2 a, sum(c1) b from ft1 group by c2) x where ft1.c2 = x.a group by x.b order by 1, 2; diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index c33916f..4dda273 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -1183,7 +1183,8 @@ postgresGetForeignPlan(PlannerInfo *root, local_exprs = lappend(local_exprs, rinfo->clause); } - if (foreignrel->reloptkind == RELOPT_JOINREL) + if (foreignrel->reloptkind == RELOPT_JOINREL || + foreignrel->reloptkind == RELOPT_UPPER_REL) { /* For a join relation, get the conditions from fdw_private structure */ remote_conds = fpinfo->remote_conds; @@ -1204,6 +1205,13 @@ postgresGetForeignPlan(PlannerInfo *root, { ListCell *lc; + /* + * Right now, we only consider grouping and aggregation beyond + * joins. Queries involving aggregates or grouping do not require + * EPQ mechanism, hence should not have an outer plan here. + */ + Assert(foreignrel->reloptkind != RELOPT_UPPER_REL); + outer_plan->targetlist = fdw_scan_tlist; foreach(lc, local_exprs) @@ -1223,17 +1231,6 @@ postgresGetForeignPlan(PlannerInfo *root, } } } - else if (foreignrel->reloptkind == RELOPT_UPPER_REL) - { - /* - * For a grouping relation, get the conditions from fdw_private - * structure. - */ - remote_conds = fpinfo->remote_conds; - local_exprs = fpinfo->local_conds; - - fdw_scan_tlist = build_tlist_to_deparse(root, foreignrel); - } /* * Build the query string to be sent for execution, and identify @@ -2478,7 +2475,7 @@ postgresExplainDirectModify(ForeignScanState *node, ExplainState *es) * estimate_path_cost_size * Get cost and size estimates for a foreign scan on given foreign relation * either a base relation or a join between foreign relations or an upper - * relation. + * relation containing foreign relations. * * param_join_conds are the parameterization clauses with outer relations. * pathkeys specify the expected sort order if any for given path being costed. @@ -4443,7 +4440,7 @@ postgresGetForeignJoinPaths(PlannerInfo *root, /* * Assess whether the aggregation, grouping and having operations can be pushed * down to the foreign server. As a side effect, save information we obtain in - * this function to PgFdwRelationInfo passed in. + * this function to PgFdwRelationInfo of the input relation. */ static bool foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel) @@ -4461,7 +4458,7 @@ foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel) if (query->groupingSets) return false; - /* Get the fpinfo of the outerrel */ + /* Get the fpinfo of the underlying scan relation. */ ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private; /* @@ -4474,10 +4471,10 @@ foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel) /* * Evaluate grouping targets and check whether they are safe to push down - * to the remote side. All GROUP BY expressions will be part of the - * grouping target and thus no need to evaluate it separately. While doing - * so, add required expressions into target list which can then be used to - * pass to remote server. + * to the foreign side. All GROUP BY expressions will be part of the + * grouping target and thus there is no need to evaluate it separately. + * While doing so, add required expressions into target list which + * can then be used to pass to foreign server. */ i = 0; foreach(lc, grouping_target->exprs) @@ -4490,7 +4487,10 @@ foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel) if (sgref && query->groupClause && query->groupingSets == NIL && get_sortgroupref_clause_noerr(sgref, query->groupClause) != NULL) { - /* Expression matched with GROUP BY, check as is */ + /* + * If any of the GROUP BY expression is not shippable we can not + * push down aggregation to the foreign server. + */ if (!is_foreign_expr(root, grouped_rel, expr, true)) return false; @@ -4521,7 +4521,7 @@ foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel) /* * Add aggregates, if any, into tlist. Plain Var nodes pulled - * are already part of GROUP BY and thus no need to add them + * are already part of some and thus no need to add them * explicitly. */ foreach(l, aggvars) @@ -4654,8 +4654,8 @@ postgresGetForeignUpperPaths(PlannerInfo *root, UpperRelationKind stage, * * Add foreign path for grouping and/or aggregation. * - * input_rel contains the underneath scan rel - * grouped_rel is the rel for which paths need to be added + * input_rel represents the underlying scan. The paths are added to the + * grouped_rel. */ static void create_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,