Feature: implement protocol version 3.2 BackendKeyData and query cancel message.
authorTatsuo Ishii <ishii@postgresql.org>
Tue, 15 Jul 2025 05:30:47 +0000 (14:30 +0900)
committerTatsuo Ishii <ishii@postgresql.org>
Tue, 15 Jul 2025 05:30:47 +0000 (14:30 +0900)
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

Author: Tatsuo Ishii <ishii@postgresql.org>
Discussion: https://www.postgresql.org/message-id/20250714.155710.1706961744888449986.ishii%40postgresql.org

src/auth/pool_auth.c
src/context/pool_query_context.c
src/include/pcp/libpcp_ext.h
src/include/pool.h
src/include/protocol/pool_process_query.h
src/include/protocol/pool_proto_modules.h
src/protocol/child.c
src/protocol/pool_process_query.c
src/protocol/pool_proto_modules.c
src/rewrite/pool_lobj.c

index 54d646bc3405ed55512cd8d367c06b2949419e90..198d8c99e1fa26edc98f0a991443f10033c1743b 100644 (file)
@@ -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,13 @@ 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")));
+
+       /*
+        * We send the BackendKeyData to frontend, which belongs to the last
+        * backend in the backend group.
+        */
+       pool_send_backend_key_data(frontend, pid, cancel_key,
+                                                          MAIN_CONNECTION(cp)->keylen, protoMajor);
        return 0;
 }
 
@@ -872,7 +890,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 +922,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
index 3b90284973df9af254dcd97eeced5a34d5a2defb..d398bee6da52944f4c76cbced86166f57fe786d6 100644 (file)
@@ -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
index d79ddc1568d28c978fd82089e5cbd2d0feab9d96..3a6d87858d0ba9f9893a965f30ccc98b52637a75 100644 (file)
@@ -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 */
index 28cf1757ca63c3dea278365c0ac50e8b72fc3f57..c34a06d2a7261847b99d65645d9b923394b965cb 100644 (file)
@@ -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);
index 7f91dbbcdd6dd187b4514279e9e99109afc0e921..e799b4d9dfac0504100fc3afbd5cb8492ffefdfe 100644 (file)
@@ -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);
index 663dcc9844c2dba0d2d06329753487e9e7befbbd..28668aa6e8a42d26729ea750ede6d5b710b047c9 100644 (file)
@@ -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);
index 7aea33540ef75ffacdc4e07b74fa46f09db8ced4..1ef88910daa7ab6af56aa1cdf2473bccee35ceee 100644 (file)
@@ -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,7 +924,20 @@ cancel_request(CancelPacket * sp)
        ereport(DEBUG1,
                        (errmsg("Cancel request received")));
 
-       /* look for cancel key from shmem info */
+       /*
+        * 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.  Frontend should have saved one of
+        * cancel key among backend groups and sent it in the cancel request
+        * message. We are looking for the backend which has the same cancel key
+        * and pid. The query we want to cancel should have been running one the
+        * backend group. So some of query cancel requests may not work but it
+        * should not be a problem. They are just ignored by the backend.
+        */
        for (i = 0; i < pool_config->num_init_children; i++)
        {
                for (j = 0; j < pool_config->max_pool; j++)
@@ -931,14 +947,19 @@ 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 i:%d",
+                                                                  c, c->database, c->user, ntohl(c->pid), ntohl(sp->pid),
+                                                                  c->keylen, keylen, 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" is a pointer to i th child, j th pool, and 0 th backend.
+                                        */
                                        c = pool_coninfo(i, j, 0);
                                        found = true;
                                        goto found;
@@ -951,12 +972,19 @@ 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 */
        }
 
+       /*
+        * We are sending cancel request message to all backend groups.  So some
+        * of query cancel requests may not work but it should not be a
+        * problem. They are just ignored by the backend.
+        */
        for (i = 0; i < NUM_BACKENDS; i++, c++)
        {
+               int32   cancel_request_code;
+
                if (!VALID_BACKEND(i))
                        continue;
 
@@ -978,18 +1006,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 + sizeof(int32));     /* 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));    /* cancel request code */
+               pool_write(con, &cancel_request_code, sizeof(int32));
+               pool_write(con, &c->pid, sizeof(int32));        /* 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 +2006,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;
index cb72e9c54c76cf4b1079f87adc50f236238f0a48..5a6b97ba1324820a9d768771e095c4c7d7f79f44 100644 (file)
@@ -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();
        {
@@ -527,8 +528,8 @@ 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_request(&cancel_packet);
+                       memcpy(cancel_packet.key, key, keylen);
+                       cancel_request(&cancel_packet, keylen + sizeof(int32) + sizeof(int32));
                }
 
                PG_RE_THROW();
@@ -1481,7 +1482,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 +1503,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 +2769,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 +2827,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 +2845,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 +2861,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 +2937,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 +3048,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 +4146,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 +4212,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 +4266,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"),
index a6336f8e278d7d126e5106c5405eae8e28338301..c2802998a02ef88ca82903f92023216a89c3c33d 100644 (file)
@@ -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")));
index 38187fe142ebf95bb8374c482996d414678d3be3..7601a93169ae791428b16334167ca105c7600883 100644 (file)
@@ -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,