Don't reset relhasindex for partitioned tables on ANALYZE
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 1 Jul 2021 16:56:30 +0000 (12:56 -0400)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 1 Jul 2021 16:56:30 +0000 (12:56 -0400)
Commit 0e69f705cc1a introduced code to analyze partitioned table;
however, that code fails to preserve pg_class.relhasindex correctly.
Fix by observing whether any indexes exist rather than accidentally
falling through to assuming none do.

Backpatch to 14.

Author: Alexander Pyhalov <a.pyhalov@postgrespro.ru>
Reviewed-by: Álvaro Herrera <alvherre@alvh.no-ip.org>
Reviewed-by: Zhihong Yu <zyu@yugabyte.com>
Discussion: https://postgr.es/m/CALNJ-vS1R3Qoe5t4tbzxrkpBtzRbPq1dDcW4RmA_a+oqweF30w@mail.gmail.com

src/backend/commands/analyze.c
src/test/regress/expected/vacuum.out
src/test/regress/sql/vacuum.sql

index 426c1e671092b44d560c618f1555cb3d3dabc1ef..0c9591415e4b97dd5c5e693af1860294284a1575 100644 (file)
@@ -420,20 +420,34 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
        /*
         * Open all indexes of the relation, and see if there are any analyzable
         * columns in the indexes.  We do not analyze index columns if there was
-        * an explicit column list in the ANALYZE command, however.  If we are
-        * doing a recursive scan, we don't want to touch the parent's indexes at
-        * all.
+        * an explicit column list in the ANALYZE command, however.
+        *
+        * If we are doing a recursive scan, we don't want to touch the parent's
+        * indexes at all.  If we're processing a partitioned table, we need to
+        * know if there are any indexes, but we don't want to process them.
         */
-       if (!inh)
+       if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+       {
+               List *idxs = RelationGetIndexList(onerel);
+
+               Irel = NULL;
+               nindexes = 0;
+               hasindex = idxs != NIL;
+               list_free(idxs);
+       }
+       else if (!inh)
+       {
                vac_open_indexes(onerel, AccessShareLock, &nindexes, &Irel);
+               hasindex = nindexes > 0;
+       }
        else
        {
                Irel = NULL;
                nindexes = 0;
+               hasindex = false;
        }
-       hasindex = (nindexes > 0);
        indexdata = NULL;
-       if (hasindex)
+       if (nindexes > 0)
        {
                indexdata = (AnlIndexData *) palloc0(nindexes * sizeof(AnlIndexData));
                for (ind = 0; ind < nindexes; ind++)
@@ -572,7 +586,7 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
                        MemoryContextResetAndDeleteChildren(col_context);
                }
 
-               if (hasindex)
+               if (nindexes > 0)
                        compute_index_stats(onerel, totalrows,
                                                                indexdata, nindexes,
                                                                rows, numrows,
@@ -660,10 +674,10 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
                /*
                 * Partitioned tables don't have storage, so we don't set any fields
                 * in their pg_class entries except for reltuples, which is necessary
-                * for auto-analyze to work properly.
+                * for auto-analyze to work properly, and relhasindex.
                 */
                vac_update_relstats(onerel, -1, totalrows,
-                                                       0, false, InvalidTransactionId,
+                                                       0, hasindex, InvalidTransactionId,
                                                        InvalidMultiXactId,
                                                        in_outer_xact);
        }
index e5771462d57b4d0b6e1b9c1e67543692dd8055bc..3e70e4c788e3ca19ef14a517ef31443684f669b1 100644 (file)
@@ -199,6 +199,28 @@ VACUUM ANALYZE vacparted(a,b,a);
 ERROR:  column "a" of relation "vacparted" appears more than once
 ANALYZE vacparted(a,b,b);
 ERROR:  column "b" of relation "vacparted" appears more than once
+-- partitioned table with index
+CREATE TABLE vacparted_i (a int primary key, b varchar(100))
+  PARTITION BY HASH (a);
+CREATE TABLE vacparted_i1 PARTITION OF vacparted_i
+  FOR VALUES WITH (MODULUS 2, REMAINDER 0);
+CREATE TABLE vacparted_i2 PARTITION OF vacparted_i
+  FOR VALUES WITH (MODULUS 2, REMAINDER 1);
+INSERT INTO vacparted_i SELECT i, 'test_'|| i from generate_series(1,10) i;
+VACUUM (ANALYZE) vacparted_i;
+VACUUM (FULL) vacparted_i;
+VACUUM (FREEZE) vacparted_i;
+SELECT relname, relhasindex FROM pg_class
+  WHERE relname LIKE 'vacparted_i%' AND relkind IN ('p','r')
+  ORDER BY relname;
+   relname    | relhasindex 
+--------------+-------------
+ vacparted_i  | t
+ vacparted_i1 | t
+ vacparted_i2 | t
+(3 rows)
+
+DROP TABLE vacparted_i;
 -- multiple tables specified
 VACUUM vaccluster, vactst;
 VACUUM vacparted, does_not_exist;
index f220fc28a700a605d210d7d2019ca9e1bf1dabd9..18cb7fd08ac6dbb1ddbf410ec5002938127bbdc2 100644 (file)
@@ -170,6 +170,22 @@ VACUUM (FREEZE) vacparted;
 VACUUM ANALYZE vacparted(a,b,a);
 ANALYZE vacparted(a,b,b);
 
+-- partitioned table with index
+CREATE TABLE vacparted_i (a int primary key, b varchar(100))
+  PARTITION BY HASH (a);
+CREATE TABLE vacparted_i1 PARTITION OF vacparted_i
+  FOR VALUES WITH (MODULUS 2, REMAINDER 0);
+CREATE TABLE vacparted_i2 PARTITION OF vacparted_i
+  FOR VALUES WITH (MODULUS 2, REMAINDER 1);
+INSERT INTO vacparted_i SELECT i, 'test_'|| i from generate_series(1,10) i;
+VACUUM (ANALYZE) vacparted_i;
+VACUUM (FULL) vacparted_i;
+VACUUM (FREEZE) vacparted_i;
+SELECT relname, relhasindex FROM pg_class
+  WHERE relname LIKE 'vacparted_i%' AND relkind IN ('p','r')
+  ORDER BY relname;
+DROP TABLE vacparted_i;
+
 -- multiple tables specified
 VACUUM vaccluster, vactst;
 VACUUM vacparted, does_not_exist;