citus/src/test/regress/expected/multi_foreign_key.out

943 lines
46 KiB
Plaintext

--
-- MULTI_FOREIGN_KEY
--
SET citus.next_shard_id TO 1350000;
-- set shard_count to 4 for faster tests, because we create/drop lots of shards in this test.
SET citus.shard_count TO 32;
-- 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 when distribution key is included in the foreign key constraint
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 when distribution key is included in the foreign key constraint
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 when distribution key included in the foreign constraint.
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 when distribution key included in the foreign constraint.
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 when distribution key included in the foreign constraint.
DROP TABLE referencing_table;
-- self referencing table with replication factor > 1
CREATE TABLE self_referencing_table(id int, ref_id int, PRIMARY KEY (id, ref_id), FOREIGN KEY(id,ref_id) REFERENCES self_referencing_table(id, ref_id));
SELECT create_distributed_table('self_referencing_table', 'id', 'hash');
ERROR: cannot create foreign key constraint
DETAIL: Citus currently supports foreign key 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 self_referencing_table;
CREATE TABLE self_referencing_table(id int, ref_id int, PRIMARY KEY (id, ref_id));
SELECT create_distributed_table('self_referencing_table', 'id', 'hash');
create_distributed_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE self_referencing_table ADD CONSTRAINT fkey FOREIGN KEY(id,ref_id) REFERENCES self_referencing_table(id, ref_id);
ERROR: cannot create foreign key constraint
DETAIL: Citus currently supports foreign key 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 self_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 since relations are not colocated or not referencing a reference table
DETAIL: A distributed table can only have foreign keys if it is referencing another colocated hash distributed table or a reference table
DROP TABLE referencing_table;
SET citus.shard_count TO 32;
-- 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: Foreign keys are supported in two cases, either in between two colocated tables including partition column in the same ordinal in the both tables or from distributed to reference tables
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: Foreign keys are supported in two cases, either in between two colocated tables including partition column in the same ordinal in the both tables or from distributed to reference tables
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 currently supports foreign key 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 creation on append and range distributed tables
-- foreign keys are supported either in between distributed tables including the
-- distribution column or from distributed tables to reference tables.
SET citus.shard_replication_factor TO 1;
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)
CREATE TABLE referencing_table(id int, ref_id int, FOREIGN KEY (id) REFERENCES referenced_table(id));
SELECT create_distributed_table('referencing_table', 'id', 'append');
ERROR: cannot create foreign key constraint since relations are not colocated or not referencing a reference table
DETAIL: A distributed table can only have foreign keys if it is referencing another colocated hash distributed table or a reference table
DROP TABLE referencing_table;
DROP TABLE referenced_table;
CREATE TABLE referenced_table(id int UNIQUE, test_column int, PRIMARY KEY(id, test_column));
SELECT create_distributed_table('referenced_table', 'id', 'range');
create_distributed_table
---------------------------------------------------------------------
(1 row)
CREATE TABLE referencing_table(id int, ref_id int,FOREIGN KEY (id) REFERENCES referenced_table(id));
SELECT create_distributed_table('referencing_table', 'id', 'range');
ERROR: cannot create foreign key constraint since relations are not colocated or not referencing a reference table
DETAIL: A distributed table can only have foreign keys if it is referencing another colocated hash distributed table or a reference table
DROP TABLE referencing_table;
DROP TABLE referenced_table;
-- test foreign constraint with correct conditions
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_xxxxxxx" violates foreign key constraint "referencing_table_ref_id_fkey_1350129"
DETAIL: Key (ref_id)=(X) is not present in table "referenced_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
-- 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_xxxxxxx" violates foreign key constraint "referencing_table_ref_id_fkey_1350129" on table "referencing_table_xxxxxxx"
DETAIL: Key (id)=(X) is still referenced from table "referencing_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
-- 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;
-- test cascading truncate
INSERT INTO referenced_table VALUES(2, 2);
INSERT INTO referencing_table VALUES(2, 2);
TRUNCATE referenced_table CASCADE;
NOTICE: truncate cascades to table "referencing_table"
SELECT * FROM referencing_table;
id | ref_id
---------------------------------------------------------------------
(0 rows)
-- 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)
-- single shard cascading delete
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)
-- multi shard cascading delete
INSERT INTO referenced_table VALUES(2, 2);
INSERT INTO referencing_table VALUES(2, 2);
DELETE FROM referenced_table;
SELECT * FROM referencing_table;
id | ref_id
---------------------------------------------------------------------
(0 rows)
-- multi shard cascading delete with alter table
INSERT INTO referenced_table VALUES(3, 3);
INSERT INTO referencing_table VALUES(3, 3);
BEGIN;
ALTER TABLE referencing_table ADD COLUMN x int DEFAULT 0;
DELETE FROM referenced_table;
COMMIT;
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_xxxxxxx" violates foreign key constraint "referencing_table_ref_id_fkey_1350257" on table "referencing_table_xxxxxxx"
DETAIL: Key (id)=(X) is still referenced from table "referencing_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
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_xxxxxxx" violates foreign key constraint "referencing_table_ref_id_fkey_1350321" on table "referencing_table_xxxxxxx"
DETAIL: Key (id)=(X) is still referenced from table "referencing_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
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_xxxxxxx" violates foreign key constraint "referencing_table_ref_id_fkey_1350385" on table "referencing_table_xxxxxxx"
DETAIL: Key (id, test_column)=(1, 1) is still referenced from table "referencing_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
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_xxxxxxx" violates foreign key constraint "referencing_table_ref_id_fkey_1350449" on table "referencing_table_xxxxxxx"
DETAIL: Key (id, test_column)=(1, 1) is still referenced from table "referencing_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
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_xxxxxxx" violates foreign key constraint "referencing_table_ref_id_fkey_1350600"
DETAIL: MATCH FULL does not allow mixing of null and nonnull key values.
CONTEXT: while executing command on localhost:xxxxx
SELECT * FROM referencing_table;
id | ref_id
---------------------------------------------------------------------
(0 rows)
DROP TABLE referencing_table;
DROP TABLE referenced_table;
-- Similar tests, but this time we push foreign key constraints created by ALTER TABLE queries
-- create tables
SET citus.shard_count TO 4;
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)
CREATE TABLE referencing_table(id int, ref_id int);
SELECT create_distributed_table('referencing_table', 'ref_id', 'hash');
create_distributed_table
---------------------------------------------------------------------
(1 row)
-- verify that we skip foreign key validation when propagation is turned off
-- not skipping validation would result in a distributed query, which emits debug messages
BEGIN;
SET LOCAL citus.enable_ddl_propagation TO off;
SET LOCAL client_min_messages TO DEBUG1;
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY (ref_id) REFERENCES referenced_table (id);
ABORT;
-- test foreign constraint creation
-- test foreign constraint creation with not supported parameters
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id) REFERENCES referenced_table(id) ON DELETE SET NULL;
ERROR: cannot create foreign key constraint
DETAIL: SET NULL or SET DEFAULT is not supported in ON DELETE operation when distribution key is included in the foreign key constraint
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id) REFERENCES referenced_table(id) ON DELETE SET DEFAULT;
ERROR: cannot create foreign key constraint
DETAIL: SET NULL or SET DEFAULT is not supported in ON DELETE operation when distribution key is included in the foreign key constraint
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id) REFERENCES referenced_table(id) ON UPDATE SET NULL;
ERROR: cannot create foreign key constraint
DETAIL: SET NULL, SET DEFAULT or CASCADE is not supported in ON UPDATE operation when distribution key included in the foreign constraint.
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id) REFERENCES referenced_table(id) ON UPDATE SET DEFAULT;
ERROR: cannot create foreign key constraint
DETAIL: SET NULL, SET DEFAULT or CASCADE is not supported in ON UPDATE operation when distribution key included in the foreign constraint.
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id) REFERENCES referenced_table(id) ON UPDATE CASCADE;
ERROR: cannot create foreign key constraint
DETAIL: SET NULL, SET DEFAULT or CASCADE is not supported in ON UPDATE operation when distribution key included in the foreign constraint.
-- test foreign constraint creation while adding the column
ALTER TABLE referencing_table ADD COLUMN referencing_col int REFERENCES referenced_table(id) ON UPDATE CASCADE;;
ERROR: cannot create foreign key constraint
DETAIL: Foreign keys are supported in two cases, either in between two colocated tables including partition column in the same ordinal in the both tables or from distributed to reference tables
-- test foreign constraint creation with multiple subcommands
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id) REFERENCES referenced_table(id),
ADD CONSTRAINT test_constraint FOREIGN KEY(id) REFERENCES referenced_table(test_column);
ERROR: cannot execute ADD CONSTRAINT command with other subcommands
HINT: You can issue each subcommand separately
-- test foreign constraint creation without giving explicit name
ALTER TABLE referencing_table ADD FOREIGN KEY(ref_id) REFERENCES referenced_table(id);
ERROR: cannot create constraint without a name on a distributed table
-- test foreign constraint creation on NOT co-located tables
DROP TABLE referencing_table;
DROP TABLE referenced_table;
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)
CREATE TABLE referencing_table(id int, ref_id int);
SELECT create_distributed_table('referencing_table', 'ref_id', 'hash', colocate_with => 'none');
create_distributed_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id) REFERENCES referenced_table(id);
ERROR: cannot create foreign key constraint since relations are not colocated or not referencing a reference table
DETAIL: A distributed table can only have foreign keys if it is referencing another colocated hash distributed table or a reference table
-- create co-located tables
DROP TABLE referencing_table;
DROP TABLE referenced_table;
CREATE TABLE referenced_table(id int UNIQUE, test_column int, PRIMARY KEY(id, test_column));
CREATE TABLE referencing_table(id int, ref_id int);
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)
-- columns for the referenced table is empty
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id) REFERENCES referenced_table ON DELETE CASCADE;
ERROR: number of referencing and referenced columns for foreign key disagree
-- test foreign constraint creation on non-partition columns
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(id) REFERENCES referenced_table(id);
ERROR: cannot create foreign key constraint
DETAIL: Foreign keys are supported in two cases, either in between two colocated tables including partition column in the same ordinal in the both tables or from distributed to reference tables
-- test foreign constraint creation while column list are in incorrect order
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(id, ref_id) REFERENCES referenced_table(id, test_column);
ERROR: cannot create foreign key constraint
DETAIL: Foreign keys are supported in two cases, either in between two colocated tables including partition column in the same ordinal in the both tables or from distributed to reference tables
-- test foreign constraint creation while column list are not in same length
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id) REFERENCES referenced_table(id, test_column);
ERROR: number of referencing and referenced columns for foreign key disagree
-- test foreign constraint creation while existing tables does not satisfy the constraint
INSERT INTO referencing_table VALUES(1, 1);
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id) REFERENCES referenced_table(id);
ERROR: insert or update on table "referencing_table_xxxxxxx" violates foreign key constraint "test_constraint_1350628"
DETAIL: Key (ref_id)=(X) is not present in table "referenced_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
-- test foreign constraint with correct conditions
DELETE FROM referencing_table WHERE ref_id = 1;
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id) REFERENCES referenced_table(id);
-- 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_xxxxxxx" violates foreign key constraint "test_constraint_1350628"
DETAIL: Key (ref_id)=(X) is not present in table "referenced_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
-- 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_xxxxxxx" violates foreign key constraint "test_constraint_1350628" on table "referencing_table_xxxxxxx"
DETAIL: Key (id)=(X) is still referenced from table "referencing_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
-- 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;
-- test DROP CONSTRAINT
ALTER TABLE referencing_table DROP CONSTRAINT test_constraint;
-- test foreign constraint options
-- test ON DELETE CASCADE
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id) REFERENCES referenced_table(id) ON DELETE CASCADE;
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)
ALTER TABLE referencing_table DROP CONSTRAINT test_constraint;
-- test ON DELETE NO ACTION + DEFERABLE + INITIALLY DEFERRED
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id) REFERENCES referenced_table(id) ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED;
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_xxxxxxx" violates foreign key constraint "test_constraint_1350628" on table "referencing_table_xxxxxxx"
DETAIL: Key (id)=(X) is still referenced from table "referencing_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
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)
ALTER TABLE referencing_table DROP CONSTRAINT test_constraint;
-- test ON DELETE RESTRICT
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id) REFERENCES referenced_table(id) ON DELETE RESTRICT;
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_xxxxxxx" violates foreign key constraint "test_constraint_1350628" on table "referencing_table_xxxxxxx"
DETAIL: Key (id)=(X) is still referenced from table "referencing_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
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)
ALTER TABLE referencing_table DROP CONSTRAINT test_constraint;
-- test ON UPDATE NO ACTION + DEFERABLE + INITIALLY DEFERRED
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id, id) REFERENCES referenced_table(id, test_column) ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED;
UPDATE referenced_table SET test_column = 10 WHERE id = 1;
ERROR: update or delete on table "referenced_table_xxxxxxx" violates foreign key constraint "test_constraint_1350628" on table "referencing_table_xxxxxxx"
DETAIL: Key (id, test_column)=(1, 1) is still referenced from table "referencing_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
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)
ALTER TABLE referencing_table DROP CONSTRAINT test_constraint;
-- test ON UPDATE RESTRICT
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id, id) REFERENCES referenced_table(id, test_column) ON UPDATE RESTRICT;
BEGIN;
UPDATE referenced_table SET test_column = 20 WHERE id = 1;
ERROR: update or delete on table "referenced_table_xxxxxxx" violates foreign key constraint "test_constraint_1350628" on table "referencing_table_xxxxxxx"
DETAIL: Key (id, test_column)=(1, 10) is still referenced from table "referencing_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
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
---------------------------------------------------------------------
10 | 1
(1 row)
SELECT * FROM referenced_table;
id | test_column
---------------------------------------------------------------------
1 | 10
(1 row)
ALTER TABLE referencing_table DROP CONSTRAINT test_constraint;
-- test MATCH SIMPLE
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id, id) REFERENCES referenced_table(id, test_column) MATCH SIMPLE;
INSERT INTO referencing_table VALUES(null, 2);
SELECT * FROM referencing_table ORDER BY 1,2;
id | ref_id
---------------------------------------------------------------------
10 | 1
| 2
(2 rows)
DELETE FROM referencing_table WHERE ref_id = 2;
ALTER TABLE referencing_table DROP CONSTRAINT test_constraint;
-- test MATCH FULL
ALTER TABLE referencing_table ADD CONSTRAINT test_constraint FOREIGN KEY(ref_id, id) REFERENCES referenced_table(id, test_column) MATCH FULL;
INSERT INTO referencing_table VALUES(null, 2);
ERROR: insert or update on table "referencing_table_xxxxxxx" violates foreign key constraint "test_constraint_1350631"
DETAIL: MATCH FULL does not allow mixing of null and nonnull key values.
CONTEXT: while executing command on localhost:xxxxx
SELECT * FROM referencing_table;
id | ref_id
---------------------------------------------------------------------
10 | 1
(1 row)
ALTER TABLE referencing_table DROP CONSTRAINT test_constraint;
-- we no longer need those tables
DROP TABLE referencing_table;
DROP TABLE referenced_table;
-- test cyclical foreign keys
CREATE TABLE cyclic_reference_table1(id int, table2_id int, PRIMARY KEY(id, table2_id));
CREATE TABLE cyclic_reference_table2(id int, table1_id int, PRIMARY KEY(id, table1_id));
SELECT create_distributed_table('cyclic_reference_table1', 'id', 'hash');
create_distributed_table
---------------------------------------------------------------------
(1 row)
SELECT create_distributed_table('cyclic_reference_table2', 'table1_id', 'hash');
create_distributed_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE cyclic_reference_table1 ADD CONSTRAINT cyclic_constraint1 FOREIGN KEY(id, table2_id) REFERENCES cyclic_reference_table2(table1_id, id) DEFERRABLE INITIALLY DEFERRED;
ALTER TABLE cyclic_reference_table2 ADD CONSTRAINT cyclic_constraint2 FOREIGN KEY(id, table1_id) REFERENCES cyclic_reference_table1(table2_id, id) DEFERRABLE INITIALLY DEFERRED;
-- test insertion to a table which has cyclic foreign constraints, we expect that to fail
INSERT INTO cyclic_reference_table1 VALUES(1, 1);
ERROR: insert or update on table "cyclic_reference_table1_1350632" violates foreign key constraint "cyclic_constraint1_1350632"
DETAIL: Key (id, table2_id)=(1, 1) is not present in table "cyclic_reference_table2_1350636".
CONTEXT: while executing command on localhost:xxxxx
-- proper insertion to table with cyclic dependency
BEGIN;
INSERT INTO cyclic_reference_table1 VALUES(1, 1);
INSERT INTO cyclic_reference_table2 VALUES(1, 1);
COMMIT;
-- verify that rows are actually inserted
SELECT * FROM cyclic_reference_table1;
id | table2_id
---------------------------------------------------------------------
1 | 1
(1 row)
SELECT * FROM cyclic_reference_table2;
id | table1_id
---------------------------------------------------------------------
1 | 1
(1 row)
-- test dropping cyclic referenced tables
-- we expect those two queries to fail
DROP TABLE cyclic_reference_table1;
ERROR: cannot drop table cyclic_reference_table1 because other objects depend on it
DETAIL: constraint cyclic_constraint2 on table cyclic_reference_table2 depends on table cyclic_reference_table1
HINT: Use DROP ... CASCADE to drop the dependent objects too.
DROP TABLE cyclic_reference_table2;
ERROR: cannot drop table cyclic_reference_table2 because other objects depend on it
DETAIL: constraint cyclic_constraint1 on table cyclic_reference_table1 depends on table cyclic_reference_table2
HINT: Use DROP ... CASCADE to drop the dependent objects too.
-- proper way of DROP with CASCADE option
DROP TABLE cyclic_reference_table1 CASCADE;
NOTICE: drop cascades to constraint cyclic_constraint2 on table cyclic_reference_table2
DROP TABLE cyclic_reference_table2 CASCADE;
-- test creation of foreign keys in a transaction
CREATE TABLE transaction_referenced_table(id int PRIMARY KEY);
CREATE TABLE transaction_referencing_table(id int, ref_id int);
BEGIN;
ALTER TABLE transaction_referencing_table ADD CONSTRAINT transaction_fk_constraint FOREIGN KEY(ref_id) REFERENCES transaction_referenced_table(id);
COMMIT;
-- test insertion to referencing table, we expect that to fail
INSERT INTO transaction_referencing_table VALUES(1, 1);
ERROR: insert or update on table "transaction_referencing_table" violates foreign key constraint "transaction_fk_constraint"
DETAIL: Key (ref_id)=(X) is not present in table "transaction_referenced_table".
-- proper insertion to both referenced and referencing tables
INSERT INTO transaction_referenced_table VALUES(1);
INSERT INTO transaction_referencing_table VALUES(1, 1);
-- verify that rows are actually inserted
SELECT * FROM transaction_referenced_table;
id
---------------------------------------------------------------------
1
(1 row)
SELECT * FROM transaction_referencing_table;
id | ref_id
---------------------------------------------------------------------
1 | 1
(1 row)
-- we no longer need those tables
DROP TABLE transaction_referencing_table;
DROP TABLE transaction_referenced_table;
-- test self referencing foreign key
CREATE TABLE self_referencing_table1(
id int,
other_column int,
other_column_ref int,
PRIMARY KEY(id, other_column),
FOREIGN KEY(id, other_column_ref) REFERENCES self_referencing_table1(id, other_column)
);
SELECT create_distributed_table('self_referencing_table1', 'id', 'hash');
create_distributed_table
---------------------------------------------------------------------
(1 row)
-- test insertion to self referencing table
INSERT INTO self_referencing_table1 VALUES(1, 1, 1);
-- we expect this query to fail
INSERT INTO self_referencing_table1 VALUES(1, 2, 3);
ERROR: insert or update on table "self_referencing_table1_1350640" violates foreign key constraint "self_referencing_table1_id_fkey_1350640"
DETAIL: Key (id, other_column_ref)=(1, 3) is not present in table "self_referencing_table1_1350640".
CONTEXT: while executing command on localhost:xxxxx
-- verify that rows are actually inserted
SELECT * FROM self_referencing_table1;
id | other_column | other_column_ref
---------------------------------------------------------------------
1 | 1 | 1
(1 row)
-- we no longer need those tables
DROP TABLE self_referencing_table1;
-- test self referencing foreign key with ALTER TABLE
CREATE TABLE self_referencing_table2(id int, other_column int, other_column_ref int, PRIMARY KEY(id, other_column));
SELECT create_distributed_table('self_referencing_table2', 'id', 'hash');
create_distributed_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE self_referencing_table2 ADD CONSTRAINT self_referencing_fk_constraint FOREIGN KEY(id, other_column_ref) REFERENCES self_referencing_table2(id, other_column);
-- test insertion to self referencing table
INSERT INTO self_referencing_table2 VALUES(1, 1, 1);
-- we expect this query to fail
INSERT INTO self_referencing_table2 VALUES(1, 2, 3);
ERROR: insert or update on table "self_referencing_table2_1350644" violates foreign key constraint "self_referencing_fk_constraint_1350644"
DETAIL: Key (id, other_column_ref)=(1, 3) is not present in table "self_referencing_table2_1350644".
CONTEXT: while executing command on localhost:xxxxx
-- verify that rows are actually inserted
SELECT * FROM self_referencing_table2;
id | other_column | other_column_ref
---------------------------------------------------------------------
1 | 1 | 1
(1 row)
-- we no longer need those tables
DROP TABLE self_referencing_table2;
-- test reference tables
-- test foreign key creation on CREATE TABLE from reference table
CREATE TABLE referenced_by_reference_table(id int PRIMARY KEY, other_column int);
SELECT create_distributed_table('referenced_by_reference_table', 'id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
CREATE TABLE reference_table(id int, referencing_column int REFERENCES referenced_by_reference_table(id));
SELECT create_reference_table('reference_table');
ERROR: cannot create foreign key constraint since foreign keys from reference tables to distributed tables are not supported
DETAIL: A reference table can only have reference keys to other reference tables
-- test foreign key creation on CREATE TABLE from + to reference table
DROP TABLE reference_table;
CREATE TABLE reference_table(id int PRIMARY KEY, referencing_column int);
SELECT create_reference_table('reference_table');
create_reference_table
---------------------------------------------------------------------
(1 row)
CREATE TABLE reference_table_second(id int, referencing_column int REFERENCES reference_table(id));
SELECT create_reference_table('reference_table_second');
create_reference_table
---------------------------------------------------------------------
(1 row)
-- test foreign key creation on CREATE TABLE from reference table to local table
CREATE TABLE referenced_local_table(id int PRIMARY KEY, other_column int);
DROP TABLE reference_table CASCADE;
NOTICE: drop cascades to constraint reference_table_second_referencing_column_fkey on table reference_table_second
CREATE TABLE reference_table(id int, referencing_column int REFERENCES referenced_local_table(id));
SELECT create_reference_table('reference_table');
ERROR: referenced table "referenced_local_table" must be a distributed table or a reference table
DETAIL: To enforce foreign keys, the referencing and referenced rows need to be stored on the same node.
HINT: You could use SELECT create_reference_table('referenced_local_table') to replicate the referenced table to all nodes
-- test foreign key creation on CREATE TABLE on self referencing reference table
CREATE TABLE self_referencing_reference_table(
id int,
other_column int,
other_column_ref int,
PRIMARY KEY(id, other_column),
FOREIGN KEY(id, other_column_ref) REFERENCES self_referencing_reference_table(id, other_column)
);
SELECT create_reference_table('self_referencing_reference_table');
create_reference_table
---------------------------------------------------------------------
(1 row)
-- test foreign key creation on ALTER TABLE from reference table
DROP TABLE reference_table;
CREATE TABLE reference_table(id int PRIMARY KEY, referencing_column int);
SELECT create_reference_table('reference_table');
create_reference_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE reference_table ADD CONSTRAINT fk FOREIGN KEY(referencing_column) REFERENCES referenced_by_reference_table(id);
ERROR: cannot create foreign key constraint since foreign keys from reference tables to distributed tables are not supported
DETAIL: A reference table can only have reference keys to other reference tables
-- test foreign key creation on ALTER TABLE to reference table
CREATE TABLE references_to_reference_table(id int, referencing_column int);
SELECT create_distributed_table('references_to_reference_table', 'referencing_column');
create_distributed_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE references_to_reference_table ADD CONSTRAINT fk FOREIGN KEY(referencing_column) REFERENCES reference_table(id);
-- test foreign key creation on ALTER TABLE from + to reference table
DROP TABLE reference_table_second;
CREATE TABLE reference_table_second(id int, referencing_column int);
SELECT create_reference_table('reference_table_second');
create_reference_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE reference_table_second ADD CONSTRAINT fk FOREIGN KEY(referencing_column) REFERENCES reference_table(id);
-- test foreign key creation on ALTER TABLE from reference table to local table
DROP TABLE reference_table CASCADE;
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to constraint fk on table references_to_reference_table
drop cascades to constraint fk on table reference_table_second
CREATE TABLE reference_table(id int PRIMARY KEY, referencing_column int);
SELECT create_reference_table('reference_table');
create_reference_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE reference_table ADD CONSTRAINT fk FOREIGN KEY(referencing_column) REFERENCES referenced_local_table(id);
ERROR: referenced table "referenced_local_table" must be a distributed table or a reference table
DETAIL: To enforce foreign keys, the referencing and referenced rows need to be stored on the same node.
HINT: You could use SELECT create_reference_table('referenced_local_table') to replicate the referenced table to all nodes
-- test foreign key creation on ALTER TABLE on self referencing reference table
DROP TABLE self_referencing_reference_table;
CREATE TABLE self_referencing_reference_table(
id int,
other_column int,
other_column_ref int,
PRIMARY KEY(id, other_column)
);
SELECT create_reference_table('self_referencing_reference_table');
create_reference_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE self_referencing_reference_table ADD CONSTRAINT fk FOREIGN KEY(id, other_column_ref) REFERENCES self_referencing_reference_table(id, other_column);
-- we no longer need those tables
DROP TABLE referenced_by_reference_table, references_to_reference_table, reference_table, reference_table_second, referenced_local_table, self_referencing_reference_table;