statement ok
SET CLUSTER SETTING sql.cross_db_fks.enabled = TRUE

# Randomize the use of insert fast path.
# The let statement will also log the value.
let $enable_insert_fast_path
SELECT random() < 0.5

statement ok
SET enable_insert_fast_path = $enable_insert_fast_path

# Insert
# ------

statement ok
CREATE TABLE parent (p INT PRIMARY KEY, other INT)

statement ok
CREATE TABLE child (c INT PRIMARY KEY, p INT NOT NULL REFERENCES parent(p))

statement error insert on table "child" violates foreign key constraint "child_p_fkey"\nDETAIL: Key \(p\)=\(1\) is not present in table "parent"\.
INSERT INTO child VALUES (1,1)

statement ok
INSERT INTO parent VALUES (1), (2)

statement error insert on table "child" violates foreign key constraint "child_p_fkey"\nDETAIL: Key \(p\)=\(3\) is not present in table "parent"\.
INSERT INTO child VALUES (1,1), (2,2), (3,3)

statement ok
INSERT INTO child VALUES (1,1), (2,2)

# Use data from a different table as input.
statement ok
CREATE TABLE xy (x INT, y INT)

statement ok
INSERT INTO xy VALUES (4, 4), (5, 5), (6, 6)

statement error insert on table "child" violates foreign key constraint "child_p_fkey"\nDETAIL: Key \(p\)=\([4-6]\) is not present in table "parent"\.
INSERT INTO child SELECT x,y FROM xy

statement ok
INSERT INTO parent SELECT x FROM xy

statement ok
INSERT INTO child SELECT x,y FROM xy

statement ok
DROP TABLE xy

statement ok
DROP TABLE child

statement ok
DROP TABLE parent

# Delete
# ------

statement ok
CREATE TABLE parent (x INT, p INT PRIMARY KEY, u INT UNIQUE)

statement ok
CREATE TABLE child (c INT PRIMARY KEY, p INT NOT NULL REFERENCES parent(p))

statement ok
INSERT INTO parent (p, u) VALUES (1, 10), (2, 20)

statement ok
INSERT INTO child VALUES (1, 1)

statement ok
DELETE FROM parent WHERE p = 2

statement error delete on table "parent" violates foreign key constraint "child_p_fkey" on table "child"\nDETAIL: Key \(p\)=\(1\) is still referenced from table "child"\.
DELETE FROM parent WHERE p = 1

statement ok
CREATE TABLE child_u (c INT PRIMARY KEY, u INT NOT NULL REFERENCES parent(u))

statement ok
DROP TABLE child

statement ok
INSERT INTO child_u VALUES (1, 10)

statement error delete on table "parent" violates foreign key constraint "child_u_u_fkey" on table "child_u"\nDETAIL: Key \(u\)=\(10\) is still referenced from table "child_u"\.
DELETE FROM parent WHERE p = 1

statement ok
DROP TABLE child_u

statement ok
DROP TABLE parent

statement ok
CREATE TABLE parent2 (p1 INT, p2 INT, other INT, PRIMARY KEY (p1, p2))

statement ok
CREATE TABLE child2 (c INT PRIMARY KEY, p1 INT, p2 INT, FOREIGN KEY (p1, p2) REFERENCES parent2 (p1, p2))

statement ok
INSERT INTO parent2 VALUES
  (10, 100),
  (10, 150),
  (20, 200)

statement ok
INSERT INTO child2 VALUES
  (1, 10, 100),
  (2, 10, NULL),
  (3, 10, 150),
  (4, 20, 200),
  (5, NULL, 100)

statement error delete on table "parent2" violates foreign key constraint "child2_p1_p2_fkey" on table "child2"\nDETAIL: Key \(p1, p2\)=\(10, 100\) is still referenced from table "child2"\.
DELETE FROM parent2 WHERE p1 = 10 AND p2 = 100

statement ok
DELETE FROM child2 WHERE p1 = 10 AND p2 = 100

statement ok
DELETE FROM parent2 WHERE p1 = 10 AND p2 = 100

statement ok
DROP TABLE child2

statement ok
DROP TABLE parent2

# Upsert
# ------

statement ok
CREATE TABLE parent (p INT PRIMARY KEY, other INT)

statement ok
CREATE TABLE child (c INT PRIMARY KEY, p INT NOT NULL REFERENCES parent(p))

statement ok
INSERT INTO parent VALUES (1), (2)

# Insert case.
statement ok
INSERT INTO child VALUES (1, 1) ON CONFLICT (c) DO UPDATE SET p = 2

statement error foreign key
INSERT INTO child VALUES (2, 10) ON CONFLICT (c) DO UPDATE SET p = 2

# Update case.
statement ok
INSERT INTO child VALUES (1, 1) ON CONFLICT (c) DO UPDATE SET p = 1

statement ok
INSERT INTO child VALUES (1, 10) ON CONFLICT (c) DO UPDATE SET p = 1

statement error foreign key
INSERT INTO child VALUES (1, 10) ON CONFLICT (c) DO UPDATE SET p = 10

statement ok
TRUNCATE child

statement ok
INSERT INTO child VALUES (1, 1)

# Both insert and update case.

# Both insert and update are invalid.

statement error foreign key
INSERT INTO child VALUES (1, 1), (2, 3) ON CONFLICT (c) DO UPDATE SET p = 3

# Insert is invalid, update is valid.

statement error foreign key
INSERT INTO child VALUES (1, 2), (2, 3) ON CONFLICT (c) DO UPDATE SET p = 1

# Insert is valid, update is invalid.

statement error foreign key
INSERT INTO child VALUES (1, 2), (2, 1) ON CONFLICT (c) DO UPDATE SET p = 3

# Both insert and update are valid.

statement ok
INSERT INTO child VALUES (1, 2), (2, 1) ON CONFLICT (c) DO UPDATE SET p = 2

statement ok
DROP TABLE child

statement ok
DROP TABLE parent

# Pseudo-deletions

statement ok
CREATE TABLE parent (a INT PRIMARY KEY, b INT, UNIQUE (b))

statement ok
CREATE TABLE child (a INT PRIMARY KEY, b INT REFERENCES parent (b))

statement ok
INSERT INTO parent VALUES (1, 2)

statement ok
INSERT INTO child VALUES (10, 2)

statement error pq: upsert on table "parent" violates foreign key constraint "child_b_fkey" on table "child"\nDETAIL: Key \(b\)=\(2\) is still referenced from table "child"\.
UPSERT INTO parent VALUES (1, 3)

statement ok
INSERT INTO parent VALUES (1, 3), (2, 2) ON CONFLICT (a) DO UPDATE SET b = 3

query II
SELECT * FROM child
----
10  2

query II rowsort
SELECT * FROM parent
----
1  3
2  2

# child references the second '2' column in parent. This mutation removes that
# row via an update, and is disallowed.
statement error pq: insert on table "parent" violates foreign key constraint "child_b_fkey" on table "child"\nDETAIL: Key \(b\)=\(2\) is still referenced from table "child"\.
INSERT INTO parent VALUES (2, 2) ON CONFLICT (a) DO UPDATE SET b = parent.b - 1

statement ok
DROP TABLE child

statement ok
DROP TABLE parent

# Self-reference.

statement ok
CREATE TABLE self (k int primary key, a int unique, b int references self(a))

statement error pq: upsert on table "self" violates foreign key constraint "self_b_fkey"\nDETAIL: Key \(b\)=\(2\) is not present in table "self"
UPSERT INTO self VALUES (1, 1, 2)

statement ok
UPSERT INTO self VALUES (1, 1, 1)

statement ok
UPSERT INTO self VALUES (1, 1, 1)

statement error pq: upsert on table "self" violates foreign key constraint "self_b_fkey"\nDETAIL: Key \(b\)=\(2\) is not present in table "self"
UPSERT INTO self VALUES (1, 1, 2)

statement ok
UPSERT INTO self VALUES (1, 2, 2)

statement error pq: upsert on table "self" violates foreign key constraint "self_b_fkey"\nDETAIL: Key \(b\)=\(2\) is not present in table "self"
UPSERT INTO self(k,a) VALUES (1, 1)

statement ok
UPSERT INTO self VALUES (1, 1, 2), (2, 2, 1)

statement ok
INSERT INTO self VALUES (2, 2, 2) ON CONFLICT (k) DO UPDATE SET b = self.b + 1

statement error pq: insert on table "self" violates foreign key constraint "self_b_fkey"\nDETAIL: Key \(b\)=\(3\) is not present in table "self"
INSERT INTO self VALUES (2, 2, 2) ON CONFLICT (k) DO UPDATE SET b = self.b + 1

statement ok
DROP TABLE self

# --- Tests that follow are copied from the fk tests and adjusted as needed.

statement ok
CREATE TABLE customers (id INT PRIMARY KEY, email STRING UNIQUE)

statement ok
INSERT INTO customers VALUES (1, 'a@co.tld'), (2, 'b@co.tld')

statement ok
CREATE TABLE products (sku STRING PRIMARY KEY, upc STRING UNIQUE, vendor STRING)

statement ok
INSERT INTO products VALUES ('VP-W9QH-W44L', '867072000006', 'Dave'), ('780', '885155001450', 'iRobot')

statement error pgcode 42P01 relation "productz" does not exist
CREATE TABLE missing (product STRING REFERENCES productz)

statement error pgcode 42P01 relation "customerz" does not exist
CREATE TABLE missing_with_col (customer INT REFERENCES customerz (id))

statement error pgcode 42703 column "idz" does not exist
CREATE TABLE missing_col (customer INT REFERENCES customers (idz))

statement ok
CREATE TABLE unindexed (customer INT REFERENCES customers)

query TTBITTTBBBF colnames,rowsort
SHOW INDEXES FROM unindexed
----
table_name  index_name      non_unique  seq_in_index  column_name  definition  direction  storing  implicit  visible  visibility
unindexed   unindexed_pkey  false       1             rowid        rowid       ASC        false    false     true     1
unindexed   unindexed_pkey  false       2             customer     customer    N/A        true     false     true     1

statement error there is no unique constraint matching given keys for referenced table products
CREATE TABLE non_unique (product STRING REFERENCES products (vendor))

statement error type of "customer" \(int\) does not match foreign key "customers"."email" \(string\)
CREATE TABLE mismatch (customer INT REFERENCES customers (email))

statement ok
CREATE TABLE orders (
  id INT,
  shipment INT,
  product STRING DEFAULT 'sprockets' REFERENCES products,
  customer INT CONSTRAINT valid_customer REFERENCES customers (id),
  PRIMARY KEY (id, shipment),
  INDEX (product),
  INDEX (customer)
)

statement ok
ALTER TABLE orders DROP CONSTRAINT orders_product_fkey

statement ok
ALTER TABLE orders ADD FOREIGN KEY (product) REFERENCES products ON DELETE NO ACTION

statement ok
ALTER TABLE orders DROP CONSTRAINT orders_product_fkey

statement ok
ALTER TABLE orders ADD FOREIGN KEY (product) REFERENCES products ON UPDATE NO ACTION

statement ok
ALTER TABLE orders DROP CONSTRAINT orders_product_fkey

statement ok
ALTER TABLE orders ADD FOREIGN KEY (product) REFERENCES products ON DELETE CASCADE

statement ok
ALTER TABLE orders DROP CONSTRAINT orders_product_fkey

statement ok
ALTER TABLE orders ADD FOREIGN KEY (product) REFERENCES products ON UPDATE CASCADE

statement ok
ALTER TABLE orders DROP CONSTRAINT orders_product_fkey

statement ok
ALTER TABLE orders ADD FOREIGN KEY (product) REFERENCES products ON DELETE SET NULL

statement ok
ALTER TABLE orders DROP CONSTRAINT orders_product_fkey

statement ok
ALTER TABLE orders ADD FOREIGN KEY (product) REFERENCES products ON UPDATE SET NULL

statement ok
ALTER TABLE orders DROP CONSTRAINT orders_product_fkey

statement ok
ALTER TABLE orders ADD FOREIGN KEY (product) REFERENCES products ON DELETE SET DEFAULT

statement ok
ALTER TABLE orders DROP CONSTRAINT orders_product_fkey

statement ok
ALTER TABLE orders ADD FOREIGN KEY (product) REFERENCES products ON UPDATE SET DEFAULT

statement ok
ALTER TABLE orders DROP CONSTRAINT orders_product_fkey

statement ok
ALTER TABLE orders ADD FOREIGN KEY (product) REFERENCES products ON DELETE RESTRICT ON UPDATE NO ACTION

statement ok
ALTER TABLE orders DROP CONSTRAINT orders_product_fkey

statement ok
ALTER TABLE orders ADD FOREIGN KEY (product) REFERENCES products ON DELETE RESTRICT ON UPDATE RESTRICT

statement ok
ALTER TABLE orders VALIDATE CONSTRAINT orders_product_fkey

statement ok
CREATE DATABASE "user content"

# "reviews" makes "products" have multiple inbound references, as well as making
# "orders" have both directions, and makes sure that we're handling escaping and
# cross-database references.
statement ok
CREATE TABLE "user content"."customer reviews" (
  id INT PRIMARY KEY,
  product STRING NOT NULL REFERENCES products,
  customer INT,
  "order" INT,
  shipment int,
  body STRING,
  CONSTRAINT customerfk FOREIGN KEY (customer) REFERENCES customers,
  CONSTRAINT orderfk FOREIGN KEY ("order", shipment) REFERENCES orders (id, shipment),
  INDEX (product),
  INDEX (customer),
  INDEX ("order")
)

statement ok
INSERT INTO orders VALUES (1, 1, '780', 2)

statement error insert on table "orders" violates foreign key constraint "orders_product_fkey"\nDETAIL: Key \(product\)=\('fake'\) is not present in table "products"
INSERT INTO orders VALUES (2, 2, 'fake', 2)

statement error pgcode 23503 delete on table "products" violates foreign key constraint "orders_product_fkey" on table "orders"\nDETAIL: Key \(sku\)=\('780'\) is still referenced from table "orders"\.
DELETE FROM products

statement ok
INSERT INTO "user content"."customer reviews" VALUES (1, '780', 2, 1, 1, NULL)

statement error pgcode 23503 insert on table "customer reviews" violates foreign key constraint "customer reviews_product_fkey"\nDETAIL: Key \(product\)=\('790'\) is not present in table "products".
INSERT INTO "user content"."customer reviews" (id, product, body) VALUES (2, '790', 'would not buy again')

statement ok
INSERT INTO "user content"."customer reviews" (id, product, body) VALUES (2, '780', 'would not buy again')

statement ok
CREATE TABLE "user content".review_stats (
  id INT PRIMARY KEY,
  upvotes INT,
  CONSTRAINT reviewfk FOREIGN KEY (id) REFERENCES "user content"."customer reviews"
)

query TTTTB
SELECT * FROM [SHOW CONSTRAINTS FROM "user content".review_stats] ORDER BY constraint_name
----
review_stats  review_stats_pkey  PRIMARY KEY  PRIMARY KEY (id ASC)                                true
review_stats  reviewfk           FOREIGN KEY  FOREIGN KEY (id) REFERENCES "customer reviews"(id)  true

statement error pgcode 23503 insert on table "review_stats" violates foreign key constraint "reviewfk"\nDETAIL: Key \(id\)=\(5\) is not present in table "customer reviews"
INSERT INTO "user content".review_stats (id, upvotes) VALUES (5, 1)

statement ok
INSERT INTO "user content".review_stats (id, upvotes) VALUES (2, 1)

statement error pgcode 23503 delete on table "customer reviews" violates foreign key constraint "reviewfk" on table "review_stats"\nDETAIL: Key \(id\)=\(2\) is still referenced from table "review_stats"\.
DELETE FROM "user content"."customer reviews" WHERE id = 2

statement ok
ALTER TABLE "user content".review_stats DROP CONSTRAINT reviewfk

query TTTTB
SHOW CONSTRAINTS FROM "user content".review_stats
----
review_stats  review_stats_pkey  PRIMARY KEY  PRIMARY KEY (id ASC)  true

statement ok
DELETE FROM "user content"."customer reviews"

statement error pgcode 23503 insert on table "orders" violates foreign key constraint "orders_product_fkey"\nDETAIL: Key \(product\)=\('790'\) is not present in table "products"
INSERT INTO orders VALUES (2, 1, '790', 2)

statement error pgcode 23503 insert on table "orders" violates foreign key constraint "valid_customer"\nDETAIL: Key \(customer\)=\(43\) is not present in table "customers"
INSERT INTO orders VALUES (2, 1, '780', 43)

