Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pMU5n-0003lO-8l for pgsql-hackers@arkaria.postgresql.org; Mon, 30 Jan 2023 13:21:03 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1pMU5m-0000Sq-7G for pgsql-hackers@arkaria.postgresql.org; Mon, 30 Jan 2023 13:21:02 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pMU5l-0000R1-9Q for pgsql-hackers@lists.postgresql.org; Mon, 30 Jan 2023 13:21:01 +0000 Received: from wout2-smtp.messagingengine.com ([64.147.123.25]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pMU5h-0000oH-Jm for pgsql-hackers@postgresql.org; Mon, 30 Jan 2023 13:21:00 +0000 Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.west.internal (Postfix) with ESMTP id 2C7CE3200AF6; Mon, 30 Jan 2023 08:20:54 -0500 (EST) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Mon, 30 Jan 2023 08:20:54 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:reply-to:sender :subject:subject:to:to:x-me-proxy:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; t=1675084853; x=1675171253; bh=R j3C2DVKHRfIb9/YTXdHvVpAzZ6vPwvySMiKKNu+HMI=; b=A2XyoKOXZMXYAJf04 eM1Bf1CpvzHixgfml/qEZnqNfnyCt6+KTqv8dfNw9IeF3b1kZulfUYfv0rMe3dU0 WjnyR35nzoB+RYt6z8V/7lMnfcT/MW23xiwL9Eql0pODOKp2Ob+nyrF8TuZM7kif dnaT2ZAm+CqA9W/IEJgDdPMbfNQNCr0I0HXQvTSvwFjd2YY/YN8OlvT/fEmaVp9S BjoZT9e0kfcAk6V+8iZpvsMy7eERSlSlDv5/C2c2zTjIzZzKGawjlhhkZevRvri8 voJCkOOha4JanATs3IshdIj1KFihb7dWIVwfZ0F8UB8AXtF4ClYmto0aqGSMV5Mq wiysg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrudefvddgheduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkgggtugfgjgesmhekreertddtjeenucfhrhhomheptehlvhgr rhhoucfjvghrrhgvrhgruceorghlvhhhvghrrhgvsegrlhhvhhdrnhhoqdhiphdrohhrgh eqnecuggftrfgrthhtvghrnhepuefggfffvdefgedvfeellefhieegvdegfeekjeehjedt hfeffeefteevveehtdfhnecuffhomhgrihhnpegvnhhtvghrphhrihhsvggusgdrtghomh dplhifnhdrnhgvthenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhl fhhrohhmpegrlhhvhhgvrhhrvgesrghlvhhhrdhnohdqihhprdhorhhg X-ME-Proxy: Feedback-ID: ia2694551:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 30 Jan 2023 08:20:52 -0500 (EST) Received: by perhan.alvh.no-ip.org (Postfix, from userid 1000) id 8717F99; Mon, 30 Jan 2023 14:06:09 +0100 (CET) Date: Mon, 30 Jan 2023 14:06:09 +0100 From: Alvaro Herrera To: Peter Eisentraut Cc: pgsql-hackers Subject: Re: dynamic result sets support in extended query protocol Message-ID: <20230130130609.mjswqhzqidc3cojl@alvherre.pgsql> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="luu7aruazautdsq4" Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --luu7aruazautdsq4 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit On 2022-Nov-22, Peter Eisentraut wrote: > I added tests using the new psql \bind command to test this functionality in > the extended query protocol, which showed that this got broken since I first > wrote this patch. This "blame" is on the pipeline mode in libpq patch > (acb7e4eb6b1c614c68a62fb3a6a5bba1af0a2659). I need to spend more time on > this and figure out how to repair it. Applying this patch, your test queries seem to work correctly. This is quite WIP, especially because there's a couple of scenarios uncovered by tests that I'd like to ensure correctness about, but if you would like to continue adding tests for extended query and dynamic result sets, it may be helpful. -- Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/ "How strange it is to find the words "Perl" and "saner" in such close proximity, with no apparent sense of irony. I doubt that Larry himself could have managed it." (ncm, http://lwn.net/Articles/174769/) --luu7aruazautdsq4 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="libpq-fix.patch.txt" diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index ec62550e38..b530c51ccd 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -2109,19 +2109,19 @@ PQgetResult(PGconn *conn) break; case PGASYNC_READY: + res = pqPrepareAsyncResult(conn); /* - * For any query type other than simple query protocol, we advance - * the command queue here. This is because for simple query - * protocol we can get the READY state multiple times before the - * command is actually complete, since the command string can - * contain many queries. In simple query protocol, the queue - * advance is done by fe-protocol3 when it receives ReadyForQuery. + * When an error has occurred, we consume one command from the + * queue for each result we return. (Normally, the command would + * be consumed as each result is read from the server.) */ if (conn->cmd_queue_head && - conn->cmd_queue_head->queryclass != PGQUERY_SIMPLE) + (conn->error_result || + (conn->result != NULL && + conn->result->resultStatus == PGRES_FATAL_ERROR))) pqCommandQueueAdvance(conn); - res = pqPrepareAsyncResult(conn); + if (conn->pipelineStatus != PQ_PIPELINE_OFF) { /* diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index 8ab6a88416..2ed74aa0f1 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -205,6 +205,10 @@ pqParseInput3(PGconn *conn) pqSaveErrorResult(conn); } } + if (conn->cmd_queue_head && + conn->cmd_queue_head->queryclass != PGQUERY_SIMPLE) + pqCommandQueueAdvance(conn); + if (conn->result) strlcpy(conn->result->cmdStatus, conn->workBuffer.data, CMDSTATUS_LEN); @@ -231,6 +235,7 @@ pqParseInput3(PGconn *conn) else { conn->pipelineStatus = PQ_PIPELINE_ON; + pqCommandQueueAdvance(conn); conn->asyncStatus = PGASYNC_READY; } } @@ -257,6 +262,7 @@ pqParseInput3(PGconn *conn) pqSaveErrorResult(conn); } } + /* XXX should we advance the command queue here? */ conn->asyncStatus = PGASYNC_READY; break; case '1': /* Parse Complete */ @@ -274,6 +280,7 @@ pqParseInput3(PGconn *conn) pqSaveErrorResult(conn); } } + pqCommandQueueAdvance(conn); conn->asyncStatus = PGASYNC_READY; } break; @@ -324,6 +331,10 @@ pqParseInput3(PGconn *conn) * really possible with the current backend.) We stop * parsing until the application accepts the current * result. + * + * Note that we must have already read one 'T' message + * previously for the same command, so we do not + * advance the command queue here. */ conn->asyncStatus = PGASYNC_READY; return; @@ -355,6 +366,7 @@ pqParseInput3(PGconn *conn) } } conn->asyncStatus = PGASYNC_READY; + pqCommandQueueAdvance(conn); } break; case 't': /* Parameter Description */ @@ -593,14 +605,20 @@ getRowDescriptions(PGconn *conn, int msgLength) /* * If we're doing a Describe, we're done, and ready to pass the result * back to the client. + * + * XXX this coding here is a bit suspicious ... */ - if ((!conn->cmd_queue_head) || - (conn->cmd_queue_head && - conn->cmd_queue_head->queryclass == PGQUERY_DESCRIBE)) + if (!conn->cmd_queue_head) { conn->asyncStatus = PGASYNC_READY; return 0; } + else if (conn->cmd_queue_head->queryclass == PGQUERY_DESCRIBE) + { + conn->asyncStatus = PGASYNC_READY; + pqCommandQueueAdvance(conn); + return 0; + } /* * We could perform additional setup for the new result set here, but for --luu7aruazautdsq4--