From a2ec0d2326a562576905f14d75391d22a0a070b3 Mon Sep 17 00:00:00 2001 From: Tatsuo Ishii Date: Wed, 23 Jul 2025 16:53:03 +0900 Subject: [PATCH v2] Allow to accept simple query even if extended queries do not end. Recently pgJDBC has started to issue simple query without ending extended query protocol sequences with sync. This brought a disaster to pgpool. So pgpool refuses to accept it. https://git.postgresql.org/gitweb/?p=pgpool2.git;a=commit;h=240c668d120065534b1d298d6facc86839fcbab9 However the situation got worse. Previously pgJDBC issued a simple query without ending extended protocol only when "autosave=always" option is given. But it was reported that pgJDBC has started to use it extensively. https://www.postgresql.org/message-id/CAGXsc%2Baoabb2xxyfckrHfTx4da8%3Ds1L9ai%2BY%2BuAS4cBPRMQD2A%40mail.gmail.com So this commit deals with the situation. When a simple query arrives without finishing extended protocol sequences, SimpleQuery() calls ProcessBackendResponse() to process pending extended query protocol replies from backend such as parse, bind or command complete messages, instead of rejecting the simple query. After this, SimpleQuery() process a simple query as usual. Discussion: https://www.postgresql.org/message-id/CAGXsc%2Baoabb2xxyfckrHfTx4da8%3Ds1L9ai%2BY%2BuAS4cBPRMQD2A%40mail.gmail.com --- src/protocol/pool_proto_modules.c | 61 ++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/src/protocol/pool_proto_modules.c b/src/protocol/pool_proto_modules.c index 11befe979..fdb41bbf0 100644 --- a/src/protocol/pool_proto_modules.c +++ b/src/protocol/pool_proto_modules.c @@ -221,23 +221,6 @@ SimpleQuery(POOL_CONNECTION *frontend, /* save last query string for logging purpose */ strlcpy(query_string_buffer, contents, sizeof(query_string_buffer)); - /* - * Check if extended query protocol message ended. If not, reject the - * query and raise an error to terminate the session to avoid hanging up. - * However if we are processing a reset query (frontend == NULL), we skip - * the check as we don't want to raise a error. - */ - if (SL_MODE) - { - if (frontend != NULL && - (pool_is_doing_extended_query_message() || - pool_pending_message_head_message())) - - ereport(FATAL, - (errmsg("simple query \"%s\" arrived before ending an extended query message", - query_string_buffer))); - } - /* show ps status */ query_ps_status(contents, backend); @@ -2930,6 +2913,44 @@ ProcessFrontendResponse(POOL_CONNECTION *frontend, ereport(LOG, (errmsg("Query message from frontend."), errdetail("query: \"%s\"", contents))); + + /* + * Check if extended query protocol message ended. If not, process + * any pending response from backend using + * ProcessBackendResponse(). However if we are processing a reset + * query (frontend == NULL), we skip the check as we don't need to + * care about any pending response from backend. + */ + if (SL_MODE) + { + int state; + short num_fields; + + if (frontend != NULL && + (pool_is_doing_extended_query_message() || + pool_pending_message_exists())) + { + ereport(DEBUG1, + (errmsg("simple query \"%s\" arrived before ending an extended query message", + contents))); + + /* if pending message exists, process it */ + while (pool_pending_message_exists()) + { + /* + * read_kind_from_backend requires that query is + * inprogress and doing extended query state because + * it needs to refer to proper query context in + * session context. + */ + pool_set_query_in_progress(); + pool_set_doing_extended_query_message(); + /* process pending responses from backend */ + ProcessBackendResponse(frontend, backend, &state, &num_fields); + } + } + pool_unset_doing_extended_query_message(); + } status = SimpleQuery(frontend, backend, len, contents); break; @@ -3080,6 +3101,12 @@ ProcessFrontendResponse(POOL_CONNECTION *frontend, return status; } +/* + * Read one backend response and process it. + * + * state: used for processing reset query + * num_fields: used in V2 protocol + */ POOL_STATUS ProcessBackendResponse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, -- 2.25.1