Fix occasional 005.jdbc test failure.
authorTatsuo Ishii <ishii@sraoss.co.jp>
Thu, 6 Apr 2023 03:43:06 +0000 (12:43 +0900)
committerTatsuo Ishii <ishii@sraoss.co.jp>
Thu, 13 Apr 2023 07:40:13 +0000 (16:40 +0900)
The direct cause of the error is:
2023-02-22 08:51:47.705: PostgreSQL JDBC Driver pid 12420: LOG:  Parse: Error or notice message from backend: : DB node id: 0 backend pid: 12488 statement: "COMMIT" message: "prepared statement "S_1" already exists"

Actually the root of the error is this:
 2023-02-22 08:51:45.242: PostgreSQL JDBC Driver pid 12420: LOG:  pool_send_and_wait: Error or notice message from backend: : DB node id: 0 backend pid: 12488 statement: "DISCARD ALL" message: "DISCARD ALL cannot be executed within a pipeline"

"DISCARD ALL" was generated by pgpool (reset_query_list) to discard
some objects including prepared statements created in the
session. Since DISCARD ALL failed, the prepared statement S_1 was not
removed. Thus the next session failed because S_1 already existed.

To fix this, new global boolean flag reset_query_error is
introduced. The flag is set inside pool_send_and_wait() when a reset
query executed by SimpleQuery() results in ERROR. If the flag is true,
backend_cleanup() discards the backend connection so that any objects,
including named statement, corresponding to the session is discarded

Discussion: https://www.pgpool.net/pipermail/pgpool-hackers/2023-February/004293.html

src/context/pool_query_context.c
src/include/pool.h
src/main/pool_globals.c
src/protocol/child.c
src/protocol/pool_process_query.c
src/protocol/pool_proto_modules.c

index 2882d776f0f2e86c49db59d86f300f04e588a391..ae18abde6b406f161f8e3f585d28b7f8b2b2e805 100644 (file)
@@ -855,8 +855,15 @@ pool_send_and_wait(POOL_QUERY_CONTEXT * query_context,
                 * Check if some error detected.  If so, emit log. This is useful when
                 * invalid encoding error occurs. In this case, PostgreSQL does not
                 * report what statement caused that error and make users confused.
+                * Also set reset_query_error to true in ERROR case. This does
+                * anything in normal query processing but when processing reset
+                * queries, this is important because it might mean DISCARD ALL
+                * command fails. If so, we need to discard the connection cache so
+                * that any session object (i.e. named statement) does not remain in
+                * the last session.
                 */
-               per_node_error_log(backend, i, string, "pool_send_and_wait: Error or notice message from backend: ", true);
+               if (per_node_error_log(backend, i, string, "pool_send_and_wait: Error or notice message from backend: ", true) == 'E')
+                       reset_query_error = true;
        }
 
        return POOL_CONTINUE;
index f2e62b74c753142246c9422099b1fdb300aefea0..42fcdb304d746c3ce6efcb724c9df114dcfbae4a 100644 (file)
@@ -571,6 +571,7 @@ typedef struct
 }                      PGVersion;
 
 extern ProcessState processState;
+extern bool    reset_query_error;      /* true if error occurs in reset queries */
 
 extern POOL_CONNECTION_POOL * pool_connection_pool; /* connection pool */
 extern volatile sig_atomic_t backend_timer_expired; /* flag for connection
index 517701bd3f0c7e9502249da4da27bfa5ebba129b..6de131dd745b3f266378a74439ae49cba6852d73 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-2023     PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -25,3 +25,4 @@
 pid_t          mypid;                          /* pgpool parent process id */
 ProcessType processType;
 ProcessState processState;
+bool           reset_query_error;      /* true if error returned from backend while processing reset queries */
index 6d7c6688bbeb5a71e372c68ce0aa114ab8103af5..e16cc240907ff2e59df513fa516273a61909a0b3 100644 (file)
@@ -5,7 +5,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2019     PgPool Global Development Group
+ * Copyright (c) 2003-2023     PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -485,8 +485,10 @@ backend_cleanup(POOL_CONNECTION * volatile *frontend, POOL_CONNECTION_POOL * vol
        if (cache_connection)
        {
                /*
-                * For those special databases, and when frontend client exits
-                * abnormally, we don't cache connection to backend.
+                * For those special databases, or when frontend client exits
+                * abnormally, we don't cache connection to backend.  Also we have to
+                * check whether reset query failed. If so, the existing connection to
+                * backend may not be used and we don't want to cache the connection.
                 */
                if ((sp &&
                         (!strcmp(sp->database, "template0") ||
@@ -495,7 +497,8 @@ backend_cleanup(POOL_CONNECTION * volatile *frontend, POOL_CONNECTION_POOL * vol
                          !strcmp(sp->database, "regression"))) ||
                        (*frontend != NULL &&
                         ((*frontend)->socket_state == POOL_SOCKET_EOF ||
-                         (*frontend)->socket_state == POOL_SOCKET_ERROR)))
+                         (*frontend)->socket_state == POOL_SOCKET_ERROR)) ||
+                       reset_query_error)
                        cache_connection = false;
        }
 
index 48b89d0e8d53213f8be60eeeca253e8b74ad9f46..578ce62cd1b6b4648c0c6e9e2c76a65ac2fde1d8 100644 (file)
@@ -3,7 +3,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2022     PgPool Global Development Group
+ * Copyright (c) 2003-2023     PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -129,6 +129,12 @@ pool_process_query(POOL_CONNECTION * frontend,
                memcached_connect();
        }
 
+       /*
+        * Reset error flag while processing reset queries.
+        * The flag is set to on inside pool_send_and_wait().
+        */
+       reset_query_error = false;
+
        for (;;)
        {
 
index 0100aee1a77696ebc6e59455dc4256e76d2d8f76..331b1cb4c444a3eab3ac7ba57247c7a03f85019d 100644 (file)
@@ -3381,11 +3381,20 @@ per_node_statement_log(POOL_CONNECTION_POOL * backend, int node_id, char *query)
  * Check kind and produce error message
  * All data read in this function is returned to stream.
  */
-void
+char
 per_node_error_log(POOL_CONNECTION_POOL * backend, int node_id, char *query, char *prefix, bool unread)
 {
        POOL_CONNECTION_POOL_SLOT *slot = backend->slots[node_id];
        char       *message;
+       char       kind;
+
+       pool_read(CONNECTION(backend, node_id), &kind, sizeof(kind));
+       pool_unread(CONNECTION(backend, node_id), &kind, sizeof(kind));
+
+       if (kind != 'E' && kind != 'N')
+       {
+               return kind;
+       }
 
        if (pool_extract_error_message(true, CONNECTION(backend, node_id), MAJOR(backend), unread, &message) == 1)
        {
@@ -3394,6 +3403,7 @@ per_node_error_log(POOL_CONNECTION_POOL * backend, int node_id, char *query, cha
                                                prefix, node_id, ntohl(slot->pid), query, message)));
                pfree(message);
        }
+       return kind;
 }
 
 /*