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,executor: add auto_random column option (#13127, #14489) #14555

Merged
merged 2 commits into from
Feb 12, 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
21 changes: 18 additions & 3 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,10 @@ type Config struct {
AlterPrimaryKey bool `toml:"alter-primary-key" json:"alter-primary-key"`
// TreatOldVersionUTF8AsUTF8MB4 is use to treat old version table/column UTF8 charset as UTF8MB4. This is for compatibility.
// Currently not support dynamic modify, because this need to reload all old version schema.
TreatOldVersionUTF8AsUTF8MB4 bool `toml:"treat-old-version-utf8-as-utf8mb4" json:"treat-old-version-utf8-as-utf8mb4"`
SplitRegionMaxNum uint64 `toml:"split-region-max-num" json:"split-region-max-num"`
StmtSummary StmtSummary `toml:"stmt-summary" json:"stmt-summary"`
TreatOldVersionUTF8AsUTF8MB4 bool `toml:"treat-old-version-utf8-as-utf8mb4" json:"treat-old-version-utf8-as-utf8mb4"`
SplitRegionMaxNum uint64 `toml:"split-region-max-num" json:"split-region-max-num"`
StmtSummary StmtSummary `toml:"stmt-summary" json:"stmt-summary"`
Experimental Experimental `toml:"experimental" json:"experimental"`
}

// Log is the log section of config.
Expand Down Expand Up @@ -335,6 +336,13 @@ type StmtSummary struct {
HistorySize int `toml:"history-size" json:"history-size"`
}

// Experimental controls the features that are still experimental: their semantics, interfaces are subject to change.
// Using these features in the production environment is not recommended.
type Experimental struct {
// Whether enable the syntax like `auto_random(3)` on the primary key column.
AllowAutoRandom bool `toml:"allow-auto-random" json:"allow-auto-random"`
}

var defaultConf = Config{
Host: "0.0.0.0",
AdvertiseAddress: "",
Expand Down Expand Up @@ -440,6 +448,9 @@ var defaultConf = Config{
RefreshInterval: 1800,
HistorySize: 24,
},
Experimental: Experimental{
AllowAutoRandom: false,
},
}

var (
Expand Down Expand Up @@ -619,6 +630,10 @@ func (c *Config) Valid() error {
if c.StmtSummary.RefreshInterval <= 0 {
return fmt.Errorf("refresh-interval in [stmt-summary] should be greater than 0")
}

if c.AlterPrimaryKey && c.Experimental.AllowAutoRandom {
return fmt.Errorf("allow-auto-random is unavailable when alter-primary-key is enabled")
}
return nil
}

Expand Down
6 changes: 6 additions & 0 deletions config/config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -353,3 +353,9 @@ refresh-interval = 1800

# the maximum history size of statement summary.
history-size = 24

# experimental section controls the features that are still experimental: their semantics,
# interfaces are subject to change, using these features in the production environment is not recommended.
[experimental]
# enable column attribute `auto_random` to be defined on the primary key column.
allow-auto-random = false
16 changes: 16 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ max-stmt-count=1000
max-sql-length=1024
refresh-interval=100
history-size=100
[experimental]
allow-auto-random = true
`)

c.Assert(err, IsNil)
Expand Down Expand Up @@ -112,6 +114,7 @@ history-size=100
c.Assert(conf.StmtSummary.MaxSQLLength, Equals, uint(1024))
c.Assert(conf.StmtSummary.RefreshInterval, Equals, 100)
c.Assert(conf.StmtSummary.HistorySize, Equals, 100)
c.Assert(conf.Experimental.AllowAutoRandom, IsTrue)
c.Assert(f.Close(), IsNil)
c.Assert(os.Remove(configFile), IsNil)

Expand Down Expand Up @@ -246,3 +249,16 @@ func (s *testConfigSuite) TestOOMActionValid(c *C) {
c.Assert(c1.Valid() == nil, Equals, tt.valid)
}
}

func (s *testConfigSuite) TestAllowAutoRandomValid(c *C) {
conf := NewConfig()
checkValid := func(allowAlterPK, allowAutoRand, shouldBeValid bool) {
conf.AlterPrimaryKey = allowAlterPK
conf.Experimental.AllowAutoRandom = allowAutoRand
c.Assert(conf.Valid() == nil, Equals, shouldBeValid)
}
checkValid(true, true, false)
checkValid(true, false, true)
checkValid(false, true, true)
checkValid(false, false, true)
}
4 changes: 2 additions & 2 deletions ddl/column_change_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,8 +352,8 @@ func getCurrentTable(d *ddl, schemaID, tableID int64) (table.Table, error) {
if err != nil {
return nil, errors.Trace(err)
}
alloc := autoid.NewAllocator(d.store, schemaID, false)
tbl, err := table.TableFromMeta(alloc, tblInfo)
alloc := autoid.NewAllocator(d.store, schemaID, false, autoid.RowIDAllocType)
tbl, err := table.TableFromMeta(autoid.NewAllocators(alloc), tblInfo)
if err != nil {
return nil, errors.Trace(err)
}
Expand Down
4 changes: 4 additions & 0 deletions ddl/ddl.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ var (
ErrFieldNotFoundPart = terror.ClassDDL.New(codeFieldNotFoundPart, mysql.MySQLErrName[mysql.ErrFieldNotFoundPart])
// ErrWrongTypeColumnValue returns 'Partition column values of incorrect type'
ErrWrongTypeColumnValue = terror.ClassDDL.New(codeWrongTypeColumnValue, mysql.MySQLErrName[mysql.ErrWrongTypeColumnValue])
// ErrInvalidAutoRandom returns when auto_random is used incorrectly.
ErrInvalidAutoRandom = terror.ClassDDL.New(codeInvalidAutoRandom, mysql.MySQLErrName[mysql.ErrInvalidAutoRandom])
)

// DDL is responsible for updating schema in data store and maintaining in-memory InfoSchema cache.
Expand Down Expand Up @@ -757,6 +759,7 @@ const (
codeSystemVersioningWrongPartitions = terror.ErrCode(mysql.ErrSystemVersioningWrongPartitions)
codeWrongPartitionTypeExpectedSystemTime = terror.ErrCode(mysql.ErrWrongPartitionTypeExpectedSystemTime)
codeWrongTypeColumnValue = terror.ErrCode(mysql.ErrWrongTypeColumnValue)
codeInvalidAutoRandom = terror.ErrCode(mysql.ErrInvalidAutoRandom)
)

func init() {
Expand Down Expand Up @@ -831,6 +834,7 @@ func init() {
codeWrongTypeColumnValue: mysql.ErrWrongTypeColumnValue,
mysql.ErrFkColumnCannotDrop: mysql.ErrFkColumnCannotDrop,
mysql.ErrFKIncompatibleColumns: mysql.ErrFKIncompatibleColumns,
mysql.ErrInvalidAutoRandom: mysql.ErrInvalidAutoRandom,
}
terror.ErrClassToMySQLCodes[terror.ClassDDL] = ddlMySQLErrCodes
}
108 changes: 100 additions & 8 deletions ddl/ddl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -876,9 +876,9 @@ func checkDuplicateColumn(cols []interface{}) error {
return nil
}

func checkIsAutoIncrementColumn(colDefs *ast.ColumnDef) bool {
for _, option := range colDefs.Options {
if option.Tp == ast.ColumnOptionAutoIncrement {
func containsColumnOption(colDef *ast.ColumnDef, opTp ast.ColumnOptionType) bool {
for _, option := range colDef.Options {
if option.Tp == opTp {
return true
}
}
Expand All @@ -897,7 +897,7 @@ func checkGeneratedColumn(colDefs []*ast.ColumnDef) error {
}
}
}
if checkIsAutoIncrementColumn(colDef) {
if containsColumnOption(colDef, ast.ColumnOptionAutoIncrement) {
exists, autoIncrementColumn = true, colDef.Name.Name.L
}
generated, depCols := findDependedColumnNames(colDef)
Expand Down Expand Up @@ -1076,6 +1076,58 @@ func checkConstraintNames(constraints []*ast.Constraint) error {
return nil
}

func setTableAutoRandomBits(tbInfo *model.TableInfo, colDefs []*ast.ColumnDef) error {
allowAutoRandom := config.GetGlobalConfig().Experimental.AllowAutoRandom
pkColName := tbInfo.GetPkName()
for _, col := range colDefs {
if containsColumnOption(col, ast.ColumnOptionAutoRandom) {
if !allowAutoRandom {
return ErrInvalidAutoRandom.GenWithStackByArgs(autoid.AutoRandomExperimentalDisabledErrMsg)
}
if !tbInfo.PKIsHandle || col.Name.Name.L != pkColName.L {
return ErrInvalidAutoRandom.GenWithStackByArgs(fmt.Sprintf(autoid.AutoRandomPKisNotHandleErrMsg, col.Name.Name.O))
}
if containsColumnOption(col, ast.ColumnOptionAutoIncrement) {
return ErrInvalidAutoRandom.GenWithStackByArgs(autoid.AutoRandomIncompatibleWithAutoIncErrMsg)
}
if containsColumnOption(col, ast.ColumnOptionDefaultValue) {
return ErrInvalidAutoRandom.GenWithStackByArgs(autoid.AutoRandomIncompatibleWithDefaultValueErrMsg)
}

autoRandBits, err := extractAutoRandomBitsFromColDef(col)
if err != nil {
return errors.Trace(err)
}
maxFieldTypeBitsLength := uint64(mysql.DefaultLengthOfMysqlTypes[col.Tp.Tp] * 8)
if autoRandBits == 0 {
return ErrInvalidAutoRandom.GenWithStackByArgs(autoid.AutoRandomNonPositive)
} else if autoRandBits >= maxFieldTypeBitsLength {
return ErrInvalidAutoRandom.GenWithStackByArgs(fmt.Sprintf(autoid.AutoRandomOverflowErrMsg, autoRandBits, maxFieldTypeBitsLength))
}
tbInfo.AutoRandomBits = autoRandBits
}
}
return nil
}

func extractAutoRandomBitsFromColDef(colDef *ast.ColumnDef) (uint64, error) {
for _, op := range colDef.Options {
if op.Tp == ast.ColumnOptionAutoRandom {
return convertAutoRandomBitsToUnsigned(op.AutoRandomBitLength)
}
}
return 0, nil
}

func convertAutoRandomBitsToUnsigned(autoRandomBits int) (uint64, error) {
if autoRandomBits == types.UnspecifiedLength {
return autoid.DefaultAutoRandomBits, nil
} else if autoRandomBits < 0 {
return 0, ErrInvalidAutoRandom.GenWithStackByArgs(autoid.AutoRandomNonPositive)
}
return uint64(autoRandomBits), nil
}

func buildTableInfo(ctx sessionctx.Context, d *ddl, tableName model.CIStr, cols []*table.Column, constraints []*ast.Constraint) (tbInfo *model.TableInfo, err error) {
tbInfo = &model.TableInfo{
Name: tableName,
Expand Down Expand Up @@ -1152,7 +1204,7 @@ func buildTableInfo(ctx sessionctx.Context, d *ddl, tableName model.CIStr, cols
if err != nil {
return nil, errors.Trace(err)
}
//check if the index is primary or uniqiue.
// check if the index is primary or unique.
switch constr.Tp {
case ast.ConstraintPrimaryKey:
idxInfo.Primary = true
Expand Down Expand Up @@ -1323,6 +1375,10 @@ func buildTableInfoWithCheck(ctx sessionctx.Context, d *ddl, s *ast.CreateTableS
tbInfo.Collate = tableCollate
tbInfo.Charset = tableCharset

if err = setTableAutoRandomBits(tbInfo, colDefs); err != nil {
return nil, errors.Trace(err)
}

pi, err := buildTablePartitionInfo(ctx, d, s)
if err != nil {
return nil, errors.Trace(err)
Expand Down Expand Up @@ -1719,9 +1775,9 @@ func checkCharsetAndCollation(cs string, co string) error {
// handleAutoIncID handles auto_increment option in DDL. It creates a ID counter for the table and initiates the counter to a proper value.
// For example if the option sets auto_increment to 10. The counter will be set to 9. So the next allocated ID will be 10.
func (d *ddl) handleAutoIncID(tbInfo *model.TableInfo, schemaID int64) error {
alloc := autoid.NewAllocator(d.store, tbInfo.GetDBID(schemaID), tbInfo.IsAutoIncColUnsigned())
allocs := autoid.NewAllocatorsFromTblInfo(d.store, schemaID, tbInfo)
tbInfo.State = model.StatePublic
tb, err := table.TableFromMeta(alloc, tbInfo)
tb, err := table.TableFromMeta(allocs, tbInfo)
if err != nil {
return errors.Trace(err)
}
Expand Down Expand Up @@ -1978,7 +2034,7 @@ func (d *ddl) RebaseAutoID(ctx sessionctx.Context, ident ast.Ident, newBase int6
if err != nil {
return errors.Trace(err)
}
autoIncID, err := t.Allocator(ctx).NextGlobalAutoID(t.Meta().ID)
autoIncID, err := t.Allocator(ctx, autoid.RowIDAllocType).NextGlobalAutoID(t.Meta().ID)
if err != nil {
return errors.Trace(err)
}
Expand Down Expand Up @@ -2524,6 +2580,8 @@ func processColumnOptions(ctx sessionctx.Context, col *table.Column, options []*
return errors.Trace(errUnsupportedModifyColumn.GenWithStackByArgs("with references"))
case ast.ColumnOptionFulltext:
return errors.Trace(errUnsupportedModifyColumn.GenWithStackByArgs("with full text"))
// Ignore ColumnOptionAutoRandom. It will be handled later.
case ast.ColumnOptionAutoRandom:
default:
return errors.Trace(errUnsupportedModifyColumn.GenWithStackByArgs(fmt.Sprintf("unknown column option type: %d", opt.Tp)))
}
Expand Down Expand Up @@ -2668,6 +2726,10 @@ func (d *ddl) getModifiableColumnJob(ctx sessionctx.Context, ident ast.Ident, or
return nil, errors.Trace(err)
}

if err = checkAutoRandom(t.Meta(), col, specNewColumn); err != nil {
return nil, errors.Trace(err)
}

job := &model.Job{
SchemaID: schema.ID,
TableID: t.Meta().ID,
Expand Down Expand Up @@ -2715,6 +2777,36 @@ func checkColumnWithIndexConstraint(tbInfo *model.TableInfo, originalCol, newCol
return nil
}

func checkAutoRandom(tableInfo *model.TableInfo, originCol *table.Column, specNewColumn *ast.ColumnDef) error {
if !config.GetGlobalConfig().Experimental.AllowAutoRandom && containsColumnOption(specNewColumn, ast.ColumnOptionAutoRandom) {
return ErrInvalidAutoRandom.GenWithStackByArgs(autoid.AutoRandomExperimentalDisabledErrMsg)
}
// Disallow add/drop/modify actions on auto_random.
newAutoRandomBit, err := extractAutoRandomBitsFromColDef(specNewColumn)
if err != nil {
return errors.Trace(err)
}
if tableInfo.AutoRandomBits != newAutoRandomBit {
return ErrInvalidAutoRandom.GenWithStackByArgs(autoid.AutoRandomAlterErrMsg)
}

if tableInfo.AutoRandomBits != 0 {
// Disallow changing the column field type.
if originCol.Tp != specNewColumn.Tp.Tp {
return ErrInvalidAutoRandom.GenWithStackByArgs(autoid.AutoRandomModifyColTypeErrMsg)
}
// Disallow changing auto_increment on auto_random column.
if containsColumnOption(specNewColumn, ast.ColumnOptionAutoIncrement) != mysql.HasAutoIncrementFlag(originCol.Flag) {
return ErrInvalidAutoRandom.GenWithStackByArgs(autoid.AutoRandomIncompatibleWithAutoIncErrMsg)
}
// Disallow specifying a default value on auto_random column.
if containsColumnOption(specNewColumn, ast.ColumnOptionDefaultValue) {
return ErrInvalidAutoRandom.GenWithStackByArgs(autoid.AutoRandomIncompatibleWithDefaultValueErrMsg)
}
}
return nil
}

// ChangeColumn renames an existing column and modifies the column's definition,
// currently we only support limited kind of changes
// that do not need to change or check data on the table.
Expand Down
Loading