v1-fix-CTEs-in-aggregates-some-more.patch
text/x-diff
Filename: v1-fix-CTEs-in-aggregates-some-more.patch
Type: text/x-diff
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v1
| File | + | − |
|---|---|---|
| src/backend/parser/parse_agg.c | 12 | 6 |
| src/test/regress/expected/with.out | 28 | 0 |
| src/test/regress/sql/with.sql | 13 | 0 |
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 3254c83cc6c..5de07a2aa9a 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -795,9 +795,16 @@ check_agg_arguments_walker(Node *node,
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.
+ * If we find a nonlocal CTE reference, force the Agg to be given
+ * level zero, i.e. make its semantic level match its syntactic level.
+ * Without this we might conclude that the Agg can be evaluated above
+ * the CTE (if it contains only Vars from above the CTE), leading to
+ * trouble. On the other hand, we shouldn't allow a CTE reference by
+ * itself to promote an Agg to be an outer Agg; that fails for
+ * cross-references to sibling CTEs. The best solution seems to be to
+ * force the Agg to level zero. (The SQL spec provides no guidance
+ * here; they disallow subqueries within aggregates, and therefore
+ * don't reach the question of what to do with CTE references.)
*/
RangeTblEntry *rte = (RangeTblEntry *) node;
@@ -810,9 +817,8 @@ check_agg_arguments_walker(Node *node,
/* ignore local CTEs of subqueries */
if (ctelevelsup >= 0)
{
- if (context->min_varlevel < 0 ||
- context->min_varlevel > ctelevelsup)
- context->min_varlevel = ctelevelsup;
+ /* nonlocal CTE, so force Agg to level zero */
+ context->min_varlevel = 0;
}
}
return false; /* allow range_table_walker to continue */
diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out
index 86fdb85c6c5..bb45cb83c62 100644
--- a/src/test/regress/expected/with.out
+++ b/src/test/regress/expected/with.out
@@ -2331,6 +2331,34 @@ from int4_tbl i4;
-2147483647 | 1
(5 rows)
+--
+-- test for bug #19106: interaction of WITH with aggregates
+--
+-- the fix for #19055 was too aggressive and broke this case
+explain (verbose, costs off)
+with a as ( select id from (values (1), (2)) as v(id) ),
+ b as ( select max((select sum(id) from a)) as agg )
+select agg from b;
+ QUERY PLAN
+--------------------------------------------
+ Aggregate
+ Output: max((InitPlan expr_1).col1)
+ InitPlan expr_1
+ -> Aggregate
+ Output: sum("*VALUES*".column1)
+ -> Values Scan on "*VALUES*"
+ Output: "*VALUES*".column1
+ -> Result
+(8 rows)
+
+with a as ( select id from (values (1), (2)) as v(id) ),
+ b as ( select max((select sum(id) from a)) as agg )
+select agg from b;
+ agg
+-----
+ 3
+(1 row)
+
--
-- test for nested-recursive-WITH bug
--
diff --git a/src/test/regress/sql/with.sql b/src/test/regress/sql/with.sql
index d88d5abb91a..e199662edd3 100644
--- a/src/test/regress/sql/with.sql
+++ b/src/test/regress/sql/with.sql
@@ -1111,6 +1111,19 @@ 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 bug #19106: interaction of WITH with aggregates
+--
+-- the fix for #19055 was too aggressive and broke this case
+explain (verbose, costs off)
+with a as ( select id from (values (1), (2)) as v(id) ),
+ b as ( select max((select sum(id) from a)) as agg )
+select agg from b;
+
+with a as ( select id from (values (1), (2)) as v(id) ),
+ b as ( select max((select sum(id) from a)) as agg )
+select agg from b;
+
--
-- test for nested-recursive-WITH bug
--