mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Reset relhassubclass upon attaching table as a partition
We don't allow inheritance parents as partitions, and have checks to prevent this; but if a table _was_ in the past an inheritance parents and all their children are removed, the pg_class.relhassubclass flag may remain set, which confuses the partition pruning code (most obviously, it results in an assertion failure; in production builds it may be worse.) Fix by resetting relhassubclass on attach. Backpatch to all supported versions. Reported-by: Alexander Lakhin <exclusion@gmail.com> Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us> Discussion: https://postgr.es/m/18550-d5e047e9a897a889@postgresql.org
This commit is contained in:
		@@ -3518,6 +3518,14 @@ StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *bound)
 | 
				
			|||||||
								 new_val, new_null, new_repl);
 | 
													 new_val, new_null, new_repl);
 | 
				
			||||||
	/* Also set the flag */
 | 
						/* Also set the flag */
 | 
				
			||||||
	((Form_pg_class) GETSTRUCT(newtuple))->relispartition = true;
 | 
						((Form_pg_class) GETSTRUCT(newtuple))->relispartition = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * We already checked for no inheritance children, but reset
 | 
				
			||||||
 | 
						 * relhassubclass in case it was left over.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (rel->rd_rel->relkind == RELKIND_RELATION && rel->rd_rel->relhassubclass)
 | 
				
			||||||
 | 
							((Form_pg_class) GETSTRUCT(newtuple))->relhassubclass = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
 | 
						CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
 | 
				
			||||||
	heap_freetuple(newtuple);
 | 
						heap_freetuple(newtuple);
 | 
				
			||||||
	table_close(classRel, RowExclusiveLock);
 | 
						table_close(classRel, RowExclusiveLock);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3909,8 +3909,16 @@ ALTER TABLE list_parted ATTACH PARTITION child FOR VALUES IN (1);
 | 
				
			|||||||
ERROR:  cannot attach inheritance child as partition
 | 
					ERROR:  cannot attach inheritance child as partition
 | 
				
			||||||
ALTER TABLE list_parted ATTACH PARTITION parent FOR VALUES IN (1);
 | 
					ALTER TABLE list_parted ATTACH PARTITION parent FOR VALUES IN (1);
 | 
				
			||||||
ERROR:  cannot attach inheritance parent as partition
 | 
					ERROR:  cannot attach inheritance parent as partition
 | 
				
			||||||
 | 
					DROP TABLE child;
 | 
				
			||||||
 | 
					-- now it should work, with a little tweak
 | 
				
			||||||
 | 
					ALTER TABLE parent ADD CONSTRAINT check_a CHECK (a > 0);
 | 
				
			||||||
 | 
					ALTER TABLE list_parted ATTACH PARTITION parent FOR VALUES IN (1);
 | 
				
			||||||
 | 
					-- test insert/update, per bug #18550
 | 
				
			||||||
 | 
					INSERT INTO parent VALUES (1);
 | 
				
			||||||
 | 
					UPDATE parent SET a = 2 WHERE a = 1;
 | 
				
			||||||
 | 
					ERROR:  new row for relation "parent" violates partition constraint
 | 
				
			||||||
 | 
					DETAIL:  Failing row contains (2, null).
 | 
				
			||||||
DROP TABLE parent CASCADE;
 | 
					DROP TABLE parent CASCADE;
 | 
				
			||||||
NOTICE:  drop cascades to table child
 | 
					 | 
				
			||||||
-- check any TEMP-ness
 | 
					-- check any TEMP-ness
 | 
				
			||||||
CREATE TEMP TABLE temp_parted (a int) PARTITION BY LIST (a);
 | 
					CREATE TEMP TABLE temp_parted (a int) PARTITION BY LIST (a);
 | 
				
			||||||
CREATE TABLE perm_part (a int);
 | 
					CREATE TABLE perm_part (a int);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2410,6 +2410,13 @@ CREATE TABLE parent (LIKE list_parted);
 | 
				
			|||||||
CREATE TABLE child () INHERITS (parent);
 | 
					CREATE TABLE child () INHERITS (parent);
 | 
				
			||||||
ALTER TABLE list_parted ATTACH PARTITION child FOR VALUES IN (1);
 | 
					ALTER TABLE list_parted ATTACH PARTITION child FOR VALUES IN (1);
 | 
				
			||||||
ALTER TABLE list_parted ATTACH PARTITION parent FOR VALUES IN (1);
 | 
					ALTER TABLE list_parted ATTACH PARTITION parent FOR VALUES IN (1);
 | 
				
			||||||
 | 
					DROP TABLE child;
 | 
				
			||||||
 | 
					-- now it should work, with a little tweak
 | 
				
			||||||
 | 
					ALTER TABLE parent ADD CONSTRAINT check_a CHECK (a > 0);
 | 
				
			||||||
 | 
					ALTER TABLE list_parted ATTACH PARTITION parent FOR VALUES IN (1);
 | 
				
			||||||
 | 
					-- test insert/update, per bug #18550
 | 
				
			||||||
 | 
					INSERT INTO parent VALUES (1);
 | 
				
			||||||
 | 
					UPDATE parent SET a = 2 WHERE a = 1;
 | 
				
			||||||
DROP TABLE parent CASCADE;
 | 
					DROP TABLE parent CASCADE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- check any TEMP-ness
 | 
					-- check any TEMP-ness
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user