ddl: unify flag processing behaviors between add/modify columns (#19467)

* ddl: unify behaviors between add/modify columns

* ddl: add a test

* ddl: improve test

* ddl: improve test
also kicked one test, as it is not operated by the tested function.

Co-authored-by: ti-srebot <66930949+ti-srebot@users.noreply.github.com>
This commit is contained in:
xhe
2020-09-01 16:20:52 +08:00
committed by GitHub
parent 82502cc5e1
commit ea7590aa86
2 changed files with 65 additions and 22 deletions

View File

@ -4269,6 +4269,44 @@ func (s *testDBSuite4) TestIssue9100(c *C) {
c.Assert(err.Error(), Equals, "[ddl:1503]A PRIMARY must include all columns in the table's partitioning function")
}
func (s *testSerialDBSuite) TestProcessColumnFlags(c *C) {
// check `processColumnFlags()`
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test_db")
tk.MustExec("create table t(a year(4) comment 'xxx', b year, c bit)")
defer s.mustExec(tk, c, "drop table t;")
check := func(n string, f func(uint) bool) {
t := testGetTableByName(c, tk.Se, "test_db", "t")
for _, col := range t.Cols() {
if strings.EqualFold(col.Name.L, n) {
c.Assert(f(col.Flag), IsTrue)
break
}
}
}
yearcheck := func(f uint) bool {
return mysql.HasUnsignedFlag(f) && mysql.HasZerofillFlag(f) && !mysql.HasBinaryFlag(f)
}
tk.MustExec("alter table t modify a year(4)")
check("a", yearcheck)
tk.MustExec("alter table t modify a year(4) unsigned")
check("a", yearcheck)
tk.MustExec("alter table t modify a year(4) zerofill")
tk.MustExec("alter table t modify b year")
check("b", yearcheck)
tk.MustExec("alter table t modify c bit")
check("c", func(f uint) bool {
return mysql.HasUnsignedFlag(f) && !mysql.HasBinaryFlag(f)
})
}
func (s *testSerialDBSuite) TestModifyColumnCharset(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test_db")

View File

@ -491,6 +491,30 @@ func isExplicitTimeStamp() bool {
return true
}
// processColumnFlags is used by columnDefToCol and processColumnOptions. It is intended to unify behaviors on `create/add` and `modify/change` statements. Check tidb#issue#19342.
func processColumnFlags(col *table.Column) {
if col.FieldType.EvalType().IsStringKind() && col.Charset == charset.CharsetBin {
col.Flag |= mysql.BinaryFlag
}
if col.Tp == mysql.TypeBit {
// For BIT field, it's charset is binary but does not have binary flag.
col.Flag &= ^mysql.BinaryFlag
col.Flag |= mysql.UnsignedFlag
}
if col.Tp == mysql.TypeYear {
// For Year field, it's charset is binary but does not have binary flag.
col.Flag &= ^mysql.BinaryFlag
col.Flag |= mysql.ZerofillFlag
}
// If you specify ZEROFILL for a numeric column, MySQL automatically adds the UNSIGNED attribute to the column.
// See https://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html for more details.
// But some types like bit and year, won't show its unsigned flag in `show create table`.
if mysql.HasZerofillFlag(col.Flag) {
col.Flag |= mysql.UnsignedFlag
}
}
// columnDefToCol converts ColumnDef to Col and TableConstraints.
// outPriKeyConstraint is the primary key constraint out of column definition. such as: create table t1 (id int , age int, primary key(id));
func columnDefToCol(ctx sessionctx.Context, offset int, colDef *ast.ColumnDef, outPriKeyConstraint *ast.Constraint) (*table.Column, []*ast.Constraint, error) {
@ -603,26 +627,9 @@ func columnDefToCol(ctx sessionctx.Context, offset int, colDef *ast.ColumnDef, o
// Set `NoDefaultValueFlag` if this field doesn't have a default value and
// it is `not null` and not an `AUTO_INCREMENT` field or `TIMESTAMP` field.
setNoDefaultValueFlag(col, hasDefaultValue)
if col.FieldType.EvalType().IsStringKind() && col.Charset == charset.CharsetBin {
col.Flag |= mysql.BinaryFlag
}
if col.Tp == mysql.TypeBit {
// For BIT field, it's charset is binary but does not have binary flag.
col.Flag &= ^mysql.BinaryFlag
col.Flag |= mysql.UnsignedFlag
}
if col.Tp == mysql.TypeYear {
// For Year field, it's charset is binary but does not have binary flag.
col.Flag &= ^mysql.BinaryFlag
col.Flag |= mysql.ZerofillFlag
}
// If you specify ZEROFILL for a numeric column, MySQL automatically adds the UNSIGNED attribute to the column.
// See https://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html for more details.
// But some types like bit and year, won't show its unsigned flag in `show create table`.
if mysql.HasZerofillFlag(col.Flag) {
col.Flag |= mysql.UnsignedFlag
}
processColumnFlags(col)
err = checkPriKeyConstraint(col, hasDefaultValue, hasNullFlag, outPriKeyConstraint)
if err != nil {
return nil, nil, errors.Trace(err)
@ -3399,9 +3406,7 @@ func processColumnOptions(ctx sessionctx.Context, col *table.Column, options []*
// it is `not null` and not an `AUTO_INCREMENT` field or `TIMESTAMP` field.
setNoDefaultValueFlag(col, hasDefaultValue)
if col.Tp == mysql.TypeBit {
col.Flag |= mysql.UnsignedFlag
}
processColumnFlags(col)
if hasDefaultValue {
return errors.Trace(checkDefaultValue(ctx, col, true))