diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 3183b2aaa1..44d173b07b 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -4398,13 +4398,7 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode) { AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab); - /* - * Foreign tables have no storage, nor do partitioned tables and - * indexes. - */ - if (tab->relkind == RELKIND_FOREIGN_TABLE || - tab->relkind == RELKIND_PARTITIONED_TABLE || - tab->relkind == RELKIND_PARTITIONED_INDEX) + if (!RELKIND_HAS_STORAGE(tab->relkind)) continue; /* @@ -4584,6 +4578,9 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode) Relation rel = NULL; ListCell *lcon; + if (!RELKIND_HAS_STORAGE(tab->relkind)) + continue; + foreach(lcon, tab->constraints) { NewConstraint *con = lfirst(lcon); diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out index 401514a3e0..5735264963 100644 --- a/src/test/regress/expected/foreign_key.out +++ b/src/test/regress/expected/foreign_key.out @@ -1674,7 +1674,7 @@ CREATE TABLE fk_partitioned_fk_full (x int, y int) PARTITION BY RANGE (x); CREATE TABLE fk_partitioned_fk_full_1 PARTITION OF fk_partitioned_fk_full DEFAULT; INSERT INTO fk_partitioned_fk_full VALUES (1, NULL); ALTER TABLE fk_partitioned_fk_full ADD FOREIGN KEY (x, y) REFERENCES fk_notpartitioned_pk MATCH FULL; -- fails -ERROR: insert or update on table "fk_partitioned_fk_full" violates foreign key constraint "fk_partitioned_fk_full_x_y_fkey" +ERROR: insert or update on table "fk_partitioned_fk_full_1" violates foreign key constraint "fk_partitioned_fk_full_x_y_fkey" DETAIL: MATCH FULL does not allow mixing of null and nonnull key values. TRUNCATE fk_partitioned_fk_full; ALTER TABLE fk_partitioned_fk_full ADD FOREIGN KEY (x, y) REFERENCES fk_notpartitioned_pk MATCH FULL; @@ -1890,7 +1890,7 @@ CREATE TABLE fk_partitioned_fk_2_2 PARTITION OF fk_partitioned_fk_2 FOR VALUES F INSERT INTO fk_partitioned_fk_2 VALUES (1600, 601), (1600, 1601); ALTER TABLE fk_partitioned_fk ATTACH PARTITION fk_partitioned_fk_2 FOR VALUES IN (1600); -ERROR: insert or update on table "fk_partitioned_fk_2" violates foreign key constraint "fk_partitioned_fk_a_b_fkey" +ERROR: insert or update on table "fk_partitioned_fk_2_1" violates foreign key constraint "fk_partitioned_fk_a_b_fkey" DETAIL: Key (a, b)=(1600, 601) is not present in table "fk_notpartitioned_pk". INSERT INTO fk_notpartitioned_pk VALUES (1600, 601), (1600, 1601); ALTER TABLE fk_partitioned_fk ATTACH PARTITION fk_partitioned_fk_2 @@ -2015,6 +2015,28 @@ alter table fkpart2.fk_part detach partition fkpart2.fk_part_1; alter table fkpart2.fk_part_1 drop constraint fkey; -- ok alter table fkpart2.fk_part_1_1 drop constraint my_fkey; -- doesn't exist ERROR: constraint "my_fkey" of relation "fk_part_1_1" does not exist +-- test the case when the referenced table is owned by a different user +DROP TABLE fk_partitioned_fk; +CREATE ROLE fk_partitioned_fk_owner; +GRANT REFERENCES ON fk_notpartitioned_pk TO fk_partitioned_fk_owner; +SET ROLE fk_partitioned_fk_owner; +CREATE TABLE fk_partitioned_fk(a int, b int) PARTITION BY LIST (a); +CREATE TABLE fk_partitioned_fk_1 PARTITION OF fk_partitioned_fk FOR VALUES IN (2048); +INSERT INTO fk_partitioned_fk VALUES (2048, 4096); +-- this should fail +ALTER TABLE fk_partitioned_fk ADD FOREIGN KEY (a, b) + REFERENCES fk_notpartitioned_pk(a, b); +ERROR: insert or update on table "fk_partitioned_fk_1" violates foreign key constraint "fk_partitioned_fk_a_b_fkey" +DETAIL: Key (a, b)=(2048, 4096) is not present in table "fk_notpartitioned_pk". +-- add the missing key and retry +RESET ROLE; +INSERT INTO fk_notpartitioned_pk (a, b) VALUES (2048, 4096); +-- We set back the role so we make sure current user doesn't have SELECT +-- access to both tables. +SET ROLE fk_partitioned_fk_owner; +ALTER TABLE fk_partitioned_fk ADD FOREIGN KEY (a, b) + REFERENCES fk_notpartitioned_pk(a, b); +RESET ROLE; \set VERBOSITY terse \\ -- suppress cascade details drop schema fkpart0, fkpart1, fkpart2 cascade; NOTICE: drop cascades to 8 other objects diff --git a/src/test/regress/sql/foreign_key.sql b/src/test/regress/sql/foreign_key.sql index beeaf3277d..78c86b6277 100644 --- a/src/test/regress/sql/foreign_key.sql +++ b/src/test/regress/sql/foreign_key.sql @@ -1440,6 +1440,27 @@ alter table fkpart2.fk_part detach partition fkpart2.fk_part_1; alter table fkpart2.fk_part_1 drop constraint fkey; -- ok alter table fkpart2.fk_part_1_1 drop constraint my_fkey; -- doesn't exist +-- test the case when the referenced table is owned by a different user +DROP TABLE fk_partitioned_fk; +CREATE ROLE fk_partitioned_fk_owner; +GRANT REFERENCES ON fk_notpartitioned_pk TO fk_partitioned_fk_owner; +SET ROLE fk_partitioned_fk_owner; +CREATE TABLE fk_partitioned_fk(a int, b int) PARTITION BY LIST (a); +CREATE TABLE fk_partitioned_fk_1 PARTITION OF fk_partitioned_fk FOR VALUES IN (2048); +INSERT INTO fk_partitioned_fk VALUES (2048, 4096); +-- this should fail +ALTER TABLE fk_partitioned_fk ADD FOREIGN KEY (a, b) + REFERENCES fk_notpartitioned_pk(a, b); +-- add the missing key and retry +RESET ROLE; +INSERT INTO fk_notpartitioned_pk (a, b) VALUES (2048, 4096); +-- We set back the role so we make sure current user doesn't have SELECT +-- access to both tables. +SET ROLE fk_partitioned_fk_owner; +ALTER TABLE fk_partitioned_fk ADD FOREIGN KEY (a, b) + REFERENCES fk_notpartitioned_pk(a, b); +RESET ROLE; + \set VERBOSITY terse \\ -- suppress cascade details drop schema fkpart0, fkpart1, fkpart2 cascade; \set VERBOSITY default