]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix inconsistencies with pg_restore --statistics[-only]
authorMichael Paquier <michael@paquier.xyz>
Mon, 15 Jun 2026 23:22:41 +0000 (08:22 +0900)
committerMichael Paquier <michael@paquier.xyz>
Mon, 15 Jun 2026 23:22:41 +0000 (08:22 +0900)
Attempting to restore a schema, a table or an index with
--only-statistics skipped all the statistics of the objects wanted.
Like for pg_dump, statistics should be included, so this created an
assymetry between dump and restore.

A second set of problems existed for --table and --index, where the
presence of --statistics skipped the restore of the stats of the
object(s) targetted.

This issue has been reported originally as related to an inconsistency
with the way extended stats restore is handled in Postgres v19, but the
issue is related to the restore of relation and attribute statistics in
v18.  Some TAP tests are added to cover all these cases.

Reported-by: Chao Li <li.evan.chao@gmail.com>
Author: Chao Li <li.evan.chao@gmail.com>
Author: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Corey Huinker <corey.huinker@gmail.com>
Discussion: https://postgr.es/m/66E80CAB-527C-42B1-BB65-3F82CF4AD998@gmail.com
Backpatch-through: 18

src/bin/pg_dump/pg_backup_archiver.c
src/bin/pg_dump/t/002_pg_dump.pl

index 4293e20b20e05d7102b8a435ade96bde01887c1d..c4e17359d9fb3b6c318a1f9df9d73b46fff1e94f 100644 (file)
@@ -3115,7 +3115,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. */
@@ -3186,14 +3185,33 @@ _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;
+
+                               /*
+                                * Statistics data can be assigned for tables or indexes, so
+                                * check both.
+                                */
+                               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;
index 9512e2d89e5d33f113096fdbd737ae48f15a7fed..dae5641f24e3ceaae7dc38f31b310011e6c6db52 100644 (file)
@@ -851,6 +851,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',
@@ -5137,6 +5191,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 => {
@@ -5166,6 +5222,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 => {