statement ok
INSERT INTO orders VALUES (2, 1, '780', 1)

# Try to point to missing FK.
statement error pgcode 23503 update on table "orders" violates foreign key constraint "orders_product_fkey"
UPDATE orders SET product = '790' WHERE id = 2

# Try to point to missing fk *while changing PK*.
statement error pgcode 23503 update on table "orders" violates foreign key constraint "orders_product_fkey"
UPDATE orders SET id = 3, product = '790' WHERE id = 2

# Change PK while leaving everything else is fine though.
statement ok
UPDATE orders SET id = 3 WHERE id = 2

# Change PK and point to different product.
statement ok
UPDATE orders SET id = 2, product = 'VP-W9QH-W44L' WHERE id = 3

statement ok
UPDATE orders SET product = '780' WHERE id = 2

# "delivery" is interesting since it references a secondary index with different col names.
statement ok
CREATE TABLE delivery (
  ts TIMESTAMP DEFAULT now(),
  "order" int,
  shipment int,
  item STRING REFERENCES products (upc),
  FOREIGN KEY ("order", shipment) REFERENCES orders (id, shipment),
  INDEX (item),
  FAMILY "primary" (ts, "order", shipment, item, rowid)
)

query TT
SHOW CREATE TABLE delivery
----
delivery  CREATE TABLE public.delivery (
            ts TIMESTAMP NULL DEFAULT now():::TIMESTAMP,
            "order" INT8 NULL,
            shipment INT8 NULL,
            item STRING NULL,
            rowid INT8 NOT VISIBLE NOT NULL DEFAULT unique_rowid(),
            CONSTRAINT delivery_pkey PRIMARY KEY (rowid ASC),
            CONSTRAINT delivery_order_shipment_fkey FOREIGN KEY ("order", shipment) REFERENCES public.orders(id, shipment),
            CONSTRAINT delivery_item_fkey FOREIGN KEY (item) REFERENCES public.products(upc),
            INDEX delivery_item_idx (item ASC)
          )

statement ok
INSERT INTO delivery ("order", shipment, item) VALUES
  (1, 1, '867072000006'), (1, 1, '867072000006'), (1, 1, '885155001450'), (1, 1, '867072000006')

statement error pgcode 23503 insert on table "delivery" violates foreign key constraint "delivery_item_fkey"\nDETAIL: Key \(item\)=\('missing'\) is not present in table "products"
INSERT INTO delivery ("order", shipment, item) VALUES
  (1, 1, '867072000006'), (1, 1, 'missing'), (1, 1, '885155001450'), (1, 1, '867072000006')

statement error pgcode 23503 insert on table "delivery" violates foreign key constraint "delivery_order_shipment_fkey"\nDETAIL: Key \(order, shipment\)=\(1, 99\) is not present in table "orders"
INSERT INTO delivery ("order", shipment, item) VALUES
  (1, 1, '867072000006'), (1, 99, '867072000006')

statement error pgcode 23503 delete on table "products" violates foreign key constraint "delivery_item_fkey" on table "delivery"\nDETAIL: Key \(upc\)=\('867072000006'\) is still referenced from table "delivery"\.
DELETE FROM products WHERE sku = 'VP-W9QH-W44L'

# Blanking a field nobody cares about is fine.
statement ok
UPDATE products SET vendor = '' WHERE sku = '780'

# No-op update should be fine.
statement ok
UPDATE products SET sku = '770' WHERE sku = '750'

# Changing referenced PK fails.
statement error pgcode 23503 update on table "products" violates foreign key constraint "orders_product_fkey" on table "orders"\nDETAIL: Key \(sku\)=\('780'\) is still referenced from table "orders"\.
UPDATE products SET sku = '770' WHERE sku = '780'

# No-op change to existing data is fine.
statement ok
UPDATE products SET upc = '885155001450' WHERE sku = '780'

# Changing referenced non-pk index fails.
statement error pgcode 23503 update on table "products" violates foreign key constraint "delivery_item_fkey" on table "delivery"\nDETAIL: Key \(upc\)=\('885155001450'\) is still referenced from table "delivery"\.
UPDATE products SET upc = 'blah' WHERE sku = '780'

statement ok
ALTER TABLE delivery DROP CONSTRAINT delivery_item_fkey

statement ok
UPDATE products SET upc = 'blah' WHERE sku = '780'

statement error pgcode 23503 foreign key violation: "delivery" row item='885155001450', rowid=[0-9]* has no match in "products"
ALTER TABLE delivery ADD FOREIGN KEY (item) REFERENCES products (upc)

query TTTTB
SELECT * FROM [SHOW CONSTRAINTS FROM delivery] ORDER BY constraint_name
----
delivery  delivery_order_shipment_fkey  FOREIGN KEY  FOREIGN KEY ("order", shipment) REFERENCES orders(id, shipment)  true
delivery  delivery_pkey                 PRIMARY KEY  PRIMARY KEY (rowid ASC)                                          true

statement ok
UPDATE products SET upc = '885155001450' WHERE sku = '780'

statement ok
ALTER TABLE delivery ADD FOREIGN KEY (item) REFERENCES products (upc)

query TTTTB
SELECT * FROM [SHOW CONSTRAINTS FROM delivery] ORDER BY constraint_name
----
delivery  delivery_item_fkey            FOREIGN KEY  FOREIGN KEY (item) REFERENCES products(upc)                      true
delivery  delivery_order_shipment_fkey  FOREIGN KEY  FOREIGN KEY ("order", shipment) REFERENCES orders(id, shipment)  true
delivery  delivery_pkey                 PRIMARY KEY  PRIMARY KEY (rowid ASC)                                          true

statement ok
ALTER TABLE "user content"."customer reviews"
  DROP CONSTRAINT orderfk

statement ok
INSERT INTO "user content"."customer reviews" (id, product, body, "order") VALUES (3, '780', 'i ordered 100 of them', 9)

statement ok
ALTER TABLE "user content"."customer reviews"
  ADD CONSTRAINT orderfk2 FOREIGN KEY ("order", shipment) REFERENCES orders (id, shipment)

# This is allowed because we match using MATCH SIMPLE.
statement ok
ALTER TABLE "user content"."customer reviews"
  VALIDATE CONSTRAINT orderfk2

# This is allowed because we match using MATCH SIMPLE.
statement ok
INSERT INTO "user content"."customer reviews" (id, product, body, "order") VALUES (4, '780', 'i ordered 101 of them', 9)

statement error pgcode 23503 insert on table "customer reviews" violates foreign key constraint "orderfk2"\nDETAIL: Key \(order, shipment\)=\(9, 1\) is not present in table "orders"
INSERT INTO "user content"."customer reviews" (id, product, body, "order", shipment) VALUES (5, '780', 'i ordered 101 of them', 9, 1)

statement error pgcode 23503 insert on table "customer reviews" violates foreign key constraint "orderfk2"\nDETAIL: Key \(order, shipment\)=\(1, 9\) is not present in table "orders"
INSERT INTO "user content"."customer reviews" (id, product, body, shipment, "order") VALUES (5, '780', 'i ordered 101 of them', 9, 1)

statement ok
ALTER TABLE delivery DROP CONSTRAINT delivery_order_shipment_fkey

statement ok
TRUNCATE orders, "user content"."customer reviews"

# Changing now non-referenced and secondary field is fine.
statement ok
UPDATE products SET sku = '750', vendor = 'roomba' WHERE sku = '780'

# Changing PK and referenced secondary index is not ok.
statement error pgcode 23503 update on table "products" violates foreign key constraint "delivery_item_fkey" on table "delivery"\nDETAIL: Key \(upc\)=\('885155001450'\) is still referenced from table "delivery"\.
UPDATE products SET sku = '780', upc = 'blah' WHERE sku = '750'

statement error pgcode 23503 delete on table "products" violates foreign key constraint "delivery_item_fkey" on table "delivery"\nDETAIL: Key \(upc\)=\('885155001450'\) is still referenced from table "delivery"\.
DELETE FROM products WHERE sku = '750'

statement error "products" is referenced by foreign key from table "orders"
TRUNCATE products

query I
SELECT count(*) FROM delivery
----
4

statement ok
TRUNCATE products CASCADE

query I
SELECT count(*) FROM delivery
----
0

statement ok
TRUNCATE delivery, products, orders, "user content"."customer reviews"

query TTTTB colnames
SELECT * FROM [SHOW CONSTRAINTS FROM orders] ORDER BY constraint_name
----
table_name  constraint_name      constraint_type  details                                                                               validated
orders      orders_pkey          PRIMARY KEY      PRIMARY KEY (id ASC, shipment ASC)                                                    true
orders      orders_product_fkey  FOREIGN KEY      FOREIGN KEY (product) REFERENCES products(sku) ON DELETE RESTRICT ON UPDATE RESTRICT  true
orders      valid_customer       FOREIGN KEY      FOREIGN KEY (customer) REFERENCES customers(id)                                       true

statement error pq: index "products_upc_key" is in use as unique constraint
DROP INDEX products@products_upc_key

statement error pq: index "products_upc_key" is in use as unique constraint
DROP INDEX products@products_upc_key RESTRICT

statement error "products_upc_key" is referenced by foreign key from table "delivery"
ALTER TABLE products DROP COLUMN upc

statement ok
ALTER TABLE delivery DROP COLUMN "item"

statement ok
DROP INDEX products@products_upc_key CASCADE

statement error "products" is referenced by foreign key from table "orders"
DROP TABLE products

statement error "products" is referenced by foreign key from table "orders"
DROP TABLE products RESTRICT

statement error referenced by foreign key from table "customer reviews"
DROP TABLE orders

statement ok
ALTER TABLE "user content"."customer reviews" DROP COLUMN "order" CASCADE

statement ok
DROP TABLE "user content"."customer reviews"

statement ok
DROP TABLE orders

statement ok
DROP TABLE products

statement ok
CREATE TABLE parent (id int primary key)

statement ok
CREATE TABLE child (id INT PRIMARY KEY, parent_id INT UNIQUE REFERENCES parent)

statement ok
CREATE TABLE grandchild (id INT PRIMARY KEY, parent_id INT REFERENCES child (parent_id), INDEX (parent_id))

statement error "parent" is referenced by foreign key from table "child"
DROP TABLE parent

statement error "child" is referenced by foreign key from table "grandchild"
DROP TABLE child

statement error pgcode 23503 foreign key
INSERT INTO child VALUES (2, 2)

statement ok
DROP TABLE parent CASCADE

statement ok
INSERT INTO child VALUES (2, 2)

statement error pgcode 23503 foreign key
INSERT INTO grandchild VALUES (1, 1)

statement ok
DROP INDEX grandchild@grandchild_parent_id_idx

statement ok
DROP TABLE grandchild

statement ok
CREATE TABLE grandchild (id INT PRIMARY KEY, parent_id INT REFERENCES child (parent_id), INDEX (parent_id))

statement error pgcode 23503 foreign key
INSERT INTO grandchild VALUES (1, 1)

statement error pq: index "child_parent_id_key" is in use as unique constraint
DROP INDEX child@child_parent_id_key

statement ok
DROP INDEX child@child_parent_id_key CASCADE

statement ok
INSERT INTO grandchild VALUES (1, 1)

statement ok
CREATE TABLE employees (id INT PRIMARY KEY, manager INT REFERENCES employees, INDEX (manager))

statement ok
INSERT INTO employees VALUES (1, NULL)

statement ok
INSERT INTO employees VALUES (2, 1), (3, 1)

statement ok
INSERT INTO employees VALUES (4, 2), (5, 3)

statement error pgcode 23503 foreign key
DELETE FROM employees WHERE id = 2

# Deleting all the rows works - we are checking the FKs after the mutation.
statement ok
DELETE FROM employees WHERE id > 1

statement ok
DROP TABLE employees

statement ok
CREATE TABLE pairs (id INT PRIMARY KEY, src INT, dest STRING, UNIQUE (src, dest))

statement ok
INSERT INTO pairs VALUES (1, 100, 'one'), (2, 200, 'two')

statement error type of "b" \(string\) does not match foreign key "pairs"."id" \(int\)
CREATE TABLE refpairs (a INT, b STRING, CONSTRAINT fk FOREIGN KEY (b) REFERENCES pairs)

statement error 2 columns must reference exactly 2 columns in referenced table \(found 1\)
CREATE TABLE refpairs (a INT, b STRING, CONSTRAINT fk FOREIGN KEY (a, b) REFERENCES pairs)

# TODO(dt): remove ordering constraint on matching index
statement ok
CREATE TABLE refpairs_wrong_order (
  a INT,
  b STRING,
  FOREIGN KEY (a, b) REFERENCES pairs (src, dest),
  INDEX (b, a)
)

query TTBITTTBBBF colnames,rowsort
SHOW INDEXES FROM refpairs_wrong_order
----
table_name            index_name                    non_unique  seq_in_index  column_name  definition  direction  storing  implicit  visible  visibility
refpairs_wrong_order  refpairs_wrong_order_b_a_idx  true        1             b            b           ASC        false    false     true     1
refpairs_wrong_order  refpairs_wrong_order_b_a_idx  true        2             a            a           ASC        false    false     true     1
refpairs_wrong_order  refpairs_wrong_order_b_a_idx  true        3             rowid        rowid       ASC        false    true      true     1
refpairs_wrong_order  refpairs_wrong_order_pkey     false       1             rowid        rowid       ASC        false    false     true     1
refpairs_wrong_order  refpairs_wrong_order_pkey     false       2             a            a           N/A        true     false     true     1
refpairs_wrong_order  refpairs_wrong_order_pkey     false       3             b            b           N/A        true     false     true     1

statement ok
CREATE TABLE refpairs_c_between (a INT, b STRING, c INT, FOREIGN KEY (a, b) REFERENCES pairs (src, dest), INDEX (a, c, b))

query TTBITTTBBBF colnames,rowsort
SHOW INDEXES FROM refpairs_c_between
----
table_name          index_name                    non_unique  seq_in_index  column_name  definition  direction  storing  implicit  visible  visibility
refpairs_c_between  refpairs_c_between_a_c_b_idx  true        1             a            a           ASC        false    false     true     1
refpairs_c_between  refpairs_c_between_a_c_b_idx  true        2             c            c           ASC        false    false     true     1
refpairs_c_between  refpairs_c_between_a_c_b_idx  true        3             b            b           ASC        false    false     true     1
refpairs_c_between  refpairs_c_between_a_c_b_idx  true        4             rowid        rowid       ASC        false    true      true     1
refpairs_c_between  refpairs_c_between_pkey       false       1             rowid        rowid       ASC        false    false     true     1
refpairs_c_between  refpairs_c_between_pkey       false       2             a            a           N/A        true     false     true     1
refpairs_c_between  refpairs_c_between_pkey       false       3             b            b           N/A        true     false     true     1
refpairs_c_between  refpairs_c_between_pkey       false       4             c            c           N/A        true     false     true     1

statement ok
CREATE TABLE refpairs (
  a INT,
  b STRING,
  c INT,
  FOREIGN KEY (a, b) REFERENCES pairs (src, dest) ON UPDATE RESTRICT,
  INDEX (a, b, c),
  FAMILY "primary" (a, b, c, rowid)
)

query TTBITTTBBBF colnames,rowsort
SHOW INDEXES FROM refpairs
----
table_name  index_name          non_unique  seq_in_index  column_name  definition  direction  storing  implicit  visible  visibility
refpairs    refpairs_a_b_c_idx  true        1             a            a           ASC        false    false     true     1
refpairs    refpairs_a_b_c_idx  true        2             b            b           ASC        false    false     true     1
refpairs    refpairs_a_b_c_idx  true        3             c            c           ASC        false    false     true     1
refpairs    refpairs_a_b_c_idx  true        4             rowid        rowid       ASC        false    true      true     1
refpairs    refpairs_pkey       false       1             rowid        rowid       ASC        false    false     true     1
refpairs    refpairs_pkey       false       2             a            a           N/A        true     false     true     1
refpairs    refpairs_pkey       false       3             b            b           N/A        true     false     true     1
refpairs    refpairs_pkey       false       4             c            c           N/A        true     false     true     1

query TT
SHOW CREATE TABLE refpairs
----
refpairs  CREATE TABLE public.refpairs (
            a INT8 NULL,
            b STRING NULL,
            c INT8 NULL,
            rowid INT8 NOT VISIBLE NOT NULL DEFAULT unique_rowid(),
            CONSTRAINT refpairs_pkey PRIMARY KEY (rowid ASC),
            CONSTRAINT refpairs_a_b_fkey FOREIGN KEY (a, b) REFERENCES public.pairs(src, dest) ON UPDATE RESTRICT,
            INDEX refpairs_a_b_c_idx (a ASC, b ASC, c ASC)
          )

