From 73deb24ac22d7051175263e6d75335e0f818822c Mon Sep 17 00:00:00 2001
From: Mahendra Singh Thalor <mahi6run@gmail.com>
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

