From 19e587d14be960fd95ff3258f727acea85e385ce Mon Sep 17 00:00:00 2001
From: Tatsuo Ishii <ishii@postgresql.org>
Date: Mon, 14 Jul 2025 15:48:53 +0900
Subject: [PATCH v1] Feature: implement protocol version 3.2 BackendKeyData and
 query cancel message.

Starting from PostgreSQL 18, frontend/backend protocol has been
changed to 3.2. In the changes the BackendKeyData and query cancel
message are modified to allow variable length cancel key.

This commit implements the changes and now we can connect to
PostgreSQL frontend and backend using 3.2 protocol.

Example session is:
PGMAXPROTOCOLVERSION="3.2" psql -p 11000 test
---
 src/auth/pool_auth.c                      | 81 +++++++++++++----------
 src/context/pool_query_context.c          |  8 ++-
 src/include/pcp/libpcp_ext.h              |  8 ++-
 src/include/pool.h                        | 11 ++-
 src/include/protocol/pool_process_query.h |  4 +-
 src/include/protocol/pool_proto_modules.h |  3 +-
 src/protocol/child.c                      | 56 ++++++++++------
 src/protocol/pool_process_query.c         | 36 ++++++----
 src/protocol/pool_proto_modules.c         |  2 +-
 src/rewrite/pool_lobj.c                   |  4 +-
 10 files changed, 133 insertions(+), 80 deletions(-)

diff --git a/src/auth/pool_auth.c b/src/auth/pool_auth.c
index 54d646bc3..8187187a0 100644
--- a/src/auth/pool_auth.c
+++ b/src/auth/pool_auth.c
@@ -58,7 +58,8 @@
 #define MAX_SASL_PAYLOAD_LEN 1024
 
 
-static POOL_STATUS pool_send_backend_key_data(POOL_CONNECTION * frontend, int pid, int key, int protoMajor);
+static void pool_send_backend_key_data(POOL_CONNECTION * frontend, int pid,
+									   char *key, int32 keylen, int protoMajor);
 static int	do_clear_text_password(POOL_CONNECTION * backend, POOL_CONNECTION * frontend, int reauth, int protoMajor);
 static void pool_send_auth_fail(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * cp);
 static int do_md5(POOL_CONNECTION * backend, POOL_CONNECTION * frontend, int reauth, int protoMajor,
@@ -92,9 +93,7 @@ connection_do_auth(POOL_CONNECTION_POOL_SLOT * cp, char *password)
 	int			length;
 	int			auth_kind;
 	char		state;
-	char	   *p;
-	int			pid,
-				key;
+	int			pid;
 	bool		keydata_done;
 
 	/*
@@ -244,6 +243,9 @@ connection_do_auth(POOL_CONNECTION_POOL_SLOT * cp, char *password)
 
 		switch (kind)
 		{
+			char	*p;
+			int32	keylen;
+
 			case 'K':			/* backend key data */
 				keydata_done = true;
 				ereport(DEBUG1,
@@ -251,12 +253,14 @@ connection_do_auth(POOL_CONNECTION_POOL_SLOT * cp, char *password)
 
 				/* read message length */
 				pool_read_with_error(cp->con, &length, sizeof(length), "message length for authentication kind 'K'");
-				if (ntohl(length) != 12)
+				length = ntohl(length);
+				keylen = length - sizeof(int32) - sizeof(int32);
+				if (keylen > MAX_CANCELKEY_LENGTH)
 				{
 					ereport(ERROR,
 							(errmsg("failed to authenticate"),
-							 errdetail("invalid backend key data length. received %d bytes when expecting 12 bytes"
-									   ,ntohl(length))));
+							 errdetail("invalid backend key data length. received %d bytes exceeding %d", 
+									   ntohl(length), MAX_CANCELKEY_LENGTH)));
 				}
 
 				/* read pid */
@@ -264,9 +268,9 @@ connection_do_auth(POOL_CONNECTION_POOL_SLOT * cp, char *password)
 				cp->pid = pid;
 
 				/* read key */