statement error pgcode 23503 insert on table "refpairs" violates foreign key constraint "refpairs_a_b_fkey"\nDETAIL: Key \(a, b\)=\(100, 'two'\) is not present in table "pairs".
INSERT INTO refpairs VALUES (100, 'two'), (200, 'two')

statement ok
INSERT INTO refpairs VALUES (100, 'one', 3), (200, 'two', null)

statement error pgcode 23503 update on table "pairs" violates foreign key constraint "refpairs_a_b_fkey" on table "refpairs"\nDETAIL: Key \(src, dest\)=\(200, 'two'\) is still referenced from table "refpairs"\.
UPDATE pairs SET dest = 'too' WHERE id = 2

statement error pgcode 23503 delete on table "pairs" violates foreign key constraint "refpairs_a_b_fkey" on table "refpairs"\nDETAIL: Key \(src, dest\)=\(200, 'two'\) is still referenced from table "refpairs"\.
DELETE FROM pairs WHERE id = 2

statement error pgcode 23503 delete on table "pairs" violates foreign key constraint "refpairs_a_b_fkey" on table "refpairs"\nDETAIL: Key \(src, dest\)=\(100, 'one'\) is still referenced from table "refpairs"\.
DELETE FROM pairs WHERE id = 1

# since PKs are handled differently than other indexes, check pk<->pk ref with no other indexes in play.
statement ok
CREATE TABLE foo (id INT PRIMARY KEY)

statement ok
CREATE TABLE bar (id INT PRIMARY KEY REFERENCES foo)

statement ok
INSERT INTO foo VALUES (2)

statement ok
INSERT INTO bar VALUES (2)

statement error pgcode 23503 delete on table "foo" violates foreign key constraint "bar_id_fkey" on table "bar"\nDETAIL: Key \(id\)=\(2\) is still referenced from table "bar"\.
DELETE FROM foo

statement ok
CREATE DATABASE otherdb

statement ok
CREATE TABLE otherdb.othertable (id INT PRIMARY KEY)

statement ok
CREATE TABLE crossdb (id INT PRIMARY KEY, FOREIGN KEY (id) REFERENCES otherdb.othertable)

statement error pgcode 23503 insert on table "crossdb" violates foreign key constraint "crossdb_id_fkey"\nDETAIL: Key \(id\)=\(2\) is not present in table "othertable".
INSERT INTO crossdb VALUES (2)

statement ok
INSERT INTO otherdb.othertable VALUES (1), (2)

statement ok
INSERT INTO crossdb VALUES (2)

statement error pgcode 23503 delete on table "othertable" violates foreign key constraint "crossdb_id_fkey" on table "crossdb"\nDETAIL: Key \(id\)=\(2\) is still referenced from table "crossdb"\.
DELETE FROM otherdb.othertable WHERE id = 2

statement error "othertable" is referenced by foreign key from table "crossdb"
DROP TABLE otherdb.othertable

statement ok
DROP TABLE otherdb.othertable, crossdb

statement ok
CREATE TABLE modules (id BIGSERIAL NOT NULL PRIMARY KEY)

statement ok
CREATE TABLE domains (id BIGSERIAL NOT NULL PRIMARY KEY)

# We'll use the unique index for the domain fk (since it is a prefix), but we
# we correctly only mark the prefix as used and thus still allow module_id to be
# used in another FK.
statement ok
CREATE TABLE domain_modules (
  id         BIGSERIAL    NOT NULL PRIMARY KEY,
  domain_id  BIGINT       NOT NULL,
  module_id  BIGINT       NOT NULL,
  CONSTRAINT domain_modules_domain_id_fk FOREIGN KEY (domain_id) REFERENCES domains (id),
  CONSTRAINT domain_modules_module_id_fk FOREIGN KEY (module_id) REFERENCES modules (id),
  CONSTRAINT domain_modules_uq UNIQUE (domain_id, module_id)
)

query TTTTB
SELECT * FROM [SHOW CONSTRAINTS FROM domain_modules] ORDER BY constraint_name
----
domain_modules  domain_modules_domain_id_fk  FOREIGN KEY  FOREIGN KEY (domain_id) REFERENCES domains(id)  true
domain_modules  domain_modules_module_id_fk  FOREIGN KEY  FOREIGN KEY (module_id) REFERENCES modules(id)  true
domain_modules  domain_modules_pkey          PRIMARY KEY  PRIMARY KEY (id ASC)                            true
domain_modules  domain_modules_uq            UNIQUE       UNIQUE (domain_id ASC, module_id ASC)           true

statement ok
INSERT INTO modules VALUES(3)

statement error insert on table "domain_modules" violates foreign key constraint "domain_modules_domain_id_fk"\nDETAIL: Key \(domain_id\)=\(2\) is not present in table "domains"
INSERT INTO domain_modules VALUES (1, 2, 3)

statement ok
CREATE TABLE tx (
  id INT NOT NULL PRIMARY KEY
)

statement ok
CREATE TABLE tx_leg (
  leg_id SERIAL NOT NULL PRIMARY KEY,
  tx_id INT NOT NULL REFERENCES tx
)

skip_on_retry

statement ok
BEGIN TRANSACTION

statement ok
INSERT INTO tx VALUES (2)

statement ok
INSERT INTO tx_leg VALUES (201, 2);

statement ok
INSERT INTO tx_leg VALUES (202, 2);

statement ok
COMMIT

statement ok
BEGIN TRANSACTION

statement error pgcode 23503 insert on table "tx_leg" violates foreign key constraint "tx_leg_tx_id_fkey"\nDETAIL: Key \(tx_id\)=\(3\) is not present in table "tx"
INSERT INTO tx_leg VALUES (302, 3);

statement ok
COMMIT

statement ok
CREATE TABLE a (id SERIAL NOT NULL, self_id INT, b_id INT NOT NULL, PRIMARY KEY (id))

statement ok
CREATE TABLE b (id SERIAL NOT NULL, PRIMARY KEY (id))

# The index needed for the fk constraint is automatically added because the table is empty
statement ok
ALTER TABLE a ADD CONSTRAINT fk_self_id FOREIGN KEY (self_id) REFERENCES a;

# The index needed for the fk constraint is automatically added because the table is empty
statement ok
ALTER TABLE a ADD CONSTRAINT fk_b FOREIGN KEY (b_id) REFERENCES b;

statement ok
INSERT INTO b VALUES (1), (2), (3);

statement ok
INSERT INTO a VALUES (1, NULL, 1)

statement ok
INSERT INTO a VALUES (2, 1, 1), (3, 1, 2)

statement ok
INSERT INTO a VALUES (4, 2, 2)

statement ok
DELETE FROM b WHERE id = 3

statement error pgcode 23503 violates foreign key
DELETE FROM b WHERE id = 2

statement error pgcode 23503 violates foreign key
DELETE FROM a WHERE id = 1

statement ok
DELETE FROM a WHERE id > 2

statement ok
DELETE FROM b WHERE id = 2

statement ok
DROP TABLE a

# Check proper GC job description formatting when removing FK back-references when dropping a table (#59221).
skipif config local-legacy-schema-changer
query TT
SELECT job_type, description FROM [SHOW JOBS] WHERE job_type = 'SCHEMA CHANGE GC' AND
 description LIKE 'GC for DROP TABLE test.public.a';
----
SCHEMA CHANGE GC  GC for DROP TABLE test.public.a

statement ok
DROP TABLE b

# A CREATE TABLE with a FK reference within a transaction.
statement ok
CREATE TABLE referee (id INT PRIMARY KEY);

statement ok
BEGIN TRANSACTION

statement ok
CREATE TABLE refers (
  a INT REFERENCES referee,
  b INT,
  INDEX b_idx (b),
  FAMILY "primary" (a, b, rowid)
)

# Add some schema changes within the same transaction to verify that a
# table that isn't yet public can be modified.
statement ok
CREATE INDEX foo ON refers (a)

statement ok
ALTER INDEX refers@b_idx RENAME TO another_idx

query TT
SHOW CREATE TABLE refers
----
refers  CREATE TABLE public.refers (
          a INT8 NULL,
          b INT8 NULL,
          rowid INT8 NOT VISIBLE NOT NULL DEFAULT unique_rowid(),
          CONSTRAINT refers_pkey PRIMARY KEY (rowid ASC),
          CONSTRAINT refers_a_fkey FOREIGN KEY (a) REFERENCES public.referee(id),
          INDEX another_idx (b ASC),
          INDEX foo (a ASC)
        )

statement ok
DROP INDEX refers@another_idx

# refers is not visible because it is in the ADD state.
query TTTTIT rowsort
SHOW TABLES FROM test
----
public  bar                   table  root  0  NULL
public  child                 table  root  0  NULL
public  customers             table  root  0  NULL
public  delivery              table  root  0  NULL
public  domain_modules        table  root  0  NULL
public  domains               table  root  0  NULL
public  foo                   table  root  0  NULL
public  grandchild            table  root  0  NULL
public  modules               table  root  0  NULL
public  pairs                 table  root  0  NULL
public  referee               table  root  0  NULL
public  refpairs              table  root  0  NULL
public  refpairs_c_between    table  root  0  NULL
public  refpairs_wrong_order  table  root  0  NULL
public  tx                    table  root  0  NULL
public  tx_leg                table  root  0  NULL
public  unindexed             table  root  0  NULL

statement ok
COMMIT

# CREATE AND DROP a table with a fk in the same transaction.
statement ok
BEGIN TRANSACTION

statement ok
CREATE TABLE refers1 (a INT REFERENCES referee);

statement ok
DROP TABLE refers1

statement ok
COMMIT

# Check that removing self-ref FK correctly removed backref too, #16070.
statement ok
CREATE TABLE employee (
   id INT PRIMARY KEY,
   manager INT,
   UNIQUE (manager)
);

statement ok
ALTER TABLE employee
   ADD CONSTRAINT emp_emp
   FOREIGN KEY (manager)
   REFERENCES employee;

statement ok
ALTER TABLE employee
   DROP CONSTRAINT emp_emp;

statement ok
SHOW CREATE TABLE employee;

# Ensure that tables with an fk reference from their pk appear correctly in
# SHOW CREATE TABLE (#17596).
statement ok
CREATE TABLE pkref_a (a INT PRIMARY KEY)

statement ok
CREATE TABLE pkref_b (b INT PRIMARY KEY REFERENCES pkref_a ON UPDATE NO ACTION ON DELETE RESTRICT)

query TT
SHOW CREATE TABLE pkref_b
----
pkref_b  CREATE TABLE public.pkref_b (
           b INT8 NOT NULL,
           CONSTRAINT pkref_b_pkey PRIMARY KEY (b ASC),
           CONSTRAINT pkref_b_b_fkey FOREIGN KEY (b) REFERENCES public.pkref_a(a) ON DELETE RESTRICT
         )

subtest 20042

statement ok
CREATE TABLE test20042 (
  x STRING PRIMARY KEY
 ,y STRING UNIQUE
 ,z STRING REFERENCES test20042(y)
);

statement ok
INSERT INTO test20042 (x, y, z) VALUES ('pk1', 'k1', null);

statement ok
INSERT INTO test20042 (x, y, z) VALUES ('pk2', 'k2 ', 'k1');

statement ok
DELETE FROM test20042 WHERE x = 'pk2';

statement ok
DELETE FROM test20042 WHERE x = 'pk1';

subtest 20045

statement ok
CREATE TABLE test20045 (
  x STRING PRIMARY KEY
 ,y STRING UNIQUE REFERENCES test20045(x)
 ,z STRING REFERENCES test20045(y)
);

statement ok
INSERT INTO test20045 (x, y, z) VALUES ('pk1', NULL, NULL);

statement ok
INSERT INTO test20045 (x, y, z) VALUES ('pk2', 'pk1', NULL);

statement ok
INSERT INTO test20045 (x, y, z) VALUES ('pk3', 'pk2', 'pk1');

statement ok
DELETE FROM test20045 WHERE x = 'pk3';

statement ok
DELETE FROM test20045 WHERE x = 'pk2';

statement ok
DELETE FROM test20045 WHERE x = 'pk1';

## Delete cascade without privileges

statement ok
CREATE DATABASE d;

statement ok
CREATE TABLE d.a (
  id STRING PRIMARY KEY
);

statement ok
CREATE TABLE d.b (
  id STRING PRIMARY KEY
 ,a_id STRING REFERENCES d.a ON DELETE CASCADE
);

statement ok
INSERT INTO d.a VALUES ('a1');

statement ok
INSERT INTO d.b VALUES ('b1', 'a1');

statement ok
GRANT ALL ON DATABASE d TO testuser;

statement ok
GRANT ALL ON d.a TO testuser;

user testuser

statement error user testuser does not have SELECT privilege on relation b
DELETE FROM d.a WHERE id = 'a1';

user root

statement ok
GRANT SELECT ON d.b TO testuser;

user testuser

statement error user testuser does not have DELETE privilege on relation b
DELETE FROM d.a WHERE id = 'a1';

user root

statement ok
GRANT DELETE ON d.b TO testuser;

user testuser

statement ok
DELETE FROM d.a WHERE id = 'a1';

user root

# Clean up after the test.
statement ok
DROP DATABASE d CASCADE;

subtest setNullWithNotNullConstraint
### Make sure that one cannot add a set null action on a NOT NULL column.

statement ok
CREATE TABLE a (
  id INT PRIMARY KEY
);

# Create a table with a NOT NULL column and a SET NULL action.
statement error pq: cannot add a SET NULL cascading action on column "test.public.not_null_table.delete_not_nullable" which has a NOT NULL constraint
CREATE TABLE not_null_table (
  id INT PRIMARY KEY
 ,delete_not_nullable INT NOT NULL REFERENCES a ON DELETE SET NULL
);

statement error pq: cannot add a SET NULL cascading action on column "test.public.not_null_table.update_not_nullable" which has a NOT NULL constraint
CREATE TABLE not_null_table (
  id INT PRIMARY KEY
 ,update_not_nullable INT NOT NULL REFERENCES a ON UPDATE SET NULL
);

# Create a table where the primary key has a SET NULL action.
statement error pq: cannot add a SET NULL cascading action on column "test.public.primary_key_table.id" which has a NOT NULL constraint
CREATE TABLE primary_key_table (
  id INT PRIMARY KEY REFERENCES a ON DELETE SET NULL
);

statement error pq: cannot add a SET NULL cascading action on column "test.public.primary_key_table.id" which has a NOT NULL constraint
CREATE TABLE primary_key_table (
  id INT PRIMARY KEY REFERENCES a ON UPDATE SET NULL
);

# Add a SET NULL action after the fact with a NOT NULL column.
statement ok
CREATE TABLE not_null_table (
  id INT PRIMARY KEY
 ,delete_not_nullable INT NOT NULL
 ,update_not_nullable INT NOT NULL
);

statement error pq: cannot add a SET NULL cascading action on column "test.public.not_null_table.delete_not_nullable" which has a NOT NULL constraint
ALTER TABLE not_null_table ADD CONSTRAINT not_null_delete_set_null
  FOREIGN KEY (delete_not_nullable) REFERENCES a (id)
  ON DELETE SET NULL;

statement error pq: cannot add a SET NULL cascading action on column "test.public.not_null_table.update_not_nullable" which has a NOT NULL constraint
ALTER TABLE not_null_table ADD CONSTRAINT not_null_update_set_null
  FOREIGN KEY (update_not_nullable) REFERENCES a (id)
  ON UPDATE SET NULL;

# Clean up so far,
statement ok
DROP TABLE not_null_table;

# Add a SET NULL action after the fact with a primary key column.
statement ok
CREATE TABLE primary_key_table (
  id INT PRIMARY KEY
);

statement error pq: cannot add a SET NULL cascading action on column "test.public.primary_key_table.id" which has a NOT NULL constraint
ALTER TABLE primary_key_table ADD CONSTRAINT not_null_set_null
  FOREIGN KEY (id) REFERENCES a (id)
  ON DELETE SET NULL;

statement error pq: cannot add a SET NULL cascading action on column "test.public.primary_key_table.id" which has a NOT NULL constraint
ALTER TABLE primary_key_table ADD CONSTRAINT not_null_set_null
  FOREIGN KEY (id) REFERENCES a (id)
  ON UPDATE SET NULL;

# Clean up the tables used so far.
statement ok
DROP TABLE primary_key_table, a;

