Skip to content

Commit

Permalink
*: support auto_random on composite clustered primary key (pingcap#38617
Browse files Browse the repository at this point in the history
  • Loading branch information
ti-chi-bot authored Feb 13, 2023
1 parent 52ae590 commit df32e3a
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 25 deletions.
56 changes: 49 additions & 7 deletions ddl/ddl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1194,7 +1194,20 @@ func containsColumnOption(colDef *ast.ColumnDef, opTp ast.ColumnOptionType) bool

// IsAutoRandomColumnID returns true if the given column ID belongs to an auto_random column.
func IsAutoRandomColumnID(tblInfo *model.TableInfo, colID int64) bool {
return tblInfo.PKIsHandle && tblInfo.ContainsAutoRandomBits() && tblInfo.GetPkColInfo().ID == colID
if !tblInfo.ContainsAutoRandomBits() {
return false
}
if tblInfo.PKIsHandle {
return tblInfo.GetPkColInfo().ID == colID
} else if tblInfo.IsCommonHandle {
pk := tables.FindPrimaryIndex(tblInfo)
if pk == nil {
return false
}
offset := pk.Columns[0].Offset
return tblInfo.Columns[offset].ID == colID
}
return false
}

func checkGeneratedColumn(ctx sessionctx.Context, colDefs []*ast.ColumnDef) error {
Expand Down Expand Up @@ -1461,16 +1474,29 @@ func getPrimaryKey(tblInfo *model.TableInfo) *model.IndexInfo {
}

func setTableAutoRandomBits(ctx sessionctx.Context, tbInfo *model.TableInfo, colDefs []*ast.ColumnDef) error {
pkColName := tbInfo.GetPkName()
for _, col := range colDefs {
if containsColumnOption(col, ast.ColumnOptionAutoRandom) {
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)
switch {
case tbInfo.PKIsHandle:
if tbInfo.GetPkName().L != col.Name.Name.L {
errMsg := fmt.Sprintf(autoid.AutoRandomMustFirstColumnInPK, col.Name.Name.O)
return ErrInvalidAutoRandom.GenWithStackByArgs(errMsg)
}
case tbInfo.IsCommonHandle:
pk := tables.FindPrimaryIndex(tbInfo)
if pk == nil {
return ErrInvalidAutoRandom.GenWithStackByArgs(autoid.AutoRandomNoClusteredPKErrMsg)
}
if col.Name.Name.L != pk.Columns[0].Name.L {
errMsg := fmt.Sprintf(autoid.AutoRandomMustFirstColumnInPK, col.Name.Name.O)
return ErrInvalidAutoRandom.GenWithStackByArgs(errMsg)
}
default:
return ErrInvalidAutoRandom.GenWithStackByArgs(autoid.AutoRandomNoClusteredPKErrMsg)
}
if containsColumnOption(col, ast.ColumnOptionAutoIncrement) {
return ErrInvalidAutoRandom.GenWithStackByArgs(autoid.AutoRandomIncompatibleWithAutoIncErrMsg)
Expand Down Expand Up @@ -4271,7 +4297,6 @@ func (d *ddl) getModifiableColumnJob(ctx context.Context, sctx sessionctx.Contex
// checkColumnWithIndexConstraint is used to check the related index constraint of the modified column.
// Index has a max-prefix-length constraint. eg: a varchar(100), index idx(a), modifying column a to a varchar(4000)
// will cause index idx to break the max-prefix-length constraint.
//
func checkColumnWithIndexConstraint(tbInfo *model.TableInfo, originalCol, newCol *model.ColumnInfo) error {
columns := make([]*model.ColumnInfo, 0, len(tbInfo.Columns))
columns = append(columns, tbInfo.Columns...)
Expand Down Expand Up @@ -4351,9 +4376,26 @@ func checkIndexInModifiableColumns(columns []*model.ColumnInfo, idxColumns []*mo
return nil
}

func isClusteredPKColumn(col *table.Column, tblInfo *model.TableInfo) bool {
switch {
case tblInfo.PKIsHandle:
return mysql.HasPriKeyFlag(col.Flag)
case tblInfo.IsCommonHandle:
pk := tables.FindPrimaryIndex(tblInfo)
for _, c := range pk.Columns {
if c.Name.L == col.Name.L {
return true
}
}
return false
default:
return false
}
}

func checkAutoRandom(tableInfo *model.TableInfo, originCol *table.Column, specNewColumn *ast.ColumnDef) (uint64, error) {
var oldRandBits uint64
if originCol.IsPKHandleColumn(tableInfo) {
if isClusteredPKColumn(originCol, tableInfo) {
oldRandBits = tableInfo.AutoRandomBits
}
newRandBits, err := extractAutoRandomBitsFromColDef(specNewColumn)
Expand Down
52 changes: 36 additions & 16 deletions ddl/serial_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1155,8 +1155,11 @@ func (s *testSerialDBSuite) TestAutoRandom(c *C) {
c.Assert(err.Error(), Equals, ddl.ErrInvalidAutoRandom.GenWithStackByArgs(fmt.Sprintf(errMsg, args...)).Error())
}

assertPKIsNotHandle := func(sql, errCol string) {
assertInvalidAutoRandomErr(sql, autoid.AutoRandomPKisNotHandleErrMsg, errCol)
assertNotFirstColPK := func(sql, errCol string) {
assertInvalidAutoRandomErr(sql, autoid.AutoRandomMustFirstColumnInPK, errCol)
}
assertNoClusteredPK := func(sql string) {
assertInvalidAutoRandomErr(sql, autoid.AutoRandomNoClusteredPKErrMsg)
}
assertAlterValue := func(sql string) {
assertInvalidAutoRandomErr(sql, autoid.AutoRandomAlterErrMsg)
Expand Down Expand Up @@ -1199,36 +1202,36 @@ func (s *testSerialDBSuite) TestAutoRandom(c *C) {
tk.MustExec("drop table t")
}

// Only bigint column can set auto_random
// 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")
assertBigIntOnly("create table t (a timestamp auto_random(3), b int, primary key (a, b) clustered)", "timestamp")

// PKIsHandle, but auto_random is defined on non-primary key.
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")
// Clustered, but auto_random is defined on non-primary key.
assertNotFirstColPK("create table t (a bigint auto_random (3) primary key, b bigint auto_random (3))", "b")
assertNotFirstColPK("create table t (a bigint auto_random (3), b bigint auto_random(3), primary key(a))", "b")
assertNotFirstColPK("create table t (a bigint auto_random (3), b bigint auto_random(3) primary key)", "a")
assertNotFirstColPK("create table t (a bigint auto_random, b bigint, primary key (b, a) clustered);", "a")

// PKIsNotHandle: no primary key.
assertPKIsNotHandle("create table t (a bigint auto_random(3), b int)", "a")
// PKIsNotHandle: primary key is not a single column.
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")
// No primary key.
assertNoClusteredPK("create table t (a bigint auto_random(3), b int)")

// PKIsNotHandle: nonclustered integer primary key.
assertPKIsNotHandle("create table t (a bigint auto_random(3) primary key nonclustered, b int)", "a")
assertPKIsNotHandle("create table t (a bigint auto_random(3) primary key nonclustered, b int)", "a")
assertPKIsNotHandle("create table t (a int, b bigint auto_random(3) primary key nonclustered)", "b")
// No clustered primary key.
assertNoClusteredPK("create table t (a bigint auto_random(3) primary key nonclustered, b int)")
assertNoClusteredPK("create table t (a int, b bigint auto_random(3) primary key nonclustered)")

// 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))")
assertWithAutoInc("create table t (a bigint auto_random(3) auto_increment, b int, primary key (a, b) clustered)")

// Can not set auto_random along with default.
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)")
assertDefault("create table t (a bigint auto_random(2) default 5, b int, primary key (a, b) clustered)")
mustExecAndDrop("create table t (a bigint auto_random primary key)", func() {
assertDefault("alter table t modify column a bigint auto_random default 3")
assertDefault("alter table t alter column a set default 3")
Expand All @@ -1237,12 +1240,14 @@ func (s *testSerialDBSuite) TestAutoRandom(c *C) {
// Overflow data type max length.
assertMaxOverflow("create table t (a bigint auto_random(64) primary key)", "a", 64)
assertMaxOverflow("create table t (a bigint auto_random(16) primary key)", "a", 16)
assertMaxOverflow("create table t (a bigint auto_random(16), b int, primary key (a, b) clustered)", "a", 16)
mustExecAndDrop("create table t (a bigint auto_random(5) primary key)", func() {
assertMaxOverflow("alter table t modify a bigint auto_random(64)", "a", 64)
assertMaxOverflow("alter table t modify a bigint auto_random(16)", "a", 16)
})

assertNonPositive("create table t (a bigint auto_random(0) primary key)")
assertNonPositive("create table t (a bigint auto_random(0), b int, primary key (a, b) clustered)")
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)" `)

Expand All @@ -1252,18 +1257,26 @@ func (s *testSerialDBSuite) TestAutoRandom(c *C) {
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))")
mustExecAndDrop("create table t (a bigint auto_random(3), b bigint, primary key (a, b) clustered)")
mustExecAndDrop("create table t (a bigint auto_random(3), b int, c char, primary key (a, c) clustered)")

// Increase auto_random bits.
mustExecAndDrop("create table t (a bigint auto_random(5) primary key)", func() {
tk.MustExec("alter table t modify a bigint auto_random(8)")
tk.MustExec("alter table t modify a bigint auto_random(10)")
tk.MustExec("alter table t modify a bigint auto_random(12)")
})
mustExecAndDrop("create table t (a bigint auto_random(5), b char(255), primary key (a, b) clustered)", func() {
tk.MustExec("alter table t modify a bigint auto_random(8)")
tk.MustExec("alter table t modify a bigint auto_random(10)")
tk.MustExec("alter table t modify a bigint auto_random(12)")
})

// 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 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))")
mustExecAndDrop("create table t (a bigint auto_random(1) auto_random(2) auto_random(3), b int, primary key (a, b) clustered)")

// Add/drop the auto_random attribute is not allowed.
mustExecAndDrop("create table t (a bigint auto_random(3) primary key)", func() {
Expand All @@ -1275,6 +1288,10 @@ func (s *testSerialDBSuite) TestAutoRandom(c *C) {
assertAlterValue("alter table t modify column c bigint")
assertAlterValue("alter table t change column c d bigint")
})
mustExecAndDrop("create table t (a bigint, b char, c bigint auto_random(3), primary key(c, a) clustered)", func() {
assertAlterValue("alter table t modify column c bigint")
assertAlterValue("alter table t change column c d bigint")
})
mustExecAndDrop("create table t (a bigint primary key)", func() {
assertOnlyChangeFromAutoIncPK("alter table t modify column a bigint auto_random(3)")
})
Expand Down Expand Up @@ -1302,6 +1319,9 @@ func (s *testSerialDBSuite) TestAutoRandom(c *C) {
mustExecAndDrop("create table t (a bigint auto_random(10) primary key)", func() {
assertDecreaseBitErr("alter table t modify column a bigint auto_random(1)")
})
mustExecAndDrop("create table t (a bigint auto_random(10), b int, primary key (a, b) clustered)", func() {
assertDecreaseBitErr("alter table t modify column a bigint auto_random(6)")
})

originStep := autoid.GetStep()
autoid.SetStep(1)
Expand Down
15 changes: 15 additions & 0 deletions executor/ddl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1130,6 +1130,21 @@ func (s *testAutoRandomSuite) TestAutoRandomTableOption(c *C) {
c.Assert(strings.Contains(err.Error(), autoid.AutoRandomRebaseNotApplicable), IsTrue, Commentf(err.Error()))
}

func (s *testAutoRandomSuite) TestAutoRandomClusteredPrimaryKey(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 auto_random(5), b int, primary key (a, b) clustered);")
tk.MustExec("insert into t (b) values (1);")
tk.MustExec("set @@allow_auto_random_explicit_insert = 0;")
tk.MustGetErrCode("insert into t values (100, 2);", errno.ErrInvalidAutoRandom)
tk.MustExec("set @@allow_auto_random_explicit_insert = 1;")
tk.MustExec("insert into t values (100, 2);")
tk.MustQuery("select b from t order by b;").Check(testkit.Rows("1", "2"))
tk.MustExec("alter table t modify column a bigint auto_random(6);")
tk.MustExec("drop table t;")
}

// Test filter different kind of allocators.
// In special ddl type, for example:
// 1: ActionRenameTable : it will abandon all the old allocators.
Expand Down
6 changes: 4 additions & 2 deletions meta/autoid/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ var (
)

const (
// AutoRandomPKisNotHandleErrMsg indicates the auto_random column attribute is defined on a non-primary key column, or the primary key is nonclustered.
AutoRandomPKisNotHandleErrMsg = "column %s is not the integer primary key, or the primary key is nonclustered"
// AutoRandomMustFirstColumnInPK is reported when auto_random is not the first column in primary key.
AutoRandomMustFirstColumnInPK = "column '%s' must be the first column in primary key"
// AutoRandomNoClusteredPKErrMsg indicates the primary key is not clustered.
AutoRandomNoClusteredPKErrMsg = "auto_random is only supported on the tables with clustered primary key"
// AutoRandomIncompatibleWithAutoIncErrMsg is reported when auto_random and auto_increment are specified on the same column.
AutoRandomIncompatibleWithAutoIncErrMsg = "auto_random is incompatible with auto_increment"
// AutoRandomIncompatibleWithDefaultValueErrMsg is reported when auto_random and default are specified on the same column.
Expand Down

0 comments on commit df32e3a

Please sign in to comment.