From 93cf9663834c39b8228ded84b4c16e70dd477501 Mon Sep 17 00:00:00 2001 From: Takayuki Tsunakawa Date: Wed, 2 Dec 2020 17:04:12 +0900 Subject: [PATCH v2] Make ALTER TABLE SET LOGGED/UNLOGGED on a partitioned table recurse --- src/backend/commands/tablecmds.c | 12 ++++ src/test/regress/expected/alter_table.out | 92 +++++++++++++++++++++++++++++++ src/test/regress/sql/alter_table.sql | 37 +++++++++++++ 3 files changed, 141 insertions(+) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index a29c14b..1392736 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -4246,6 +4246,8 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE; tab->newrelpersistence = RELPERSISTENCE_PERMANENT; } + if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context); pass = AT_PASS_MISC; break; case AT_SetUnLogged: /* SET UNLOGGED */ @@ -4261,6 +4263,8 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE; tab->newrelpersistence = RELPERSISTENCE_UNLOGGED; } + if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context); pass = AT_PASS_MISC; break; case AT_DropOids: /* SET WITHOUT OIDS */ @@ -5713,6 +5717,14 @@ ATSimpleRecursion(List **wqueue, Relation rel, continue; /* find_all_inheritors already got lock */ childrel = relation_open(childrelid, NoLock); + /* Skip foreign partitions when SET LOGGED/UNLOGGED */ + if ((cmd->subtype == AT_SetLogged || + cmd->subtype == AT_SetUnLogged) && + childrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE) + { + relation_close(childrel, NoLock); + continue; + } CheckTableNotInUse(childrel, "ALTER TABLE"); ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context); relation_close(childrel, NoLock); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 0ce6ee4..e9e21a4 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -3472,6 +3472,98 @@ ALTER TABLE logged1 SET UNLOGGED; -- silently do nothing DROP TABLE logged3; DROP TABLE logged2; DROP TABLE logged1; +-- set partitioned table logged/unlogged +CREATE TABLE part_logged_parent (key integer PRIMARY KEY, val text) + PARTITION BY RANGE (key); +CREATE TABLE part_logged_child1 PARTITION OF part_logged_parent + FOR VALUES FROM (1) TO (10); +CREATE TABLE part_logged_child2 PARTITION OF part_logged_parent + FOR VALUES FROM (11) TO (20); +ALTER TABLE part_logged_parent SET UNLOGGED; -- children become unlogged +CREATE TABLE part_logged_child3 (LIKE part_logged_parent); +ALTER TABLE part_logged_parent ATTACH PARTITION part_logged_child3 + FOR VALUES FROM (21) TO (30); -- child3 remains logged +-- check relpersistence +SELECT relname, relkind, relpersistence FROM pg_class WHERE relname ~ '^part_logged' +UNION ALL +SELECT 'toast table for ' || r.relname, t.relkind, t.relpersistence FROM pg_class r JOIN pg_class t ON t.oid = r.reltoastrelid WHERE r.relname ~ '^part_logged' +UNION ALL +SELECT 'toast index for ' || r.relname, ri.relkind, ri.relpersistence FROM pg_class r join pg_class t ON t.oid = r.reltoastrelid JOIN pg_index i ON i.indrelid = t.oid JOIN pg_class ri ON ri.oid = i.indexrelid WHERE r.relname ~ '^part_logged' +ORDER BY relname; + relname | relkind | relpersistence +------------------------------------+---------+---------------- + part_logged_child1 | r | u + part_logged_child1_pkey | i | u + part_logged_child2 | r | u + part_logged_child2_pkey | i | u + part_logged_child3 | r | p + part_logged_child3_pkey | i | p + part_logged_parent | p | p + part_logged_parent_pkey | I | p + toast index for part_logged_child1 | i | u + toast index for part_logged_child2 | i | u + toast index for part_logged_child3 | i | p + toast table for part_logged_child1 | t | u + toast table for part_logged_child2 | t | u + toast table for part_logged_child3 | t | p +(14 rows) + +ALTER TABLE part_logged_parent SET LOGGED; -- children become logged +-- check relpersistence +SELECT relname, relkind, relpersistence FROM pg_class WHERE relname ~ '^part_logged' +UNION ALL +SELECT 'toast table for ' || r.relname, t.relkind, t.relpersistence FROM pg_class r JOIN pg_class t ON t.oid = r.reltoastrelid WHERE r.relname ~ '^part_logged' +UNION ALL +SELECT 'toast index for ' || r.relname, ri.relkind, ri.relpersistence FROM pg_class r join pg_class t ON t.oid = r.reltoastrelid JOIN pg_index i ON i.indrelid = t.oid JOIN pg_class ri ON ri.oid = i.indexrelid WHERE r.relname ~ '^part_logged' +ORDER BY relname; + relname | relkind | relpersistence +------------------------------------+---------+---------------- + part_logged_child1 | r | p + part_logged_child1_pkey | i | p + part_logged_child2 | r | p + part_logged_child2_pkey | i | p + part_logged_child3 | r | p + part_logged_child3_pkey | i | p + part_logged_parent | p | p + part_logged_parent_pkey | I | p + toast index for part_logged_child1 | i | p + toast index for part_logged_child2 | i | p + toast index for part_logged_child3 | i | p + toast table for part_logged_child1 | t | p + toast table for part_logged_child2 | t | p + toast table for part_logged_child3 | t | p +(14 rows) + +CREATE TABLE logged_fk_child (key integer PRIMARY KEY, fk integer REFERENCES part_logged_child2); +ALTER TABLE part_logged_parent SET UNLOGGED; -- fails because logged table references a child +ERROR: could not change table "part_logged_child2" to unlogged because it references logged table "logged_fk_child" +-- check relpersistence +SELECT relname, relkind, relpersistence FROM pg_class WHERE relname ~ '^part_logged' +UNION ALL +SELECT 'toast table for ' || r.relname, t.relkind, t.relpersistence FROM pg_class r JOIN pg_class t ON t.oid = r.reltoastrelid WHERE r.relname ~ '^part_logged' +UNION ALL +SELECT 'toast index for ' || r.relname, ri.relkind, ri.relpersistence FROM pg_class r join pg_class t ON t.oid = r.reltoastrelid JOIN pg_index i ON i.indrelid = t.oid JOIN pg_class ri ON ri.oid = i.indexrelid WHERE r.relname ~ '^part_logged' +ORDER BY relname; + relname | relkind | relpersistence +------------------------------------+---------+---------------- + part_logged_child1 | r | p + part_logged_child1_pkey | i | p + part_logged_child2 | r | p + part_logged_child2_pkey | i | p + part_logged_child3 | r | p + part_logged_child3_pkey | i | p + part_logged_parent | p | p + part_logged_parent_pkey | I | p + toast index for part_logged_child1 | i | p + toast index for part_logged_child2 | i | p + toast index for part_logged_child3 | i | p + toast table for part_logged_child1 | t | p + toast table for part_logged_child2 | t | p + toast table for part_logged_child3 | t | p +(14 rows) + +DROP TABLE logged_fk_child; +DROP TABLE part_logged_parent; -- test ADD COLUMN IF NOT EXISTS CREATE TABLE test_add_column(c1 integer); \d test_add_column diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 4cc55d8..18c0a69 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2188,6 +2188,43 @@ ALTER TABLE logged1 SET UNLOGGED; -- silently do nothing DROP TABLE logged3; DROP TABLE logged2; DROP TABLE logged1; +-- set partitioned table logged/unlogged +CREATE TABLE part_logged_parent (key integer PRIMARY KEY, val text) + PARTITION BY RANGE (key); +CREATE TABLE part_logged_child1 PARTITION OF part_logged_parent + FOR VALUES FROM (1) TO (10); +CREATE TABLE part_logged_child2 PARTITION OF part_logged_parent + FOR VALUES FROM (11) TO (20); +ALTER TABLE part_logged_parent SET UNLOGGED; -- children become unlogged +CREATE TABLE part_logged_child3 (LIKE part_logged_parent); +ALTER TABLE part_logged_parent ATTACH PARTITION part_logged_child3 + FOR VALUES FROM (21) TO (30); -- child3 remains logged +-- check relpersistence +SELECT relname, relkind, relpersistence FROM pg_class WHERE relname ~ '^part_logged' +UNION ALL +SELECT 'toast table for ' || r.relname, t.relkind, t.relpersistence FROM pg_class r JOIN pg_class t ON t.oid = r.reltoastrelid WHERE r.relname ~ '^part_logged' +UNION ALL +SELECT 'toast index for ' || r.relname, ri.relkind, ri.relpersistence FROM pg_class r join pg_class t ON t.oid = r.reltoastrelid JOIN pg_index i ON i.indrelid = t.oid JOIN pg_class ri ON ri.oid = i.indexrelid WHERE r.relname ~ '^part_logged' +ORDER BY relname; +ALTER TABLE part_logged_parent SET LOGGED; -- children become logged +-- check relpersistence +SELECT relname, relkind, relpersistence FROM pg_class WHERE relname ~ '^part_logged' +UNION ALL +SELECT 'toast table for ' || r.relname, t.relkind, t.relpersistence FROM pg_class r JOIN pg_class t ON t.oid = r.reltoastrelid WHERE r.relname ~ '^part_logged' +UNION ALL +SELECT 'toast index for ' || r.relname, ri.relkind, ri.relpersistence FROM pg_class r join pg_class t ON t.oid = r.reltoastrelid JOIN pg_index i ON i.indrelid = t.oid JOIN pg_class ri ON ri.oid = i.indexrelid WHERE r.relname ~ '^part_logged' +ORDER BY relname; +CREATE TABLE logged_fk_child (key integer PRIMARY KEY, fk integer REFERENCES part_logged_child2); +ALTER TABLE part_logged_parent SET UNLOGGED; -- fails because logged table references a child +-- check relpersistence +SELECT relname, relkind, relpersistence FROM pg_class WHERE relname ~ '^part_logged' +UNION ALL +SELECT 'toast table for ' || r.relname, t.relkind, t.relpersistence FROM pg_class r JOIN pg_class t ON t.oid = r.reltoastrelid WHERE r.relname ~ '^part_logged' +UNION ALL +SELECT 'toast index for ' || r.relname, ri.relkind, ri.relpersistence FROM pg_class r join pg_class t ON t.oid = r.reltoastrelid JOIN pg_index i ON i.indrelid = t.oid JOIN pg_class ri ON ri.oid = i.indexrelid WHERE r.relname ~ '^part_logged' +ORDER BY relname; +DROP TABLE logged_fk_child; +DROP TABLE part_logged_parent; -- test ADD COLUMN IF NOT EXISTS CREATE TABLE test_add_column(c1 integer); -- 2.10.1