Re: BUG #19106: Potential regression with CTE materialization planning in Postgres 18
Tom Lane <tgl@sss.pgh.pa.us>
From: Tom Lane <tgl@sss.pgh.pa.us>
To: "Kamil Monicz" <kamil@monicz.dev>
Cc: pgsql-bugs@lists.postgresql.org, Peter Eisentraut <peter@eisentraut.org>,
Vik Fearing <vik@postgresfriends.org>
Date: 2025-11-10T21:05:58Z
Lists: pgsql-bugs
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Don't allow CTEs to determine semantic levels of aggregates.
- b85397481ce3 14.21 landed
- 9f5a58aacf65 15.16 landed
- 35b5c62c3ad9 19 (unreleased) landed
- 1c8c3206f4e0 16.12 landed
- 12bc3291772e 18.2 landed
- 075a763e2d42 17.8 landed
-
Calculate agglevelsup correctly when Aggref contains a CTE.
- b0cc0a71e0a0 19 (unreleased) cited
Attachments
- v1-fix-CTEs-in-aggregates-some-more.patch (text/x-diff) patch v1
[ cc'ing Peter and Vik for possible input on SQL-standard question ] I wrote: > This worked up until commit b0cc0a71e, and since then it hits an > assertion failure in check_agglevels_and_constraints(); or if you > don't have asserts enabled then the planner gets confused, because > the max() aggregate function is given the wrong agglevelsup. > I need to think through what is the correct behavior for cross-CTE > references like these. Sadly, this is too late for this week's > releases ... Here is a draft fix for this. What it basically decides is that commit b0cc0a71e was in error to suppose that an outer CTE reference should work like an outer Var reference. In this even-more-simplified test case: 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; it's pretty obvious that the reference to "a" should not cause us to act as though the max() aggregate belongs to the outer "WITH ... SELECT agg FROM b" query level. However, if it doesn't belong there, where does it belong? The draft patch takes the approach of forcing agglevelsup to zero anytime we find a CTE reference within an aggregate's arguments (unless it is to a CTE defined inside those arguments). That means such an aggregate always has its syntactic level and cannot be treated as an outer aggregate even if it otherwise references (only) outer Vars. I don't have a huge amount of confidence in this being the final answer; it seems like it might still be too simplistic. But I'm not sure what to do instead. It's at least less likely to break cases that worked before b0cc0a71e, since "it's level zero" is pretty much the default answer anyway. I looked at the SQL standard for possible guidance and found none: they disallow subqueries altogether within aggregate arguments, so they need not consider such cases. I am curious though whether Peter or Vik know if the committee ever considered relaxing that restriction, and if so whether they stopped to think about this particular point. regards, tom lane