--
-- 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_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_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_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 citus.skip_constraint_validation is set to ON
-- not skipping validation would result in a distributed query, which emits debug messages
BEGIN;
SET LOCAL citus.skip_constraint_validation TO on;
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);
-- 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_other_column_ref_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 and local tables to distributed tables are not supported
DETAIL:  Reference tables and local tables can only have foreign keys to reference tables and local 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
NOTICE:  drop cascades to constraint reference_table_second_referencing_column_fkey_1350653 on table public.reference_table_second_1350653
CONTEXT:  SQL statement "SELECT citus_drop_all_shards(v_obj.objid, v_obj.schema_name, v_obj.object_name, drop_shards_metadata_only := false)"
PL/pgSQL function citus_drop_trigger() line XX at PERFORM
CREATE TABLE reference_table(id int, referencing_column int REFERENCES referenced_local_table(id));
SELECT create_reference_table('reference_table');
 create_reference_table
---------------------------------------------------------------------

(1 row)

-- 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;
NOTICE:  removing table public.referenced_local_table from metadata as it is not connected to any reference tables via foreign keys
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 and local tables to distributed tables are not supported
DETAIL:  Reference tables and local tables can only have foreign keys to reference tables and local 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
NOTICE:  drop cascades to constraint fk_1350662 on table public.reference_table_second_1350662
CONTEXT:  SQL statement "SELECT citus_drop_all_shards(v_obj.objid, v_obj.schema_name, v_obj.object_name, drop_shards_metadata_only := false)"
PL/pgSQL function citus_drop_trigger() line XX at PERFORM
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);
-- 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);
-- make sure that if fkey is dropped
-- Citus can see up-to date fkey graph
CREATE TABLE dropfkeytest1 (x int unique);
CREATE TABLE dropfkeytest2 (x int8);
ALTER TABLE dropfkeytest2 ADD CONSTRAINT fkey1 FOREIGN KEY (x) REFERENCES dropfkeytest1(x);
SELECT create_distributed_table ('dropfkeytest1', 'x');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- this should error out
SELECT create_distributed_table ('dropfkeytest2', 'x', colocate_with:='none');
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
ALTER TABLE dropfkeytest2 DROP CONSTRAINT fkey1;
-- this should work
SELECT create_distributed_table ('dropfkeytest2', 'x', colocate_with:='none');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

DROP TABLE dropfkeytest1, dropfkeytest2 CASCADE;
-- make sure that if a column that is in a fkey is dropped
-- Citus can see up-to date fkey graph
CREATE TABLE dropfkeytest1 (x int unique);
CREATE TABLE dropfkeytest2 (x int8, y int8);
ALTER TABLE dropfkeytest2 ADD CONSTRAINT fkey1 FOREIGN KEY (y) REFERENCES dropfkeytest1(x);
SELECT create_distributed_table ('dropfkeytest1', 'x');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- this should error out
SELECT create_distributed_table ('dropfkeytest2', 'y', colocate_with:='none');
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
ALTER TABLE dropfkeytest2 DROP COLUMN y;
-- this should work
SELECT create_distributed_table ('dropfkeytest2', 'x', colocate_with:='none');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

DROP TABLE dropfkeytest1, dropfkeytest2 CASCADE;
-- make sure that even if a column that is in a multi-column index is dropped
-- Citus can see up-to date fkey graph
CREATE TABLE dropfkeytest1 (x int, y int);
CREATE UNIQUE INDEX indd ON dropfkeytest1(x, y);
CREATE TABLE dropfkeytest2 (x int8, y int8);
ALTER TABLE dropfkeytest2 ADD CONSTRAINT fkey1 FOREIGN KEY (x, y) REFERENCES dropfkeytest1(x, y);
SELECT create_distributed_table ('dropfkeytest1', 'x');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- this should error out
SELECT create_distributed_table ('dropfkeytest2', 'y', colocate_with:='none');
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
ALTER TABLE dropfkeytest2 DROP COLUMN y CASCADE;
-- this should work
SELECT create_distributed_table ('dropfkeytest2', 'x', colocate_with:='none');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

DROP TABLE dropfkeytest1, dropfkeytest2 CASCADE;
-- make sure that even if a column that is in a multi-column fkey is dropped
-- Citus can see up-to date fkey graph
CREATE TABLE dropfkeytest1 (x int, y int);
CREATE UNIQUE INDEX indd ON dropfkeytest1(x, y);
CREATE TABLE dropfkeytest2 (x int8, y int8);
ALTER TABLE dropfkeytest2 ADD CONSTRAINT fkey1 FOREIGN KEY (x, y) REFERENCES dropfkeytest1(x, y);
SELECT create_distributed_table ('dropfkeytest1', 'x');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- this should error out
SELECT create_distributed_table ('dropfkeytest2', 'y', colocate_with:='none');
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
ALTER TABLE dropfkeytest1 DROP COLUMN y CASCADE;
NOTICE:  drop cascades to constraint fkey1 on table dropfkeytest2
-- this should work
SELECT create_distributed_table ('dropfkeytest2', 'x', colocate_with:='none');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

