diff --git a/ddl/db_partition_test.go b/ddl/db_partition_test.go index 38aa43e4e7755..f359687210efc 100644 --- a/ddl/db_partition_test.go +++ b/ddl/db_partition_test.go @@ -2246,14 +2246,6 @@ func TestExchangePartitionTableCompatiable(t *testing.T) { "alter table pt8 exchange partition p0 with table nt8;", dbterror.ErrTablesDifferentMetadata, }, - { - // foreign key test - // Partition table doesn't support to add foreign keys in mysql - "create table pt9 (id int not null primary key auto_increment,t_id int not null) partition by hash(id) partitions 1;", - "create table nt9 (id int not null primary key auto_increment, t_id int not null,foreign key fk_id (t_id) references pt5(id));", - "alter table pt9 exchange partition p0 with table nt9;", - dbterror.ErrPartitionExchangeForeignKey, - }, { // Generated column (virtual) "create table pt10 (id int not null, lname varchar(30), fname varchar(100) generated always as (concat(lname,' ')) virtual) partition by hash(id) partitions 1;", diff --git a/ddl/fktest/foreign_key_test.go b/ddl/fktest/foreign_key_test.go index 349d9b39ea682..ba466a8cef07b 100644 --- a/ddl/fktest/foreign_key_test.go +++ b/ddl/fktest/foreign_key_test.go @@ -667,6 +667,28 @@ func TestCreateTableWithForeignKeyError(t *testing.T) { create: "create table t2 (id int key, constraint fk foreign key (id) references t1(name5678901234567890123456789012345678901234567890123456789012345));", err: "[ddl:1059]Identifier name 'name5678901234567890123456789012345678901234567890123456789012345' is too long", }, + // Test foreign key with temporary table + { + refer: "create temporary table t1 (id int key);", + create: "create table t2 (id int key, constraint fk foreign key (id) references t1(id));", + err: "[schema:1824]Failed to open the referenced table 't1'", + }, + { + refer: "create table t1 (id int key);", + create: "create temporary table t2 (id int key, constraint fk foreign key (id) references t1(id));", + err: "[schema:1215]Cannot add foreign key constraint", + }, + // Test foreign key with partition table + { + refer: "create table t1 (id int key) partition by hash(id) partitions 3;", + create: "create table t2 (id int key, constraint fk foreign key (id) references t1(id));", + err: "[schema:1506]Foreign key clause is not yet supported in conjunction with partitioning", + }, + { + refer: "create table t1 (id int key);", + create: "create table t2 (id int key, constraint fk foreign key (id) references t1(id)) partition by hash(id) partitions 3;", + err: "[schema:1506]Foreign key clause is not yet supported in conjunction with partitioning", + }, } for _, ca := range cases { tk.MustExec("drop table if exists t2") @@ -1415,6 +1437,40 @@ func TestAlterTableAddForeignKeyError(t *testing.T) { alter: "alter table t2 add constraint name5678901234567890123456789012345678901234567890123456789012345 foreign key (b) references t1(id)", err: "[ddl:1059]Identifier name 'name5678901234567890123456789012345678901234567890123456789012345' is too long", }, + // Test foreign key with temporary table. + { + prepares: []string{ + "create temporary table t1 (id int key);", + "create table t2 (a int, b int unique);", + }, + alter: "alter table t2 add constraint fk foreign key (b) references t1(id)", + err: "[schema:1824]Failed to open the referenced table 't1'", + }, + { + prepares: []string{ + "create table t1 (id int key);", + "create temporary table t2 (a int, b int unique);", + }, + alter: "alter table t2 add constraint fk foreign key (b) references t1(id)", + err: "[ddl:8200]TiDB doesn't support ALTER TABLE for local temporary table", + }, + // Test foreign key with partition table + { + prepares: []string{ + "create table t1 (id int key) partition by hash(id) partitions 3;", + "create table t2 (id int key);", + }, + alter: "alter table t2 add constraint fk foreign key (id) references t1(id)", + err: "[schema:1506]Foreign key clause is not yet supported in conjunction with partitioning", + }, + { + prepares: []string{ + "create table t1 (id int key);", + "create table t2 (id int key) partition by hash(id) partitions 3;;", + }, + alter: "alter table t2 add constraint fk foreign key (id) references t1(id)", + err: "[schema:1506]Foreign key clause is not yet supported in conjunction with partitioning", + }, } for i, ca := range cases { tk.MustExec("drop table if exists t2") @@ -1608,3 +1664,39 @@ func TestAddForeignKeyInBigTable(t *testing.T) { tk.MustExec("alter table employee add foreign key fk_1(pid) references employee(id)") require.Less(t, time.Since(start), time.Minute) } + +func TestForeignKeyWithCacheTable(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 refer cache table. + tk.MustExec("create table t1 (id int key);") + tk.MustExec("insert into t1 values (1),(2),(3),(4)") + tk.MustExec("alter table t1 cache;") + tk.MustExec("create table t2 (b int);") + tk.MustExec("alter table t2 add constraint fk foreign key (b) references t1(id) on delete cascade on update cascade") + tk.MustExec("insert into t2 values (1),(2),(3),(4)") + tk.MustGetDBError("insert into t2 values (5)", plannercore.ErrNoReferencedRow2) + tk.MustExec("update t1 set id = id+10 where id=1") + tk.MustExec("delete from t1 where id<10") + tk.MustQuery("select * from t1").Check(testkit.Rows("11")) + tk.MustQuery("select * from t2").Check(testkit.Rows("11")) + tk.MustExec("alter table t1 nocache;") + tk.MustExec("drop table t1,t2;") + + // Test add foreign key on cache table. + tk.MustExec("create table t1 (id int key);") + tk.MustExec("create table t2 (b int);") + tk.MustExec("alter table t2 add constraint fk foreign key (b) references t1(id) on delete cascade on update cascade") + tk.MustExec("alter table t2 cache;") + tk.MustExec("insert into t1 values (1),(2),(3),(4)") + tk.MustExec("insert into t2 values (1),(2),(3),(4)") + tk.MustGetDBError("insert into t2 values (5)", plannercore.ErrNoReferencedRow2) + tk.MustExec("update t1 set id = id+10 where id=1") + tk.MustExec("delete from t1 where id<10") + tk.MustQuery("select * from t1").Check(testkit.Rows("11")) + tk.MustQuery("select * from t2").Check(testkit.Rows("11")) + tk.MustExec("alter table t2 nocache;") + tk.MustExec("drop table t1,t2;") +} diff --git a/ddl/foreign_key.go b/ddl/foreign_key.go index e2506770e27c4..1a06719cb404b 100644 --- a/ddl/foreign_key.go +++ b/ddl/foreign_key.go @@ -266,6 +266,9 @@ func checkTableForeignKey(referTblInfo, tblInfo *model.TableInfo, fkInfo *model. if referTblInfo.TTLInfo != nil { return dbterror.ErrUnsupportedTTLReferencedByFK } + if referTblInfo.GetPartitionInfo() != nil || tblInfo.GetPartitionInfo() != nil { + return infoschema.ErrForeignKeyOnPartitioned + } // check refer columns in parent table. for i := range fkInfo.RefCols { diff --git a/errors.toml b/errors.toml index 7d5be840c0432..0c5f5765d1269 100644 --- a/errors.toml +++ b/errors.toml @@ -2411,6 +2411,11 @@ error = ''' Changing schema from '%-.192s' to '%-.192s' is not allowed. ''' +["schema:1506"] +error = ''' +Foreign key clause is not yet supported in conjunction with partitioning +''' + ["schema:1822"] error = ''' Failed to add the foreign key constraint. Missing index for constraint '%s' in the referenced table '%s' diff --git a/infoschema/error.go b/infoschema/error.go index a7e4929a35bcc..d89d3e3dc8201 100644 --- a/infoschema/error.go +++ b/infoschema/error.go @@ -64,6 +64,8 @@ var ( ErrKeyNotExists = dbterror.ClassSchema.NewStd(mysql.ErrKeyDoesNotExist) // ErrCannotAddForeign returns for foreign key exists. ErrCannotAddForeign = dbterror.ClassSchema.NewStd(mysql.ErrCannotAddForeign) + // ErrForeignKeyOnPartitioned returns for foreign key on partition table. + ErrForeignKeyOnPartitioned = dbterror.ClassSchema.NewStd(mysql.ErrForeignKeyOnPartitioned) // ErrForeignKeyNotMatch returns for foreign key not match. ErrForeignKeyNotMatch = dbterror.ClassSchema.NewStd(mysql.ErrWrongFkDef) // ErrIndexExists returns for index already exists.