]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
pgbench: fix verbose error message corruption with multiple threads
authorFujii Masao <fujii@postgresql.org>
Thu, 14 May 2026 03:30:34 +0000 (12:30 +0900)
committerFujii Masao <fujii@postgresql.org>
Thu, 14 May 2026 03:30:34 +0000 (12:30 +0900)
When pgbench runs with multiple threads and verbose error reporting is
enabled (--verbose-errors), multiple clients can build verbose error
messages concurrently. Previously, a function-local static
PQExpBuffer was used for these messages, causing the buffer to be
shared across threads. This was not thread-safe and could result in
corrupted or incorrect log output.

Fix this by using a local PQExpBufferData instead of a static buffer.
This keeps verbose error messages correct during concurrent execution.

Backpatch to v15, where this issue was introduced.

Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Alex Guo <guo.alex.hengchen@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwER1AjGXpkKB9t9820NBhMQ_Ghv7=HsKeodUr3=SZsF4g@mail.gmail.com
Backpatch-through: 15

src/bin/pgbench/pgbench.c

index 69b12a919a432d86ff480b1507b62b3b88493cdb..0b2bb9340b5dc7de96b68fc02d31e6884fa86636 100644 (file)
@@ -3630,22 +3630,19 @@ getTransactionStatus(PGconn *con)
 static void
 printVerboseErrorMessages(CState *st, pg_time_usec_t *now, bool is_retry)
 {
-       static PQExpBuffer buf = NULL;
+       PQExpBufferData buf;
 
-       if (buf == NULL)
-               buf = createPQExpBuffer();
-       else
-               resetPQExpBuffer(buf);
+       initPQExpBuffer(&buf);
 
-       printfPQExpBuffer(buf, "client %d ", st->id);
-       appendPQExpBufferStr(buf, (is_retry ?
-                                                          "repeats the transaction after the error" :
-                                                          "ends the failed transaction"));
-       appendPQExpBuffer(buf, " (try %u", st->tries);
+       printfPQExpBuffer(&buf, "client %d ", st->id);
+       appendPQExpBufferStr(&buf, (is_retry ?
+                                                               "repeats the transaction after the error" :
+                                                               "ends the failed transaction"));
+       appendPQExpBuffer(&buf, " (try %u", st->tries);
 
        /* Print max_tries if it is not unlimited. */
        if (max_tries)
-               appendPQExpBuffer(buf, "/%u", max_tries);
+               appendPQExpBuffer(&buf, "/%u", max_tries);
 
        /*
         * If the latency limit is used, print a percentage of the current
@@ -3654,12 +3651,14 @@ printVerboseErrorMessages(CState *st, pg_time_usec_t *now, bool is_retry)
        if (latency_limit)
        {
                pg_time_now_lazy(now);
-               appendPQExpBuffer(buf, ", %.3f%% of the maximum time of tries was used",
+               appendPQExpBuffer(&buf, ", %.3f%% of the maximum time of tries was used",
                                                  (100.0 * (*now - st->txn_scheduled) / latency_limit));
        }
-       appendPQExpBufferStr(buf, ")\n");
+       appendPQExpBufferStr(&buf, ")\n");
 
-       pg_log_info("%s", buf->data);
+       pg_log_info("%s", buf.data);
+
+       termPQExpBuffer(&buf);
 }
 
 /*