From 08b42ef276524a874b4823614ef0716251374032 Mon Sep 17 00:00:00 2001 From: Taiki Koshino Date: Mon, 17 Aug 2026 22:06:04 +0900 Subject: [PATCH v1] Fix hang on deferred constraint errors in pipeline mode PostgreSQL 19 and later include a psql_pipeline regression test for a deferred constraint violation at commit time. When this test is run through Pgpool-II, it hangs after reporting the constraint violation. The test sends Sync at the end of a pipeline containing an INSERT into a table with a DEFERRABLE INITIALLY DEFERRED primary key. PostgreSQL detects the duplicate key while processing Sync and returns an ErrorResponse. Previously, read_kind_from_backend() removed the pending Sync message when it received the ErrorResponse. ErrorResponse processing then incorrectly concluded that Sync had not yet been received from the frontend and waited for another Sync. Since psql had already sent Sync as part of \endpipeline, both sides waited indefinitely and the psql_pipeline test failed to complete. Keep the pending Sync message in the queue when an ErrorResponse is received. This allows error processing to recognize that Sync has already been received and to continue processing through ReadyForQuery. This patch has been verified to apply to master and versions V4_7_STABLE through V4_3_STABLE. --- src/protocol/pool_process_query.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/protocol/pool_process_query.c b/src/protocol/pool_process_query.c index ca01d1ea5..b25d4cda3 100644 --- a/src/protocol/pool_process_query.c +++ b/src/protocol/pool_process_query.c @@ -3878,6 +3878,12 @@ read_kind_from_backend(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, * Also if it's 't' (parameter description) and the pulled message was * 'describe', the message must not be pulled out so that the row * description message from backend matches the describe message. + * + * If an ErrorResponse is returned while processing Sync, the Sync + * pending message must also be left in the queue. This can happen when + * a deferred constraint check fails while committing an implicit + * transaction. ErrorResponse processing uses the pending Sync message + * to determine that Sync has already been received from the frontend. */ if (SL_MODE && pool_is_doing_extended_query_message() && msg) { @@ -3886,7 +3892,8 @@ read_kind_from_backend(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, *decided_kind == 'N' || *decided_kind == 'G' || *decided_kind == 'H' || *decided_kind == 'd' || *decided_kind == 'c')) || - (msg->type == POOL_DESCRIBE && *decided_kind == 't')) + (msg->type == POOL_DESCRIBE && *decided_kind == 't') || + (msg->type == POOL_SYNC && *decided_kind == 'E')) { ereport(DEBUG5, (errmsg("read_kind_from_backend: pending message was left"))); -- 2.52.0