fix-foreign-key-check.patch
application/octet-stream
Filename: fix-foreign-key-check.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/backend/commands/tablecmds.c | 4 | 7 |
| src/test/regress/expected/foreign_key.out | 24 | 2 |
| src/test/regress/sql/foreign_key.sql | 21 | 0 |
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