From 84935ea888d8ef607af6afb521cee8d98a85d1db Mon Sep 17 00:00:00 2001
From: Yugo Nagata <nagata@sraoss.co.jp>
Date: Wed, 24 Sep 2025 22:23:25 +0900
Subject: [PATCH v13 1/3] Fix assertion failure and verbose messages in
 pipeline mode

commandError() is called to report errors when they can be retried, and
it previously assumed that errors are always detected during SQL command
execution. However, in pipeline mode, an error may also be detected when
a \endpipeline meta-command is executed.

This caused an assertion failure. To fix this, it is now assumed that
errors can also be detected in this case.

Additionally, in pipeline mode, the error message reported in
readCommandResponse() was lost, because it was reset when PQgetResult()
returned NULL to indicate the end of query processing. To fix this, save
the previous error message and use it for reporting.
---
 src/bin/pgbench/pgbench.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index 3cafd88ac53..de00669f288 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -3059,7 +3059,13 @@ commandFailed(CState *st, const char *cmd, const char *message)
 static void
 commandError(CState *st, const char *message)
 {
-	Assert(sql_script[st->use_file].commands[st->command]->type == SQL_COMMAND);
+	/*
+	 * Errors should only be detected during an SQL command or the \endpipeline
+	 * meta command. Any other case triggers an assertion failure.
+	 */
+	Assert(sql_script[st->use_file].commands[st->command]->type == SQL_COMMAND ||
+		   sql_script[st->use_file].commands[st->command]->meta == META_ENDPIPELINE);
+
 	pg_log_info("client %d got an error in command %d (SQL) of script %d; %s",
 				st->id, st->command, st->use_file, message);
 }
@@ -3265,6 +3271,7 @@ readCommandResponse(CState *st, MetaCommand meta, char *varprefix)
 	PGresult   *res;
 	PGresult   *next_res;
 	int			qrynum = 0;
+	char	   *errmsg;
 
 	/*
 	 * varprefix should be set only with \gset or \aset, and \endpipeline and
@@ -3280,6 +3287,8 @@ readCommandResponse(CState *st, MetaCommand meta, char *varprefix)
 	{
 		bool		is_last;
 
+		errmsg = pg_strdup(PQerrorMessage(st->con));
+
 		/* peek at the next result to know whether the current is last */
 		next_res = PQgetResult(st->con);
 		is_last = (next_res == NULL);
@@ -3349,7 +3358,7 @@ readCommandResponse(CState *st, MetaCommand meta, char *varprefix)
 				st->num_syncs--;
 				if (st->num_syncs == 0 && PQexitPipelineMode(st->con) != 1)
 					pg_log_error("client %d failed to exit pipeline mode: %s", st->id,
-								 PQerrorMessage(st->con));
+								 errmsg);
 				break;
 
 			case PGRES_NONFATAL_ERROR:
@@ -3359,7 +3368,7 @@ readCommandResponse(CState *st, MetaCommand meta, char *varprefix)
 				if (canRetryError(st->estatus))
 				{
 					if (verbose_errors)
-						commandError(st, PQerrorMessage(st->con));
+						commandError(st, errmsg);
 					goto error;
 				}
 				/* fall through */
@@ -3367,14 +3376,14 @@ readCommandResponse(CState *st, MetaCommand meta, char *varprefix)
 			default:
 				/* anything else is unexpected */
 				pg_log_error("client %d script %d aborted in command %d query %d: %s",
-							 st->id, st->use_file, st->command, qrynum,
-							 PQerrorMessage(st->con));
+							 st->id, st->use_file, st->command, qrynum, errmsg);
 				goto error;
 		}
 
 		PQclear(res);
 		qrynum++;
 		res = next_res;
+		pg_free(errmsg);
 	}
 
 	if (qrynum == 0)
@@ -3388,6 +3397,7 @@ readCommandResponse(CState *st, MetaCommand meta, char *varprefix)
 error:
 	PQclear(res);
 	PQclear(next_res);
+	pg_free(errmsg);
 	do
 	{
 		res = PQgetResult(st->con);
-- 
2.43.0