DROP TABLE dropfkeytest1, dropfkeytest2 CASCADE;
-- make sure that even if an index which fkey relies on is dropped
-- Citus can see up-to date fkey graph
-- also irrelevant index drops doesn't affect this
CREATE TABLE dropfkeytest1 (x int);
CREATE UNIQUE INDEX i1 ON dropfkeytest1(x);
CREATE UNIQUE INDEX unrelated_idx ON dropfkeytest1(x);
CREATE TABLE dropfkeytest2 (x int8, y int8);
ALTER TABLE dropfkeytest2 ADD CONSTRAINT fkey1 FOREIGN KEY (y) REFERENCES dropfkeytest1(x);
SELECT create_distributed_table ('dropfkeytest1', 'x');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- this should error out
SELECT create_distributed_table ('dropfkeytest2', 'y', colocate_with:='none');
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 INDEX unrelated_idx CASCADE;
-- should still error out since we didn't drop the index that foreign key depends on
SELECT create_distributed_table ('dropfkeytest2', 'x', colocate_with:='none');
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 INDEX i1 CASCADE;
NOTICE:  drop cascades to constraint fkey1 on table dropfkeytest2
-- this should work
SELECT create_distributed_table ('dropfkeytest2', 'x', colocate_with:='none');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

DROP TABLE dropfkeytest1, dropfkeytest2 CASCADE;
-- make sure that even if a uniqueness constraint which fkey depends on is dropped
-- Citus can see up-to date fkey graph
CREATE TABLE dropfkeytest1 (x int unique);
CREATE TABLE dropfkeytest2 (x int8, y int8);
ALTER TABLE dropfkeytest2 ADD CONSTRAINT fkey1 FOREIGN KEY (y) REFERENCES dropfkeytest1(x);
SELECT create_distributed_table ('dropfkeytest1', 'x');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- this should error out
SELECT create_distributed_table ('dropfkeytest2', 'y', colocate_with:='none');
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
ALTER TABLE dropfkeytest1 DROP CONSTRAINT dropfkeytest1_x_key CASCADE;
NOTICE:  drop cascades to constraint fkey1 on table dropfkeytest2
-- this should work
SELECT create_distributed_table ('dropfkeytest2', 'x', colocate_with:='none');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

DROP TABLE dropfkeytest1, dropfkeytest2 CASCADE;
-- make sure that even if a primary key which fkey depends on is dropped
-- Citus can see up-to date fkey graph
CREATE TABLE dropfkeytest1 (x int primary key);
CREATE TABLE dropfkeytest2 (x int8, y int8);
ALTER TABLE dropfkeytest2 ADD CONSTRAINT fkey1 FOREIGN KEY (y) REFERENCES dropfkeytest1(x);
SELECT create_distributed_table ('dropfkeytest1', 'x');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- this should error out
SELECT create_distributed_table ('dropfkeytest2', 'y', colocate_with:='none');
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
ALTER TABLE dropfkeytest1 DROP CONSTRAINT dropfkeytest1_pkey CASCADE;
NOTICE:  drop cascades to constraint fkey1 on table dropfkeytest2
-- this should work
SELECT create_distributed_table ('dropfkeytest2', 'x', colocate_with:='none');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

DROP TABLE dropfkeytest1, dropfkeytest2 CASCADE;
-- make sure that even if a schema which fkey depends on is dropped
-- Citus can see up-to date fkey graph
CREATE SCHEMA fkeytestsc;
CREATE TABLE fkeytestsc.dropfkeytest1 (x int unique);
CREATE TABLE dropfkeytest2 (x int8, y int8);
ALTER TABLE dropfkeytest2 ADD CONSTRAINT fkey1 FOREIGN KEY (y) REFERENCES fkeytestsc.dropfkeytest1(x);
SELECT create_distributed_table ('fkeytestsc.dropfkeytest1', 'x');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- this should error out
SELECT create_distributed_table ('dropfkeytest2', 'y', colocate_with:='none');
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 SCHEMA fkeytestsc CASCADE;
NOTICE:  drop cascades to 2 other objects
DETAIL:  drop cascades to table fkeytestsc.dropfkeytest1
drop cascades to constraint fkey1 on table dropfkeytest2
-- this should work
SELECT create_distributed_table ('dropfkeytest2', 'x', colocate_with:='none');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

