]> granicus.if.org Git - postgresql/commitdiff
Include ALTER INDEX SET STATISTICS in pg_dump
authorMichael Paquier <michael@paquier.xyz>
Tue, 18 Dec 2018 00:28:16 +0000 (09:28 +0900)
committerMichael Paquier <michael@paquier.xyz>
Tue, 18 Dec 2018 00:28:16 +0000 (09:28 +0900)
The new grammar pattern of ALTER INDEX SET STATISTICS able to use column
numbers on top of the existing column names introduced by commit 5b6d13e
forgot to add support for the feature in pg_dump, so defining statistics
on index columns was missing from the dumps, potentially causing silent
planning problems with a subsequent restore.

pg_dump ought to not use column names in what it generates as these are
automatically generated by the server and could conflict with real
relation attributes with matching patterns.  "expr" and "exprN", N
incremented automatically after the creation of the first one, are used
as default attribute names for index expressions, and that could easily
match what is defined in other relations, causing the dumps to fail if
some of those attributes are renamed at some point.  So to avoid any
problems, the new grammar with column numbers gets used.

Reported-by: Ronan Dunklau
Author: Michael Paquier
Reviewed-by: Tom Lane, Adrien Nayrat, Amul Sul
Discussion: https://postgr.es/m/CAARsnT3UQ4V=yDNW468w8RqHfYiY9mpn2r_c5UkBJ97NAApUEw@mail.gmail.com
Backpatch-through: 11, where the new syntax has been introduced.

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

index 637c79af48349a2cc723c7a3bd70fc7be4c56b86..341b1a51f2a52935d8851e15a7b2021d5b4efd53 100644 (file)
@@ -6712,7 +6712,9 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                                i_conoid,
                                i_condef,
                                i_tablespace,
-                               i_indreloptions;
+                               i_indreloptions,
+                               i_indstatcols,
+                               i_indstatvals;
        int                     ntups;
 
        for (i = 0; i < numTables; i++)
@@ -6766,7 +6768,15 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                                                          "c.oid AS conoid, "
                                                          "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
                                                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
-                                                         "t.reloptions AS indreloptions "
+                                                         "t.reloptions AS indreloptions, "
+                                                         "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
+                                                         "  FROM pg_catalog.pg_attribute "
+                                                         "  WHERE attrelid = i.indexrelid AND "
+                                                         "    attstattarget >= 0) AS indstatcols,"
+                                                         "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
+                                                         "  FROM pg_catalog.pg_attribute "
+                                                         "  WHERE attrelid = i.indexrelid AND "
+                                                         "    attstattarget >= 0) AS indstatvals "
                                                          "FROM pg_catalog.pg_index i "
                                                          "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
                                                          "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
@@ -6803,7 +6813,9 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                                                          "c.oid AS conoid, "
                                                          "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
                                                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
-                                                         "t.reloptions AS indreloptions "
+                                                         "t.reloptions AS indreloptions, "
+                                                         "'' AS indstatcols, "
+                                                         "'' AS indstatvals "
                                                          "FROM pg_catalog.pg_index i "
                                                          "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
                                                          "LEFT JOIN pg_catalog.pg_constraint c "
@@ -6836,7 +6848,9 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                                                          "c.oid AS conoid, "
                                                          "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
                                                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
-                                                         "t.reloptions AS indreloptions "
+                                                         "t.reloptions AS indreloptions, "
+                                                         "'' AS indstatcols, "
+                                                         "'' AS indstatvals "
                                                          "FROM pg_catalog.pg_index i "
                                                          "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
                                                          "LEFT JOIN pg_catalog.pg_constraint c "
@@ -6865,7 +6879,9 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                                                          "c.oid AS conoid, "
                                                          "null AS condef, "
                                                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
-                                                         "t.reloptions AS indreloptions "
+                                                         "t.reloptions AS indreloptions, "
+                                                         "'' AS indstatcols, "
+                                                         "'' AS indstatvals "
                                                          "FROM pg_catalog.pg_index i "
                                                          "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
                                                          "LEFT JOIN pg_catalog.pg_depend d "
@@ -6897,7 +6913,9 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                                                          "c.oid AS conoid, "
                                                          "null AS condef, "
                                                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
-                                                         "null AS indreloptions "
+                                                         "null AS indreloptions, "
+                                                         "'' AS indstatcols, "
+                                                         "'' AS indstatvals "
                                                          "FROM pg_catalog.pg_index i "
                                                          "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
                                                          "LEFT JOIN pg_catalog.pg_depend d "
@@ -6935,6 +6953,8 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                i_condef = PQfnumber(res, "condef");
                i_tablespace = PQfnumber(res, "tablespace");
                i_indreloptions = PQfnumber(res, "indreloptions");
