diff --git a/ddl/db_partition_test.go b/ddl/db_partition_test.go index 1744a955b8410..58a1d9e92ea25 100644 --- a/ddl/db_partition_test.go +++ b/ddl/db_partition_test.go @@ -1478,6 +1478,40 @@ func TestAlterTableTruncatePartitionByListColumns(t *testing.T) { tk.MustQuery("select * from t").Check(testkit.Rows()) } +func TestAlterTableTruncatePartitionPreSplitRegion(t *testing.T) { + store, clean := testkit.CreateMockStore(t) + defer clean() + tk := testkit.NewTestKit(t, store) + atomic.StoreUint32(&ddl.EnableSplitTableRegion, 1) + tk.MustExec("set @@global.tidb_scatter_region=1;") + tk.MustExec("use test;") + + tk.MustExec("drop table if exists t1;") + tk.MustExec(`CREATE TABLE t1 (id int, c varchar(128), key c(c)) partition by range (id) ( + partition p0 values less than (10), + partition p1 values less than MAXVALUE)`) + re := tk.MustQuery("show table t1 regions") + rows := re.Rows() + require.Len(t, rows, 2) + tk.MustExec(`alter table t1 truncate partition p0`) + re = tk.MustQuery("show table t1 regions") + rows = re.Rows() + require.Len(t, rows, 2) + + tk.MustExec("drop table if exists t2;") + tk.MustExec(`CREATE TABLE t2(id bigint(20) NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) NONCLUSTERED) SHARD_ROW_ID_BITS=4 PRE_SPLIT_REGIONS=3 PARTITION BY RANGE (id) ( + PARTITION p1 VALUES LESS THAN (10), + PARTITION p2 VALUES LESS THAN (20), + PARTITION p3 VALUES LESS THAN (MAXVALUE))`) + re = tk.MustQuery("show table t2 regions") + rows = re.Rows() + require.Len(t, rows, 24) + tk.MustExec(`alter table t2 truncate partition p3`) + re = tk.MustQuery("show table t2 regions") + rows = re.Rows() + require.Len(t, rows, 24) +} + func TestCreateTableWithKeyPartition(t *testing.T) { store, clean := testkit.CreateMockStore(t) defer clean() diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index e9574e5dc0231..b7b6e0df0698f 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -3752,30 +3752,35 @@ func (d *ddl) TruncateTablePartition(ctx sessionctx.Context, ident ast.Ident, sp return errors.Trace(dbterror.ErrPartitionMgmtOnNonpartitioned) } - var pids []int64 - if spec.OnAllPartitions { - pids = make([]int64, len(meta.GetPartitionInfo().Definitions)) - for i, def := range meta.GetPartitionInfo().Definitions { - pids[i] = def.ID + getTruncatedParts := func(pi *model.PartitionInfo) (*model.PartitionInfo, error) { + if spec.OnAllPartitions { + return pi.Clone(), nil } - } else { + var defs []model.PartitionDefinition // MySQL allows duplicate partition names in truncate partition // so we filter them out through a hash - pidMap := make(map[int64]bool) + posMap := make(map[int]bool) for _, name := range spec.PartitionNames { - pid, err := tables.FindPartitionByName(meta, name.L) - if err != nil { - return errors.Trace(err) + pos := pi.FindPartitionDefinitionByName(name.L) + if pos < 0 { + return nil, errors.Trace(table.ErrUnknownPartition.GenWithStackByArgs(name.L, ident.Name.O)) + } + if _, ok := posMap[pos]; !ok { + defs = append(defs, pi.Definitions[pos]) + posMap[pos] = true } - pidMap[pid] = true - } - // linter makezero does not handle changing pids to zero length, - // so create a new var and then assign to pids... - newPids := make([]int64, 0, len(pidMap)) - for pid := range pidMap { - newPids = append(newPids, pid) } - pids = newPids + pi = pi.Clone() + pi.Definitions = defs + return pi, nil + } + pi, err := getTruncatedParts(meta.GetPartitionInfo()) + if err != nil { + return err + } + pids := make([]int64, 0, len(pi.Definitions)) + for i := range pi.Definitions { + pids = append(pids, pi.Definitions[i].ID) } job := &model.Job{ @@ -3789,11 +3794,16 @@ func (d *ddl) TruncateTablePartition(ctx sessionctx.Context, ident ast.Ident, sp } err = d.DoDDLJob(ctx, job) + err = d.callHookOnChanged(err) if err != nil { return errors.Trace(err) } - err = d.callHookOnChanged(err) - return errors.Trace(err) + if _, tb, err := d.getSchemaAndTableByIdent(ctx, ident); err == nil { + if p, err := getTruncatedParts(tb.Meta().GetPartitionInfo()); err == nil { + d.preSplitAndScatter(ctx, tb.Meta(), p) + } + } + return nil } func (d *ddl) DropTablePartition(ctx sessionctx.Context, ident ast.Ident, spec *ast.AlterTableSpec) error { diff --git a/parser/model/model.go b/parser/model/model.go index 05e3afbaa0ce4..4228708ae28d5 100644 --- a/parser/model/model.go +++ b/parser/model/model.go @@ -1092,15 +1092,15 @@ func (ci *PartitionDefinition) Clone() PartitionDefinition { } // FindPartitionDefinitionByName finds PartitionDefinition by name. -func (t *TableInfo) FindPartitionDefinitionByName(partitionDefinitionName string) *PartitionDefinition { +func (pi *PartitionInfo) FindPartitionDefinitionByName(partitionDefinitionName string) int { lowConstrName := strings.ToLower(partitionDefinitionName) - definitions := t.Partition.Definitions + definitions := pi.Definitions for i := range definitions { if definitions[i].Name.L == lowConstrName { - return &t.Partition.Definitions[i] + return i } } - return nil + return -1 } // IndexColumn provides index column info.