# Now test composite foreign keys
statement ok
CREATE TABLE a (
  id1 INT
 ,id2 INT
 ,PRIMARY KEY (id2, id1)
);

# Create a table with a NOT NULL column and a SET NULL action.
statement error pq: cannot add a SET NULL cascading action on column "test.public.not_null_table.ref1" which has a NOT NULL constraint
CREATE TABLE not_null_table (
  id INT PRIMARY KEY
 ,ref1 INT NOT NULL
 ,ref2 INT NOT NULL
 ,INDEX (ref1, ref2)
 ,FOREIGN KEY (ref1, ref2) REFERENCES a (id2, id1) ON DELETE SET NULL
);

statement error pq: cannot add a SET NULL cascading action on column "test.public.not_null_table.ref1" which has a NOT NULL constraint
CREATE TABLE not_null_table (
  id INT PRIMARY KEY
 ,ref1 INT NOT NULL
 ,ref2 INT NOT NULL
 ,INDEX (ref1, ref2)
 ,FOREIGN KEY (ref1, ref2) REFERENCES a (id2, id1) ON UPDATE SET NULL
);

statement error pq: cannot add a SET NULL cascading action on column "test.public.not_null_table.ref1" which has a NOT NULL constraint
CREATE TABLE not_null_table (
  id INT PRIMARY KEY
 ,ref1 INT NOT NULL
 ,ref2 INT
 ,INDEX (ref1, ref2)
 ,FOREIGN KEY (ref1, ref2) REFERENCES a (id2, id1) ON DELETE SET NULL
);

statement error pq: cannot add a SET NULL cascading action on column "test.public.not_null_table.ref1" which has a NOT NULL constraint
CREATE TABLE not_null_table (
  id INT PRIMARY KEY
 ,ref1 INT NOT NULL
 ,ref2 INT
 ,INDEX (ref1, ref2)
 ,FOREIGN KEY (ref1, ref2) REFERENCES a (id2, id1) ON UPDATE SET NULL
);

statement error pq: cannot add a SET NULL cascading action on column "test.public.not_null_table.ref2" which has a NOT NULL constraint
CREATE TABLE not_null_table (
  id INT PRIMARY KEY
 ,ref1 INT
 ,ref2 INT NOT NULL
 ,INDEX (ref1, ref2)
 ,FOREIGN KEY (ref1, ref2) REFERENCES a (id2, id1) ON DELETE SET NULL
);

statement error pq: cannot add a SET NULL cascading action on column "test.public.not_null_table.ref2" which has a NOT NULL constraint
CREATE TABLE not_null_table (
  id INT PRIMARY KEY
 ,ref1 INT
 ,ref2 INT NOT NULL
 ,INDEX (ref1, ref2)
 ,FOREIGN KEY (ref1, ref2) REFERENCES a (id2, id1) ON UPDATE SET NULL
);

# Create a table where the primary key has a SET NULL action.
statement error pq: cannot add a SET NULL cascading action on column "test.public.primary_key_table.ref1" which has a NOT NULL constraint
CREATE TABLE primary_key_table (
  ref1 INT
 ,ref2 INT
 ,PRIMARY KEY (ref2, ref1)
 ,FOREIGN KEY (ref1, ref2) REFERENCES a (id2, id1) ON DELETE SET NULL
);

# Create a table where the primary key has a SET NULL action.
statement error pq: cannot add a SET NULL cascading action on column "test.public.primary_key_table.ref1" which has a NOT NULL constraint
CREATE TABLE primary_key_table (
  ref1 INT
 ,ref2 INT
 ,PRIMARY KEY (ref2, ref1)
 ,FOREIGN KEY (ref1, ref2) REFERENCES a (id2, id1) ON UPDATE SET NULL
);

statement error pq: cannot add a SET NULL cascading action on column "test.public.primary_key_table.ref2" which has a NOT NULL constraint
CREATE TABLE primary_key_table (
  ref1 INT
 ,ref2 INT
 ,PRIMARY KEY (ref2, ref1)
 ,FOREIGN KEY (ref2, ref1) REFERENCES a (id2, id1) ON DELETE SET NULL
);

statement error pq: cannot add a SET NULL cascading action on column "test.public.primary_key_table.ref2" which has a NOT NULL constraint
CREATE TABLE primary_key_table (
  ref1 INT
 ,ref2 INT
 ,PRIMARY KEY (ref2, ref1)
 ,FOREIGN KEY (ref2, ref1) REFERENCES a (id2, id1) ON UPDATE SET NULL
);

# Clean up after the test.
statement ok
DROP TABLE a;

subtest setDefaultWithoutDefault
### Make sure that one cannot add a SET DEFAULT action with no default values
### on a column.

statement ok
CREATE TABLE a (
  id INT PRIMARY KEY
);

# Create a table with no DEFAULT expressions column and a SET DEFAULT action.
statement ok
CREATE TABLE delete_no_default_table (
  id INT PRIMARY KEY
 ,delete_no_default INT REFERENCES a ON DELETE SET DEFAULT
);

statement error pq: cannot add a SET DEFAULT cascading action on column "test.public.update_no_default_table.update_no_default" which has a NOT NULL constraint and a NULL default expression
CREATE TABLE update_no_default_table (
  id INT PRIMARY KEY
 ,update_no_default INT NOT NULL REFERENCES a ON UPDATE SET DEFAULT
);

# Create a table where the primary key has a SET DEFAULT action.
# Primary keys are not allowed to be NULL
statement error pq: cannot add a SET DEFAULT cascading action on column "test.public.primary_key_table_set_default.id" which has a NOT NULL constraint and a NULL default expression
CREATE TABLE primary_key_table_set_default (
  id INT PRIMARY KEY REFERENCES a ON DELETE SET DEFAULT
);

statement error pq: cannot add a SET DEFAULT cascading action on column "test.public.primary_key_table.id" which has a NOT NULL constraint and a NULL default expression
CREATE TABLE primary_key_table (
  id INT PRIMARY KEY REFERENCES a ON UPDATE SET DEFAULT
);

# Add a SET DEFAULT action after the to a column with no DEFAULT expression.
statement ok
CREATE TABLE no_default_table (
  id INT PRIMARY KEY
 ,delete_no_default INT
 ,update_no_default INT
);

statement ok
ALTER TABLE no_default_table ADD CONSTRAINT no_default_delete_set_default
  FOREIGN KEY (delete_no_default) REFERENCES a (id)
  ON DELETE SET DEFAULT;

statement ok
ALTER TABLE no_default_table ADD CONSTRAINT no_default_update_set_default
  FOREIGN KEY (update_no_default) REFERENCES a (id)
  ON UPDATE SET DEFAULT;

# Clean up so far,
statement ok
DROP TABLE no_default_table;

# Add a SET DEFAULT action after the fact with a primary key column that has no
# DEFAULT expression.
statement ok
CREATE TABLE primary_key_table (
  id INT PRIMARY KEY
);

# id is a primary key and thus cannot be NULL
statement error pq: cannot add a SET DEFAULT cascading action on column "test.public.primary_key_table.id" which has a NOT NULL constraint and a NULL default expression
ALTER TABLE primary_key_table ADD CONSTRAINT no_default_delete_set_default
  FOREIGN KEY (id) REFERENCES a (id)
  ON DELETE SET DEFAULT;

statement error pq: cannot add a SET DEFAULT cascading action on column "test.public.primary_key_table.id" which has a NOT NULL constraint and a NULL default expression
ALTER TABLE primary_key_table ADD CONSTRAINT no_default_update_set_default
  FOREIGN KEY (id) REFERENCES a (id)
  ON UPDATE SET DEFAULT;

# Clean up the tables used so far.
statement ok
DROP TABLE primary_key_table, delete_no_default_table, a;

# Now test composite foreign keys
statement ok
CREATE TABLE a (
  id1 INT
 ,id2 INT
 ,PRIMARY KEY (id2, id1)
);

# Create a table with a column without a DEFAULT expression and a SET DEFAULT action.
statement ok
CREATE TABLE no_default_table (
  id INT PRIMARY KEY
 ,ref1 INT
 ,ref2 INT
 ,INDEX (ref1, ref2)
 ,FOREIGN KEY (ref1, ref2) REFERENCES a (id2, id1) ON DELETE SET DEFAULT
);

statement ok
INSERT INTO a VALUES (1, 2)

statement ok
INSERT INTO a VALUES (3, 4)

statement ok
INSERT INTO no_default_table VALUES (6, 2, 1)

query III colnames
SELECT * FROM no_default_table
----
id  ref1  ref2
6   2     1

statement ok
DELETE FROM a WHERE id1=1

query III colnames
SELECT * FROM no_default_table
----
id  ref1  ref2
6   NULL  NULL

statement ok
CREATE TABLE no_default_table_on_update (
  id INT PRIMARY KEY
 ,ref1 INT
 ,ref2 INT
 ,INDEX (ref1, ref2)
 ,FOREIGN KEY (ref1, ref2) REFERENCES a (id2, id1) ON UPDATE SET DEFAULT
);

statement ok
INSERT INTO no_default_table_on_update VALUES (0, 4, 3)

query III colnames
SELECT * FROM no_default_table_on_update
----
id  ref1  ref2
0   4     3

statement ok
UPDATE a SET id1=33, id2=44 WHERE id1=3;

query III colnames
SELECT * FROM no_default_table_on_update
----
id  ref1  ref2
0   NULL  NULL

statement ok
CREATE TABLE no_default_table_ref2_default_on_delete (
  id INT PRIMARY KEY
 ,ref1 INT
 ,ref2 INT DEFAULT 1
 ,INDEX (ref1, ref2)
 ,FOREIGN KEY (ref1, ref2) REFERENCES a (id2, id1) ON DELETE SET DEFAULT
);

statement ok
CREATE TABLE no_default_table_ref2_default_on_update (
  id INT PRIMARY KEY
 ,ref1 INT
 ,ref2 INT DEFAULT 1
 ,INDEX (ref1, ref2)
 ,FOREIGN KEY (ref1, ref2) REFERENCES a (id2, id1) ON UPDATE SET DEFAULT
);

statement ok
CREATE TABLE no_default_table_ref1_default_on_delete (
  id INT PRIMARY KEY
 ,ref1 INT DEFAULT 1
 ,ref2 INT
 ,INDEX (ref1, ref2)
 ,FOREIGN KEY (ref1, ref2) REFERENCES a (id2, id1) ON DELETE SET DEFAULT
);

statement ok
CREATE TABLE no_default_table_ref1_default_on_update (
  id INT PRIMARY KEY
 ,ref1 INT DEFAULT 1
 ,ref2 INT
 ,INDEX (ref1, ref2)
 ,FOREIGN KEY (ref1, ref2) REFERENCES a (id2, id1) ON UPDATE SET DEFAULT
);

# Create a table with a NOT NULL column and a SET NULL action.
statement error pq: cannot add a SET DEFAULT cascading action on column "test.public.not_null_table.ref1" which has a NOT NULL constraint and a NULL default expression
CREATE TABLE not_null_table (
  id INT PRIMARY KEY
 ,ref1 INT NOT NULL
 ,ref2 INT NOT NULL
 ,INDEX (ref1, ref2)
 ,FOREIGN KEY (ref1, ref2) REFERENCES a (id2, id1) ON DELETE SET DEFAULT
);

# Clean up after the test.
statement ok
DROP TABLE a, no_default_table, no_default_table_on_update, no_default_table_ref2_default_on_delete,
no_default_table_ref2_default_on_update, no_default_table_ref1_default_on_delete,
no_default_table_ref1_default_on_update

subtest unvalidated_fk_plan

# To get an unvalidated foreign key for testing, use the loophole that we
# currently don't support adding a validated FK in the same transaction as
# CREATE TABLE

statement ok
CREATE TABLE a (
  x STRING NULL,
  y STRING NULL,
  z STRING NULL,
  CONSTRAINT "primary" PRIMARY KEY (z, y, x)
)

statement ok
CREATE TABLE b (
  a_y STRING NULL,
  a_x STRING NULL,
  a_z STRING NULL,
  INDEX idx (a_z, a_y, a_x)
)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', 'y1', 'z1')

statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) NOT VALID

statement error pq: foreign key violation: "b" row a_z='z1', a_y='y1', a_x='x2', rowid=[0-9]* has no match in "a"
ALTER TABLE b VALIDATE CONSTRAINT fk_ref

# Verify that the optimizer doesn't use an unvalidated constraint to simplify plans.
query TTT
SELECT
  s.a_z, s.a_y, s.a_x
FROM
  (SELECT * FROM b WHERE a_z IS NOT NULL AND a_y IS NOT NULL AND a_x IS NOT NULL) AS s
  LEFT JOIN a AS t ON s.a_z = t.z AND s.a_y = t.y AND s.a_x = t.x
WHERE
  t.z IS NULL
----
z1 y1 x2

statement ok
DROP TABLE a, b

subtest Composite_Simple
# Originally from 26748.

# Test composite key with two columns.
statement ok
CREATE TABLE a (
  x STRING NULL
 ,y STRING NULL
 ,CONSTRAINT "primary" PRIMARY KEY (y, x)
);

statement ok
CREATE TABLE b (
 a_y STRING NULL
 ,a_x STRING NULL
 ,CONSTRAINT fk_ref FOREIGN KEY (a_y, a_x) REFERENCES a (y, x)
);

statement ok
INSERT INTO a (x, y) VALUES ('x1', 'y1')

# All of these are allowed because we do composite matching using MATCH SIMPLE.
statement ok
INSERT INTO b (a_x) VALUES ('x1')

statement ok
INSERT INTO b (a_y) VALUES ('y1')

statement ok
INSERT INTO b (a_y, a_x) VALUES ('y1', NULL)

statement ok
INSERT INTO b (a_y, a_x) VALUES (NULL, 'x1')

statement ok
INSERT INTO b (a_x, a_y) VALUES ('x1', 'y1')

statement ok
INSERT INTO b (a_x, a_y) VALUES (NULL, NULL)

statement ok
DROP TABLE b, a

# Test composite key with three columns.
statement ok
CREATE TABLE a (
  x STRING NULL
 ,y STRING NULL
 ,z STRING NULL
 ,CONSTRAINT "primary" PRIMARY KEY (z, y, x)
);

statement ok
CREATE TABLE b (
  a_y STRING NULL
 ,a_x STRING NULL
 ,a_z STRING NULL
 ,CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x)
);

statement ok
INSERT INTO a (x, y, z) VALUES ('x1', 'y1', 'z1')

# All of these are allowed because we do composite matching using MATCH SIMPLE.
statement ok
INSERT INTO b (a_x) VALUES ('x1')

statement ok
INSERT INTO b (a_y) VALUES ('y1')

statement ok
INSERT INTO b (a_z) VALUES ('z1')

statement ok
INSERT INTO b (a_x, a_y) VALUES ('x1', 'y1')

statement ok
INSERT INTO b (a_x, a_y) VALUES (NULL, 'y1')

statement ok
INSERT INTO b (a_x, a_y) VALUES ('x1', NULL)

statement ok
INSERT INTO b (a_x, a_z) VALUES ('x1', 'z1')

statement ok
INSERT INTO b (a_x, a_z) VALUES (NULL, 'z1')

statement ok
INSERT INTO b (a_x, a_z) VALUES ('x1', NULL)

statement ok
INSERT INTO b (a_y, a_z) VALUES ('y1', 'z1')

statement ok
INSERT INTO b (a_y, a_z) VALUES (NULL, 'z1')

statement ok
INSERT INTO b (a_y, a_z) VALUES ('y1', NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', NULL, NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y1', NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, NULL, 'z1')

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', 'y1', NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', NULL, 'z1')

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y1', 'z1')

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, NULL, NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', NULL, NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y2', NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, NULL, 'z2')

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', 'y2', NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', NULL, 'z2')

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y2', 'z2')

statement ok
DROP TABLE b, a

subtest Composite_Simple_Add_Constraint_Valid
# Test ADD CONSTRAINT validation by inserting valid rows before the constraint is added.

statement ok
CREATE TABLE a (
  x STRING NULL
 ,y STRING NULL
 ,z STRING NULL
 ,CONSTRAINT "primary" PRIMARY KEY (z, y, x)
);

statement ok
CREATE TABLE b (
  a_y STRING NULL
 ,a_x STRING NULL
 ,a_z STRING NULL
 ,INDEX idx (a_z, a_y, a_x)
);

statement ok
INSERT INTO a (x, y, z) VALUES ('x1', 'y1', 'z1')

