Commit be280cda authored by Alvaro Herrera's avatar Alvaro Herrera

Don't reset relhasindex for partitioned tables on ANALYZE

Commit 0e69f705 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: default avatarÁlvaro Herrera <alvherre@alvh.no-ip.org>
Reviewed-by: default avatarZhihong Yu <zyu@yugabyte.com>
Discussion: https://postgr.es/m/CALNJ-vS1R3Qoe5t4tbzxrkpBtzRbPq1dDcW4RmA_a+oqweF30w@mail.gmail.com
parent c4774ce3
...@@ -420,20 +420,34 @@ do_analyze_rel(Relation onerel, VacuumParams *params, ...@@ -420,20 +420,34 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
/* /*
* Open all indexes of the relation, and see if there are any analyzable * 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 * 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 * an explicit column list in the ANALYZE command, however.
* doing a recursive scan, we don't want to touch the parent's indexes at *
* all. * 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); vac_open_indexes(onerel, AccessShareLock, &nindexes, &Irel);
hasindex = nindexes > 0;
}
else else
{ {
Irel = NULL; Irel = NULL;
nindexes = 0; nindexes = 0;
hasindex = false;
} }
hasindex = (nindexes > 0);
indexdata = NULL; indexdata = NULL;
if (hasindex) if (nindexes > 0)
{ {
indexdata = (AnlIndexData *) palloc0(nindexes * sizeof(AnlIndexData)); indexdata = (AnlIndexData *) palloc0(nindexes * sizeof(AnlIndexData));
for (ind = 0; ind < nindexes; ind++) for (ind = 0; ind < nindexes; ind++)
...@@ -572,7 +586,7 @@ do_analyze_rel(Relation onerel, VacuumParams *params, ...@@ -572,7 +586,7 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
MemoryContextResetAndDeleteChildren(col_context); MemoryContextResetAndDeleteChildren(col_context);
} }
if (hasindex) if (nindexes > 0)
compute_index_stats(onerel, totalrows, compute_index_stats(onerel, totalrows,
indexdata, nindexes, indexdata, nindexes,
rows, numrows, rows, numrows,
...@@ -660,10 +674,10 @@ do_analyze_rel(Relation onerel, VacuumParams *params, ...@@ -660,10 +674,10 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
/* /*
* Partitioned tables don't have storage, so we don't set any fields * Partitioned tables don't have storage, so we don't set any fields
* in their pg_class entries except for reltuples, which is necessary * 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, vac_update_relstats(onerel, -1, totalrows,
0, false, InvalidTransactionId, 0, hasindex, InvalidTransactionId,
InvalidMultiXactId, InvalidMultiXactId,
in_outer_xact); in_outer_xact);
} }
......
...@@ -199,6 +199,28 @@ VACUUM ANALYZE vacparted(a,b,a); ...@@ -199,6 +199,28 @@ VACUUM ANALYZE vacparted(a,b,a);
ERROR: column "a" of relation "vacparted" appears more than once ERROR: column "a" of relation "vacparted" appears more than once
ANALYZE vacparted(a,b,b); ANALYZE vacparted(a,b,b);
ERROR: column "b" of relation "vacparted" appears more than once 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 -- multiple tables specified
VACUUM vaccluster, vactst; VACUUM vaccluster, vactst;
VACUUM vacparted, does_not_exist; VACUUM vacparted, does_not_exist;
......
...@@ -170,6 +170,22 @@ VACUUM (FREEZE) vacparted; ...@@ -170,6 +170,22 @@ VACUUM (FREEZE) vacparted;
VACUUM ANALYZE vacparted(a,b,a); VACUUM ANALYZE vacparted(a,b,a);
ANALYZE vacparted(a,b,b); 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 -- multiple tables specified
VACUUM vaccluster, vactst; VACUUM vaccluster, vactst;
VACUUM vacparted, does_not_exist; VACUUM vacparted, does_not_exist;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment