Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1uywTt-00EjbH-Kl for pgsql-bugs@arkaria.postgresql.org; Wed, 17 Sep 2025 18:02:13 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1uywTr-009nxu-FK for pgsql-bugs@arkaria.postgresql.org; Wed, 17 Sep 2025 18:02:12 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1uywTr-009nxm-6t for pgsql-bugs@lists.postgresql.org; Wed, 17 Sep 2025 18:02:12 +0000 Received: from sss.pgh.pa.us ([68.162.161.243]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1uywTp-000wl3-2J for pgsql-bugs@lists.postgresql.org; Wed, 17 Sep 2025 18:02:11 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.15.2/8.15.2) with ESMTP id 58HI293O1652187; Wed, 17 Sep 2025 14:02:09 -0400 From: Tom Lane To: dllggyx@outlook.com cc: pgsql-bugs@lists.postgresql.org Subject: Re: BUG #19055: Server crash at ExecInterpExpr In-reply-to: <19055-6970cfa8556a394d@postgresql.org> References: <19055-6970cfa8556a394d@postgresql.org> Comments: In-reply-to PG Bug reporting form message dated "Wed, 17 Sep 2025 14:34:23 -0000" MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0" Content-ID: <1652152.1758132102.0@sss.pgh.pa.us> Date: Wed, 17 Sep 2025 14:02:09 -0400 Message-ID: <1652186.1758132129@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk ------- =_aaaaaaaaaa0 Content-Type: text/plain; charset="us-ascii" Content-ID: <1652152.1758132102.1@sss.pgh.pa.us> PG Bug reporting form writes: > PoC: > SELECT FROM ( SELECT generate_series ( 1 , '31' ) x ) GROUP BY ( x ) WINDOW > w AS ( ORDER BY ( WITH x AS ( WITH x AS ( SELECT sum ( x ) ) SELECT DISTINCT > * FROM x ) ( SELECT ( count ( ( SELECT x FROM x ) ) ) ) ) ) Interesting example. De-obfuscating a little bit, we have SELECT 1 FROM ( SELECT generate_series ( 1 , '31' ) gs ) ss GROUP BY ( gs ) WINDOW w AS ( ORDER BY ( WITH x1 AS -- MATERIALIZED ( WITH x2 AS ( SELECT sum ( gs ) ) SELECT DISTINCT * FROM x2 ) SELECT ( count ( ( SELECT gs FROM x1 ) ) ) ) ); If you stick in MATERIALIZED where I show, then instead of an executor assertion failure you get ERROR: could not find CTE "x1" which is also what happens in branches pre-dating default inlining of CTEs. The problem appears to be that the count() aggregate is assigned the wrong agglevelsup: it's labeled with agglevelsup = 1, implying that it belongs to the outer query level (which is where its "gs" input comes from). Then when we try to pull it up to the outer level, the contained reference to the x1 CTE becomes dangling --- the planner can't find any x1 in that level. Or, if we don't say MATERIALIZED, the planner tries to inline x1 and just botches things entirely. I suspect it's getting confused about which level "sum(gs)" belongs to, but I didn't bother running down the details. In any case, this is the parser's fault. Because the count() references x1, it should not be given an agglevelsup higher than where x1 is. The attached seems to fix it. I need to think of a test case with less extraneous crud, though... Thanks for the report! regards, tom lane ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name="fix-agglevelsup-calculation-with-CTEs.patch"; charset="us-ascii" Content-ID: <1652152.1758132102.2@sss.pgh.pa.us> Content-Description: fix-agglevelsup-calculation-with-CTEs.patch diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c index 0ac8966e30f..2bef05b4833 100644 --- a/src/backend/parser/parse_agg.c +++ b/src/backend/parser/parse_agg.c @@ -791,6 +791,33 @@ check_agg_arguments_walker(Node *node, parser_errposition(context->pstate, ((WindowFunc *) node)->location))); } + + if (IsA(node, RangeTblEntry)) + { + /* + * CTE references act as though they were Vars of the CTE's level. + * Typically this doesn't matter because the sub-select containing the + * CTE RTE will also contain Vars referencing that RTE; but if it does + * not, we end with an invalid query tree if we don't do this. + */ + 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 +827,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; } ------- =_aaaaaaaaaa0--