From d8c7f63deba7a5c259c716921872bc8ca01a78fb Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Mon, 15 Jun 2026 16:50:50 +0900
Subject: [PATCH v4] Fix pg_restore with --schema/--table and
 --statistics[-only]

Attempting to restore a schema or a table with only statistics skipped
all the statistics of the schema, but it should not.  A second set of
problems existed for --table, where the presence of --statistics or
--statistics-only with a table skipped the restore of the stats.

Some tests are added for both cases.
---
 src/bin/pg_dump/pg_backup_archiver.c | 32 ++++++++++-----
 src/bin/pg_dump/t/002_pg_dump.pl     | 60 ++++++++++++++++++++++++++++
 2 files changed, 83 insertions(+), 9 deletions(-)

diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index 2fd773ad84f..aea853a5bf9 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -3175,7 +3175,6 @@ _tocEntryRequired(TocEntry *te, teSection curSection, ArchiveHandle *AH)
 	 */
 	if (strcmp(te->desc, "ACL") == 0 ||
 		strcmp(te->desc, "COMMENT") == 0 ||
-		strcmp(te->desc, "STATISTICS DATA") == 0 ||
 		strcmp(te->desc, "SECURITY LABEL") == 0)
 	{
 		/* Database properties react to createDB, not selectivity options. */
@@ -3246,14 +3245,29 @@ _tocEntryRequired(TocEntry *te, teSection curSection, ArchiveHandle *AH)
 
 		if (ropt->selTypes)
 		{
-			if (strcmp(te->desc, "TABLE") == 0 ||
-				strcmp(te->desc, "TABLE DATA") == 0 ||
-				strcmp(te->desc, "VIEW") == 0 ||
-				strcmp(te->desc, "FOREIGN TABLE") == 0 ||
-				strcmp(te->desc, "MATERIALIZED VIEW") == 0 ||
-				strcmp(te->desc, "MATERIALIZED VIEW DATA") == 0 ||
-				strcmp(te->desc, "SEQUENCE") == 0 ||
-				strcmp(te->desc, "SEQUENCE SET") == 0)
+			if (strcmp(te->desc, "STATISTICS DATA") == 0)
+			{
+				bool		dumpthis = false;
+
+				if (ropt->selTable &&
+					(ropt->tableNames.head == NULL ||
+					 simple_string_list_member(&ropt->tableNames, te->tag)))
+					dumpthis = true;
+				if (ropt->selIndex &&
+					(ropt->indexNames.head == NULL ||
+					 simple_string_list_member(&ropt->indexNames, te->tag)))
+					dumpthis = true;
+				if (!dumpthis)
+					return 0;
+			}
+			else if (strcmp(te->desc, "TABLE") == 0 ||
+					 strcmp(te->desc, "TABLE DATA") == 0 ||
+					 strcmp(te->desc, "VIEW") == 0 ||
+					 strcmp(te->desc, "FOREIGN TABLE") == 0 ||
+					 strcmp(te->desc, "MATERIALIZED VIEW") == 0 ||
+					 strcmp(te->desc, "MATERIALIZED VIEW DATA") == 0 ||
+					 strcmp(te->desc, "SEQUENCE") == 0 ||
+					 strcmp(te->desc, "SEQUENCE SET") == 0)
 			{
 				if (!ropt->selTable)
 					return 0;
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index 3ee9fda50e4..bb59ea3dfcd 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -587,6 +587,60 @@ my %pgdump_runs = (
 			'postgres',
 		],
 	},
+	statistics_only_with_schema => {
+		dump_cmd => [
+			'pg_dump', '--no-sync',
+			'--format' => 'custom',
+			'--file' => "$tempdir/statistics_only_with_schema.dump",
+			'--statistics-only',
+			'--schema' => 'dump_test',
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'--format' => 'custom',
+			'--file' => "$tempdir/statistics_only_with_schema.sql",
+			'--statistics-only',
+			'--schema' => 'dump_test',
+			"$tempdir/statistics_only_with_schema.dump",
+		],
+	},
+	statistics_only_with_table => {
+		dump_cmd => [
+			'pg_dump', '--no-sync',
+			'--format' => 'custom',
+			'--file' => "$tempdir/statistics_only_with_table.dump",
+			'--statistics',
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'--format' => 'custom',
+			'--file' => "$tempdir/statistics_only_with_table.sql",
+			'--statistics-only',
+			'--table' => 'test_table',
+			'--schema' => 'dump_test',
+			"$tempdir/statistics_only_with_table.dump",
+		],
+	},
+	statistics_only_with_index => {
+		dump_cmd => [
+			'pg_dump', '--no-sync',
+			'--format' => 'custom',
+			'--file' => "$tempdir/statistics_only_with_index.dump",
+			'--statistics',
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'--format' => 'custom',
+			'--file' => "$tempdir/statistics_only_with_index.sql",
+			'--statistics-only',
+			'--index' => '"dump_test"\'s post-data index',
+			'--schema' => 'dump_test',
+			"$tempdir/statistics_only_with_index.dump",
+		],
+	},
 	no_schema => {
 		dump_cmd => [
 			'pg_dump', '--no-sync',
@@ -4850,6 +4904,8 @@ my %tests = (
 			no_schema => 1,
 			section_post_data => 1,
 			statistics_only => 1,
+			statistics_only_with_schema => 1,
+			statistics_only_with_index => 1,
 			schema_only_with_statistics => 1,
 		},
 		unlike => {
@@ -4878,6 +4934,7 @@ my %tests = (
 			no_schema => 1,
 			section_post_data => 1,
 			statistics_only => 1,
+			statistics_only_with_schema => 1,
 			schema_only_with_statistics => 1,
 		},
 		unlike => {
@@ -4907,6 +4964,9 @@ my %tests = (
 			section_data => 1,
 			section_post_data => 1,
 			statistics_only => 1,
+			statistics_only_with_schema => 1,
+			statistics_only_with_index => 1,
+			statistics_only_with_table => 1,
 			schema_only_with_statistics => 1,
 		},
 		unlike => {
-- 
2.50.1 (Apple Git-155)