# All of these are allowed because we do composite matching using MATCH SIMPLE.
statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', NULL, NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y1', NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, NULL, 'z1')

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', 'y1', NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', NULL, 'z1')

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y1', 'z1')

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, NULL, NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', NULL, NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y2', NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, NULL, 'z2')

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', 'y2', NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', NULL, 'z2')

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y2', 'z2')

statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x)

statement ok
DROP TABLE b, a

subtest Composite_Simple_Add_Constraint_Invalid
# Test ADD CONSTRAINT validation by inserting invalid rows before the constraint is added, one at a time.

statement ok
CREATE TABLE a (
  x STRING NULL
 ,y STRING NULL
 ,z STRING NULL
 ,CONSTRAINT "primary" PRIMARY KEY (z, y, x)
);

statement ok
CREATE TABLE b (
  a_y STRING NULL
 ,a_x STRING NULL
 ,a_z STRING NULL
 ,INDEX idx (a_z, a_y, a_x)
);

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', 'y1', 'z1')

statement error foreign key violation: "b" row a_z='z1', a_y='y1', a_x='x2', rowid=[0-9]* has no match in "a"
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x)

statement ok
TRUNCATE b

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', 'y2', 'z1')

statement error foreign key violation: "b" row a_z='z1', a_y='y2', a_x='x2', rowid=[0-9]* has no match in "a"
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x)

statement ok
TRUNCATE b

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', 'y2', 'z2')

statement error foreign key violation: "b" row a_z='z2', a_y='y2', a_x='x2', rowid=[0-9]* has no match in "a"
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x)

statement ok
DROP TABLE b, a

subtest Composite_Simple_Unvalidated
# Test inserting into table with an unvalidated constraint, and running VALIDATE CONSTRAINT later

# Test composite key with two columns.
statement ok
CREATE TABLE a (
  x STRING NULL
 ,y STRING NULL
 ,CONSTRAINT "primary" PRIMARY KEY (y, x)
);

statement ok
CREATE TABLE b (
  a_y STRING NULL
 ,a_x STRING NULL
);

# Add the constraint separately so that it's unvalidated, so we can test VALIDATE CONSTRAINT.
statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_y, a_x) REFERENCES a (y, x) NOT VALID

statement ok
INSERT INTO a (x, y) VALUES ('x1', 'y1')

# All of these are allowed because we do composite matching using MATCH SIMPLE.
statement ok
INSERT INTO b (a_x) VALUES ('x1')

statement ok
INSERT INTO b (a_y) VALUES ('y1')

statement ok
INSERT INTO b (a_y, a_x) VALUES ('y1', NULL)

statement ok
INSERT INTO b (a_y, a_x) VALUES (NULL, 'x1')

statement ok
INSERT INTO b (a_y, a_x) VALUES ('y2', NULL)

statement ok
INSERT INTO b (a_y, a_x) VALUES (NULL, 'x2')

statement ok
INSERT INTO b (a_x, a_y) VALUES ('x1', 'y1')

statement ok
INSERT INTO b (a_x, a_y) VALUES (NULL, NULL)

statement ok
ALTER TABLE b VALIDATE CONSTRAINT fk_ref

statement ok
DROP TABLE b, a

# Test composite key with three columns.
statement ok
CREATE TABLE a (
  x STRING NULL
 ,y STRING NULL
 ,z STRING NULL
 ,CONSTRAINT "primary" PRIMARY KEY (z, y, x)
);

statement ok
CREATE TABLE b (
  a_y STRING NULL
 ,a_x STRING NULL
 ,a_z STRING NULL
);

# Add the constraint separately so that it's unvalidated, so we can test VALIDATE CONSTRAINT.
statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) NOT VALID

statement ok
INSERT INTO a (x, y, z) VALUES ('x1', 'y1', 'z1')

# All of these are allowed because we do composite matching using MATCH SIMPLE.
statement ok
INSERT INTO b (a_x) VALUES ('x1')

statement ok
INSERT INTO b (a_y) VALUES ('y1')

statement ok
INSERT INTO b (a_z) VALUES ('z1')

statement ok
INSERT INTO b (a_x, a_y) VALUES ('x1', 'y1')

statement ok
INSERT INTO b (a_x, a_y) VALUES (NULL, 'y1')

statement ok
INSERT INTO b (a_x, a_y) VALUES ('x1', NULL)

statement ok
INSERT INTO b (a_x, a_z) VALUES ('x1', 'z1')

statement ok
INSERT INTO b (a_x, a_z) VALUES (NULL, 'z1')

statement ok
INSERT INTO b (a_x, a_z) VALUES ('x1', NULL)

statement ok
INSERT INTO b (a_y, a_z) VALUES ('y1', 'z1')

statement ok
INSERT INTO b (a_y, a_z) VALUES (NULL, 'z1')

statement ok
INSERT INTO b (a_y, a_z) VALUES ('y1', NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', NULL, NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y1', NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, NULL, 'z1')

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', 'y1', NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', NULL, 'z1')

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y1', 'z1')

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', NULL, NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y2', NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, NULL, 'z2')

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', 'y2', NULL)

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', NULL, 'z2')

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y2', 'z2')

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, NULL, NULL)

statement ok
ALTER TABLE b VALIDATE CONSTRAINT fk_ref

statement ok
DROP TABLE b, a

#subtest Composite_Simple_Validate_Constraint_Invalid

subtest Composite_Full
# Originally from 26748.

# Test composite key with two columns.
statement ok
CREATE TABLE a (
  x STRING NULL,
  y STRING NULL,
  CONSTRAINT "primary" PRIMARY KEY (y, x)
);

statement ok
CREATE TABLE b (
  a_y STRING NULL,
  a_x STRING NULL
);

# Add the constraint separately so that it's unvalidated, so we can test VALIDATE CONSTRAINT.
statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_y, a_x) REFERENCES a (y, x) MATCH FULL NOT VALID

statement ok
INSERT INTO a (x, y) VALUES ('x1', 'y1')

# These statements should all fail because this uses MATCH FULL.
statement error missing value for column "a_y" in multi-part foreign key
INSERT INTO b (a_x) VALUES ('x1')

statement error missing value for column "a_x" in multi-part foreign key
INSERT INTO b (a_y) VALUES ('y1')

statement error insert on table "b" violates foreign key constraint "fk_ref"\nDETAIL: MATCH FULL does not allow mixing of null and nonnull key values
INSERT INTO b (a_y, a_x) VALUES ('y1', NULL)

statement error insert on table "b" violates foreign key constraint "fk_ref"\nDETAIL: MATCH FULL does not allow mixing of null and nonnull key values
INSERT INTO b (a_y, a_x) VALUES (NULL, 'x1')

# These next two statements should still be allowed.
statement ok
INSERT INTO b (a_x, a_y) VALUES ('x1', 'y1')

statement ok
INSERT INTO b (a_x, a_y) VALUES (NULL, NULL)

statement ok
DROP TABLE b, a

# Test composite key with three columns.
statement ok
CREATE TABLE a (
  x STRING NULL,
  y STRING NULL,
  z STRING NULL,
  CONSTRAINT "primary" PRIMARY KEY (z, y, x)
);

statement ok
CREATE TABLE b (
  a_y STRING NULL,
  a_x STRING NULL,
  a_z STRING NULL
);

statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL NOT VALID

statement ok
INSERT INTO a (x, y, z) VALUES ('x1', 'y1', 'z1')

# These statements should all fail because this uses MATCH FULL.
statement error missing values for columns \["a_y" "a_z"\] in multi-part foreign key
INSERT INTO b (a_x) VALUES ('x1')

statement error missing values for columns \["a_x" "a_z"\] in multi-part foreign key
INSERT INTO b (a_y) VALUES ('y1')

statement error missing values for columns \["a_x" "a_y"\] in multi-part foreign key
INSERT INTO b (a_z) VALUES ('z1')

statement error missing value for column "a_z" in multi-part foreign key
INSERT INTO b (a_x, a_y) VALUES ('x1', 'y1')

statement error missing value for column "a_z" in multi-part foreign key
INSERT INTO b (a_x, a_y) VALUES (NULL, 'y1')

statement error missing value for column "a_z" in multi-part foreign key
INSERT INTO b (a_x, a_y) VALUES ('x1', NULL)

statement error missing value for column "a_y" in multi-part foreign key
INSERT INTO b (a_x, a_z) VALUES ('x1', 'z1')

statement error missing value for column "a_y" in multi-part foreign key
INSERT INTO b (a_x, a_z) VALUES (NULL, 'z1')

statement error missing value for column "a_y" in multi-part foreign key
INSERT INTO b (a_x, a_z) VALUES ('x1', NULL)

statement error missing value for column "a_x" in multi-part foreign key
INSERT INTO b (a_y, a_z) VALUES ('y1', 'z1')

statement error missing value for column "a_x" in multi-part foreign key
INSERT INTO b (a_y, a_z) VALUES (NULL, 'z1')

statement error missing value for column "a_x" in multi-part foreign key
INSERT INTO b (a_y, a_z) VALUES ('y1', NULL)

statement error insert on table "b" violates foreign key constraint "fk_ref"\nDETAIL: MATCH FULL does not allow mixing of null and nonnull key values
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', NULL, NULL)

statement error insert on table "b" violates foreign key constraint "fk_ref"\nDETAIL: MATCH FULL does not allow mixing of null and nonnull key values
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y1', NULL)

statement error insert on table "b" violates foreign key constraint "fk_ref"\nDETAIL: MATCH FULL does not allow mixing of null and nonnull key values
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, NULL, 'z1')

statement error insert on table "b" violates foreign key constraint "fk_ref"\nDETAIL: MATCH FULL does not allow mixing of null and nonnull key values
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', 'y1', NULL)

statement error insert on table "b" violates foreign key constraint "fk_ref"\nDETAIL: MATCH FULL does not allow mixing of null and nonnull key values
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', NULL, 'z1')

statement error insert on table "b" violates foreign key constraint "fk_ref"\nDETAIL: MATCH FULL does not allow mixing of null and nonnull key values
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y1', 'z1')

# This statement should still be allowed.
statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, NULL, NULL)

statement ok
DROP TABLE b, a

subtest Composite_Full_Add_Constraint_Valid
# Test ADD CONSTRAINT validation by inserting valid rows before the constraint is added.

statement ok
CREATE TABLE a (
  x STRING NULL
 ,y STRING NULL
 ,z STRING NULL
 ,CONSTRAINT "primary" PRIMARY KEY (z, y, x)
);

statement ok
CREATE TABLE b (
  a_y STRING NULL
 ,a_x STRING NULL
 ,a_z STRING NULL
 ,INDEX idx (a_z, a_y, a_x)
);

statement ok
INSERT INTO a (x, y, z) VALUES ('x1', 'y1', 'z1')

# This statement should still be allowed.
statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, NULL, NULL)

statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x)

statement ok
DROP TABLE b, a

subtest Composite_Full_Validate_Constraint_Invalid
# Test VALIDATE CONSTRAINT by inserting invalid rows before the constraint is added, one at a time.

statement ok
CREATE TABLE a (
  x STRING NULL
 ,y STRING NULL
 ,z STRING NULL
 ,CONSTRAINT "primary" PRIMARY KEY (z, y, x)
);

statement ok
CREATE TABLE b (
  a_y STRING NULL
 ,a_x STRING NULL
 ,a_z STRING NULL
 ,INDEX idx (a_z, a_y, a_x)
);

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', NULL, NULL)

statement error foreign key violation: MATCH FULL does not allow mixing of null and nonnull values
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL

statement ok
TRUNCATE b

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y1', NULL)

statement error foreign key violation: MATCH FULL does not allow mixing of null and nonnull values
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL

statement ok
TRUNCATE b

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, NULL, 'z1')

statement error foreign key violation: MATCH FULL does not allow mixing of null and nonnull values
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL

statement ok
TRUNCATE b

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', 'y1', NULL)

statement error foreign key violation: MATCH FULL does not allow mixing of null and nonnull values
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL

statement ok
TRUNCATE b

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', NULL, 'z1')

statement error foreign key violation: MATCH FULL does not allow mixing of null and nonnull values
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL

statement ok
TRUNCATE b

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y1', 'z1')

statement error foreign key violation: MATCH FULL does not allow mixing of null and nonnull values
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL

statement ok
TRUNCATE b

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', 'y1', 'z1')

statement error foreign key violation: "b" row a_z='z1', a_y='y1', a_x='x2', rowid=[0-9]* has no match in "a"
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL

statement ok
TRUNCATE b

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', 'y2', 'z1')

statement error foreign key violation: "b" row a_z='z1', a_y='y2', a_x='x2', rowid=[0-9]* has no match in "a"
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL

statement ok
TRUNCATE b

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', 'y2', 'z2')

statement error foreign key violation: "b" row a_z='z2', a_y='y2', a_x='x2', rowid=[0-9]* has no match in "a"
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL

statement ok
DROP TABLE b, a

subtest Composite_Full_Validate_Later
# Test inserting into table with an unvalidated constraint, and running VALIDATE CONSTRAINT later

# Test composite key with two columns.
statement ok
CREATE TABLE a (
  x STRING NULL
 ,y STRING NULL
 ,CONSTRAINT "primary" PRIMARY KEY (y, x)
);

statement ok
CREATE TABLE b (
  a_y STRING NULL
 ,a_x STRING NULL
);

# Add the constraint separately so that it's unvalidated, so we can test VALIDATE CONSTRAINT.
statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_y, a_x) REFERENCES a (y, x) MATCH FULL NOT VALID

statement ok
INSERT INTO a (x, y) VALUES ('x1', 'y1')

# These statements should all fail because this uses MATCH FULL.
statement error missing value for column "a_y" in multi-part foreign key
INSERT INTO b (a_x) VALUES ('x1')

statement error missing value for column "a_x" in multi-part foreign key
INSERT INTO b (a_y) VALUES ('y1')

statement error insert on table "b" violates foreign key constraint "fk_ref"\nDETAIL: MATCH FULL does not allow mixing of null and nonnull key values
INSERT INTO b (a_y, a_x) VALUES ('y1', NULL)

statement error insert on table "b" violates foreign key constraint "fk_ref"\nDETAIL: MATCH FULL does not allow mixing of null and nonnull key values
INSERT INTO b (a_y, a_x) VALUES (NULL, 'x1')

# These next two statements should still be allowed.
statement ok
INSERT INTO b (a_x, a_y) VALUES ('x1', 'y1')

statement ok
INSERT INTO b (a_x, a_y) VALUES (NULL, NULL)

statement ok
ALTER TABLE b VALIDATE CONSTRAINT fk_ref

statement ok
DROP TABLE b, a

# Test composite key with three columns.
statement ok
CREATE TABLE a (
  x STRING NULL
 ,y STRING NULL
 ,z STRING NULL
 ,CONSTRAINT "primary" PRIMARY KEY (z, y, x)
);

statement ok
CREATE TABLE b (
  a_y STRING NULL
 ,a_x STRING NULL
 ,a_z STRING NULL
);

# Add the constraint separately so that it's unvalidated, so we can test VALIDATE CONSTRAINT.
statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL NOT VALID

statement ok
INSERT INTO a (x, y, z) VALUES ('x1', 'y1', 'z1')

# These statements should all fail because this uses MATCH FULL.
statement error missing values for columns \["a_y" "a_z"\] in multi-part foreign key
INSERT INTO b (a_x) VALUES ('x1')

statement error missing values for columns \["a_x" "a_z"\] in multi-part foreign key
INSERT INTO b (a_y) VALUES ('y1')

statement error missing values for columns \["a_x" "a_y"\] in multi-part foreign key
INSERT INTO b (a_z) VALUES ('z1')

statement error missing value for column "a_z" in multi-part foreign key
INSERT INTO b (a_x, a_y) VALUES ('x1', 'y1')

statement error missing value for column "a_z" in multi-part foreign key
INSERT INTO b (a_x, a_y) VALUES (NULL, 'y1')

statement error missing value for column "a_z" in multi-part foreign key
INSERT INTO b (a_x, a_y) VALUES ('x1', NULL)

statement error missing value for column "a_y" in multi-part foreign key
INSERT INTO b (a_x, a_z) VALUES ('x1', 'z1')

statement error missing value for column "a_y" in multi-part foreign key
INSERT INTO b (a_x, a_z) VALUES (NULL, 'z1')

statement error missing value for column "a_y" in multi-part foreign key
INSERT INTO b (a_x, a_z) VALUES ('x1', NULL)

statement error missing value for column "a_x" in multi-part foreign key
INSERT INTO b (a_y, a_z) VALUES ('y1', 'z1')

