diff --git a/ddl/db_partition_test.go b/ddl/db_partition_test.go index 77121a00c9e99..62a1a9127544c 100644 --- a/ddl/db_partition_test.go +++ b/ddl/db_partition_test.go @@ -935,6 +935,76 @@ func (s *testIntegrationSuite4) TestAlterTableExchangePartition(c *C) { tk.MustExec("alter table e12 add index (a);") tk.MustGetErrCode("alter table e12 exchange partition p0 with table e14", tmysql.ErrPartitionExchangeDifferentOption) + // test for tiflash replica + tk.MustExec("create table e15 (a int) partition by hash(a) partitions 1;") + tk.MustExec("create table e16 (a int)") + tk.MustExec("alter table e15 set tiflash replica 1;") + tk.MustExec("alter table e16 set tiflash replica 2;") + + e15 := testGetTableByName(c, s.ctx, "test", "e15") + partition := e15.Meta().Partition + + err := domain.GetDomain(tk.Se).DDL().UpdateTableReplicaInfo(tk.Se, partition.Definitions[0].ID, true) + c.Assert(err, IsNil) + + e16 := testGetTableByName(c, s.ctx, "test", "e16") + err = domain.GetDomain(tk.Se).DDL().UpdateTableReplicaInfo(tk.Se, e16.Meta().ID, true) + c.Assert(err, IsNil) + + tk.MustGetErrCode("alter table e15 exchange partition p0 with table e16", tmysql.ErrTablesDifferentMetadata) + tk.MustExec("drop table e15, e16") + + tk.MustExec("create table e15 (a int) partition by hash(a) partitions 1;") + tk.MustExec("create table e16 (a int)") + tk.MustExec("alter table e15 set tiflash replica 1;") + tk.MustExec("alter table e16 set tiflash replica 1;") + + e15 = testGetTableByName(c, s.ctx, "test", "e15") + partition = e15.Meta().Partition + + err = domain.GetDomain(tk.Se).DDL().UpdateTableReplicaInfo(tk.Se, partition.Definitions[0].ID, true) + c.Assert(err, IsNil) + + e16 = testGetTableByName(c, s.ctx, "test", "e16") + err = domain.GetDomain(tk.Se).DDL().UpdateTableReplicaInfo(tk.Se, e16.Meta().ID, true) + c.Assert(err, IsNil) + + tk.MustExec("alter table e15 exchange partition p0 with table e16") + + e15 = testGetTableByName(c, s.ctx, "test", "e15") + + partition = e15.Meta().Partition + + c.Assert(e15.Meta().TiFlashReplica, NotNil) + c.Assert(e15.Meta().TiFlashReplica.Available, IsTrue) + c.Assert(e15.Meta().TiFlashReplica.AvailablePartitionIDs, DeepEquals, []int64{partition.Definitions[0].ID}) + + e16 = testGetTableByName(c, s.ctx, "test", "e16") + c.Assert(e16.Meta().TiFlashReplica, NotNil) + c.Assert(e16.Meta().TiFlashReplica.Available, IsTrue) + + tk.MustExec("drop table e15, e16") + tk.MustExec("create table e15 (a int) partition by hash(a) partitions 1;") + tk.MustExec("create table e16 (a int)") + tk.MustExec("alter table e16 set tiflash replica 1;") + + tk.MustExec("alter table e15 set tiflash replica 1 location labels 'a', 'b';") + + tk.MustGetErrCode("alter table e15 exchange partition p0 with table e16", tmysql.ErrTablesDifferentMetadata) + + tk.MustExec("alter table e16 set tiflash replica 1 location labels 'a', 'b';") + + e15 = testGetTableByName(c, s.ctx, "test", "e15") + partition = e15.Meta().Partition + + err = domain.GetDomain(tk.Se).DDL().UpdateTableReplicaInfo(tk.Se, partition.Definitions[0].ID, true) + c.Assert(err, IsNil) + + e16 = testGetTableByName(c, s.ctx, "test", "e16") + err = domain.GetDomain(tk.Se).DDL().UpdateTableReplicaInfo(tk.Se, e16.Meta().ID, true) + c.Assert(err, IsNil) + + tk.MustExec("alter table e15 exchange partition p0 with table e16") } func (s *testIntegrationSuite4) TestExchangePartitionTableCompatiable(c *C) { @@ -1134,7 +1204,6 @@ func (s *testIntegrationSuite4) TestExchangePartitionTableCompatiable(c *C) { tk.MustExec(t.exchangeSQL) } } - } func (s *testIntegrationSuite7) TestExchangePartitionExpressIndex(c *C) { diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index e4ba5dbbdf1c4..ac91b8e947a5e 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -2852,6 +2852,25 @@ func checkFieldTypeCompatible(ft *types.FieldType, other *types.FieldType) bool return true } +func checkTiFlashReplicaCompatible(source *model.TiFlashReplicaInfo, target *model.TiFlashReplicaInfo) bool { + if source == target { + return true + } + if source == nil || target == nil { + return false + } + if source.Count != target.Count || + source.Available != target.Available || len(source.LocationLabels) != len(target.LocationLabels) { + return false + } + for i, lable := range source.LocationLabels { + if target.LocationLabels[i] != lable { + return false + } + } + return true +} + func checkTableDefCompatible(source *model.TableInfo, target *model.TableInfo) error { // check auto_random if source.AutoRandomBits != target.AutoRandomBits || @@ -2859,7 +2878,7 @@ func checkTableDefCompatible(source *model.TableInfo, target *model.TableInfo) e source.Collate != target.Collate || source.ShardRowIDBits != target.ShardRowIDBits || source.MaxShardRowIDBits != target.MaxShardRowIDBits || - source.TiFlashReplica != target.TiFlashReplica { + !checkTiFlashReplicaCompatible(source.TiFlashReplica, target.TiFlashReplica) { return errors.Trace(ErrTablesDifferentMetadata) } if len(source.Cols()) != len(target.Cols()) { diff --git a/ddl/partition.go b/ddl/partition.go index 6791c91bab5a4..fda69dc48b570 100644 --- a/ddl/partition.go +++ b/ddl/partition.go @@ -812,6 +812,15 @@ func (w *worker) onExchangeTablePartition(d *ddlCtx, t *meta.Meta, job *model.Jo // exchange table meta id partDef.ID = nt.ID + if pt.TiFlashReplica != nil { + for i, id := range pt.TiFlashReplica.AvailablePartitionIDs { + if id == tempID { + pt.TiFlashReplica.AvailablePartitionIDs[i] = partDef.ID + break + } + } + } + err = t.UpdateTable(ptSchemaID, pt) if err != nil { job.State = model.JobStateCancelled