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

ddl: Add some limit for auto_random (#17119) #18538

Merged
merged 2 commits into from
Jul 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions ddl/ddl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1113,6 +1113,10 @@ func setTableAutoRandomBits(ctx sessionctx.Context, tbInfo *model.TableInfo, col
if !allowAutoRandom {
return ErrInvalidAutoRandom.GenWithStackByArgs(autoid.AutoRandomExperimentalDisabledErrMsg)
}
if col.Tp.Tp != mysql.TypeLonglong {
return ErrInvalidAutoRandom.GenWithStackByArgs(
fmt.Sprintf(autoid.AutoRandomOnNonBigIntColumn, types.TypeStr(col.Tp.Tp)))
}
if !tbInfo.PKIsHandle || col.Name.Name.L != pkColName.L {
errMsg := fmt.Sprintf(autoid.AutoRandomPKisNotHandleErrMsg, col.Name.Name.O)
return ErrInvalidAutoRandom.GenWithStackByArgs(errMsg)
Expand All @@ -1132,9 +1136,9 @@ func setTableAutoRandomBits(ctx sessionctx.Context, tbInfo *model.TableInfo, col
layout := autoid.NewAutoRandomIDLayout(col.Tp, autoRandBits)
if autoRandBits == 0 {
return ErrInvalidAutoRandom.GenWithStackByArgs(autoid.AutoRandomNonPositive)
} else if autoRandBits >= layout.TypeBitsLength {
errMsg := fmt.Sprintf(autoid.AutoRandomOverflowErrMsg, col.Name.Name.L,
layout.TypeBitsLength, autoRandBits, col.Name.Name.L, layout.TypeBitsLength-1)
} else if autoRandBits > autoid.MaxAutoRandomBits {
errMsg := fmt.Sprintf(autoid.AutoRandomOverflowErrMsg,
autoid.MaxAutoRandomBits, autoRandBits, col.Name.Name.O)
return ErrInvalidAutoRandom.GenWithStackByArgs(errMsg)
}
tbInfo.AutoRandomBits = autoRandBits
Expand Down
87 changes: 42 additions & 45 deletions ddl/serial_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/pingcap/tidb/ddl"
ddlutil "github.com/pingcap/tidb/ddl/util"
"github.com/pingcap/tidb/domain"
"github.com/pingcap/tidb/errno"
"github.com/pingcap/tidb/infoschema"
"github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/meta"
Expand Down Expand Up @@ -848,18 +849,21 @@ func (s *testSerialSuite) TestAutoRandom(c *C) {
assertWithAutoInc := func(sql string) {
assertInvalidAutoRandomErr(sql, autoid.AutoRandomIncompatibleWithAutoIncErrMsg)
}
assertOverflow := func(sql, colType string, autoRandBits, maxFieldLength uint64) {
assertInvalidAutoRandomErr(sql, autoid.AutoRandomOverflowErrMsg, colType, maxFieldLength, autoRandBits, colType, maxFieldLength-1)
assertOverflow := func(sql, colName string, autoRandBits uint64) {
assertInvalidAutoRandomErr(sql, autoid.AutoRandomOverflowErrMsg, autoid.MaxAutoRandomBits, autoRandBits, colName)
}
assertModifyColType := func(sql string) {
assertInvalidAutoRandomErr(sql, autoid.AutoRandomModifyColTypeErrMsg)
tk.MustGetErrCode(sql, errno.ErrUnsupportedDDLOperation)
}
assertDefault := func(sql string) {
assertInvalidAutoRandomErr(sql, autoid.AutoRandomIncompatibleWithDefaultValueErrMsg)
}
assertNonPositive := func(sql string) {
assertInvalidAutoRandomErr(sql, autoid.AutoRandomNonPositive)
}
assertBigIntOnly := func(sql, colType string) {
assertInvalidAutoRandomErr(sql, autoid.AutoRandomOnNonBigIntColumn, colType)
}
mustExecAndDrop := func(sql string, fns ...func()) {
tk.MustExec(sql)
for _, f := range fns {
Expand All @@ -870,67 +874,62 @@ func (s *testSerialSuite) TestAutoRandom(c *C) {

testutil.ConfigTestUtils.SetupAutoRandomTestConfig()
defer testutil.ConfigTestUtils.RestoreAutoRandomTestConfig()

// Only bigint column can set auto_random
assertBigIntOnly("create table t (a char primary key auto_random(3), b int)", "char")
assertBigIntOnly("create table t (a varchar(255) primary key auto_random(3), b int)", "varchar")
assertBigIntOnly("create table t (a timestamp primary key auto_random(3), b int)", "timestamp")

// PKIsHandle, but auto_random is defined on non-primary key.
assertPKIsNotHandle("create table t (a bigint auto_random (3) primary key, b int auto_random (3))", "b")
assertPKIsNotHandle("create table t (a bigint auto_random (3), b int auto_random(3), primary key(a))", "b")
assertPKIsNotHandle("create table t (a bigint auto_random (3), b int auto_random(3) primary key)", "a")
assertPKIsNotHandle("create table t (a bigint auto_random (3) primary key, b bigint auto_random (3))", "b")
assertPKIsNotHandle("create table t (a bigint auto_random (3), b bigint auto_random(3), primary key(a))", "b")
assertPKIsNotHandle("create table t (a bigint auto_random (3), b bigint auto_random(3) primary key)", "a")

// PKIsNotHandle: no primary key.
assertPKIsNotHandle("create table t (a int auto_random(3), b int)", "a")
assertPKIsNotHandle("create table t (a bigint auto_random(3), b int)", "a")
// PKIsNotHandle: primary key is not integer column.
assertPKIsNotHandle("create table t (a char primary key auto_random(3), b int)", "a")
assertPKIsNotHandle("create table t (a varchar(255) primary key auto_random(3), b int)", "a")
assertPKIsNotHandle("create table t (a timestamp primary key auto_random(3), b int)", "a")
// PKIsNotHandle: primary key is not a single column.
assertPKIsNotHandle("create table t (a bigint auto_random(3), b int, primary key (a, b))", "a")
assertPKIsNotHandle("create table t (a int auto_random(3), b int, c char, primary key (a, c))", "a")
assertPKIsNotHandle("create table t (a bigint auto_random(3), b bigint, primary key (a, b))", "a")
assertPKIsNotHandle("create table t (a bigint auto_random(3), b int, c char, primary key (a, c))", "a")

// Can not set auto_random along with auto_increment.
assertWithAutoInc("create table t (a bigint auto_random(3) primary key auto_increment)")
assertWithAutoInc("create table t (a bigint primary key auto_increment auto_random(3))")
assertWithAutoInc("create table t (a bigint auto_increment primary key auto_random(3))")
assertWithAutoInc("create table t (a bigint auto_random(3) auto_increment, primary key (a))")

// Overflow data type max length.
assertOverflow("create table t (a bigint auto_random(65) primary key)", "a", 65, 64)
assertOverflow("create table t (a int auto_random(33) primary key)", "a", 33, 32)
assertOverflow("create table t (a mediumint auto_random(25) primary key)", "a", 25, 24)
assertOverflow("create table t (a smallint auto_random(17) primary key)", "a", 17, 16)
assertOverflow("create table t (a tinyint auto_random(9) primary key)", "a", 9, 8)

assertNonPositive("create table t (a bigint auto_random(0) primary key)")

// Can not set auto_random along with default.
assertDefault("create table t (a int auto_random primary key default 3)")
assertDefault("create table t (a bigint auto_random primary key default 3)")
assertDefault("create table t (a bigint auto_random(2) primary key default 5)")
mustExecAndDrop("create table t (a int auto_random primary key)", func() {
assertDefault("alter table t modify column a int auto_random default 3")
mustExecAndDrop("create table t (a bigint auto_random primary key)", func() {
assertDefault("alter table t modify column a bigint auto_random default 3")
})

// Basic usage.
mustExecAndDrop("create table t (a bigint auto_random(4) primary key, b varchar(255))")
mustExecAndDrop("create table t (a bigint primary key auto_random(4), b varchar(255))")
mustExecAndDrop("create table t (a bigint auto_random(4), b varchar(255), primary key (a))")
// Overflow data type max length.
assertOverflow("create table t (a bigint auto_random(64) primary key)", "a", 64)
assertOverflow("create table t (a bigint auto_random(16) primary key)", "a", 16)

// Different primary key field types.
assertNonPositive("create table t (a bigint auto_random(0) primary key)")
tk.MustGetErrMsg("create table t (a bigint auto_random(-1) primary key)",
`[parser:1064]You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use line 1 column 38 near "-1) primary key)" `)

// Basic usage.
mustExecAndDrop("create table t (a bigint auto_random(1) primary key)")
mustExecAndDrop("create table t (a bigint auto_random(4) primary key)")
mustExecAndDrop("create table t (a int auto_random(4) primary key)")
mustExecAndDrop("create table t (a mediumint auto_random(4) primary key)")
mustExecAndDrop("create table t (a smallint auto_random(4) primary key)")
mustExecAndDrop("create table t (a tinyint auto_random(4) primary key)")
mustExecAndDrop("create table t (a bigint auto_random(15) primary key)")
mustExecAndDrop("create table t (a bigint primary key auto_random(4))")
mustExecAndDrop("create table t (a bigint auto_random(4), primary key (a))")

// Auto_random can occur multiple times like other column attributes.
mustExecAndDrop("create table t (a bigint auto_random(3) auto_random(2) primary key)")
mustExecAndDrop("create table t (a int, b bigint auto_random(3) primary key auto_random(2))")
mustExecAndDrop("create table t (a int auto_random(1) auto_random(2) auto_random(3), primary key (a))")
mustExecAndDrop("create table t (a bigint, b bigint auto_random(3) primary key auto_random(2))")
mustExecAndDrop("create table t (a bigint auto_random(1) auto_random(2) auto_random(3), primary key (a))")

// Add/drop the auto_random attribute is not allowed.
mustExecAndDrop("create table t (a bigint auto_random(3) primary key)", func() {
assertAlterValue("alter table t modify column a bigint")
assertAlterValue("alter table t change column a b bigint")
})
mustExecAndDrop("create table t (a int, b char, c int auto_random(3), primary key(c))", func() {
mustExecAndDrop("create table t (a bigint, b char, c bigint auto_random(3), primary key(c))", func() {
assertAlterValue("alter table t modify column c bigint")
assertAlterValue("alter table t change column c d bigint")
})
Expand All @@ -940,7 +939,10 @@ func (s *testSerialSuite) TestAutoRandom(c *C) {
})

// Modifying the field type of a auto_random column is not allowed.
mustExecAndDrop("create table t (a tinyint primary key auto_random(3))", func() {
// Here the throw error is `ERROR 8200 (HY000): Unsupported modify column: length 11 is less than origin 20`,
// instead of `ERROR 8216 (HY000): Invalid auto random: modifying the auto_random column type is not supported`
// Because the origin column is `bigint`, it can not change to any other column type in TiDB limitation.
mustExecAndDrop("create table t (a bigint primary key auto_random(3))", func() {
assertModifyColType("alter table t modify column a int auto_random(3)")
assertModifyColType("alter table t modify column a mediumint auto_random(3)")
assertModifyColType("alter table t modify column a smallint auto_random(3)")
Expand All @@ -955,13 +957,8 @@ func (s *testSerialSuite) TestAutoRandom(c *C) {
c.Assert(tk.Se.GetSessionVars().StmtCtx.WarningCount(), Equals, uint16(0))
})
}
assertShowWarningCorrect("create table t (a tinyint unsigned auto_random(6) primary key)", 3)
assertShowWarningCorrect("create table t (a tinyint unsigned auto_random(5) primary key)", 7)
assertShowWarningCorrect("create table t (a tinyint auto_random(4) primary key)", 7)
assertShowWarningCorrect("create table t (a bigint auto_random(62) primary key)", 1)
assertShowWarningCorrect("create table t (a bigint unsigned auto_random(61) primary key)", 7)
assertShowWarningCorrect("create table t (a int auto_random(30) primary key)", 1)
assertShowWarningCorrect("create table t (a int auto_random(29) primary key)", 3)
assertShowWarningCorrect("create table t (a bigint auto_random(15) primary key)", 281474976710655)
assertShowWarningCorrect("create table t (a bigint unsigned auto_random(15) primary key)", 562949953421311)

// Test insert into auto_random column explicitly is not allowed by default.
assertExplicitInsertDisallowed := func(sql string) {
Expand Down
27 changes: 10 additions & 17 deletions executor/ddl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -854,36 +854,29 @@ func (s *testAutoRandomSuite) TestAutoRandomBitsData(c *C) {
}

// Test explicit insert.
tk.MustExec("create table t (a tinyint primary key auto_random(2), b int)")
for i := 1; i <= 100; i++ {
tk.MustExec("insert into t values (?, ?)", i, i)
autoRandBitsUpperBound := 2<<47 - 1
tk.MustExec("create table t (a bigint primary key auto_random(15), b int)")
for i := -10; i < 10; i++ {
tk.MustExec(fmt.Sprintf("insert into t values(%d, %d)", i+autoRandBitsUpperBound, i))
}
_, err := tk.Exec("insert into t (b) values (0)")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, autoid.ErrAutoRandReadFailed.GenWithStackByArgs().Error())
tk.MustExec("drop table t")

// Test overflow.
tk.MustExec("create table t (a tinyint primary key auto_random(2), b int)")
for i := 0; i < 31; /* 2^(8-2-1)-1 */ i++ {
tk.MustExec(fmt.Sprintf("insert into t (b) values (%d)", i))
}
_, err = tk.Exec("insert into t (b) values (0)")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, autoid.ErrAutoRandReadFailed.GenWithStackByArgs().Error())
tk.MustExec("drop table t")

// Test rebase.
tk.MustExec("create table t (a tinyint primary key auto_random(2), b int)")
tk.MustExec("insert into t values (31, 2)")
tk.MustExec("create table t (a bigint primary key auto_random(15), b int)")
// Here we cannot fill the all values for a `bigint` column,
// so firstly we rebase auto_rand to the position before overflow.
tk.MustExec(fmt.Sprintf("insert into t values (%d, %d)", autoRandBitsUpperBound, 1))
_, err = tk.Exec("insert into t (b) values (0)")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, autoid.ErrAutoRandReadFailed.GenWithStackByArgs().Error())
tk.MustExec("drop table t")

tk.MustExec("create table t (a tinyint primary key auto_random(2), b int)")
tk.MustExec("create table t (a bigint primary key auto_random(15), b int)")
tk.MustExec("insert into t values (1, 2)")
tk.MustExec("update t set a = 31 where a = 1")
tk.MustExec(fmt.Sprintf("update t set a = %d where a = 1", autoRandBitsUpperBound))
_, err = tk.Exec("insert into t (b) values (0)")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, autoid.ErrAutoRandReadFailed.GenWithStackByArgs().Error())
Expand Down
8 changes: 4 additions & 4 deletions executor/insert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -979,7 +979,7 @@ func (s *testSuite9) TestAutoRandomID(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec(`use test`)
tk.MustExec(`drop table if exists ar`)
tk.MustExec(`create table ar (id int key auto_random, name char(10))`)
tk.MustExec(`create table ar (id bigint key auto_random, name char(10))`)

tk.MustExec(`insert into ar(id) values (null)`)
rs := tk.MustQuery(`select id from ar`)
Expand Down Expand Up @@ -1028,7 +1028,7 @@ func (s *testSuite9) TestMultiAutoRandomID(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec(`use test`)
tk.MustExec(`drop table if exists ar`)
tk.MustExec(`create table ar (id int key auto_random, name char(10))`)
tk.MustExec(`create table ar (id bigint key auto_random, name char(10))`)

tk.MustExec(`insert into ar(id) values (null),(null),(null)`)
rs := tk.MustQuery(`select id from ar order by id`)
Expand Down Expand Up @@ -1077,7 +1077,7 @@ func (s *testSuite9) TestAutoRandomIDAllowZero(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec(`use test`)
tk.MustExec(`drop table if exists ar`)
tk.MustExec(`create table ar (id int key auto_random, name char(10))`)
tk.MustExec(`create table ar (id bigint key auto_random, name char(10))`)

rs := tk.MustQuery(`select @@session.sql_mode`)
sqlMode := rs.Rows()[0][0].(string)
Expand Down Expand Up @@ -1117,7 +1117,7 @@ func (s *testSuite9) TestAutoRandomIDExplicit(c *C) {

tk.MustExec(`use test`)
tk.MustExec(`drop table if exists ar`)
tk.MustExec(`create table ar (id int key auto_random, name char(10))`)
tk.MustExec(`create table ar (id bigint key auto_random, name char(10))`)

tk.MustExec(`insert into ar(id) values (1)`)
tk.MustQuery(`select id from ar`).Check(testkit.Rows("1"))
Expand Down
4 changes: 2 additions & 2 deletions executor/seqtest/seq_executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1255,7 +1255,7 @@ func (s *seqTestSuite) TestAutoRandIDRetry(c *C) {
tk.MustExec("create database if not exists auto_random_retry")
tk.MustExec("use auto_random_retry")
tk.MustExec("drop table if exists t")
tk.MustExec("create table t (id int auto_random(3) primary key)")
tk.MustExec("create table t (id bigint auto_random(3) primary key)")

extractMaskedOrderedHandles := func() []int64 {
handles, err := ddltestutil.ExtractAllTableHandles(tk.Se, "auto_random_retry", "t")
Expand Down Expand Up @@ -1331,7 +1331,7 @@ func (s *seqTestSuite) TestAutoRandRecoverTable(c *C) {
defer autoid.SetStep(stp)

// Check rebase auto_random id.
tk.MustExec("create table t_recover_auto_rand (a int auto_random(5) primary key);")
tk.MustExec("create table t_recover_auto_rand (a bigint auto_random(5) primary key);")
tk.MustExec("insert into t_recover_auto_rand values (),(),()")
tk.MustExec("drop table t_recover_auto_rand")
tk.MustExec("recover table t_recover_auto_rand")
Expand Down
8 changes: 6 additions & 2 deletions executor/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,12 @@ func rebaseAutoRandomValue(sctx sessionctx.Context, t table.Table, newData *type
if err != nil {
return err
}
shardBits := tableInfo.AutoRandomBits + 1 // sign bit is reserved.
recordID = recordID << shardBits >> shardBits
if recordID < 0 {
return nil
}
layout := autoid.NewAutoRandomIDLayout(&col.FieldType, tableInfo.AutoRandomBits)
// Set bits except incremental_bits to zero.
recordID = recordID & (1<<layout.IncrementalBits - 1)
return t.Allocators(sctx).Get(autoid.AutoRandomType).Rebase(tableInfo.ID, recordID, true)
}

Expand Down
4 changes: 2 additions & 2 deletions infoschema/tables_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -600,10 +600,10 @@ func (s *testTableSuite) TestTableRowIDShardingInfo(c *C) {
testutil.ConfigTestUtils.SetupAutoRandomTestConfig()
defer testutil.ConfigTestUtils.RestoreAutoRandomTestConfig()

tk.MustExec("CREATE TABLE `sharding_info_test_db`.`t4` (a int key auto_random)")
tk.MustExec("CREATE TABLE `sharding_info_test_db`.`t4` (a bigint key auto_random)")
assertShardingInfo("t4", "PK_AUTO_RANDOM_BITS=5")

tk.MustExec("CREATE TABLE `sharding_info_test_db`.`t5` (a int key auto_random(1))")
tk.MustExec("CREATE TABLE `sharding_info_test_db`.`t5` (a bigint key auto_random(1))")
assertShardingInfo("t5", "PK_AUTO_RANDOM_BITS=1")

tk.MustExec("DROP DATABASE `sharding_info_test_db`")
Expand Down
35 changes: 23 additions & 12 deletions meta/autoid/autoid.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ const RowIDBitLength = 64
// DefaultAutoRandomBits is the default value of auto sharding.
const DefaultAutoRandomBits = 5

// MaxAutoRandomBits is the max value of auto sharding.
const MaxAutoRandomBits = 15

// Test needs to change it, so it's a variable.
var step = int64(30000)

Expand Down Expand Up @@ -911,8 +914,14 @@ func TestModifyBaseAndEndInjection(alloc Allocator, base, end int64) {
}

// AutoRandomIDLayout is used to calculate the bits length of different section in auto_random id.
// Layout(64 bits):
// [zero_padding] [sign_bit] [shard_bits] [incremental_bits]
// The primary key with auto_random can only be `bigint` column, the total layout length of auto random is 64 bits.
// These are two type of layout:
// 1. Signed bigint:
// | [sign_bit] | [shard_bits] | [incremental_bits] |
// sign_bit(1 fixed) + shard_bits(15 max) + incremental_bits(the rest) = total_layout_bits(64 fixed)
// 2. Unsigned bigint:
// | [shard_bits] | [incremental_bits] |
// shard_bits(15 max) + incremental_bits(the rest) = total_layout_bits(64 fixed)
// Please always use NewAutoRandomIDLayout() to instantiate.
type AutoRandomIDLayout struct {
FieldType *types.FieldType
Expand All @@ -925,17 +934,19 @@ type AutoRandomIDLayout struct {

// NewAutoRandomIDLayout create an instance of AutoRandomIDLayout.
func NewAutoRandomIDLayout(fieldType *types.FieldType, shardBits uint64) *AutoRandomIDLayout {
layout := &AutoRandomIDLayout{
FieldType: fieldType,
ShardBits: shardBits,
}
layout.TypeBitsLength = uint64(mysql.DefaultLengthOfMysqlTypes[fieldType.Tp] * 8)
layout.HasSignBit = !mysql.HasUnsignedFlag(fieldType.Flag)
layout.IncrementalBits = layout.TypeBitsLength - shardBits
if layout.HasSignBit {
layout.IncrementalBits -= 1
typeBitsLength := uint64(mysql.DefaultLengthOfMysqlTypes[mysql.TypeLonglong] * 8)
incrementalBits := typeBitsLength - shardBits
hasSignBit := !mysql.HasUnsignedFlag(fieldType.Flag)
if hasSignBit {
incrementalBits -= 1
}
return &AutoRandomIDLayout{
FieldType: fieldType,
ShardBits: shardBits,
TypeBitsLength: typeBitsLength,
IncrementalBits: incrementalBits,
HasSignBit: hasSignBit,
}
return layout
}

// IncrementalBitsCapacity returns the max capacity of incremental section of the current layout.
Expand Down
Loading