statement error missing value for column "a_x" in multi-part foreign key
INSERT INTO b (a_y, a_z) VALUES (NULL, 'z1')

statement error missing value for column "a_x" in multi-part foreign key
INSERT INTO b (a_y, a_z) VALUES ('y1', NULL)

statement error insert on table "b" violates foreign key constraint "fk_ref"\nDETAIL: MATCH FULL does not allow mixing of null and nonnull key values
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', NULL, NULL)

statement error insert on table "b" violates foreign key constraint "fk_ref"\nDETAIL: MATCH FULL does not allow mixing of null and nonnull key values
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y1', NULL)

statement error insert on table "b" violates foreign key constraint "fk_ref"\nDETAIL: MATCH FULL does not allow mixing of null and nonnull key values
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, NULL, 'z1')

statement error insert on table "b" violates foreign key constraint "fk_ref"\nDETAIL: MATCH FULL does not allow mixing of null and nonnull key values
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', 'y1', NULL)

statement error insert on table "b" violates foreign key constraint "fk_ref"\nDETAIL: MATCH FULL does not allow mixing of null and nonnull key values
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', NULL, 'z1')

statement error insert on table "b" violates foreign key constraint "fk_ref"\nDETAIL: MATCH FULL does not allow mixing of null and nonnull key values
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y1', 'z1')

# This statement should still be allowed.
statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, NULL, NULL)

statement ok
ALTER TABLE b VALIDATE CONSTRAINT fk_ref

statement ok
DROP TABLE b, a

subtest Composite_Full_Validate_Constraint_Invalid
# Test VALIDATE CONSTRAINT by inserting invalid rows before the constraint is added, one at a time.

statement ok
CREATE TABLE a (
  x STRING NULL
 ,y STRING NULL
 ,z STRING NULL
 ,CONSTRAINT "primary" PRIMARY KEY (z, y, x)
);

statement ok
CREATE TABLE b (
  a_y STRING NULL
 ,a_x STRING NULL
 ,a_z STRING NULL
 ,INDEX idx (a_z, a_y, a_x)
);

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', NULL, NULL)

statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL NOT VALID

statement error foreign key violation: MATCH FULL does not allow mixing of null and nonnull values
ALTER TABLE b VALIDATE CONSTRAINT fk_ref

statement ok
TRUNCATE b

statement ok
ALTER TABLE b DROP CONSTRAINT fk_ref

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y1', NULL)

statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL NOT VALID

statement error foreign key violation: MATCH FULL does not allow mixing of null and nonnull values
ALTER TABLE b VALIDATE CONSTRAINT fk_ref

statement ok
TRUNCATE b

statement ok
ALTER TABLE b DROP CONSTRAINT fk_ref

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, NULL, 'z1')

statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL NOT VALID

statement error foreign key violation: MATCH FULL does not allow mixing of null and nonnull values
ALTER TABLE b VALIDATE CONSTRAINT fk_ref

statement ok
TRUNCATE b

statement ok
ALTER TABLE b DROP CONSTRAINT fk_ref

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', 'y1', NULL)

statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL NOT VALID

statement error foreign key violation: MATCH FULL does not allow mixing of null and nonnull values
ALTER TABLE b VALIDATE CONSTRAINT fk_ref

statement ok
TRUNCATE b

statement ok
ALTER TABLE b DROP CONSTRAINT fk_ref

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x1', NULL, 'z1')

statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL NOT VALID

statement error foreign key violation: MATCH FULL does not allow mixing of null and nonnull values
ALTER TABLE b VALIDATE CONSTRAINT fk_ref

statement ok
TRUNCATE b

statement ok
ALTER TABLE b DROP CONSTRAINT fk_ref

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES (NULL, 'y1', 'z1')

statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL NOT VALID

statement error foreign key violation: MATCH FULL does not allow mixing of null and nonnull values
ALTER TABLE b VALIDATE CONSTRAINT fk_ref

statement ok
TRUNCATE b

statement ok
ALTER TABLE b DROP CONSTRAINT fk_ref

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', 'y1', 'z1')

statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL NOT VALID

statement error pq: foreign key violation: "b" row a_z='z1', a_y='y1', a_x='x2', rowid=[0-9]* has no match in "a"
ALTER TABLE b VALIDATE CONSTRAINT fk_ref

statement ok
TRUNCATE b

statement ok
ALTER TABLE b DROP CONSTRAINT fk_ref

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', 'y2', 'z1')

statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL NOT VALID

statement error pq: foreign key violation: "b" row a_z='z1', a_y='y2', a_x='x2', rowid=[0-9]* has no match in "a"
ALTER TABLE b VALIDATE CONSTRAINT fk_ref

statement ok
TRUNCATE b

statement ok
ALTER TABLE b DROP CONSTRAINT fk_ref

statement ok
INSERT INTO b (a_x, a_y, a_z) VALUES ('x2', 'y2', 'z2')

statement ok
ALTER TABLE b ADD CONSTRAINT fk_ref FOREIGN KEY (a_z, a_y, a_x) REFERENCES a (z, y, x) MATCH FULL NOT VALID

statement error pq: foreign key violation: "b" row a_z='z2', a_y='y2', a_x='x2', rowid=[0-9]* has no match in "a"
ALTER TABLE b VALIDATE CONSTRAINT fk_ref

statement ok
DROP TABLE b, a

subtest auto_add_fk_with_composite_index_to_empty_table

statement ok
CREATE TABLE parent_composite_index (a_id INT NOT NULL, b_id INT NOT NULL, PRIMARY KEY (a_id, b_id))

statement ok
CREATE TABLE child_composite_index (id SERIAL NOT NULL, parent_a_id INT, parent_b_id INT, PRIMARY KEY (id))

# The (composite) index needed for the fk constraint is automatically added because the table is empty
statement ok
ALTER TABLE child_composite_index ADD CONSTRAINT fk_id FOREIGN KEY (parent_a_id, parent_b_id) REFERENCES parent_composite_index;

statement ok
INSERT INTO parent_composite_index VALUES (100, 200)

statement ok
INSERT INTO child_composite_index VALUES (1, 100, 200)

statement error insert on table "child_composite_index" violates foreign key constraint "fk_id"\nDETAIL: Key \(parent_a_id, parent_b_id\)=\(100, 300\) is not present in table "parent_composite_index"
INSERT INTO child_composite_index VALUES (2, 100, 300)

statement ok
DROP TABLE child_composite_index, parent_composite_index

subtest auto_add_fk_to_nonempty_table_error

statement ok
CREATE TABLE nonempty_a (id SERIAL NOT NULL, self_id INT, b_id INT NOT NULL, PRIMARY KEY (id))

statement ok
CREATE TABLE nonempty_b (id SERIAL NOT NULL, PRIMARY KEY (id))

statement ok
INSERT INTO nonempty_b VALUES (1), (2), (3);

statement ok
INSERT INTO nonempty_a VALUES (1, NULL, 1)

statement ok
ALTER TABLE nonempty_a ADD CONSTRAINT fk_self_id FOREIGN KEY (self_id) REFERENCES nonempty_a;

statement ok
ALTER TABLE nonempty_a ADD CONSTRAINT fk_b FOREIGN KEY (b_id) REFERENCES nonempty_b;

statement ok
DROP TABLE nonempty_a, nonempty_b

subtest auto_add_fk_index_name_collision

statement ok
CREATE TABLE parent_name_collision (id SERIAL NOT NULL, PRIMARY KEY (id))

statement ok
CREATE TABLE child_name_collision (id SERIAL NOT NULL, parent_id INT, other_col INT)

statement ok
CREATE INDEX child_name_collision_auto_index_fk_id ON child_name_collision (other_col)

# Testing the unusual case where an index already exists that has the same name
# as the index to be auto-generated when adding a fk constraint to an empty
# table (but the existing index is not on the referencing column), in which
# case the ALTER TABLE will create another name for the index.
statement ok
ALTER TABLE child_name_collision ADD CONSTRAINT fk_id FOREIGN KEY (parent_id) references parent_name_collision

subtest auto_add_fk_duplicate_cols_error

statement ok
CREATE TABLE parent (a_id INT, b_id INT, PRIMARY KEY (a_id, b_id))

statement ok
CREATE TABLE child_duplicate_cols (id INT, parent_id INT, PRIMARY KEY (id))

# The fk constraint is invalid because it has duplicate columns, so automatically adding the index fails
statement error pgcode 42830 foreign key contains duplicate column ".*parent_id"
ALTER TABLE child_duplicate_cols ADD CONSTRAINT fk FOREIGN KEY (parent_id, parent_id) references parent

statement ok
DROP TABLE parent, child_duplicate_cols

# Check that a FK cannot be added to a column being backfilled.
# If this behavior is changed you should create a test similar to
# TestCRUDWhileColumnBackfill to test that CRUD operations operating
# with FK relationships work correctly over NON NULL columns that
# are still being backfilled.
subtest cannot_add_fk_on_col_needing_backfill

statement ok
CREATE TABLE parentid (
    k INT NOT NULL PRIMARY KEY,
    v INT NOT NULL
);

statement ok
CREATE TABLE childid (
    id INT NOT NULL PRIMARY KEY
);

# Make tables non-empty.
statement ok
INSERT INTO parentid (k, v) VALUES (0, 1); INSERT INTO childid (id) VALUES (2);

statement error column \"id\" does not exist
BEGIN; ALTER TABLE parentid ADD id INT NOT NULL AS (k + 2) STORED; ALTER TABLE childid ADD CONSTRAINT fk_id FOREIGN KEY (id) REFERENCES parentid (id);

statement ok
ROLLBACK;

subtest dont_check_nulls
# Make sure that nulls are never checked while executing FK constraints.

statement ok
CREATE TABLE t1(x INT UNIQUE)

statement ok
INSERT INTO t1(x) VALUES (1), (null)

statement ok
CREATE TABLE t2(
  x INT REFERENCES t1(x)
)

statement ok
INSERT INTO t2(x) VALUES (1), (null)

statement ok
DELETE FROM t1 WHERE x IS NULL

statement ok
DROP TABLE t1, t2 CASCADE

subtest test_not_valid_fk

statement ok
CREATE TABLE person (id INT PRIMARY KEY, age INT, name STRING)

statement ok
CREATE TABLE pet (id INT PRIMARY KEY, name STRING)

statement ok
INSERT INTO pet VALUES (0, 'crookshanks')

statement error pq: foreign key violation: "pet" row id=0 has no match in "person"
ALTER TABLE pet ADD CONSTRAINT fk_constraint FOREIGN KEY (id) REFERENCES person (id)

statement ok
ALTER TABLE pet ADD CONSTRAINT fk_constraint FOREIGN KEY (id) REFERENCES person (id) NOT VALID

query TTTTB
SELECT * FROM [SHOW CONSTRAINTS FROM pet] ORDER BY constraint_name
----
pet  fk_constraint  FOREIGN KEY  FOREIGN KEY (id) REFERENCES person(id) NOT VALID  false
pet  pet_pkey       PRIMARY KEY  PRIMARY KEY (id ASC)                              true

statement error pq: foreign key violation: "pet" row id=0 has no match in "person"
ALTER TABLE pet VALIDATE CONSTRAINT fk_constraint

statement ok
INSERT INTO person VALUES (0, 18, 'Hermione Granger')

statement ok
ALTER TABLE pet VALIDATE CONSTRAINT fk_constraint

query TTTTB
SELECT * FROM [SHOW CONSTRAINTS FROM pet] ORDER BY constraint_name
----
pet  fk_constraint  FOREIGN KEY  FOREIGN KEY (id) REFERENCES person(id)  true
pet  pet_pkey       PRIMARY KEY  PRIMARY KEY (id ASC)                    true

statement ok
DROP TABLE person, pet

statement ok
DROP TABLE child

# Update
# ------

statement ok
CREATE TABLE parent (x INT, p INT PRIMARY KEY, u INT UNIQUE)

statement ok
CREATE TABLE child (c INT PRIMARY KEY, p INT NOT NULL REFERENCES parent(p))

statement ok
INSERT INTO parent (p, u) VALUES (1, 10), (2, 20)

statement ok
INSERT INTO child VALUES (1, 1)

# Updating the referenced table
statement error update on table "parent" violates foreign key constraint "child_p_fkey" on table "child"\nDETAIL: Key \(p\)=\(1\) is still referenced from table "child"\.
UPDATE parent SET p = 3 WHERE p = 1

statement ok
UPDATE parent SET p = 3 WHERE p = 2

statement ok
UPDATE parent SET p = 3 WHERE p = 10

# Updating the referencing table
statement ok
UPDATE child SET p = 3 WHERE p = 1

statement ok
DELETE FROM child

statement ok
DELETE FROM parent

statement ok
INSERT INTO parent (p, u) VALUES (2, 10), (3, 20)

statement ok
INSERT INTO child (c, p) VALUES (200, 2)

# These two test cases are sort of undefined behavior, since their
# success/failure depends on the order in which the updates are performed.
statement error duplicate key value violates unique constraint "parent_pkey"\nDETAIL: Key \(p\)=\(3\) already exists\.
UPDATE parent SET p = p + 1

statement ok
UPDATE parent SET p = p - 1

# This case illustrates why it's insufficient to just check the "old" values,
# even in the absence of temporary unique constraint violations. In this case,
# the "new" and "old" values are the same, so we have to ensure that we don't
# run deletion FK checks on old values which were replaced with new ones.
statement ok
UPDATE parent SET p = p

statement ok
CREATE TABLE self (x INT PRIMARY KEY, y INT NOT NULL REFERENCES self(x))

statement ok
INSERT INTO self VALUES (1, 2), (2, 3), (3, 4), (4, 1)

statement error update on table "self" violates foreign key constraint "self_y_fkey"
UPDATE self SET y = 5 WHERE y = 1

statement error update on table "self" violates foreign key constraint "self_y_fkey" on table "self"\nDETAIL: Key \(x\)=\(4\) is still referenced from table "self"\.
UPDATE self SET x = 5 WHERE y = 1

statement ok
TRUNCATE self

statement ok
INSERT INTO self VALUES (1, 1)

statement ok
UPDATE self SET x = 5, y = 5

statement ok
CREATE TABLE two (a int, b int, primary key (a, b))

statement ok
INSERT INTO two VALUES (1, 1), (1, 3), (3, 3)

statement ok
CREATE TABLE fam (
  a INT,
  b INT,
  c INT,
  d INT,
  e INT,
  FAMILY (a, b, c),
  FAMILY (d, e),
  FOREIGN KEY (c, d) REFERENCES two (a, b)
)

statement ok
INSERT INTO fam VALUES (10, 10, 1, 1, 10)

# Ensure that we fetch all relevant columns for a foreign key. Here we have
# FKs that span column families.

# NOTE: when we no longer require indexes to be created for FKs, ensure that
# these still scan all the relevant FK columns.
statement ok
UPDATE fam SET d = 3

statement ok
UPDATE fam SET c = 3

statement ok
CREATE TABLE match_full (
  a INT,
  b INT,
  FOREIGN KEY (a, b) REFERENCES two (a, b) MATCH FULL
)

statement ok
INSERT INTO match_full VALUES (1, 1)

statement error update on table "match_full" violates foreign key constraint "match_full_a_b_fkey"
UPDATE match_full SET a = NULL

statement ok
UPDATE match_full SET a = NULL, b = NULL

statement ok
CREATE TABLE match_simple (
  a INT,
  b INT,
  FOREIGN KEY (a, b) REFERENCES two (a, b) MATCH SIMPLE
)

statement ok
INSERT INTO match_simple VALUES (1, 1)

statement ok
UPDATE match_simple SET a = NULL

# Test that when the foreign key is a primary index we only look up the primary
# family.
subtest families

statement ok
CREATE TABLE fam_parent (
  k INT PRIMARY KEY,
  a INT,
  b INT NOT NULL,
  FAMILY (k, a),
  FAMILY (b)
)

statement ok
CREATE TABLE fam_child (
  k INT PRIMARY KEY,
  fk INT REFERENCES fam_parent(k)
)

statement ok
INSERT INTO fam_parent VALUES (1, 1, 1)

statement ok
GRANT ALL ON fam_parent TO testuser;
GRANT ALL ON fam_child TO testuser;

# Open a transaction that modifies b.
statement ok
BEGIN

statement count 1
UPDATE fam_parent SET b = b+1 WHERE k = 1

user testuser

# Run an INSERT which needs to check existence of the row. If we try to scan
# the entire row, this blocks on the other transaction. We should only be
# scanning the primary column family. A critical reason why this works is
# because column b is NOT NULL, so the UPDATE statement does not read or
# acquire FOR UPDATE locks on the primary column family because a lookup
# on b's column family is enough to determine whether the row exists or not.
statement ok
INSERT INTO fam_child VALUES (1, 1)

