Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

executor: fix split table with large integers #21277

Merged
merged 9 commits into from
Mar 15, 2021
3 changes: 2 additions & 1 deletion ddl/backfilling.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,8 @@ func splitTableRanges(t table.PhysicalTable, store kv.Storage, startKey, endKey
return nil, errors.Trace(err)
}
if len(ranges) == 0 {
return nil, errors.Trace(errInvalidSplitRegionRanges)
errMsg := fmt.Sprintf("cannot find region in range [%s, %s]", startKey.String(), endKey.String())
return nil, errors.Trace(errInvalidSplitRegionRanges.GenWithStackByArgs(errMsg))
}
return ranges, nil
}
Expand Down
2 changes: 1 addition & 1 deletion errno/errname.go
Original file line number Diff line number Diff line change
Expand Up @@ -965,7 +965,7 @@ var MySQLErrName = map[uint16]*mysql.ErrMessage{
ErrUnknownTypeLength: mysql.Message("Unknown length for type %d", nil),
ErrUnknownFractionLength: mysql.Message("Unknown length for type %d and fraction %d", nil),
ErrInvalidDDLJobVersion: mysql.Message("Version %d of DDL job is greater than current one: %d", nil),
ErrInvalidSplitRegionRanges: mysql.Message("Failed to split region ranges", nil),
ErrInvalidSplitRegionRanges: mysql.Message("Failed to split region ranges: %s", nil),
ErrReorgPanic: mysql.Message("Reorg worker panic", nil),
ErrInvalidDDLState: mysql.Message("Invalid %s state: %v", nil),
ErrCancelledDDLJob: mysql.Message("Cancelled DDL job", nil),
Expand Down
5 changes: 5 additions & 0 deletions errors.toml
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,11 @@ error = '''
Export failed: %s
'''

["executor:8212"]
error = '''
Failed to split region ranges: %s
'''

["expression:1139"]
error = '''
Got error '%-.64s' from regexp
Expand Down
1 change: 1 addition & 0 deletions executor/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ var (
ErrRoleNotGranted = dbterror.ClassPrivilege.NewStd(mysql.ErrRoleNotGranted)
ErrDeadlock = dbterror.ClassExecutor.NewStd(mysql.ErrLockDeadlock)
ErrQueryInterrupted = dbterror.ClassExecutor.NewStd(mysql.ErrQueryInterrupted)
ErrInvalidSplitRegionRanges = dbterror.ClassExecutor.NewStd(mysql.ErrInvalidSplitRegionRanges)

ErrBRIEBackupFailed = dbterror.ClassExecutor.NewStd(mysql.ErrBRIEBackupFailed)
ErrBRIERestoreFailed = dbterror.ClassExecutor.NewStd(mysql.ErrBRIERestoreFailed)
Expand Down
26 changes: 17 additions & 9 deletions executor/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import (
"github.com/pingcap/tidb/ddl"
"github.com/pingcap/tidb/domain"
"github.com/pingcap/tidb/domain/infosync"
"github.com/pingcap/tidb/errno"
"github.com/pingcap/tidb/executor"
"github.com/pingcap/tidb/expression"
"github.com/pingcap/tidb/infoschema"
Expand Down Expand Up @@ -4736,9 +4737,7 @@ func (s *testSplitTable) TestSplitRegion(c *C) {
// Test for split index region.
// Check min value is more than max value.
tk.MustExec(`split table t index idx1 between (0) and (1000000000) regions 10`)
_, err = tk.Exec(`split table t index idx1 between (2,'a') and (1,'c') regions 10`)
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "Split index `idx1` region lower value (2,a) should less than the upper value (1,c)")
tk.MustGetErrCode(`split table t index idx1 between (2,'a') and (1,'c') regions 10`, errno.ErrInvalidSplitRegionRanges)

// Check min value is invalid.
_, err = tk.Exec(`split table t index idx1 between () and (1) regions 10`)
Expand Down Expand Up @@ -4768,9 +4767,7 @@ func (s *testSplitTable) TestSplitRegion(c *C) {
// Test for split table region.
tk.MustExec(`split table t between (0) and (1000000000) regions 10`)
// Check the lower value is more than the upper value.
_, err = tk.Exec(`split table t between (2) and (1) regions 10`)
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "Split table `t` region lower value 2 should less than the upper value 1")
tk.MustGetErrCode(`split table t between (2) and (1) regions 10`, errno.ErrInvalidSplitRegionRanges)

// Check the lower value is invalid.
_, err = tk.Exec(`split table t between () and (1) regions 10`)
Expand Down Expand Up @@ -4798,9 +4795,7 @@ func (s *testSplitTable) TestSplitRegion(c *C) {
c.Assert(err.Error(), Equals, "[types:1265]Incorrect value: 'aa' for column '_tidb_rowid'")

// Test split table region step is too small.
_, err = tk.Exec(`split table t between (0) and (100) regions 10`)
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "Split table `t` region step value should more than 1000, step 10 is invalid")
tk.MustGetErrCode(`split table t between (0) and (100) regions 10`, errno.ErrInvalidSplitRegionRanges)

// Test split region by syntax.
tk.MustExec(`split table t by (0),(1000),(1000000)`)
Expand All @@ -4823,6 +4818,19 @@ func (s *testSplitTable) TestSplitRegion(c *C) {
tk.MustQuery("split region for partition table t partition (p3,p4) between (100000000) and (1000000000) regions 5;").Check(testkit.Rows("8 1"))
}

func (s *testSplitTable) TestSplitRegionEdgeCase(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test;")

tk.MustExec("drop table if exists t;")
tk.MustExec("create table t(a bigint(20) auto_increment primary key);")
tk.MustExec("split table t between (-9223372036854775808) and (9223372036854775807) regions 16;")

tk.MustExec("drop table if exists t;")
tk.MustExec("create table t(a int(20) auto_increment primary key);")
tk.MustGetErrCode("split table t between (-9223372036854775808) and (9223372036854775807) regions 16;", errno.ErrDataOutOfRange)
}

func (s *testSplitTable) TestClusterIndexSplitTableIntegration(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("drop database if exists test_cluster_index_index_split_table_integration;")
Expand Down
11 changes: 7 additions & 4 deletions executor/split.go
Original file line number Diff line number Diff line change
Expand Up @@ -547,21 +547,24 @@ func (e *SplitTableRegionExec) calculateIntBoundValue() (lowerValue int64, step
lowerRecordID := e.lower[0].GetUint64()
upperRecordID := e.upper[0].GetUint64()
if upperRecordID <= lowerRecordID {
return 0, 0, errors.Errorf("Split table `%s` region lower value %v should less than the upper value %v", e.tableInfo.Name, lowerRecordID, upperRecordID)
errMsg := fmt.Sprintf("lower value %v should less than the upper value %v", lowerRecordID, upperRecordID)
return 0, 0, ErrInvalidSplitRegionRanges.GenWithStackByArgs(errMsg)
}
step = int64((upperRecordID - lowerRecordID) / uint64(e.num))
lowerValue = int64(lowerRecordID)
} else {
lowerRecordID := e.lower[0].GetInt64()
upperRecordID := e.upper[0].GetInt64()
if upperRecordID <= lowerRecordID {
return 0, 0, errors.Errorf("Split table `%s` region lower value %v should less than the upper value %v", e.tableInfo.Name, lowerRecordID, upperRecordID)
errMsg := fmt.Sprintf("lower value %v should less than the upper value %v", lowerRecordID, upperRecordID)
return 0, 0, ErrInvalidSplitRegionRanges.GenWithStackByArgs(errMsg)
}
step = (upperRecordID - lowerRecordID) / int64(e.num)
step = int64(uint64(upperRecordID-lowerRecordID) / uint64(e.num))
lowerValue = lowerRecordID
}
if step < minRegionStepValue {
return 0, 0, errors.Errorf("Split table `%s` region step value should more than %v, step %v is invalid", e.tableInfo.Name, minRegionStepValue, step)
errMsg := fmt.Sprintf("the region size is too small, expected at least %d, but got %d", step, minRegionStepValue)
return 0, 0, ErrInvalidSplitRegionRanges.GenWithStackByArgs(errMsg)
}
return lowerValue, step, nil
}
Expand Down