From b364cfdfaf6b24e18c8f6017111306259f87c0f4 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Mon, 6 Jun 2022 11:07:27 +0900 Subject: [PATCH] Fix psql's single transaction mode on client-side errors with -c/-f switches psql --single-transaction is able to handle multiple -c and -f switches in a single transaction since d5563d7d, but this had the surprising behavior of forcing a transaction COMMIT even if psql failed with an error in the client (for example incorrect path given to \copy), which would generate an error, but still commit any changes that were already applied in the backend. This commit makes the behavior more consistent, by enforcing a transaction ROLLBACK if any commands fail, both client-side and backend-side, so as no changes are applied if one error happens in any of them. Some tests are added on HEAD to provide some coverage about all that. Backend-side errors are unreliable as IPC::Run can complain on SIGPIPE if psql quits before reading a query result, but that should work properly in the case where any errors come from psql itself, which is what the original report is about. Reported-by: Christoph Berg Author: Kyotaro Horiguchi, Michael Paquier Discussion: https://postgr.es/m/17504-76b68018e130415e@postgresql.org Backpatch-through: 10 --- doc/src/sgml/ref/psql-ref.sgml | 6 ++++-- src/bin/psql/startup.c | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 1802330b70..fc0e3e4d8a 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -591,8 +591,10 @@ EOF psql to issue a BEGIN command before the first such option and a COMMIT command after the last one, thereby wrapping all the commands into a single - transaction. This ensures that either all the commands complete - successfully, or no changes are applied. + transaction. If any of the commands fails, a + ROLLBACK command is sent instead. This ensures that + either all the commands complete successfully, or no changes are + applied. diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c index 392b96eb86..ce180e1cd7 100644 --- a/src/bin/psql/startup.c +++ b/src/bin/psql/startup.c @@ -412,7 +412,9 @@ main(int argc, char *argv[]) if (options.single_txn) { - if ((res = PSQLexec("COMMIT")) == NULL) + res = PSQLexec((successResult == EXIT_SUCCESS) ? + "COMMIT" : "ROLLBACK"); + if (res == NULL) { if (pset.on_error_stop) {