-- -- MULTI_FOREIGN_KEY -- ALTER SEQUENCE pg_catalog.pg_dist_shardid_seq RESTART 1350000; ALTER SEQUENCE pg_catalog.pg_dist_jobid_seq RESTART 1350000; -- set shard_count to 4 for faster tests, because we create/drop lots of shards in this test. SET citus.shard_count TO 4; -- create tables CREATE TABLE referenced_table(id int UNIQUE, test_column int, PRIMARY KEY(id, test_column)); SELECT create_distributed_table('referenced_table', 'id', 'hash'); create_distributed_table -------------------------- (1 row) -- test foreign constraint creation with not supported parameters CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY(ref_id) REFERENCES referenced_table(id) ON DELETE SET NULL); SELECT create_distributed_table('referencing_table', 'ref_id', 'hash'); ERROR: cannot create foreign key constraint DETAIL: SET NULL or SET DEFAULT is not supported in ON DELETE operation. DROP TABLE referencing_table; CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY(ref_id) REFERENCES referenced_table(id) ON DELETE SET DEFAULT); SELECT create_distributed_table('referencing_table', 'ref_id', 'hash'); ERROR: cannot create foreign key constraint DETAIL: SET NULL or SET DEFAULT is not supported in ON DELETE operation. DROP TABLE referencing_table; CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY(ref_id) REFERENCES referenced_table(id) ON UPDATE SET NULL); SELECT create_distributed_table('referencing_table', 'ref_id', 'hash'); ERROR: cannot create foreign key constraint DETAIL: SET NULL, SET DEFAULT or CASCADE is not supported in ON UPDATE operation. DROP TABLE referencing_table; CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY(ref_id) REFERENCES referenced_table(id) ON UPDATE SET DEFAULT); SELECT create_distributed_table('referencing_table', 'ref_id', 'hash'); ERROR: cannot create foreign key constraint DETAIL: SET NULL, SET DEFAULT or CASCADE is not supported in ON UPDATE operation. DROP TABLE referencing_table; CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY(ref_id) REFERENCES referenced_table(id) ON UPDATE CASCADE); SELECT create_distributed_table('referencing_table', 'ref_id', 'hash'); ERROR: cannot create foreign key constraint DETAIL: SET NULL, SET DEFAULT or CASCADE is not supported in ON UPDATE operation. DROP TABLE referencing_table; -- test foreign constraint creation on NOT co-located tables SET citus.shard_count TO 8; CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY(ref_id) REFERENCES referenced_table(id)); SELECT create_distributed_table('referencing_table', 'ref_id', 'hash'); ERROR: cannot create foreign key constraint DETAIL: Foreign key constraint can only be created on co-located tables. DROP TABLE referencing_table; SET citus.shard_count TO 4; -- test foreign constraint creation on non-partition columns CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY(id) REFERENCES referenced_table(id)); SELECT create_distributed_table('referencing_table', 'ref_id', 'hash'); ERROR: cannot create foreign key constraint DETAIL: Partition column must exist both referencing and referenced side of the foreign constraint statement and it must be in the same ordinal in both sides. DROP TABLE referencing_table; -- test foreign constraint creation while column list are in incorrect order CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY(id, ref_id) REFERENCES referenced_table(id, test_column)); SELECT create_distributed_table('referencing_table', 'ref_id', 'hash'); ERROR: cannot create foreign key constraint DETAIL: Partition column must exist both referencing and referenced side of the foreign constraint statement and it must be in the same ordinal in both sides. DROP TABLE referencing_table; -- test foreign constraint with replication factor > 1 CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY(ref_id) REFERENCES referenced_table(id)); SELECT create_distributed_table('referencing_table', 'ref_id', 'hash'); ERROR: cannot create foreign key constraint DETAIL: Citus Community Edition currently supports foreignkey constraints only for "citus.shard_replication_factor = 1". HINT: Please change "citus.shard_replication_factor to 1". To learn more about using foreign keys with other replication factors, please contact us at https://citusdata.com/about/contact_us. DROP TABLE referencing_table; DROP TABLE referenced_table; -- test foreign constraint with correct conditions SET citus.shard_replication_factor TO 1; CREATE TABLE referenced_table(id int UNIQUE, test_column int, PRIMARY KEY(id, test_column)); CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY(ref_id) REFERENCES referenced_table(id)); SELECT create_distributed_table('referenced_table', 'id', 'hash'); create_distributed_table -------------------------- (1 row) SELECT create_distributed_table('referencing_table', 'ref_id', 'hash'); create_distributed_table -------------------------- (1 row) -- test inserts -- test insert to referencing table while there is NO corresponding value in referenced table INSERT INTO referencing_table VALUES(1, 1); ERROR: insert or update on table "referencing_table_1350008" violates foreign key constraint "referencing_table_ref_id_fkey_1350008" DETAIL: Key (ref_id)=(1) is not present in table "referenced_table_1350004". CONTEXT: while executing command on localhost:57637 -- test insert to referencing while there is corresponding value in referenced table INSERT INTO referenced_table VALUES(1, 1); INSERT INTO referencing_table VALUES(1, 1); -- test deletes -- test delete from referenced table while there is corresponding value in referencing table DELETE FROM referenced_table WHERE id = 1; ERROR: update or delete on table "referenced_table_1350004" violates foreign key constraint "referencing_table_ref_id_fkey_1350008" on table "referencing_table_1350008" DETAIL: Key (id)=(1) is still referenced from table "referencing_table_1350008". CONTEXT: while executing command on localhost:57637 -- test delete from referenced table while there is NO corresponding value in referencing table DELETE FROM referencing_table WHERE ref_id = 1; DELETE FROM referenced_table WHERE id = 1; -- drop table for next tests DROP TABLE referencing_table; DROP TABLE referenced_table; -- test foreign constraint options -- test ON DELETE CASCADE CREATE TABLE referenced_table(id int UNIQUE, test_column int, PRIMARY KEY(id, test_column)); CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY(ref_id) REFERENCES referenced_table(id) ON DELETE CASCADE); SELECT create_distributed_table('referenced_table', 'id', 'hash'); create_distributed_table -------------------------- (1 row) SELECT create_distributed_table('referencing_table', 'ref_id', 'hash'); create_distributed_table -------------------------- (1 row) INSERT INTO referenced_table VALUES(1, 1); INSERT INTO referencing_table VALUES(1, 1); DELETE FROM referenced_table WHERE id = 1; SELECT * FROM referencing_table; id | ref_id ----+-------- (0 rows) SELECT * FROM referenced_table; id | test_column ----+------------- (0 rows) DROP TABLE referencing_table; DROP TABLE referenced_table; -- test ON DELETE NO ACTION + DEFERABLE + INITIALLY DEFERRED CREATE TABLE referenced_table(id int UNIQUE, test_column int, PRIMARY KEY(id, test_column)); CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY(ref_id) REFERENCES referenced_table(id) ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED); SELECT create_distributed_table('referenced_table', 'id', 'hash'); create_distributed_table -------------------------- (1 row) SELECT create_distributed_table('referencing_table', 'ref_id', 'hash'); create_distributed_table -------------------------- (1 row) INSERT INTO referenced_table VALUES(1, 1); INSERT INTO referencing_table VALUES(1, 1); DELETE FROM referenced_table WHERE id = 1; ERROR: update or delete on table "referenced_table_1350020" violates foreign key constraint "referencing_table_ref_id_fkey_1350024" on table "referencing_table_1350024" DETAIL: Key (id)=(1) is still referenced from table "referencing_table_1350024". CONTEXT: while executing command on localhost:57637 BEGIN; DELETE FROM referenced_table WHERE id = 1; DELETE FROM referencing_table WHERE ref_id = 1; COMMIT; SELECT * FROM referencing_table; id | ref_id ----+-------- (0 rows) SELECT * FROM referenced_table; id | test_column ----+------------- (0 rows) DROP TABLE referencing_table; DROP TABLE referenced_table; -- test ON DELETE RESTRICT CREATE TABLE referenced_table(id int UNIQUE, test_column int, PRIMARY KEY(id, test_column)); CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY(ref_id) REFERENCES referenced_table(id) ON DELETE RESTRICT); SELECT create_distributed_table('referenced_table', 'id', 'hash'); create_distributed_table -------------------------- (1 row) SELECT create_distributed_table('referencing_table', 'ref_id', 'hash'); create_distributed_table -------------------------- (1 row) INSERT INTO referenced_table VALUES(1, 1); INSERT INTO referencing_table VALUES(1, 1); BEGIN; DELETE FROM referenced_table WHERE id = 1; ERROR: update or delete on table "referenced_table_1350028" violates foreign key constraint "referencing_table_ref_id_fkey_1350032" on table "referencing_table_1350032" DETAIL: Key (id)=(1) is still referenced from table "referencing_table_1350032". CONTEXT: while executing command on localhost:57637 DELETE FROM referencing_table WHERE ref_id = 1; ERROR: current transaction is aborted, commands ignored until end of transaction block COMMIT; SELECT * FROM referencing_table; id | ref_id ----+-------- 1 | 1 (1 row) SELECT * FROM referenced_table; id | test_column ----+------------- 1 | 1 (1 row) DROP TABLE referencing_table; DROP TABLE referenced_table; -- test ON UPDATE NO ACTION + DEFERABLE + INITIALLY DEFERRED CREATE TABLE referenced_table(id int UNIQUE, test_column int, PRIMARY KEY(id, test_column)); CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY(ref_id, id) REFERENCES referenced_table(id, test_column) ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED); SELECT create_distributed_table('referenced_table', 'id', 'hash'); create_distributed_table -------------------------- (1 row) SELECT create_distributed_table('referencing_table', 'ref_id', 'hash'); create_distributed_table -------------------------- (1 row) INSERT INTO referenced_table VALUES(1, 1); INSERT INTO referencing_table VALUES(1, 1); UPDATE referenced_table SET test_column = 10 WHERE id = 1; ERROR: update or delete on table "referenced_table_1350036" violates foreign key constraint "referencing_table_ref_id_fkey_1350040" on table "referencing_table_1350040" DETAIL: Key (id, test_column)=(1, 1) is still referenced from table "referencing_table_1350040". CONTEXT: while executing command on localhost:57637 BEGIN; UPDATE referenced_table SET test_column = 10 WHERE id = 1; UPDATE referencing_table SET id = 10 WHERE ref_id = 1; COMMIT; SELECT * FROM referencing_table; id | ref_id ----+-------- 10 | 1 (1 row) SELECT * FROM referenced_table; id | test_column ----+------------- 1 | 10 (1 row) DROP TABLE referencing_table; DROP TABLE referenced_table; -- test ON UPDATE RESTRICT CREATE TABLE referenced_table(id int UNIQUE, test_column int, PRIMARY KEY(id, test_column)); CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY(ref_id, id) REFERENCES referenced_table(id, test_column) ON UPDATE RESTRICT); SELECT create_distributed_table('referenced_table', 'id', 'hash'); create_distributed_table -------------------------- (1 row) SELECT create_distributed_table('referencing_table', 'ref_id', 'hash'); create_distributed_table -------------------------- (1 row) INSERT INTO referenced_table VALUES(1, 1); INSERT INTO referencing_table VALUES(1, 1); BEGIN; UPDATE referenced_table SET test_column = 20 WHERE id = 1; ERROR: update or delete on table "referenced_table_1350044" violates foreign key constraint "referencing_table_ref_id_fkey_1350048" on table "referencing_table_1350048" DETAIL: Key (id, test_column)=(1, 1) is still referenced from table "referencing_table_1350048". CONTEXT: while executing command on localhost:57637 UPDATE referencing_table SET id = 20 WHERE ref_id = 1; ERROR: current transaction is aborted, commands ignored until end of transaction block COMMIT; SELECT * FROM referencing_table; id | ref_id ----+-------- 1 | 1 (1 row) SELECT * FROM referenced_table; id | test_column ----+------------- 1 | 1 (1 row) DROP TABLE referencing_table; DROP TABLE referenced_table; -- test MATCH SIMPLE CREATE TABLE referenced_table(id int UNIQUE, test_column int, PRIMARY KEY(id, test_column)); CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY(ref_id, id) REFERENCES referenced_table(id, test_column) MATCH SIMPLE); SELECT create_distributed_table('referenced_table', 'id', 'hash'); create_distributed_table -------------------------- (1 row) SELECT create_distributed_table('referencing_table', 'ref_id', 'hash'); create_distributed_table -------------------------- (1 row) INSERT INTO referencing_table VALUES(null, 2); SELECT * FROM referencing_table; id | ref_id ----+-------- | 2 (1 row) DELETE FROM referencing_table WHERE ref_id = 2; DROP TABLE referencing_table; DROP TABLE referenced_table; -- test MATCH FULL CREATE TABLE referenced_table(id int UNIQUE, test_column int, PRIMARY KEY(id, test_column)); CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY(ref_id, id) REFERENCES referenced_table(id, test_column) MATCH FULL); SELECT create_distributed_table('referenced_table', 'id', 'hash'); create_distributed_table -------------------------- (1 row) SELECT create_distributed_table('referencing_table', 'ref_id', 'hash'); create_distributed_table -------------------------- (1 row) INSERT INTO referencing_table VALUES(null, 2); ERROR: insert or update on table "referencing_table_1350067" violates foreign key constraint "referencing_table_ref_id_fkey_1350067" DETAIL: MATCH FULL does not allow mixing of null and nonnull key values. CONTEXT: while executing command on localhost:57638 SELECT * FROM referencing_table; id | ref_id ----+-------- (0 rows) DROP TABLE referencing_table; DROP TABLE referenced_table;