diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/parser/parse_agg.c | 28 | ||||
-rw-r--r-- | src/test/regress/expected/with.out | 34 | ||||
-rw-r--r-- | src/test/regress/sql/with.sql | 14 |
3 files changed, 75 insertions, 1 deletions
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c index 0ac8966e30f..3254c83cc6c 100644 --- a/src/backend/parser/parse_agg.c +++ b/src/backend/parser/parse_agg.c @@ -791,6 +791,32 @@ check_agg_arguments_walker(Node *node, parser_errposition(context->pstate, ((WindowFunc *) node)->location))); } + + if (IsA(node, RangeTblEntry)) + { + /* + * CTE references act similarly to Vars of the CTE's level. Without + * this we might conclude that the Agg can be evaluated above the CTE, + * leading to trouble. + */ + RangeTblEntry *rte = (RangeTblEntry *) node; + + if (rte->rtekind == RTE_CTE) + { + int ctelevelsup = rte->ctelevelsup; + + /* convert levelsup to frame of reference of original query */ + ctelevelsup -= context->sublevels_up; + /* ignore local CTEs of subqueries */ + if (ctelevelsup >= 0) + { + if (context->min_varlevel < 0 || + context->min_varlevel > ctelevelsup) + context->min_varlevel = ctelevelsup; + } + } + return false; /* allow range_table_walker to continue */ + } if (IsA(node, Query)) { /* Recurse into subselects */ @@ -800,7 +826,7 @@ check_agg_arguments_walker(Node *node, result = query_tree_walker((Query *) node, check_agg_arguments_walker, context, - 0); + QTW_EXAMINE_RTES_BEFORE); context->sublevels_up--; return result; } diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out index f015e997276..c3932c7b94c 100644 --- a/src/test/regress/expected/with.out +++ b/src/test/regress/expected/with.out @@ -2298,6 +2298,40 @@ from int4_tbl; (5 rows) -- +-- test for bug #19055: interaction of WITH with aggregates +-- +-- The reference to cte1 must determine the aggregate's level, +-- even though it contains no Vars referencing cte1 +explain (verbose, costs off) +select f1, (with cte1(x,y) as (select 1,2) + select count((select i4.f1 from cte1))) as ss +from int4_tbl i4; + QUERY PLAN +-------------------------------------------- + Seq Scan on public.int4_tbl i4 + Output: i4.f1, (SubPlan 2) + SubPlan 2 + -> Aggregate + Output: count((InitPlan 1).col1) + InitPlan 1 + -> Result + Output: i4.f1 + -> Result +(9 rows) + +select f1, (with cte1(x,y) as (select 1,2) + select count((select i4.f1 from cte1))) as ss +from int4_tbl i4; + f1 | ss +-------------+---- + 0 | 1 + 123456 | 1 + -123456 | 1 + 2147483647 | 1 + -2147483647 | 1 +(5 rows) + +-- -- test for nested-recursive-WITH bug -- WITH RECURSIVE t(j) AS ( diff --git a/src/test/regress/sql/with.sql b/src/test/regress/sql/with.sql index b1cae161290..d88d5abb91a 100644 --- a/src/test/regress/sql/with.sql +++ b/src/test/regress/sql/with.sql @@ -1098,6 +1098,20 @@ select ( with cte(foo) as ( values(f1) ) from int4_tbl; -- +-- test for bug #19055: interaction of WITH with aggregates +-- +-- The reference to cte1 must determine the aggregate's level, +-- even though it contains no Vars referencing cte1 +explain (verbose, costs off) +select f1, (with cte1(x,y) as (select 1,2) + select count((select i4.f1 from cte1))) as ss +from int4_tbl i4; + +select f1, (with cte1(x,y) as (select 1,2) + select count((select i4.f1 from cte1))) as ss +from int4_tbl i4; + +-- -- test for nested-recursive-WITH bug -- WITH RECURSIVE t(j) AS ( |