mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Don't lose partitioned table reltuples=0 after relhassubclass=f.
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 375aed36ad introduced
maintenance of partitioned table pg_class.reltuples.
Reported by Alexander Lakhin.
Discussion: https://postgr.es/m/a295b499-dcab-6a99-c06e-01cf60593344@gmail.com
			
			
This commit is contained in:
		@@ -637,7 +637,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,
 | 
			
		||||
@@ -672,6 +676,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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user