user root

statement ok
COMMIT

subtest foreign_key_multiple_output_columns

# Create a recursive table: messages refs good_users refs users.
# Sometimes, messages refs users directly.

statement ok
CREATE TABLE users (
  id INTEGER PRIMARY KEY
)

statement ok
CREATE TABLE good_users (
  id INTEGER PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE,
  id2 INTEGER UNIQUE
)

statement ok
CREATE SEQUENCE message_seq START 1 INCREMENT 1

statement ok
CREATE TABLE messages (
  message_id INT PRIMARY KEY DEFAULT nextval('message_seq'),
  user_id_1 integer REFERENCES good_users(id) ON DELETE CASCADE ON UPDATE CASCADE,
  user_id_2 integer REFERENCES good_users(id) ON DELETE CASCADE ON UPDATE CASCADE, -- this is recursive through good_users
  text string
)

# Add the same foreign key twice onto user.
statement ok
ALTER TABLE messages ADD FOREIGN KEY (user_id_1) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE

statement ok
ALTER TABLE messages ADD FOREIGN KEY (user_id_1) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE

# Insert some rows
statement ok
INSERT INTO users(id) VALUES (1), (2), (3)

statement ok
INSERT INTO good_users(id, id2) VALUES (1, 10), (2, 20), (3, 30)

statement ok
INSERT INTO messages (user_id_1, user_id_2, text) VALUES
  (1, 2, 'hi jordan'),
  (2, 1, 'hi oliver'),
  (1, 2, 'you are a good user jordan'),
  (1, 3, 'you are a good user too rohan'),
  (3, 1, 'lucy is a good user')

query error 999.*good_users
INSERT INTO messages (user_id_1, user_id_2, text) VALUES
  (999, 1, 'you are a bad user')

# Now try and update the user_id.
statement ok
update users set id = id * 10

# See that it propagates.
query I
SELECT * FROM users ORDER BY id ASC
----
10
20
30

query II
SELECT * FROM good_users ORDER BY id ASC
----
10  10
20  20
30  30

query IIT
SELECT user_id_1, user_id_2, text FROM messages ORDER BY message_id ASC
----
10  20  hi jordan
20  10  hi oliver
10  20  you are a good user jordan
10  30  you are a good user too rohan
30  10  lucy is a good user

# Delete from users should work as well
statement ok
DELETE FROM users WHERE id = 30

# See that it propagates.
query I
SELECT * FROM users ORDER BY id ASC
----
10
20

query II
SELECT * FROM good_users ORDER BY id ASC
----
10  10
20  20

query IIT
SELECT user_id_1, user_id_2, text FROM messages ORDER BY message_id ASC
----
10  20  hi jordan
20  10  hi oliver
10  20  you are a good user jordan

# Add a foreign key on id2, which is a different column.
# This one is restrictive on updates and deletes.
statement ok
ALTER TABLE messages ADD FOREIGN KEY (user_id_1) REFERENCES good_users(id2)

statement ok
ALTER TABLE good_users ADD FOREIGN KEY (id2) REFERENCES users(id)

# Updating should no longer work, since we have a restrict.
statement error update on table "users" violates foreign key constraint "good_users_id2_fkey" on table "good_users"\nDETAIL: Key \(id\)=\(20\) is still referenced from table "good_users"\.
UPDATE users SET id = id * 100 WHERE id = 20

# Insert some more stuff -- make sure it still behaves as expected.
statement ok
INSERT INTO users VALUES (40)

statement ok
INSERT INTO good_users VALUES (40, 40)

statement ok
INSERT INTO messages (user_id_1, user_id_2, text) VALUES
  (10, 40, 'oh hi mark'),
  (40, 10, 'youre tearing me apart lisa!')

query error 999.*good_users
INSERT INTO messages (user_id_1, user_id_2, text) VALUES
  (999, 40, 'johnny is my best friend')

# And sanity check everything.
query IIT
SELECT user_id_1, user_id_2, text FROM messages ORDER BY message_id ASC
----
10  20  hi jordan
20  10  hi oliver
10  20  you are a good user jordan
10  40  oh hi mark
40  10  youre tearing me apart lisa!

# Delete should still be okay since the cascade from id1 should "win".
statement ok
DELETE FROM users WHERE id = 20

query IIT
SELECT user_id_1, user_id_2, text FROM messages ORDER BY message_id ASC
----
10  40  oh hi mark
40  10  youre tearing me apart lisa!

# Drop everything.
statement ok
DROP TABLE users CASCADE

statement ok
DROP TABLE good_users CASCADE

statement ok
DROP TABLE messages

# Test conflicting foreign keys ON DELETE and ON UPDATE - some known corner cases.
# SET NULL/SET DEFAULT/CASCADE have priority and are evaluated in order, followed
# by RESTRICT/NO ACTION.

#
# ON DELETE
#

statement ok
CREATE TABLE t1 (a INT PRIMARY KEY); CREATE TABLE t2 (a INT DEFAULT 1)

# 'ON DELETE NO ACTION', followed by 'ON DELETE SET NULL'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON DELETE NO ACTION; ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON DELETE SET NULL

statement ok
insert into t1 values (123); insert into t2 values (123)

statement ok
DELETE FROM t1 WHERE a = 123

query I
SELECT * FROM t2
----
NULL

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

# 'ON DELETE NO ACTION', followed by 'ON DELETE CASCADE'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON DELETE NO ACTION;

statement ok
ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON DELETE CASCADE

statement ok
insert into t1 values (123); insert into t2 values (123)

statement ok
DELETE FROM t1 WHERE a = 123

query I
SELECT * FROM t2
----

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

# 'ON DELETE RESTRICT', followed by 'ON DELETE SET NULL'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON DELETE RESTRICT;

statement ok
ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON DELETE SET NULL

statement ok
insert into t1 values (123); insert into t2 values (123)

statement ok
DELETE FROM t1 WHERE a = 123

query I
SELECT * FROM t2
----
NULL

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

# 'ON DELETE RESTRICT', followed by 'ON DELETE CASCADE'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON DELETE RESTRICT;

statement ok
ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON DELETE CASCADE

statement ok
insert into t1 values (123); insert into t2 values (123)

statement ok
DELETE FROM t1 WHERE a = 123

query I
SELECT * FROM t2
----

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

# 'ON DELETE CASCADE', followed by 'ON DELETE SET DEFAULT'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON DELETE CASCADE;

statement ok
ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON DELETE SET DEFAULT

statement ok
insert into t1 values (123); insert into t2 values (123)

statement ok
DELETE FROM t1 WHERE a = 123

query I
SELECT * FROM t2
----

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

# 'ON DELETE CASCADE', followed by 'ON DELETE SET NULL'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON DELETE CASCADE;

statement ok
ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON DELETE SET NULL

statement ok
insert into t1 values (123); insert into t2 values (123)

statement ok
DELETE FROM t1 WHERE a = 123

query I
SELECT * FROM t2
----

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

# 'ON DELETE SET DEFAULT', followed by 'ON DELETE CASCADE'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON DELETE SET DEFAULT;
ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON DELETE CASCADE

statement ok
INSERT INTO t1 VALUES (123);
INSERT INTO t2 VALUES (123)

statement error pq: update on table "t2" violates foreign key constraint "fk1"\nDETAIL: Key \(a\)=\(1\) is not present in table "t1"\.
DELETE FROM t1 WHERE a = 123

query I
SELECT * FROM t2
----
123

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

# 'ON DELETE SET DEFAULT', followed by 'ON DELETE SET NULL'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON DELETE SET DEFAULT;
ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON DELETE SET NULL

statement ok
INSERT INTO t1 VALUES (123);
INSERT INTO t2 VALUES (123)

statement error pq: update on table "t2" violates foreign key constraint "fk1"\nDETAIL: Key \(a\)=\(1\) is not present in table "t1"\.
DELETE FROM t1 WHERE a = 123

query I
SELECT * FROM t2
----
123

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

# 'ON DELETE SET NULL', followed by 'ON DELETE SET DEFAULT'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON DELETE SET NULL;

statement ok
ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON DELETE SET DEFAULT

statement ok
insert into t1 values (123); insert into t2 values (123)

statement ok
DELETE FROM t1 WHERE a = 123

query I
SELECT * FROM t2
----
NULL

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

statement ok
DROP TABLE t2 CASCADE;

statement ok
DROP TABLE t1 CASCADE

#
# ON UPDATE
#

statement ok
CREATE TABLE t1 (a INT PRIMARY KEY);

statement ok
CREATE TABLE t2 (a INT DEFAULT 1)

# 'ON UPDATE NO ACTION', followed by 'ON UPDATE SET NULL'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON UPDATE NO ACTION;

statement ok
ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON UPDATE SET NULL

statement ok
insert into t1 values (123);

statement ok
insert into t2 values (123)

statement ok
UPDATE t1 SET a = 2 WHERE a = 123

query I
SELECT * FROM t2
----
NULL

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

# 'ON UPDATE NO ACTION', followed by 'ON UPDATE CASCADE'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON UPDATE NO ACTION;

statement ok
ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON UPDATE CASCADE

statement ok
insert into t1 values (123);

statement ok
insert into t2 values (123); UPDATE t1 SET a = 2 WHERE a = 123

query I
SELECT * FROM t2
----
2

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

# 'ON UPDATE RESTRICT', followed by 'ON UPDATE SET NULL'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON UPDATE RESTRICT;

statement ok
ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON UPDATE SET NULL

statement ok
insert into t1 values (123); insert into t2 values (123)

statement ok
UPDATE t1 SET a = 2 WHERE a = 123

query I
SELECT * FROM t2
----
NULL

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

# 'ON UPDATE RESTRICT', followed by 'ON UPDATE CASCADE'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON UPDATE RESTRICT;

statement ok
ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON UPDATE CASCADE

statement ok
insert into t1 values (123); insert into t2 values (123)

statement ok
UPDATE t1 SET a = 2 WHERE a = 123

query I
SELECT * FROM t2
----
2

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

# 'ON UPDATE CASCADE', followed by 'ON UPDATE SET DEFAULT'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON UPDATE CASCADE;

statement ok
ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON UPDATE SET DEFAULT

statement ok
insert into t1 values (123); insert into t2 values (123)

statement ok
UPDATE t1 SET a = 2 WHERE a = 123

query I
SELECT * FROM t2
----
2

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

# 'ON UPDATE CASCADE', followed by 'ON UPDATE SET NULL'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON UPDATE CASCADE;

statement ok
ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON UPDATE SET NULL

statement ok
insert into t1 values (123); insert into t2 values (123)

statement ok
UPDATE t1 SET a = 2 WHERE a = 123

query I
SELECT * FROM t2
----
2

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

# 'ON UPDATE SET DEFAULT', followed by 'ON UPDATE CASCADE'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON UPDATE SET DEFAULT

statement ok
ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON UPDATE CASCADE

statement ok
insert into t1 values (123); insert into t2 values (123)

statement error pq: update on table "t2" violates foreign key constraint "fk1"\nDETAIL: Key \(a\)=\(1\) is not present in table "t1"\.
UPDATE t1 SET a = 2 WHERE a = 123

query I
SELECT * FROM t2
----
123

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

# 'ON UPDATE SET DEFAULT', followed by 'ON UPDATE SET NULL'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON UPDATE SET DEFAULT;

statement ok
ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON UPDATE SET NULL

statement ok
insert into t1 values (123); insert into t2 values (123)

statement error update on table "t2" violates foreign key constraint "fk1"\nDETAIL: Key \(a\)=\(1\) is not present in table "t1"\.
UPDATE t1 SET a = 2 WHERE a = 123

query I
SELECT * FROM t2
----
123

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

# 'ON UPDATE SET NULL', followed by 'ON UPDATE SET DEFAULT'
statement ok
ALTER TABLE t2 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1 ON UPDATE SET NULL;

statement ok
ALTER TABLE t2 ADD CONSTRAINT fk2 FOREIGN KEY (a) REFERENCES t1 ON UPDATE SET DEFAULT

statement ok
insert into t1 values (123); insert into t2 values (123)

statement ok
UPDATE t1 SET a = 2 WHERE a = 123

query I
SELECT * FROM t2
----
NULL

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk1;

statement ok
ALTER TABLE t2 DROP CONSTRAINT fk2;

statement ok
TRUNCATE TABLE t2;

statement ok
TRUNCATE TABLE t1

statement ok
DROP TABLE t2 CASCADE;

statement ok
DROP TABLE t1 CASCADE

# Test FK check that is using a non-unique index (#43969). In this case the
# index on k2 is preferred because it doesn't contain unnecessary column v.
statement ok
CREATE TABLE nonunique_idx_parent (
  k1 INT,
  k2 INT,
  v INT,
  CONSTRAINT "primary" PRIMARY KEY (k1, k2),
  INDEX (k2)
)

statement ok
CREATE TABLE nonunique_idx_child (
  k INT PRIMARY KEY,
  ref1 INT,
  ref2 INT,
  CONSTRAINT "fk" FOREIGN KEY (ref1, ref2) REFERENCES nonunique_idx_parent (k1, k2)
)

statement ok
INSERT INTO nonunique_idx_parent VALUES (1, 10)

statement ok
INSERT INTO nonunique_idx_child VALUES (0, 1, 10)

# Stepping regression test. There was a bug where having cascades disables txn
# stepping which caused issues when executing postqueries, so a query which
# involved a mixed situation would error out.

statement ok
SET enable_multiple_modifications_of_table = true

statement ok
CREATE TABLE x (
    k INT PRIMARY KEY
)

statement ok
CREATE TABLE y (
    y INT PRIMARY KEY,
    b INT NULL REFERENCES x(k),
    c INT NULL REFERENCES x(k) ON DELETE CASCADE
)

statement ok
WITH
    a AS (INSERT INTO y VALUES (1) RETURNING 1), b AS (DELETE FROM x WHERE true RETURNING 1)
SELECT
    *
FROM
    a

statement ok
RESET enable_multiple_modifications_of_table

# Test that reversing a constraint addition after adding a self foreign key
# works correctly.

subtest reverse_failed_self_fk

statement ok
CREATE TABLE add_self_fk_fail (k int primary key, a int unique, b int);

statement ok
INSERT INTO add_self_fk_fail VALUES (1, 2, 3);

statement error foreign key violation: "add_self_fk_fail" row b=3, k=1 has no match in "add_self_fk_fail"
ALTER TABLE add_self_fk_fail ADD CONSTRAINT self_fk FOREIGN KEY (b) REFERENCES add_self_fk_fail (a);

# The error from running will be reported to the user but if there is an
# error reverting it will be in the jobs table. Ensure that there was no
# problem reverting the change.

query T
select error from [SHOW JOBS] WHERE description LIKE '%add_self_fk_fail%'
----
foreign key violation: "add_self_fk_fail" row b=3, k=1 has no match in "add_self_fk_fail"

statement ok
DROP TABLE add_self_fk_fail

# Test that we disallow cross-database foreign key references, depending on the
# cluster setting.

subtest cross_db_fks

statement ok
SET CLUSTER SETTING sql.cross_db_fks.enabled = FALSE

statement ok
CREATE DATABASE db1

statement ok
CREATE DATABASE db2

statement ok
USE db1

statement ok
CREATE TABLE parent (p INT PRIMARY KEY);

statement ok
CREATE TABLE child1 (c INT PRIMARY KEY, p INT REFERENCES parent(p))

statement ok
CREATE TABLE child2 (c INT PRIMARY KEY, p INT REFERENCES db1.public.parent(p))

statement ok
CREATE TABLE db1.public.child3 (c INT PRIMARY KEY, p INT REFERENCES db1.public.parent(p))

statement error foreign references between databases are not allowed
CREATE TABLE db2.public.child (c INT PRIMARY KEY, p INT REFERENCES parent(p))

statement ok
CREATE SCHEMA sc1

# Cross-schema references should always be allowed.
statement ok
CREATE TABLE db1.sc1.child (c INT PRIMARY KEY, p INT REFERENCES db1.public.parent(p))

statement ok
USE db2

statement error foreign references between databases are not allowed
CREATE TABLE child (c INT PRIMARY KEY, p INT REFERENCES db1.public.parent(p))

statement error foreign references between databases are not allowed
CREATE TABLE db2.public.child (c INT PRIMARY KEY, p INT REFERENCES db1.public.parent(p))

