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 1ubRJ7-000owk-9F for pgsql-bugs@arkaria.postgresql.org; Mon, 14 Jul 2025 22:05:57 +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 1ubRJ3-00EQVN-H3 for pgsql-bugs@arkaria.postgresql.org; Mon, 14 Jul 2025 22:05:54 +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 1ubRJ3-00EQV5-8l for pgsql-bugs@lists.postgresql.org; Mon, 14 Jul 2025 22:05:53 +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 1ubRJ2-007Isg-0d for pgsql-bugs@lists.postgresql.org; Mon, 14 Jul 2025 22:05:52 +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 56EM5oop792013; Mon, 14 Jul 2025 18:05:50 -0400 From: Tom Lane To: Aleksander Alekseev cc: pgsql-bugs@lists.postgresql.org, exclusion@gmail.com Subject: Re: BUG #18984: Empty prepared statement from psql \parse triggers assert in PortalRunMulti In-reply-to: <743115.1752529222@sss.pgh.pa.us> References: <18984-0f4778a6599ac3ae@postgresql.org> <715434.1752521761@sss.pgh.pa.us> <743115.1752529222@sss.pgh.pa.us> Comments: In-reply-to Tom Lane message dated "Mon, 14 Jul 2025 17:40:22 -0400" MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0" Content-ID: <791973.1752530722.0@sss.pgh.pa.us> Date: Mon, 14 Jul 2025 18:05:50 -0400 Message-ID: <792012.1752530750@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: <791973.1752530722.1@sss.pgh.pa.us> I wrote: > The attached quick draft (needs attention to comments) results in > regression=# \parse s > regression=# execute s; > EXECUTE > which matches the behavior of pre-v12 servers. Another way that's perhaps a bit less magical is to make ExecuteQuery substitute the right thing, as attached. I'm not entirely sure whether this leaves any other code paths that can reach that Assert; but on the other hand, if there are any, CMDTAG_EXECUTE is probably wrong for them. BTW, the reason why EXPLAIN EXECUTE isn't at risk is that it's going to return CMDTAG_EXPLAIN. regards, tom lane ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name="wip2-avoid-failure-with-empty-prepared-query.patch"; charset="us-ascii" Content-ID: <791973.1752530722.2@sss.pgh.pa.us> Content-Description: wip2-avoid-failure-with-empty-prepared-query.patch diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index 34b6410d6a2..6ecc24fdba8 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -159,6 +159,7 @@ ExecuteQuery(ParseState *pstate, EState *estate = NULL; Portal portal; char *query_string; + CommandTag commandTag; int eflags; long count; @@ -196,6 +197,15 @@ ExecuteQuery(ParseState *pstate, cplan = GetCachedPlan(entry->plansource, paramLI, NULL, NULL); plan_list = cplan->stmt_list; + /* + * Normally the PlanSource will have a usable commandTag, but if it has an + * empty statement list, then not so much. Substitute EXECUTE to avoid + * failing because we have no commandTag to report to the client. + */ + commandTag = entry->plansource->commandTag; + if (commandTag == CMDTAG_UNKNOWN) + commandTag = CMDTAG_EXECUTE; + /* * DO NOT add any logic that could possibly throw an error between * GetCachedPlan and PortalDefineQuery, or you'll leak the plan refcount. @@ -203,7 +213,7 @@ ExecuteQuery(ParseState *pstate, PortalDefineQuery(portal, NULL, query_string, - entry->plansource->commandTag, + commandTag, plan_list, cplan); ------- =_aaaaaaaaaa0--