fix-foreign-key-check.patch

application/octet-stream

Filename: fix-foreign-key-check.patch
Type: application/octet-stream
Part: 0
Message: Re: Fix foreign key constraint check for partitioned tables

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