]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Don't lose partitioned table reltuples=0 after relhassubclass=f.
authorNoah Misch <noah@leadboat.com>
Sat, 13 Jul 2024 15:09:33 +0000 (08:09 -0700)
committerNoah Misch <noah@leadboat.com>
Sat, 13 Jul 2024 15:09:37 +0000 (08:09 -0700)
ANALYZE sets relhassubclass=f when a partitioned table no longer has
partitions.  An ANALYZE doing that proceeded to apply the inplace update
of pg_class.reltuples to the old pg_class tuple instead of the new
tuple, losing that reltuples=0 change if the ANALYZE committed.
Non-partitioning inheritance trees were unaffected.  Back-patch to v14,
where commit 375aed36ad83f0e021e9bdd3a0034c0c992c66dc introduced
maintenance of partitioned table pg_class.reltuples.

Reported by Alexander Lakhin.

Discussion: https://postgr.es/m/a295b499-dcab-6a99-c06e-01cf60593344@gmail.com

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

index fb5a47daf37b1937ced6f0d327a4f38cd376f998..bda364552cacc020b4dd4f9986ca5c0843ef633b 100644 (file)
@@ -636,7 +636,11 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
 
                visibilitymap_count(onerel, &relallvisible, NULL);
 
-               /* Update pg_class for table relation */
+               /*
+                * Update pg_class for table relation.  CCI first, in case acquirefunc
+                * updated pg_class.
+                */
+               CommandCounterIncrement();
                vac_update_relstats(onerel,
                                                        relpages,
                                                        totalrows,
@@ -671,6 +675,7 @@ 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 and relhasindex.
                 */
+               CommandCounterIncrement();
                vac_update_relstats(onerel, -1, totalrows,
                                                        0, hasindex, InvalidTransactionId,
                                                        InvalidMultiXactId,
index 4def90b80575020a313c86ad4ad3d385afcc31a5..4aaf4f025d3b0f3040af0cf53f60dbdad3c71b30 100644 (file)
@@ -82,6 +82,53 @@ BEGIN;
 INSERT INTO vactst SELECT generate_series(301, 400);
 DELETE FROM vactst WHERE i % 5 <> 0; -- delete a few rows inside
 ANALYZE vactst;
+COMMIT;
+-- Test ANALYZE setting relhassubclass=f for non-partitioning inheritance
+BEGIN;
+CREATE TABLE past_inh_parent ();
+CREATE TABLE past_inh_child () INHERITS (past_inh_parent);
+INSERT INTO past_inh_child DEFAULT VALUES;
+INSERT INTO past_inh_child DEFAULT VALUES;
+ANALYZE past_inh_parent;
+SELECT reltuples, relhassubclass
+  FROM pg_class WHERE oid = 'past_inh_parent'::regclass;
+ reltuples | relhassubclass 
+-----------+----------------
+         0 | t
+(1 row)
+
+DROP TABLE past_inh_child;
+ANALYZE past_inh_parent;
+SELECT reltuples, relhassubclass
+  FROM pg_class WHERE oid = 'past_inh_parent'::regclass;
+ reltuples | relhassubclass 
+-----------+----------------
+         0 | f
+(1 row)
+
+COMMIT;
+-- Test ANALYZE setting relhassubclass=f for partitioning
+BEGIN;
+CREATE TABLE past_parted (i int) PARTITION BY LIST(i);
+CREATE TABLE past_part PARTITION OF past_parted FOR VALUES IN (1);
+INSERT INTO past_parted VALUES (1),(1);
+ANALYZE past_parted;
+DROP TABLE past_part;
+SELECT reltuples, relhassubclass
+  FROM pg_class WHERE oid = 'past_parted'::regclass;
+ reltuples | relhassubclass 
+-----------+----------------
+         2 | t
+(1 row)
+
+ANALYZE past_parted;
+SELECT reltuples, relhassubclass
+  FROM pg_class WHERE oid = 'past_parted'::regclass;
+ reltuples | relhassubclass 
+-----------+----------------
+         0 | f
+(1 row)
+
 COMMIT;
 VACUUM FULL pg_am;
 VACUUM FULL pg_class;
index 51d7b1fecc71044fd66a27a19f99ebfe8a9125df..ae36b546410ad01dcf151013a5eea90fbe319f55 100644 (file)
@@ -67,6 +67,35 @@ DELETE FROM vactst WHERE i % 5 <> 0; -- delete a few rows inside
 ANALYZE vactst;
 COMMIT;
 
+-- Test ANALYZE setting relhassubclass=f for non-partitioning inheritance
+BEGIN;
+CREATE TABLE past_inh_parent ();
+CREATE TABLE past_inh_child () INHERITS (past_inh_parent);
+INSERT INTO past_inh_child DEFAULT VALUES;
+INSERT INTO past_inh_child DEFAULT VALUES;
+ANALYZE past_inh_parent;
+SELECT reltuples, relhassubclass
+  FROM pg_class WHERE oid = 'past_inh_parent'::regclass;
+DROP TABLE past_inh_child;
+ANALYZE past_inh_parent;
+SELECT reltuples, relhassubclass
+  FROM pg_class WHERE oid = 'past_inh_parent'::regclass;
+COMMIT;
+
+-- Test ANALYZE setting relhassubclass=f for partitioning
+BEGIN;
+CREATE TABLE past_parted (i int) PARTITION BY LIST(i);
+CREATE TABLE past_part PARTITION OF past_parted FOR VALUES IN (1);
+INSERT INTO past_parted VALUES (1),(1);
+ANALYZE past_parted;
+DROP TABLE past_part;
+SELECT reltuples, relhassubclass
+  FROM pg_class WHERE oid = 'past_parted'::regclass;
+ANALYZE past_parted;
+SELECT reltuples, relhassubclass
+  FROM pg_class WHERE oid = 'past_parted'::regclass;
+COMMIT;
+
 VACUUM FULL pg_am;
 VACUUM FULL pg_class;
 VACUUM FULL pg_database;