Hi,
Commit 7ca548f23a6 reverted pg_dumpall's non-text output format support
per Noah Misch's post-commit review. That revert was scoped carefully to
remove only the feature itself, but its commit message notes one piece of
unavoidable collateral damage:
Because the feature restructured pg_dumpall.c and pg_restore.c (pg_restore's
main() was split into restore_one_database() plus a dispatcher) and
interleaved its option checks with the conflicting-option refactor in the
same regions, the cosmetic check_mut_excl_opts() reflow of those two files'
option blocks is inseparable from the feature and comes out with it; the
behavior is unchanged.
In other words, pg_restore.c and pg_dumpall.c both went back to their old,
ad hoc pairwise "if (a && b) pg_fatal(...)" style option-conflict checks,
even though converting them to use the shared check_mut_excl_opts() helper
(added by b2898baaf7e, and already used by pg_dump.c) is a purely mechanical,
behavior-preserving cleanup with no dependency on the reverted feature's
design.
Attached are two small, independent patches that redo that conversion on
top of current master:
0001 - pg_restore.c: converts its *-only / --no-* / --statistics /
--clean / --single-transaction conflict checks to
check_mut_excl_opts().
0002 - pg_dumpall.c: same conversion for --exclude-database, the *-only
options, their --no-* counterparts, --statistics, and --clean.
Also tracks -s/--schema-only locally (schema_only), which
pg_dumpall previously just passed through to pg_dump without
recording, since check_mut_excl_opts() needs it. Updates the
expected error text in the TAP tests to match
check_mut_excl_opts()'s "options X and Y cannot be used together"
wording, and adds coverage for a couple of option pairs that
previously had no dedicated test.
Both patches preserve the exact pre-existing error-message wording and
option-reporting order for every combination that already had test
coverage; I verified this with the full src/bin/pg_dump TAP suite
(make check), which passes cleanly with both patches applied.
They're independent of each other and can be applied/reviewed in either
order or separately.
I think we can commit those into v19 and master. Please review and let
me know feedback.
--
Thanks and Regards
Mahendra Singh Thalor
EnterpriseDB: http://www.enterprisedb.com
From 9d0f85c942c71b4bffdc08c1b26aec60a8f412f6 Mon Sep 17 00:00:00 2001
From: Mahendra Singh Thalor <[email protected]>
Date: Tue, 14 Jul 2026 13:35:48 +0530
Subject: [PATCH] pg_restore: Use check_mut_excl_opts() for mutually-exclusive
options
Replace the ad hoc pairwise if/pg_fatal() checks for conflicting
command-line options with calls to the shared check_mut_excl_opts()
helper, matching the style already used in pg_dump.c. This covers
the *-only options, their --no-* counterparts, --statistics vs
--no-statistics, --statistics vs *-only, --clean vs --data-only,
--single-transaction vs --transaction-size, and -C vs
--single-transaction.
No behavior change; error message wording and option-reporting
order are preserved exactly.
---
src/bin/pg_dump/pg_restore.c | 75 +++++++++++++++---------------------
1 file changed, 30 insertions(+), 45 deletions(-)
diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c
index 84b8d410c9e..8be609c5170 100644
--- a/src/bin/pg_dump/pg_restore.c
+++ b/src/bin/pg_dump/pg_restore.c
@@ -377,56 +377,41 @@ main(int argc, char **argv)
pg_fatal("invalid restrict key");
}
- /* reject conflicting "-only" options */
- if (data_only && schema_only)
- pg_fatal("options %s and %s cannot be used together",
- "-s/--schema-only", "-a/--data-only");
- if (schema_only && statistics_only)
- pg_fatal("options %s and %s cannot be used together",
- "-s/--schema-only", "--statistics-only");
- if (data_only && statistics_only)
- pg_fatal("options %s and %s cannot be used together",
- "-a/--data-only", "--statistics-only");
-
- /* reject conflicting "-only" and "no-" options */
- if (data_only && no_data)
- pg_fatal("options %s and %s cannot be used together",
- "-a/--data-only", "--no-data");
- if (schema_only && no_schema)
- pg_fatal("options %s and %s cannot be used together",
- "-s/--schema-only", "--no-schema");
- if (statistics_only && no_statistics)
- pg_fatal("options %s and %s cannot be used together",
- "--statistics-only", "--no-statistics");
-
- /* reject conflicting "no-" options */
- if (with_statistics && no_statistics)
- pg_fatal("options %s and %s cannot be used together",
- "--statistics", "--no-statistics");
-
- /* reject conflicting "only-" options */
- if (data_only && with_statistics)
- pg_fatal("options %s and %s cannot be used together",
- "-a/--data-only", "--statistics");
- if (schema_only && with_statistics)
- pg_fatal("options %s and %s cannot be used together",
- "-s/--schema-only", "--statistics");
-
- if (data_only && opts->dropSchema)
- pg_fatal("options %s and %s cannot be used together",
- "-c/--clean", "-a/--data-only");
-
- if (opts->single_txn && opts->txn_size > 0)
- pg_fatal("options %s and %s cannot be used together",
- "-1/--single-transaction", "--transaction-size");
+ /* *-only options are incompatible with each other */
+ check_mut_excl_opts(schema_only, "-s/--schema-only",
+ data_only, "-a/--data-only",
+ statistics_only, "--statistics-only");
+
+ /* --no-* and *-only for same thing are incompatible */
+ check_mut_excl_opts(data_only, "-a/--data-only",
+ no_data, "--no-data");
+ check_mut_excl_opts(schema_only, "-s/--schema-only",
+ no_schema, "--no-schema");
+ check_mut_excl_opts(statistics_only, "--statistics-only",
+ no_statistics, "--no-statistics");
+
+ /* --statistics and --no-statistics are incompatible */
+ check_mut_excl_opts(with_statistics, "--statistics",
+ no_statistics, "--no-statistics");
+
+ /* --statistics is incompatible with *-only (except --statistics-only) */
+ check_mut_excl_opts(data_only, "-a/--data-only",
+ schema_only, "-s/--schema-only",
+ with_statistics, "--statistics");
+
+ /* --clean is incompatible with --data-only */
+ check_mut_excl_opts(opts->dropSchema, "-c/--clean",
+ data_only, "-a/--data-only");
+
+ check_mut_excl_opts(opts->single_txn, "-1/--single-transaction",
+ opts->txn_size > 0, "--transaction-size");
/*
* -C is not compatible with -1, because we can't create a database inside
* a transaction block.
*/
- if (opts->createDB && opts->single_txn)
- pg_fatal("options %s and %s cannot be used together",
- "-C/--create", "-1/--single-transaction");
+ check_mut_excl_opts(opts->createDB, "-C/--create",
+ opts->single_txn, "-1/--single-transaction");
/* Can't do single-txn mode with multiple connections */
if (opts->single_txn && numWorkers > 1)
--
2.52.0
From 73deb24ac22d7051175263e6d75335e0f818822c Mon Sep 17 00:00:00 2001
From: Mahendra Singh Thalor <[email protected]>
Date: Tue, 14 Jul 2026 13:42:36 +0530
Subject: [PATCH] pg_dumpall: Use check_mut_excl_opts() for mutually-exclusive
options
Replace the ad hoc if/pg_log_error() and if/pg_fatal() checks for
conflicting command-line options with calls to the shared
check_mut_excl_opts() helper, matching the style already used in
pg_dump.c and pg_restore.c. This covers --exclude-database vs the
global *-only options, the *-only options against each other, their
--no-* counterparts, --statistics vs --no-statistics, --statistics
vs *-only, and --clean vs --data-only.
Track -s/--schema-only locally (as schema_only) so it can
participate in these checks, matching how the other *-only options
are already tracked.
Update the expected error text in the TAP tests to match
check_mut_excl_opts()'s "options X and Y cannot be used together"
wording, and add coverage for the option pairs that previously had
no dedicated test.
---
src/bin/pg_dump/pg_dumpall.c | 77 +++++++++++----------
src/bin/pg_dump/t/001_basic.pl | 34 ++++++++-
src/bin/pg_dump/t/005_pg_dump_filterfile.pl | 4 +-
3 files changed, 73 insertions(+), 42 deletions(-)
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index c53e77c2878..0743bb48e48 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -27,6 +27,7 @@
#include "common/string.h"
#include "connectdb.h"
#include "dumputils.h"
+#include "fe_utils/option_utils.h"
#include "fe_utils/string_utils.h"
#include "filter.h"
#include "getopt_long.h"
@@ -201,6 +202,7 @@ main(int argc, char *argv[])
bool data_only = false;
bool globals_only = false;
bool roles_only = false;
+ bool schema_only = false;
bool tablespaces_only = false;
PGconn *conn;
int encoding;
@@ -299,6 +301,7 @@ main(int argc, char *argv[])
break;
case 's':
+ schema_only = true;
appendPQExpBufferStr(pgdumpopts, " -s");
break;
@@ -395,50 +398,48 @@ main(int argc, char *argv[])
exit_nicely(1);
}
- if (database_exclude_patterns.head != NULL &&
- (globals_only || roles_only || tablespaces_only))
- {
- pg_log_error("option %s cannot be used together with %s, %s, or %s",
- "--exclude-database",
- "-g/--globals-only", "-r/--roles-only", "-t/--tablespaces-only");
- pg_log_error_hint("Try \"%s --help\" for more information.", progname);
- exit_nicely(1);
- }
+ /* --exclude-database is incompatible with global *-only options */
+ check_mut_excl_opts(database_exclude_patterns.head, "--exclude-database",
+ globals_only, "-g/--globals-only",
+ roles_only, "-r/--roles-only",
+ tablespaces_only, "-t/--tablespaces-only");
+
+ /* *-only options are incompatible with each other */
+ check_mut_excl_opts(data_only, "-a/--data-only",
+ globals_only, "-g/--globals-only",
+ roles_only, "-r/--roles-only",
+ schema_only, "-s/--schema-only",
+ statistics_only, "--statistics-only",
+ tablespaces_only, "-t/--tablespaces-only");
+
+ /* --no-* and *-only for same thing are incompatible */
+ check_mut_excl_opts(data_only, "-a/--data-only",
+ no_data, "--no-data");
+ check_mut_excl_opts(schema_only, "-s/--schema-only",
+ no_schema, "--no-schema");
+ check_mut_excl_opts(statistics_only, "--statistics-only",
+ no_statistics, "--no-statistics");
+
+ /* --statistics and --no-statistics are incompatible */
+ check_mut_excl_opts(with_statistics, "--statistics",
+ no_statistics, "--no-statistics");
+
+ /* --statistics is incompatible with *-only (except --statistics-only) */
+ check_mut_excl_opts(with_statistics, "--statistics",
+ data_only, "-a/--data-only",
+ globals_only, "-g/--globals-only",
+ roles_only, "-r/--roles-only",
+ schema_only, "-s/--schema-only",
+ tablespaces_only, "-t/--tablespaces-only");
- /* Make sure the user hasn't specified a mix of globals-only options */
- if (globals_only && roles_only)
- {
- pg_log_error("options %s and %s cannot be used together",
- "-g/--globals-only", "-r/--roles-only");
- pg_log_error_hint("Try \"%s --help\" for more information.", progname);
- exit_nicely(1);
- }
-
- if (globals_only && tablespaces_only)
- {
- pg_log_error("options %s and %s cannot be used together",
- "-g/--globals-only", "-t/--tablespaces-only");
- pg_log_error_hint("Try \"%s --help\" for more information.", progname);
- exit_nicely(1);
- }
+ /* --clean and --data-only are incompatible */
+ check_mut_excl_opts(output_clean, "-c/--clean",
+ data_only, "-a/--data-only");
if (if_exists && !output_clean)
pg_fatal("option %s requires option %s",
"--if-exists", "-c/--clean");
- /* --clean and --data-only are incompatible */
- if (output_clean && data_only)
- pg_fatal("options %s and %s cannot be used together",
- "-c/--clean", "-a/--data-only");
-
- if (roles_only && tablespaces_only)
- {
- pg_log_error("options %s and %s cannot be used together",
- "-r/--roles-only", "-t/--tablespaces-only");
- pg_log_error_hint("Try \"%s --help\" for more information.", progname);
- exit_nicely(1);
- }
-
/*
* If password values are not required in the dump, switch to using
* pg_roles which is equally useful, just more likely to have unrestricted
diff --git a/src/bin/pg_dump/t/001_basic.pl b/src/bin/pg_dump/t/001_basic.pl
index b2558046224..d89ba4a4ceb 100644
--- a/src/bin/pg_dump/t/001_basic.pl
+++ b/src/bin/pg_dump/t/001_basic.pl
@@ -246,8 +246,38 @@ command_fails_like(
# also fails for -r and -t, but it seems pointless to add more tests for those.
command_fails_like(
[ 'pg_dumpall', '--exclude-database=foo', '--globals-only' ],
- qr/\Qpg_dumpall: error: option --exclude-database cannot be used together with -g\/--globals-only\E/,
- 'pg_dumpall: option --exclude-database cannot be used together with -g/--globals-only'
+ qr/\Qpg_dumpall: error: options --exclude-database and -g\/--globals-only cannot be used together\E/,
+ 'pg_dumpall: options --exclude-database and -g/--globals-only cannot be used together'
+);
+
+command_fails_like(
+ [ 'pg_dumpall', '-a', '--no-data' ],
+ qr/\Qpg_dumpall: error: options -a\/--data-only and --no-data cannot be used together\E/,
+ 'pg_dumpall: options -a\/--data-only and --no-data cannot be used together'
+);
+
+command_fails_like(
+ [ 'pg_dumpall', '-s', '--no-schema' ],
+ qr/\Qpg_dumpall: error: options -s\/--schema-only and --no-schema cannot be used together\E/,
+ 'pg_dumpall: options -s\/--schema-only and --no-schema cannot be used together'
+);
+
+command_fails_like(
+ [ 'pg_dumpall', '--statistics-only', '--no-statistics' ],
+ qr/\Qpg_dumpall: error: options --statistics-only and --no-statistics cannot be used together\E/,
+ 'pg_dumpall: options --statistics-only and --no-statistics cannot be used together'
+);
+
+command_fails_like(
+ [ 'pg_dumpall', '--statistics', '--no-statistics' ],
+ qr/\Qpg_dumpall: error: options --statistics and --no-statistics cannot be used together\E/,
+ 'pg_dumpall: options --statistics-only and --no-statistics cannot be used together'
+);
+
+command_fails_like(
+ [ 'pg_dumpall', '--statistics', '--tablespaces-only' ],
+ qr/\Qpg_dumpall: error: options --statistics and -t\/--tablespaces-only cannot be used together\E/,
+ 'pg_dumpall: options --statistics and -t\/--tablespaces-only cannot be used together'
);
done_testing();
diff --git a/src/bin/pg_dump/t/005_pg_dump_filterfile.pl b/src/bin/pg_dump/t/005_pg_dump_filterfile.pl
index 72a7c90c6af..cecf0442088 100644
--- a/src/bin/pg_dump/t/005_pg_dump_filterfile.pl
+++ b/src/bin/pg_dump/t/005_pg_dump_filterfile.pl
@@ -570,8 +570,8 @@ command_fails_like(
'--filter' => "$tempdir/inputfile.txt",
'--globals-only'
],
- qr/\Qpg_dumpall: error: option --exclude-database cannot be used together with -g\/--globals-only\E/,
- 'pg_dumpall: option --exclude-database cannot be used together with -g/--globals-only'
+ qr/\Qpg_dumpall: error: options --exclude-database and -g\/--globals-only cannot be used together\E/,
+ 'pg_dumpall: options --exclude-database and -g/--globals-only cannot be used together'
);
# Test invalid filter command
--
2.52.0