DROP TABLE dropfkeytest2 CASCADE;
-- make sure that even if a table which fkey depends on is dropped
-- Citus can see up-to date fkey graph
CREATE TABLE dropfkeytest1 (x int unique);
CREATE TABLE dropfkeytest2 (x int8, y int8);
ALTER TABLE dropfkeytest2 ADD CONSTRAINT fkey1 FOREIGN KEY (y) REFERENCES dropfkeytest1(x);
SELECT create_distributed_table ('dropfkeytest1', 'x');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- this should error out
SELECT create_distributed_table ('dropfkeytest2', 'y', colocate_with:='none');
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 dropfkeytest1 CASCADE;
NOTICE:  drop cascades to constraint fkey1 on table dropfkeytest2
-- this should work
SELECT create_distributed_table ('dropfkeytest2', 'x', colocate_with:='none');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE set_on_default_test_referenced(
    col_1 int, col_2 int, col_3 int, col_4 int,
    unique (col_1, col_3)
);
SELECT create_reference_table('set_on_default_test_referenced');
 create_reference_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE set_on_default_test_referencing(
    col_1 int, col_2 int, col_3 serial, col_4 int,
    FOREIGN KEY(col_1, col_3)
    REFERENCES set_on_default_test_referenced(col_1, col_3)
    ON UPDATE SET DEFAULT
);
ERROR:  cannot create foreign key constraint since Citus does not support ON DELETE / UPDATE SET DEFAULT actions on the columns that default to sequences
CREATE TABLE set_on_default_test_referencing(
    col_1 serial, col_2 int, col_3 int, col_4 int
);
SELECT create_reference_table('set_on_default_test_referencing');
 create_reference_table
---------------------------------------------------------------------

(1 row)

-- from reference to reference, fkey doesn't exist before calling the UDFs
ALTER TABLE set_on_default_test_referencing ADD CONSTRAINT fkey
FOREIGN KEY(col_1, col_3) REFERENCES set_on_default_test_referenced(col_1, col_3)
ON DELETE SET DEFAULT;
ERROR:  cannot create foreign key constraint since Citus does not support ON DELETE / UPDATE SET DEFAULT actions on the columns that default to sequences
DROP TABLE set_on_default_test_referencing;
CREATE TABLE set_on_default_test_referencing(
    col_1 int, col_2 serial, col_3 int, col_4 bigserial
);
SELECT create_reference_table('set_on_default_test_referencing');
 create_reference_table
---------------------------------------------------------------------

(1 row)

-- ok since referencing columns are not based on sequences
ALTER TABLE set_on_default_test_referencing ADD CONSTRAINT fkey
FOREIGN KEY(col_1, col_3) REFERENCES set_on_default_test_referenced(col_1, col_3)
ON DELETE SET DEFAULT;
DROP TABLE set_on_default_test_referencing;
CREATE SEQUENCE test_sequence;
CREATE TABLE set_on_default_test_referencing(
    col_1 int, col_2 int, col_3 int DEFAULT nextval('test_sequence'), col_4 int
);
SELECT create_distributed_table('set_on_default_test_referencing', 'col_1');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- from distributed to reference, fkey doesn't exist before calling the UDFs
ALTER TABLE set_on_default_test_referencing ADD CONSTRAINT fkey
FOREIGN KEY(col_1, col_3) REFERENCES set_on_default_test_referenced(col_1, col_3)
ON DELETE SET DEFAULT ON UPDATE SET DEFAULT;
ERROR:  cannot create foreign key constraint since Citus does not support ON DELETE / UPDATE SET DEFAULT actions on the columns that default to sequences
DROP TABLE set_on_default_test_referenced;
CREATE TABLE set_on_default_test_referenced(
    col_1 int, col_2 int, col_3 int, col_4 int,
    unique (col_1, col_3)
);
SELECT create_distributed_table('set_on_default_test_referenced', 'col_1');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

DROP TABLE set_on_default_test_referencing;
CREATE TABLE set_on_default_test_referencing(
    col_1 bigserial, col_2 int, col_3 int DEFAULT nextval('test_sequence'), col_4 int,
    FOREIGN KEY(col_1, col_3)
    REFERENCES set_on_default_test_referenced(col_1, col_3)
    ON DELETE SET DEFAULT
);
-- from distributed to distributed, fkey exists before calling the UDFs
SELECT create_distributed_table('set_on_default_test_referencing', 'col_1');
ERROR:  cannot create foreign key constraint since Citus does not support ON DELETE / UPDATE SET DEFAULT actions on the columns that default to sequences
DROP TABLE set_on_default_test_referencing;
CREATE TABLE set_on_default_test_referencing(
    col_1 int DEFAULT nextval('test_sequence'), col_2 int, col_3 int, col_4 int
);
SELECT create_distributed_table('set_on_default_test_referencing', 'col_1');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- from distributed to distributed, fkey doesn't exist before calling the UDFs
ALTER TABLE set_on_default_test_referencing ADD CONSTRAINT fkey
FOREIGN KEY(col_1, col_3) REFERENCES set_on_default_test_referenced(col_1, col_3)
ON DELETE SET DEFAULT;
ERROR:  cannot create foreign key constraint since Citus does not support ON DELETE / UPDATE SET DEFAULT actions on the columns that default to sequences
-- 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, dropfkeytest2,
           set_on_default_test_referenced, set_on_default_test_referencing;
NOTICE:  drop cascades to constraint fk_1350663 on table public.reference_table_1350663
CONTEXT:  SQL statement "SELECT citus_drop_all_shards(v_obj.objid, v_obj.schema_name, v_obj.object_name, drop_shards_metadata_only := false)"
PL/pgSQL function citus_drop_trigger() line XX at PERFORM