-				pool_read_with_error(cp->con, &key, sizeof(key),
-									 "key for authentication kind 'K'");
-				cp->key = key;
+				keylen = length - sizeof(int32) - sizeof(int32);
+				p = pool_read2(cp->con, keylen);
+				memcpy(cp->key, p, keylen);
 				break;
 
 			case 'Z':			/* Ready for query */
@@ -332,14 +336,15 @@ pool_do_auth(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * cp)
 {
 	signed char kind;
 	int			pid;
-	int			key;
 	int			protoMajor;
 	int			length;
 	int			authkind;
 	int			i;
 	int			message_length = 0;
 	StartupPacket *sp;
-
+	int32		keylen;	/* cancel key length */
+	char	cancel_key[MAX_CANCELKEY_LENGTH];
+	char		*p;
 
 	protoMajor = MAIN_CONNECTION(cp)->sp->major;
 
@@ -722,17 +727,23 @@ read_kind:
 	}
 
 	/*
-	 * message length (V3 only)
+	 * Read BackendKeyData message length.
 	 */
 	if (protoMajor == PROTO_MAJOR_V3)
 	{
-		if ((length = pool_read_message_length(cp)) != 12)
+		length = pool_read_message_length(cp);
+		keylen = length - sizeof(int32) - sizeof(int32);
+		if (keylen > MAX_CANCELKEY_LENGTH)
 		{
 			ereport(ERROR,
-					(errmsg("authentication failed"),
-					 errdetail("invalid messages length(%d) for BackendKeyData", length)));
+					(errcode(ERRCODE_PROTOCOL_VIOLATION),
+					 errmsg("cancel key length exceeds 256 bytes")));
 		}
 	}
+	else
+			keylen = 4;
+
+	elog(DEBUG1, "cancel key length: %d", keylen);
 
 	/*
 	 * OK, read pid and secret key
@@ -758,13 +769,17 @@ read_kind:
 			CONNECTION_SLOT(cp, i)->pid = cp->info[i].pid = pid;
 
 			/* read key */
-			if (pool_read(CONNECTION(cp, i), &key, sizeof(key)) < 0)
+			p = pool_read2(CONNECTION(cp, i), keylen);
+			if (p == NULL)
 			{
 				ereport(ERROR,
 						(errmsg("authentication failed"),
-						 errdetail("failed to read key in slot %d", i)));
+						 errdetail("failed to read key of length: %d in slot %d", keylen, i)));
 			}
-			CONNECTION_SLOT(cp, i)->key = cp->info[i].key = key;
+			memcpy(CONNECTION_SLOT(cp, i)->key, p, keylen);
+			memcpy(cp->info[i].key, p, keylen);
+			memcpy(cancel_key, p, keylen);
+			CONNECTION_SLOT(cp, i)->keylen = cp->info[i].keylen = keylen;
 
 			cp->info[i].major = sp->major;
 
@@ -791,10 +806,9 @@ read_kind:
 				(errmsg("authentication failed"),
 				 errdetail("pool_do_auth: all backends are down")));
 	}
-	if (pool_send_backend_key_data(frontend, pid, key, protoMajor))
-		ereport(ERROR,
-				(errmsg("authentication failed"),
-				 errdetail("failed to send backend data to frontend")));
+
+	pool_send_backend_key_data(frontend, pid, cancel_key,
+							   MAIN_CONNECTION(cp)->keylen, protoMajor);
 	return 0;
 }
 
@@ -872,7 +886,8 @@ pool_do_reauth(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * cp)
 	pool_write_and_flush(frontend, &msglen, sizeof(msglen));
 
 	/* send BackendKeyData */
-	pool_send_backend_key_data(frontend, MAIN_CONNECTION(cp)->pid, MAIN_CONNECTION(cp)->key, protoMajor);
+	pool_send_backend_key_data(frontend, MAIN_CONNECTION(cp)->pid, MAIN_CONNECTION(cp)->key,
+							   MAIN_CONNECTION(cp)->keylen, protoMajor);
 
 	return 0;
 }