+               i_indstatcols = PQfnumber(res, "indstatcols");
+               i_indstatvals = PQfnumber(res, "indstatvals");
 
                tbinfo->indexes = indxinfo =
                        (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
@@ -6958,6 +6978,8 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                        indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
                        indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
                        indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
+                       indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
+                       indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
                        indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
                        parseOidArray(PQgetvalue(res, j, i_indkey),
                                                  indxinfo[j].indkeys, indxinfo[j].indnattrs);
@@ -16148,6 +16170,13 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
         */
        if (!is_constraint)
        {
+               char       *indstatcols = indxinfo->indstatcols;
+               char       *indstatvals = indxinfo->indstatvals;
+               char      **indstatcolsarray = NULL;
+               char      **indstatvalsarray = NULL;
+               int                     nstatcols;
+               int                     nstatvals;
+
                if (dopt->binary_upgrade)
                        binary_upgrade_set_pg_class_oids(fout, q,
                                                                                         indxinfo->dobj.catId.oid, true);
@@ -16171,6 +16200,32 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
                                                          qindxname);
                }
 
+               /*
+                * If the index has any statistics on some of its columns, generate
+                * the associated ALTER INDEX queries.
+                */
+               if (parsePGArray(indstatcols, &indstatcolsarray, &nstatcols) &&
+                       parsePGArray(indstatvals, &indstatvalsarray, &nstatvals) &&
+                       nstatcols == nstatvals)
+               {
+                       int                     j;
+
+                       for (j = 0; j < nstatcols; j++)
+                       {
+                               appendPQExpBuffer(q, "ALTER INDEX %s ",
+                                                                 fmtQualifiedDumpable(indxinfo));
+
+                               /*
+                                * Note that this is a column number, so no quotes should be
+                                * used.
+                                */
+                               appendPQExpBuffer(q, "ALTER COLUMN %s ",
+                                                                 indstatcolsarray[j]);
+                               appendPQExpBuffer(q, "SET STATISTICS %s;\n",
+                                                                 indstatvalsarray[j]);
+                       }
+               }
+
                /* If the index defines identity, we need to record that. */
                if (indxinfo->indisreplident)
                {
@@ -16194,6 +16249,11 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
                                                 q->data, delq->data, NULL,
                                                 NULL, 0,
                                                 NULL, NULL);
+
+               if (indstatcolsarray)
+                       free(indstatcolsarray);
+               if (indstatvalsarray)
+                       free(indstatvalsarray);
        }
 
        /* Dump Index Comments */
index 789d6a24e2f27879516e9d78444e87782068a505..1d997fa36f92bab63bf4a7a0dcf775b04a3bf2a7 100644 (file)
@@ -360,6 +360,8 @@ typedef struct _indxInfo
        char       *indexdef;
        char       *tablespace;         /* tablespace in which index is stored */
        char       *indreloptions;      /* options specified by WITH (...) */
+       char       *indstatcols;        /* column numbers with statistics */
+       char       *indstatvals;        /* statistic values for columns */
        int                     indnkeyattrs;   /* number of index key attributes */
        int                     indnattrs;              /* total number of index attributes */
        Oid                *indkeys;            /* In spite of the name 'indkeys' this field
index 46dbb078cf636d4864cdab570135cc8775b7934b..245fcbf5ce987319863c77d7b02480399dfbbf55 100644 (file)
@@ -2343,6 +2343,28 @@ my %tests = (
                unlike => { exclude_dump_test_schema => 1, },
        },
 
+       'CREATE TABLE table_with_stats' => {
+               create_order => 98,
+               create_sql   => 'CREATE TABLE dump_test.table_index_stats (
+                                                  col1 int,
+                                                  col2 int,
+                                                  col3 int);
+                                                CREATE INDEX index_with_stats
+                                                 ON dump_test.table_index_stats
+                                                 ((col1 + 1), col1, (col2 + 1), (col3 + 1));
+                                                ALTER INDEX dump_test.index_with_stats
+                                                  ALTER COLUMN 1 SET STATISTICS 400;
+                                                ALTER INDEX dump_test.index_with_stats
+                                                  ALTER COLUMN 3 SET STATISTICS 500;',
+               regexp => qr/^
+                       \QALTER INDEX dump_test.index_with_stats ALTER COLUMN 1 SET STATISTICS 400;\E\n
+                       \QALTER INDEX dump_test.index_with_stats ALTER COLUMN 3 SET STATISTICS 500;\E\n
+                       /xms,
+               like =>
+                       { %full_runs, %dump_test_schema_runs, section_post_data => 1, },
+               unlike => { exclude_dump_test_schema => 1, },
+       },
+
        'CREATE STATISTICS extended_stats_no_options' => {
                create_order => 97,
                create_sql   => 'CREATE STATISTICS dump_test.test_ext_stats_no_options