diff --git a/ddl/fktest/foreign_key_test.go b/ddl/fktest/foreign_key_test.go index df461fa048e5c..489e125dc8a3c 100644 --- a/ddl/fktest/foreign_key_test.go +++ b/ddl/fktest/foreign_key_test.go @@ -1810,3 +1810,28 @@ func TestForeignKeyAndConcurrentDDL(t *testing.T) { } } } + +func TestForeignKeyAndRenameIndex(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("set @@foreign_key_checks=1;") + tk.MustExec("use test") + tk.MustExec("create table t1 (id int key, b int, index idx1(b));") + tk.MustExec("create table t2 (id int key, b int, constraint fk foreign key (b) references t1(b));") + tk.MustExec("insert into t1 values (1,1),(2,2)") + tk.MustExec("insert into t2 values (1,1),(2,2)") + tk.MustGetDBError("insert into t2 values (3,3)", plannercore.ErrNoReferencedRow2) + tk.MustGetDBError("delete from t1 where id=1", plannercore.ErrRowIsReferenced2) + tk.MustExec("alter table t1 rename index idx1 to idx2") + tk.MustExec("alter table t2 rename index fk to idx") + tk.MustGetDBError("insert into t2 values (3,3)", plannercore.ErrNoReferencedRow2) + tk.MustGetDBError("delete from t1 where id=1", plannercore.ErrRowIsReferenced2) + tk.MustExec("alter table t2 drop foreign key fk") + tk.MustExec("alter table t2 add foreign key fk (b) references t1(b) on delete cascade on update cascade") + tk.MustExec("alter table t1 rename index idx2 to idx3") + tk.MustExec("alter table t2 rename index idx to idx0") + tk.MustExec("delete from t1 where id=1") + tk.MustQuery("select * from t1").Check(testkit.Rows("2 2")) + tk.MustQuery("select * from t2").Check(testkit.Rows("2 2")) + tk.MustExec("admin check table t1,t2") +} diff --git a/executor/fktest/foreign_key_test.go b/executor/fktest/foreign_key_test.go index 670c273b4cb1c..fb29d391aaf09 100644 --- a/executor/fktest/foreign_key_test.go +++ b/executor/fktest/foreign_key_test.go @@ -2745,3 +2745,97 @@ func TestForeignKeyMetaInKeyColumnUsage(t *testing.T) { "INFORMATION_SCHEMA.KEY_COLUMN_USAGE where CONSTRAINT_SCHEMA='test' and TABLE_NAME='t2' and REFERENCED_TABLE_SCHEMA is not null and REFERENCED_COLUMN_NAME is not null;"). Check(testkit.Rows("fk test t2 a test t1 a", "fk test t2 b test t1 b")) } + +func TestForeignKeyAndGeneratedColumn(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("set @@foreign_key_checks=1") + tk.MustExec("use test") + // Test foreign key with parent column is virtual generated column. + tk.MustExec("create table t1 (a int, b int as (a+1) virtual, index(b));") + tk.MustGetErrMsg("create table t2 (a int, b int, constraint fk foreign key(b) references t1(b));", "[schema:3733]Foreign key 'fk' uses virtual column 'b' which is not supported.") + // Test foreign key with child column is virtual generated column. + tk.MustExec("drop table t1") + tk.MustExec("create table t1 (a int key);") + tk.MustGetErrMsg("create table t2 (a int, c int as (a+1) virtual, constraint fk foreign key(c) references t1(a));", "[schema:3733]Foreign key 'fk' uses virtual column 'c' which is not supported.") + // Test foreign key with parent column is stored generated column. + tk.MustExec("drop table if exists t1,t2") + tk.MustExec("create table t1 (a int, b int as (a) stored, index(b));") + tk.MustExec("create table t2 (a int, b int, constraint fk foreign key(b) references t1(b) on delete cascade on update cascade);") + tk.MustExec("insert into t1 (a) values (1),(2)") + tk.MustExec("insert into t2 (a) values (1),(2)") + tk.MustExec("update t2 set b=a") + tk.MustExec("insert into t2 values (1,1),(2,2)") + tk.MustGetDBError("insert into t2 values (3,3)", plannercore.ErrNoReferencedRow2) + tk.MustQuery("select * from t2 order by a").Check(testkit.Rows("1 1", "1 1", "2 2", "2 2")) + tk.MustExec("update t1 set a=a+10 where a=1") + tk.MustQuery("select * from t1 order by a").Check(testkit.Rows("2 2", "11 11")) + tk.MustQuery("select * from t2 order by a").Check(testkit.Rows("1 11", "1 11", "2 2", "2 2")) + tk.MustExec("delete from t1 where a=2") + tk.MustQuery("select * from t1 order by a").Check(testkit.Rows("11 11")) + tk.MustQuery("select * from t2 order by a").Check(testkit.Rows("1 11", "1 11")) + // Test foreign key with parent and child column is stored generated column. + tk.MustExec("drop table if exists t1,t2") + tk.MustExec("create table t1 (a int, b int as (a) stored, index(b));") + tk.MustGetErrMsg("create table t2 (a int, b int as (a) stored, constraint fk foreign key(b) references t1(b) on update cascade);", "[ddl:3104]Cannot define foreign key with ON UPDATE CASCADE clause on a generated column.") + tk.MustGetErrMsg("create table t2 (a int, b int as (a) stored, constraint fk foreign key(b) references t1(b) on delete set null);", "[ddl:3104]Cannot define foreign key with ON DELETE SET NULL clause on a generated column.") + tk.MustExec("create table t2 (a int, b int as (a) stored, constraint fk foreign key(b) references t1(b));") + tk.MustExec("insert into t1 (a) values (1),(2)") + tk.MustExec("insert into t2 (a) values (1),(2)") + tk.MustGetDBError("insert into t2 (a) values (3)", plannercore.ErrNoReferencedRow2) + tk.MustQuery("select * from t2 order by a").Check(testkit.Rows("1 1", "2 2")) + tk.MustGetDBError("delete from t1 where b=1", plannercore.ErrRowIsReferenced2) + tk.MustGetDBError("update t1 set a=a+10 where a=1", plannercore.ErrRowIsReferenced2) + tk.MustExec("alter table t2 drop foreign key fk") + tk.MustExec("alter table t2 add foreign key fk (b) references t1(b) on delete cascade") + tk.MustExec("delete from t1 where a=1") + tk.MustQuery("select * from t1 order by a").Check(testkit.Rows("2 2")) + tk.MustQuery("select * from t2 order by a").Check(testkit.Rows("2 2")) +} + +func TestForeignKeyAndExpressionIndex(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("set @@foreign_key_checks=1") + tk.MustExec("use test") + tk.MustExec("create table t1 (a int, b int, index idx1 (b), index idx2 ((b*2)));") + tk.MustExec("create table t2 (a int, b int, index((b*2)), constraint fk foreign key(b) references t1(b));") + tk.MustExec("insert into t1 values (1,1),(2,2)") + tk.MustExec("insert into t2 values (1,1),(2,2)") + tk.MustGetDBError("insert into t2 values (3,3)", plannercore.ErrNoReferencedRow2) + tk.MustGetDBError("update t1 set b=b+10 where b=1", plannercore.ErrRowIsReferenced2) + tk.MustGetDBError("delete from t1 where b=1", plannercore.ErrRowIsReferenced2) + tk.MustGetErrMsg("alter table t1 drop index idx1", "[ddl:1553]Cannot drop index 'idx1': needed in a foreign key constraint") + tk.MustGetErrMsg("alter table t2 drop index fk", "[ddl:1553]Cannot drop index 'fk': needed in a foreign key constraint") + tk.MustExec("alter table t2 drop foreign key fk") + tk.MustExec("alter table t2 add foreign key fk (b) references t1(b) on delete set null on update cascade") + tk.MustExec("update t1 set b=b+10 where b=1") + tk.MustExec("delete from t1 where b=2") + tk.MustQuery("select * from t1 order by a").Check(testkit.Rows("1 11")) + tk.MustQuery("select * from t2 order by a").Check(testkit.Rows("1 11", "2 ")) + tk.MustExec("admin check table t1") + tk.MustExec("admin check table t2") +} + +func TestForeignKeyAndMultiValuedIndex(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("set @@foreign_key_checks=1") + tk.MustExec("use test") + tk.MustExec("create table t1 (id int primary key, a json, b int generated always as (a->'$.id') stored, index idx1(b), index idx2((cast(a ->'$.data' as signed array))))") + tk.MustExec("create table t2 (id int, b int, constraint fk foreign key(b) references t1(b));") + tk.MustExec(`insert into t1 (id, a) values (1, '{"id": "1", "data": [1,11,111]}')`) + tk.MustExec(`insert into t1 (id, a) values (2, '{"id": "2", "data": [2,22,222]}')`) + tk.MustExec("insert into t2 values (1,1),(2,2)") + tk.MustGetDBError("insert into t2 values (3,3)", plannercore.ErrNoReferencedRow2) + tk.MustGetDBError(`update t1 set a='{"id": "10", "data": [1,11,111]}' where id=1`, plannercore.ErrRowIsReferenced2) + tk.MustGetDBError(`delete from t1 where id=1`, plannercore.ErrRowIsReferenced2) + tk.MustExec("alter table t2 drop foreign key fk") + tk.MustExec("alter table t2 add foreign key fk (b) references t1(b) on delete set null on update cascade") + tk.MustExec(`update t1 set a='{"id": "10", "data": [1,11,111]}' where id=1`) + tk.MustExec(`delete from t1 where id=2`) + tk.MustQuery("select id,b from t1 order by id").Check(testkit.Rows("1 10")) + tk.MustQuery("select id,b from t2 order by id").Check(testkit.Rows("1 10", "2 ")) + tk.MustExec("admin check table t1") + tk.MustExec("admin check table t2") +}