@@ -903,29 +918,27 @@ pool_send_auth_fail(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * cp)
 }
 
 /*
- * Send backend key data to frontend. if success return 0 otherwise non 0.
+ * Send backend key data to frontend.
  */
-static POOL_STATUS pool_send_backend_key_data(POOL_CONNECTION * frontend, int pid, int key, int protoMajor)
+static void
+pool_send_backend_key_data(POOL_CONNECTION * frontend, int pid,
+						   char *key, int32 keylen, int protoMajor)
 {
 	char		kind;
-	int			len;
+	int32		len;
 
 	/* Send backend key data */
 	kind = 'K';
 	pool_write(frontend, &kind, 1);
 	if (protoMajor == PROTO_MAJOR_V3)
 	{
-		len = htonl(12);
+		len = htonl(sizeof(int32) + sizeof(int32) + keylen);
 		pool_write(frontend, &len, sizeof(len));
 	}
 	ereport(DEBUG1,
-			(errmsg("sending backend key data"),
-			 errdetail("send pid %d to frontend", ntohl(pid))));
-
+			(errmsg("sending backend key data")));
 	pool_write(frontend, &pid, sizeof(pid));
-	pool_write_and_flush(frontend, &key, sizeof(key));
-
-	return 0;
+	pool_write_and_flush(frontend, key, keylen);
 }
 
 static void
diff --git a/src/context/pool_query_context.c b/src/context/pool_query_context.c
index 3b9028497..d398bee6d 100644
--- a/src/context/pool_query_context.c
+++ b/src/context/pool_query_context.c
@@ -4,7 +4,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2024	PgPool Global Development Group
+ * Copyright (c) 2003-2025	PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -663,7 +663,8 @@ pool_send_and_wait(POOL_QUERY_CONTEXT * query_context,
 												   CONNECTION(backend, i),
 												   MAJOR(backend),
 												   MAIN_CONNECTION(backend)->pid,
-												   MAIN_CONNECTION(backend)->key);
+												   MAIN_CONNECTION(backend)->key,
+												   MAIN_CONNECTION(backend)->keylen);
 
 		/*
 		 * Check if some error detected.  If so, emit log. This is useful when
@@ -880,7 +881,8 @@ pool_extended_send_and_wait(POOL_QUERY_CONTEXT * query_context,
 													   CONNECTION(backend, i),
 													   MAJOR(backend),
 													   MAIN_CONNECTION(backend)->pid,
-													   MAIN_CONNECTION(backend)->key);
+													   MAIN_CONNECTION(backend)->key,
+													   MAIN_CONNECTION(backend)->keylen);
 
 			/*
 			 * Check if some error detected.  If so, emit log. This is useful
diff --git a/src/include/pcp/libpcp_ext.h b/src/include/pcp/libpcp_ext.h
index d79ddc156..3a6d87858 100644
--- a/src/include/pcp/libpcp_ext.h
+++ b/src/include/pcp/libpcp_ext.h
@@ -136,6 +136,11 @@ typedef enum
 	CONNECTING
 }			ProcessStatus;
 
+/*
+ * mamimum cancel key length
+*/
+#define	MAX_CANCELKEY_LENGTH	256
+
 /*
  * Connection pool information. Placed on shared memory area.
  */
@@ -147,7 +152,8 @@ typedef struct
 	int			major;			/* protocol major version */
 	int			minor;			/* protocol minor version */
 	int			pid;			/* backend process id */
-	int			key;			/* cancel key */
+	char		key[MAX_CANCELKEY_LENGTH];			/* cancel key */
+	int32		keylen;			/* cancel key length */
 	int			counter;		/* used counter */
 	time_t		create_time;	/* connection creation time */
 	time_t		client_connection_time;	/* client connection time */