statement ok
CREATE TABLE child (c INT PRIMARY KEY, p INT)

statement error foreign references between databases are not allowed
ALTER TABLE child ADD CONSTRAINT fk FOREIGN KEY (p) REFERENCES db1.public.parent(p)

statement ok
USE db1

statement error foreign references between databases are not allowed
ALTER TABLE db2.public.child ADD CONSTRAINT fk FOREIGN KEY (p) REFERENCES parent(p)

statement ok
SET CLUSTER SETTING sql.cross_db_fks.enabled = TRUE

statement ok
ALTER TABLE db2.public.child ADD CONSTRAINT fk FOREIGN KEY (p) REFERENCES parent(p)

statement ok
USE db2

statement ok
CREATE TABLE child2 (c INT PRIMARY KEY, p INT REFERENCES db1.public.parent(p))


# Validate that cross DB foreign keys are detected by internal tables
query TTTTTTT
select * from "".crdb_internal.cross_db_references ORDER BY object_name
----
db2  public  child   db1  public  parent  table foreign key reference
db2  public  child2  db1  public  parent  table foreign key reference

# Ensure later tests only operate on the test database to avoid
# confusion.
statement ok
USE test;

statement ok
SET CLUSTER SETTING sql.cross_db_fks.enabled = FALSE


# Test that foreign keys cannot reference columns that are indexed by a partial
# unique index or a partial unique constraint. Partial unique indexes and
# constraints do not guarantee uniqueness in the entire table.

statement ok
SET experimental_enable_unique_without_index_constraints = true

statement ok
CREATE TABLE partial_parent (
  p INT,
  UNIQUE INDEX (p) WHERE p > 100,
  UNIQUE WITHOUT INDEX (p) WHERE p > 0
)

statement error there is no unique constraint matching given keys for referenced table partial_parent
CREATE TABLE partial_child (p INT REFERENCES partial_parent (p))

# Test that rowid can be referenced in a foreign key constraint.
subtest 59582_reference_rowid

statement ok
CREATE TABLE parent_59582(a INT);
CREATE TABLE child_59582(i INT);

statement ok
ALTER TABLE child_59582 ADD FOREIGN KEY (i) REFERENCES child_59582(rowid)

statement ok
DROP TABLE parent_59582, child_59582

# Regression test for #65890. Duplicate column IDs in the input of an insert
# fast path should not cause internal errors when shuffling columns during FK
# violations.
subtest 65890

statement ok
SET enable_insert_fast_path = true

statement ok
CREATE TABLE t65890_p (
  k INT PRIMARY KEY,
  a INT,
  b INT,
  UNIQUE (a),
  UNIQUE INDEX ba_idx (b, a),
  FAMILY (k, a, b)
)

statement ok
CREATE TABLE t65890_c (
  k INT PRIMARY KEY,
  b INT,
  a INT,
  FAMILY (k, b, a)
)

statement ok
ALTER TABLE t65890_c ADD CONSTRAINT fk FOREIGN KEY (a) REFERENCES t65890_p(a)

statement error insert on table "t65890_c" violates foreign key constraint "fk"\nDETAIL: Key \(a\)=\(1\) is not present in table "t65890_p"\.
INSERT INTO t65890_c SELECT 1, 1, 1

statement ok
ALTER TABLE t65890_c DROP CONSTRAINT fk

statement ok
ALTER TABLE t65890_c ADD CONSTRAINT fk FOREIGN KEY (a, b) REFERENCES t65890_p(a, b)

# Ensure that a fast path on ba_idx is used.
skipif config weak-iso-level-configs
query T
SELECT * FROM [EXPLAIN INSERT INTO t65890_c (k, b, a) VALUES (1, 2, 3)] OFFSET 3
----
• insert fast path
  into: t65890_c(k, b, a)
  auto commit
  FK check: t65890_p@ba_idx
  size: 3 columns, 1 row

onlyif config weak-iso-level-configs
query T
SELECT * FROM [EXPLAIN INSERT INTO t65890_c (k, b, a) VALUES (1, 2, 3)] OFFSET 3
----
• insert fast path
  into: t65890_c(k, b, a)
  auto commit
  FK check: t65890_p@ba_idx
  FK check locking strength: for share
  FK check locking durability: guaranteed
  size: 3 columns, 1 row

statement error insert on table "t65890_c" violates foreign key constraint "fk"\nDETAIL: Key \(a, b\)=\(3, 2\) is not present in table "t65890_p"\.
INSERT INTO t65890_c (k, b, a) VALUES (1, 2, 3)

statement error insert on table "t65890_c" violates foreign key constraint "fk"\nDETAIL: Key \(a, b\)=\(2, 2\) is not present in table "t65890_p"\.
INSERT INTO t65890_c SELECT 1, 2, 2

statement ok
SET enable_insert_fast_path = $enable_insert_fast_path

subtest reference_constraint_different_order

# https://github.com/cockroachdb/cockroach/issues/63324
# Referencing an existing constraint by fields in a different order
# should still find existing constraint.

statement ok
CREATE TABLE reference_constraint_different_order_parent (
  a INT8 NOT NULL,
  b INT8 NOT NULL,
  c INT8 NOT NULL,
  p_str VARCHAR(10),
  PRIMARY KEY (a, b, c)
);
CREATE TABLE reference_constraint_different_order_child (
  id INT8,
  x INT8,
  y INT8,
  z INT8,
  c_str VARCHAR(10)
)

statement ok
ALTER TABLE reference_constraint_different_order_child
  ADD CONSTRAINT p_fk FOREIGN KEY (x, y, z) REFERENCES reference_constraint_different_order_parent (a, c, b)

statement ok
INSERT
INTO
	reference_constraint_different_order_parent
VALUES (1, 2, 3, 'par_val');
INSERT
INTO reference_constraint_different_order_child
VALUES (99, 1, 3, 2, 'child_val')

query IIIITIIIT colnames
SELECT
	*
FROM
	reference_constraint_different_order_child
	NATURAL JOIN reference_constraint_different_order_parent
----
id  x  y  z  c_str      a  b  c  p_str
99  1  3  2  child_val  1  2  3  par_val

statement error insert on table "reference_constraint_different_order_child" violates foreign key constraint "p_fk"
INSERT
INTO reference_constraint_different_order_child
VALUES (99, 1, 2, 3, 'child_val')

# Regression test for #68307.
statement ok
CREATE TABLE t1 (a INT8 PRIMARY KEY);
CREATE TABLE t2 (a INT8 PRIMARY KEY);
CREATE TABLE t3 (a INT8 PRIMARY KEY, b INT8 REFERENCES t1 (a), c INT8 REFERENCES t2 (a));
INSERT INTO t1 VALUES (1);
INSERT INTO t2 VALUES (1);

statement error violates foreign key constraint "t3_b_fkey"
INSERT INTO t3 VALUES (1, 1, 1), (2, 2, NULL)

statement error violates foreign key constraint "t3_c_fkey"
INSERT INTO t3 VALUES (1, 1, 1), (2, NULL, 2)

statement ok
DROP TABLE t3, t1, t2

# Test notice is sent when foreign key col type is not identical to referenced
# col when either creating a new table or adding FK to an existing table
subtest notice_on_fk_ref_col_type_mismatch

statement ok
CREATE DATABASE db_type_test

statement ok
CREATE TABLE db_type_test.public.parent (id INT8 PRIMARY KEY, name STRING NULL)

# Weak isolation levels emit extra notices, so skip them.
skipif config weak-iso-level-configs
query T noticetrace
CREATE TABLE db_type_test.public.child_1 (id INT8 PRIMARY KEY, parent_id INT4 NULL REFERENCES db_type_test.public.parent(id), name STRING NULL)
----
NOTICE: type of foreign key column "parent_id" (INT4) is not identical to referenced column "parent"."id" (INT8)

onlyif config weak-iso-level-configs
statement ok
CREATE TABLE db_type_test.public.child_1 (id INT8 PRIMARY KEY, parent_id INT4 NULL REFERENCES db_type_test.public.parent(id), name STRING NULL)

statement ok
CREATE TABLE db_type_test.public.child_2 (id INT8 PRIMARY KEY, parent_id INT4 NULL, name STRING NULL)

# Weak isolation levels emit extra notices, so skip them.
skipif config weak-iso-level-configs
query T noticetrace
ALTER TABLE db_type_test.public.child_2 ADD CONSTRAINT child_2_fk_parent_id FOREIGN KEY (parent_id) REFERENCES db_type_test.public.parent(id)
----
NOTICE: type of foreign key column "parent_id" (INT4) is not identical to referenced column "parent"."id" (INT8)

onlyif config weak-iso-level-configs
statement ok
ALTER TABLE db_type_test.public.child_2 ADD CONSTRAINT child_2_fk_parent_id FOREIGN KEY (parent_id) REFERENCES db_type_test.public.parent(id)

statement ok
DROP DATABASE db_type_test

# Regression test for #76852. Correctly maintain child indexes on virtual
# columns during a cascading delete.
statement ok
CREATE TABLE p76852 (
  p STRING PRIMARY KEY,
  i INT
);
CREATE TABLE c76852 (
  b BOOL,
  v STRING AS (b::STRING) VIRTUAL,
  p STRING REFERENCES p76852 (p) ON DELETE CASCADE,
  PRIMARY KEY (p, b),
  INDEX idx (v)
);

statement ok
INSERT INTO p76852 (p, i) VALUES ('foo', 1);
INSERT INTO c76852 (b, p) VALUES (true, 'foo');
DELETE FROM p76852 WHERE true;

# Fast path case.
query B
SELECT b FROM c76852@idx WHERE b
----

statement ok
INSERT INTO p76852 (p, i) VALUES ('foo', 1);
INSERT INTO c76852 (b, p) VALUES (true, 'foo');
DELETE FROM p76852 WHERE i = 1;

# Non-fast path case.
query B
SELECT b FROM c76852@idx WHERE b
----

# Tests the scenario where a foreign key constraint is added and the table
# referencing it is dropped.
subtest 79972

statement ok
CREATE TABLE drop_fk_during_addition (name INT8);
CREATE TABLE drop_fk_during_addition_ref (name INT8 PRIMARY KEY);

statement ok
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ALTER TABLE drop_fk_during_addition
	ADD CONSTRAINT fk FOREIGN KEY (name) REFERENCES drop_fk_during_addition_ref (name);
DROP TABLE drop_fk_during_addition_ref;

statement error pgcode XXA00 pq: transaction committed but schema change aborted with error: .* referenced table "drop_fk_during_addition_ref" \(271\) is dropped.*
COMMIT;

# Regression test for #80828. Do not attempt a fast path cascading delete when
# a descendent is in the process of being added.
subtest 80828

statement ok
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
CREATE TABLE parent80828 (id int primary key);
CREATE TABLE child80828 (id INT PRIMARY KEY, pid INT NOT NULL REFERENCES parent80828(id) ON DELETE CASCADE, UNIQUE INDEX (pid));
INSERT INTO parent80828 VALUES (1);
INSERT INTO child80828 VALUES (1, 1);
COMMIT;

statement ok
SET CLUSTER SETTING jobs.registry.interval.base = .00001;

# Set a pause point so that grandchild stays in the "adding" state.
statement ok
SET CLUSTER SETTING jobs.debug.pausepoints = 'schemachanger.before.exec'

# See issue #87266, this table prevents the legacy schema changer from dropping
# the database, which is unexpected
skipif config local-legacy-schema-changer
statement error job .* was paused before it completed with reason: pause point "schemachanger.before.exec" hit
CREATE TABLE grandchild80828 (parent_id INT NOT NULL REFERENCES child80828(pid) ON DELETE CASCADE);

statement ok
DELETE FROM parent80828 WHERE id = 1;

# Clear the pause point.
statement ok
RESET CLUSTER SETTING jobs.debug.pausepoints

statement ok
RESET CLUSTER SETTING jobs.registry.interval.base

query I
SELECT count(*) FROM parent80828
----
0

query I
SELECT count(*) FROM child80828
----
0

# See #104546 which was a regression when an invalid column name was specified,
# when adding a FK reference.
subtest unknown_column_name

statement ok
create table t104546 (a int primary key);
create table t104546_fk_src (a int primary key, b int);

statement error pgcode 42703 column "b" does not exist
alter table t104546 add constraint con foreign key (b) references t104546_fk_src(b);

statement ok
create schema sc1;
create schema sc2;
create table sc1.parent (p int primary key);
create table sc2.child(p int primary key, r int REFERENCES sc1.parent (p));

query TTTTTT rowsort
SELECT constraint_catalog, constraint_schema, constraint_name, unique_constraint_catalog, unique_constraint_schema, unique_constraint_name
FROM  information_schema.referential_constraints WHERE unique_constraint_schema='sc1';
----
test  sc2  child_r_fkey  test  sc1  parent_pkey

subtest ensure_notice_when_fk_type_not_equal_in_alter

statement ok
CREATE TABLE t1_fk ( pk INT PRIMARY KEY, col1 CHAR(7), col2 INT4, UNIQUE (col1,col2), FAMILY f1 (pk,col1,col2) );

skipif config weak-iso-level-configs
query T noticetrace
CREATE TABLE t2_fk ( pk INT PRIMARY KEY, t1_fk_col1 CHAR(8), t1_fk_col2 INT4, col3 INT, FOREIGN KEY (t1_fk_col1,t1_fk_col2) REFERENCES t1_fk(col1, col2), FAMILY f1 (pk,t1_fk_col1,t1_fk_col2) );
----
NOTICE: type of foreign key column "t1_fk_col1" (CHAR(8)) is not identical to referenced column "t1_fk"."col1" (CHAR(7))

onlyif config weak-iso-level-configs
query T noticetrace
CREATE TABLE t2_fk ( pk INT PRIMARY KEY, t1_fk_col1 CHAR(8), t1_fk_col2 INT4, col3 INT, FOREIGN KEY (t1_fk_col1,t1_fk_col2) REFERENCES t1_fk(col1, col2), FAMILY f1 (pk,t1_fk_col1,t1_fk_col2) );
----
NOTICE: setting transaction isolation level to SERIALIZABLE due to schema change
NOTICE: type of foreign key column "t1_fk_col1" (CHAR(8)) is not identical to referenced column "t1_fk"."col1" (CHAR(7))

# Test trivial data type change
skipif config local-legacy-schema-changer
skipif config weak-iso-level-configs
query T noticetrace
ALTER TABLE t2_fk ALTER COLUMN t1_fk_col2 SET DATA TYPE INT8
----
NOTICE: type of foreign key column "t1_fk_col2" (INT8) is not identical to referenced column "t1_fk"."col2" (INT4)

onlyif config weak-iso-level-configs
query T noticetrace
ALTER TABLE t2_fk ALTER COLUMN t1_fk_col2 SET DATA TYPE INT8
----
NOTICE: setting transaction isolation level to SERIALIZABLE due to schema change
NOTICE: type of foreign key column "t1_fk_col2" (INT8) is not identical to referenced column "t1_fk"."col2" (INT4)

# Test validation data type change
skipif config local-legacy-schema-changer weak-iso-level-configs
query T noticetrace
ALTER TABLE t2_fk ALTER COLUMN t1_fk_col1 SET DATA TYPE CHAR(5)
----
NOTICE: type of foreign key column "t1_fk_col1" (CHAR(5)) is not identical to referenced column "t1_fk"."col1" (CHAR(7))

onlyif config weak-iso-level-configs
query T noticetrace
ALTER TABLE t2_fk ALTER COLUMN t1_fk_col1 SET DATA TYPE CHAR(5)
----
NOTICE: setting transaction isolation level to SERIALIZABLE due to schema change
NOTICE: type of foreign key column "t1_fk_col1" (CHAR(5)) is not identical to referenced column "t1_fk"."col1" (CHAR(7))


skipif config local-legacy-schema-changer
query TT
SHOW CREATE TABLE t2_fk
----
t2_fk  CREATE TABLE public.t2_fk (
         pk INT8 NOT NULL,
         t1_fk_col1 CHAR(5) NULL,
         t1_fk_col2 INT8 NULL,
         col3 INT8 NULL,
         CONSTRAINT t2_fk_pkey PRIMARY KEY (pk ASC),
         CONSTRAINT t2_fk_t1_fk_col1_t1_fk_col2_fkey FOREIGN KEY (t1_fk_col1, t1_fk_col2) REFERENCES public.t1_fk(col1, col2),
         FAMILY f1 (pk, t1_fk_col1, t1_fk_col2, col3)
       )

statement ok
DROP TABLE t2_fk;
DROP TABLE t1_fk;

subtest end