diff --git a/src/include/pool.h b/src/include/pool.h
index 28cf1757c..c34a06d2a 100644
--- a/src/include/pool.h
+++ b/src/include/pool.h
@@ -185,7 +185,7 @@ typedef struct CancelPacket
 {
 	int			protoVersion;	/* Protocol version */
 	int			pid;			/* backend process id */
-	int			key;			/* cancel key */
+	char		key[MAX_CANCELKEY_LENGTH];			/* cancel key */
 }			CancelPacket;
 
 #define MAX_PASSWORD_SIZE		1024
@@ -294,7 +294,12 @@ typedef struct
 {
 	StartupPacket *sp;			/* startup packet info */
 	int			pid;			/* backend pid */
-	int			key;			/* cancel key */
+	char		key[MAX_CANCELKEY_LENGTH];			/* cancel key */
+	/*
+	 * Cancel key length. In protocol version 3.0, it is 4.
+	 * In 3.2 or later, the maximum length is 256.
+	 */
+	int32		keylen;
 	POOL_CONNECTION *con;
 	time_t		closetime;		/* absolute time in second when the connection
 								 * closed if 0, that means the connection is
@@ -655,7 +660,7 @@ extern void pcp_main(int *fds);
 extern void do_child(int *fds);
 extern void child_exit(int code);
 
-extern void cancel_request(CancelPacket * sp);
+extern void cancel_request(CancelPacket * sp, int32 len);
 extern void check_stop_request(void);
 extern void pool_initialize_private_backend_status(void);
 extern int	send_to_pg_frontend(char *data, int len, bool flush);
diff --git a/src/include/protocol/pool_process_query.h b/src/include/protocol/pool_process_query.h
index 7f91dbbcd..e799b4d9d 100644
--- a/src/include/protocol/pool_process_query.h
+++ b/src/include/protocol/pool_process_query.h
@@ -3,7 +3,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2020	PgPool Global Development Group
+ * Copyright (c) 2003-2025	PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -35,7 +35,7 @@ extern void per_node_statement_log(POOL_CONNECTION_POOL * backend,
 extern int	pool_extract_error_message(bool read_kind, POOL_CONNECTION * backend,
 									   int major, bool unread, char **message);
 extern POOL_STATUS do_command(POOL_CONNECTION * frontend, POOL_CONNECTION * backend,
-							  char *query, int protoMajor, int pid, int key, int no_ready_for_query);
+							  char *query, int protoMajor, int pid, char *key, int keylen, int no_ready_for_query);
 extern void do_query(POOL_CONNECTION * backend, char *query, POOL_SELECT_RESULT * *result, int major);
 extern void free_select_result(POOL_SELECT_RESULT * result);
 extern int	compare(const void *p1, const void *p2);
diff --git a/src/include/protocol/pool_proto_modules.h b/src/include/protocol/pool_proto_modules.h
index 663dcc984..28668aa6e 100644
--- a/src/include/protocol/pool_proto_modules.h
+++ b/src/include/protocol/pool_proto_modules.h
@@ -151,7 +151,8 @@ extern int RowDescription(POOL_CONNECTION * frontend,
 			   POOL_CONNECTION_POOL * backend,
 			   short *result);
 
-extern void wait_for_query_response_with_trans_cleanup(POOL_CONNECTION * frontend, POOL_CONNECTION * backend, int protoVersion, int pid, int key);
+extern void wait_for_query_response_with_trans_cleanup(POOL_CONNECTION * frontend, POOL_CONNECTION * backend,
+													   int protoVersion, int pid, char *key, int keylen);
 extern POOL_STATUS wait_for_query_response(POOL_CONNECTION * frontend, POOL_CONNECTION * backend, int protoVersion);
 extern bool is_select_query(Node *node, char *sql);
 extern bool is_commit_query(Node *node);
diff --git a/src/protocol/child.c b/src/protocol/child.c
index 7aea33540..1bef0421c 100644
--- a/src/protocol/child.c
+++ b/src/protocol/child.c
@@ -624,14 +624,16 @@ read_startup_packet(POOL_CONNECTION * cp)
 	len = ntohl(len);
 	len -= sizeof(len);
 
-	if (len <= 0 || len >= MAX_STARTUP_PACKET_LENGTH)
+	if (len < 4 || len > MAX_STARTUP_PACKET_LENGTH)
 		ereport(ERROR,
 				(errmsg("failed while reading startup packet"),
 				 errdetail("incorrect packet length (%d)", len)));
 
 	sp->startup_packet = palloc0(len);
 
-	/* read startup packet */
+	/*
+	 * Read startup packet except the length of the message.
+	 */
 	pool_read_with_error(cp, sp->startup_packet, len,
 						 "startup packet");
 
@@ -861,7 +863,8 @@ connect_using_existing_connection(POOL_CONNECTION * frontend,
 						do_command(frontend, CONNECTION(backend, i),
 								   command_buf, MAJOR(backend),
 								   MAIN_CONNECTION(backend)->pid,
-								   MAIN_CONNECTION(backend)->key, 0);
+								   MAIN_CONNECTION(backend)->key,
+								   MAIN_CONNECTION(backend)->keylen, 0);
 					}
 					PG_CATCH();
 					{
@@ -902,7 +905,7 @@ connect_using_existing_connection(POOL_CONNECTION * frontend,
  * process cancel request
  */
 void
-cancel_request(CancelPacket * sp)
+cancel_request(CancelPacket * sp, int32 splen)
 {
 	int			len;
 	int			fd;
@@ -911,8 +914,8 @@ cancel_request(CancelPacket * sp)
 				j,
 				k;
 	ConnectionInfo *c = NULL;
-	CancelPacket cp;
 	bool		found = false;
+	int32		keylen;	/* cancel key length */
 
 	if (pool_config->log_client_messages)
 		ereport(LOG,
@@ -921,6 +924,12 @@ cancel_request(CancelPacket * sp)
 	ereport(DEBUG1,
 			(errmsg("Cancel request received")));
 
+	/*
+	 * Cancel key length is cancel message length - cancel request code -
+	 * process id.
+	 */
+	keylen = splen - sizeof(int32) - sizeof(int32);
+
 	/* look for cancel key from shmem info */
 	for (i = 0; i < pool_config->num_init_children; i++)
 	{
@@ -931,13 +940,18 @@ cancel_request(CancelPacket * sp)
 				c = pool_coninfo(i, j, k);
 				ereport(DEBUG2,
 						(errmsg("processing cancel request"),
-						 errdetail("connection info: address:%p database:%s user:%s pid:%d key:%d i:%d",
-								   c, c->database, c->user, ntohl(c->pid), ntohl(c->key), i)));
-				if (c->pid == sp->pid && c->key == sp->key)
+						 errdetail("connection info: address:%p database:%s user:%s pid:%d sp.pid:%d keylen:%d sp.keylen:%d key:%02x%02x%02x%02x sp.key:%x%x%x%x i:%d",
+								   c, c->database, c->user, ntohl(c->pid), ntohl(sp->pid),
+								   c->keylen, keylen,
+								   c->key[0], c->key[1], c->key[2], c->key[3],
+								   sp->key[0], sp->key[1], sp->key[2], sp->key[3],
+								   i)));
+				if (c->pid == sp->pid && c->keylen == keylen &&
+					memcmp(c->key, sp->key, keylen) == 0)
 				{
 					ereport(DEBUG1,
 							(errmsg("processing cancel request"),
-							 errdetail("found pid:%d key:%d i:%d", ntohl(c->pid), ntohl(c->key), i)));
+							 errdetail("found pid:%d keylen:%d i:%d", ntohl(c->pid), c->keylen, i)));
 
 					c = pool_coninfo(i, j, 0);
 					found = true;
@@ -951,12 +965,14 @@ found:
 	if (!found)
 	{
 		ereport(LOG,
-				(errmsg("invalid cancel key: pid:%d key:%d", ntohl(sp->pid), ntohl(sp->key))));
+				(errmsg("invalid cancel key: pid:%d keylen:%d", ntohl(sp->pid), keylen)));
 		return;					/* invalid key */
 	}
 
 	for (i = 0; i < NUM_BACKENDS; i++, c++)
 	{
+		int32	cancel_request_code;
+
 		if (!VALID_BACKEND(i))
 			continue;
 
@@ -978,18 +994,18 @@ found:
 
 		pool_set_db_node_id(con, i);
 
-		len = htonl(sizeof(len) + sizeof(CancelPacket));
-		pool_write(con, &len, sizeof(len));
-
-		cp.protoVersion = sp->protoVersion;
-		cp.pid = c->pid;
-		cp.key = c->key;
+		len = htonl(splen + 4);	/* splen does not include packet length field */
+		pool_write(con, &len, sizeof(len));	/* send cancel messages length */
+		cancel_request_code = htonl(PG_PROTOCOL(1234,5678));
+		pool_write(con, &cancel_request_code, 4);
+		pool_write(con, &c->pid, 4);	/* send pid */
+		pool_write(con, c->key, keylen);	/* send cancel key */
 
 		ereport(LOG,
-				(errmsg("forwarding cancel request to backend"),
-				 errdetail("canceling backend pid:%d key: %d", ntohl(cp.pid), ntohl(cp.key))));
+				(errmsg("forwarding cancel request to backend %d", i),
+				 errdetail("canceling backend pid: %d keylen: %d", ntohl(sp->pid), keylen)));
 
-		if (pool_write_and_flush_noerror(con, &cp, sizeof(CancelPacket)) < 0)
+		if (pool_flush_noerror(con) < 0)
 			ereport(WARNING,
 					(errmsg("failed to send cancel request to backend %d", i)));
 
@@ -1978,7 +1994,7 @@ retry_startup:
 	/* cancel request? */
 	if (sp->major == 1234 && sp->minor == 5678)
 	{
-		cancel_request((CancelPacket *) sp->startup_packet);
+		cancel_request((CancelPacket *) sp->startup_packet, sp->len);
 		pool_free_startup_packet(sp);
 		connection_count_down();
 		return NULL;
diff --git a/src/protocol/pool_process_query.c b/src/protocol/pool_process_query.c
index cb72e9c54..2c8075b11 100644
--- a/src/protocol/pool_process_query.c
+++ b/src/protocol/pool_process_query.c
@@ -3,7 +3,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2024	PgPool Global Development Group
+ * Copyright (c) 2003-2025	PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -512,7 +512,8 @@ send_simplequery_message(POOL_CONNECTION * backend, int len, char *string, int m
  */
 
 void
-wait_for_query_response_with_trans_cleanup(POOL_CONNECTION * frontend, POOL_CONNECTION * backend, int protoVersion, int pid, int key)
+wait_for_query_response_with_trans_cleanup(POOL_CONNECTION * frontend, POOL_CONNECTION * backend,
+										   int protoVersion, int pid, char *key, int keylen)
 {
 	PG_TRY();
 	{
@@ -528,6 +529,7 @@ wait_for_query_response_with_trans_cleanup(POOL_CONNECTION * frontend, POOL_CONN
 			cancel_packet.protoVersion = htonl(PROTO_CANCEL);
 			cancel_packet.pid = pid;
 			cancel_packet.key = key;
+			cancel_packet.keylen = keylen;
 			cancel_request(&cancel_packet);
 		}
 
@@ -1481,7 +1483,7 @@ pool_send_readyforquery(POOL_CONNECTION * frontend)
  */
 POOL_STATUS
 do_command(POOL_CONNECTION * frontend, POOL_CONNECTION * backend,
-		   char *query, int protoMajor, int pid, int key, int no_ready_for_query)
+		   char *query, int protoMajor, int pid, char *key, int keylen, int no_ready_for_query)
 {
 	int			len;
 	char		kind;
@@ -1502,7 +1504,8 @@ do_command(POOL_CONNECTION * frontend, POOL_CONNECTION * backend,
 											   backend,
 											   protoMajor,
 											   pid,
-											   key);
+											   key,
+											   keylen);
 
 	/*
 	 * We must check deadlock error here. If a deadlock error is detected by a
@@ -2767,7 +2770,7 @@ insert_lock(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend, char *qu
 		else
 		{
 			status = do_command(frontend, MAIN(backend), qbuf, MAJOR(backend), MAIN_CONNECTION(backend)->pid,
-								MAIN_CONNECTION(backend)->key, 0);
+								MAIN_CONNECTION(backend)->key, MAIN_CONNECTION(backend)->keylen, 0);
 		}
 	}
 	else if (lock_kind == 2)
@@ -2825,7 +2828,7 @@ insert_lock(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend, char *qu
 			else
 			{
 				status = do_command(frontend, MAIN(backend), qbuf, MAJOR(backend), MAIN_CONNECTION(backend)->pid,
-									MAIN_CONNECTION(backend)->key, 0);
+									MAIN_CONNECTION(backend)->key, MAIN_CONNECTION(backend)->keylen ,0);
 			}
 		}
 	}
@@ -2843,7 +2846,8 @@ insert_lock(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend, char *qu
 		{
 			if (deadlock_detected)
 				status = do_command(frontend, CONNECTION(backend, i), POOL_ERROR_QUERY, PROTO_MAJOR_V3,
-									MAIN_CONNECTION(backend)->pid, MAIN_CONNECTION(backend)->key, 0);
+									MAIN_CONNECTION(backend)->pid,
+									MAIN_CONNECTION(backend)->key, MAIN_CONNECTION(backend)->keylen, 0);
 			else
 			{
 				if (lock_kind == 1)
@@ -2858,7 +2862,8 @@ insert_lock(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend, char *qu
 					else
 					{
 						status = do_command(frontend, CONNECTION(backend, i), qbuf, PROTO_MAJOR_V3,
-											MAIN_CONNECTION(backend)->pid, MAIN_CONNECTION(backend)->key, 0);
+											MAIN_CONNECTION(backend)->pid,
+											MAIN_CONNECTION(backend)->key, MAIN_CONNECTION(backend)->keylen, 0);
 					}
 				}
 				else if (lock_kind == 2 || lock_kind == 3)
@@ -2933,7 +2938,8 @@ static POOL_STATUS add_lock_target(POOL_CONNECTION * frontend, POOL_CONNECTION_P
 		per_node_statement_log(backend, MAIN_NODE_ID, "LOCK TABLE pgpool_catalog.insert_lock IN SHARE ROW EXCLUSIVE MODE");
 
 		if (do_command(frontend, MAIN(backend), "LOCK TABLE pgpool_catalog.insert_lock IN SHARE ROW EXCLUSIVE MODE",
-					   PROTO_MAJOR_V3, MAIN_CONNECTION(backend)->pid, MAIN_CONNECTION(backend)->key, 0) != POOL_CONTINUE)
+					   PROTO_MAJOR_V3, MAIN_CONNECTION(backend)->pid,
+					   MAIN_CONNECTION(backend)->key, MAIN_CONNECTION(backend)->keylen, 0) != POOL_CONTINUE)
 			ereport(ERROR,
 					(errmsg("unable to add lock target"),
 					 errdetail("do_command returned DEADLOCK status")));
@@ -3043,7 +3049,8 @@ static POOL_STATUS insert_oid_into_insert_lock(POOL_CONNECTION * frontend,
 
 	per_node_statement_log(backend, MAIN_NODE_ID, qbuf);
 	status = do_command(frontend, MAIN(backend), qbuf, PROTO_MAJOR_V3,
-						MAIN_CONNECTION(backend)->pid, MAIN_CONNECTION(backend)->key, 0);
+						MAIN_CONNECTION(backend)->pid,
+						MAIN_CONNECTION(backend)->key, MAIN_CONNECTION(backend)->keylen, 0);
 	return status;
 }
 
@@ -4140,7 +4147,8 @@ start_internal_transaction(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * ba
 				per_node_statement_log(backend, i, "BEGIN");
 
 				if (do_command(frontend, CONNECTION(backend, i), "BEGIN", MAJOR(backend),
-							   MAIN_CONNECTION(backend)->pid, MAIN_CONNECTION(backend)->key, 0) != POOL_CONTINUE)
+							   MAIN_CONNECTION(backend)->pid,
+							   MAIN_CONNECTION(backend)->key, MAIN_CONNECTION(backend)->keylen, 0) != POOL_CONTINUE)
 					ereport(ERROR,
 							(errmsg("unable to start the internal transaction"),
 							 errdetail("do_command returned DEADLOCK status")));
@@ -4205,7 +4213,8 @@ end_internal_transaction(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * back
 				PG_TRY();
 				{
 					if (do_command(frontend, CONNECTION(backend, i), "COMMIT", MAJOR(backend),
-								   MAIN_CONNECTION(backend)->pid, MAIN_CONNECTION(backend)->key, 1) != POOL_CONTINUE)
+								   MAIN_CONNECTION(backend)->pid,
+								   MAIN_CONNECTION(backend)->key, MAIN_CONNECTION(backend)->keylen, 1) != POOL_CONTINUE)
 					{
 						ereport(ERROR,
 								(errmsg("unable to COMMIT the transaction"),
@@ -4258,7 +4267,8 @@ end_internal_transaction(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * back
 			PG_TRY();
 			{
 				if (do_command(frontend, MAIN(backend), "COMMIT", MAJOR(backend),
-							   MAIN_CONNECTION(backend)->pid, MAIN_CONNECTION(backend)->key, 1) != POOL_CONTINUE)
+							   MAIN_CONNECTION(backend)->pid,
+							   MAIN_CONNECTION(backend)->key, MAIN_CONNECTION(backend)->keylen, 1) != POOL_CONTINUE)
 				{
 					ereport(ERROR,
 							(errmsg("unable to COMMIT the transaction"),
diff --git a/src/protocol/pool_proto_modules.c b/src/protocol/pool_proto_modules.c
index a6336f8e2..c2802998a 100644
--- a/src/protocol/pool_proto_modules.c
+++ b/src/protocol/pool_proto_modules.c
@@ -2490,7 +2490,7 @@ static POOL_STATUS close_standby_transactions(POOL_CONNECTION * frontend,
 			per_node_statement_log(backend, i, "COMMIT");
 			if (do_command(frontend, CONNECTION(backend, i), "COMMIT", MAJOR(backend),
 						   MAIN_CONNECTION(backend)->pid,
-						   MAIN_CONNECTION(backend)->key, 0) != POOL_CONTINUE)
+						   MAIN_CONNECTION(backend)->key, MAIN_CONNECTION(backend)->keylen, 0) != POOL_CONTINUE)
 				ereport(ERROR,
 						(errmsg("unable to close standby transactions"),
 						 errdetail("do_command returned DEADLOCK status")));
diff --git a/src/rewrite/pool_lobj.c b/src/rewrite/pool_lobj.c
index 38187fe14..7601a9316 100644
--- a/src/rewrite/pool_lobj.c
+++ b/src/rewrite/pool_lobj.c
@@ -5,7 +5,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2010	PgPool Global Development Group
+ * Copyright (c) 2003-2025	PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -174,7 +174,7 @@ pool_rewrite_lo_creat(char kind, char *packet, int packet_len,
 	snprintf(qbuf, sizeof(qbuf), "LOCK TABLE %s IN SHARE ROW EXCLUSIVE MODE", pool_config->lobj_lock_table);
 	per_node_statement_log(backend, MAIN_NODE_ID, qbuf);
 	status = do_command(frontend, MAIN(backend), qbuf, MAJOR(backend), MAIN_CONNECTION(backend)->pid,
-						MAIN_CONNECTION(backend)->key, 0);
+						MAIN_CONNECTION(backend)->key, MAIN_CONNECTION(backend)->keylen, 0);
 	if (status == POOL_END)
 	{
 		ereport(WARNING,
-- 
2.25.1

