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: fix alter table charset bug and compatibility #9790

Merged
merged 25 commits into from
Apr 4, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
60ff970
ddl: fix alter table charset bug and compatibility
crazycs520 Mar 18, 2019
6ed875d
refine code
crazycs520 Mar 19, 2019
38c6b31
Merge branch 'master' into fix-alter-table-charset
crazycs520 Mar 19, 2019
90e6a33
Merge branch 'master' into fix-alter-table-charset
crazycs520 Mar 19, 2019
051abaa
address comment
crazycs520 Mar 19, 2019
0880f62
Merge branch 'fix-alter-table-charset' of https://github.com/crazycs5…
crazycs520 Mar 19, 2019
0bbbdcb
Merge branch 'master' of https://github.com/pingcap/tidb into fix-alt…
crazycs520 Mar 19, 2019
78ef367
address comment
crazycs520 Mar 19, 2019
552deb2
address comment
crazycs520 Mar 19, 2019
81addf7
add comment
crazycs520 Mar 20, 2019
260e21f
address comment
crazycs520 Mar 21, 2019
322f9a6
add test
crazycs520 Mar 21, 2019
ceb0dd5
Merge branch 'master' into fix-alter-table-charset
crazycs520 Mar 25, 2019
1ca6af7
Merge branch 'master' into fix-alter-table-charset
crazycs520 Mar 25, 2019
b3f4e97
Merge branch 'master' of https://github.com/pingcap/tidb into fix-alt…
crazycs520 Mar 26, 2019
834da81
fix test and address comment
crazycs520 Mar 26, 2019
e87ad6b
add test and fix compatible problem
crazycs520 Mar 26, 2019
21897bd
add comment
crazycs520 Mar 26, 2019
8de39eb
add comment
crazycs520 Mar 27, 2019
bc37d9d
Merge branch 'master' into fix-alter-table-charset
crazycs520 Mar 27, 2019
17313a7
address comment
crazycs520 Mar 29, 2019
c450a8d
Merge branch 'fix-alter-table-charset' of https://github.com/crazycs5…
crazycs520 Mar 29, 2019
6d27392
Merge branch 'master' of https://github.com/pingcap/tidb into fix-alt…
crazycs520 Mar 29, 2019
2d7b645
Merge branch 'master' of https://github.com/pingcap/tidb into fix-alt…
crazycs520 Apr 4, 2019
306ad18
Merge branch 'master' into fix-alter-table-charset
crazycs520 Apr 4, 2019
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
52 changes: 52 additions & 0 deletions ddl/db_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
. "github.com/pingcap/check"
"github.com/pingcap/errors"
"github.com/pingcap/parser/ast"
"github.com/pingcap/parser/charset"
"github.com/pingcap/parser/model"
"github.com/pingcap/parser/mysql"
tmysql "github.com/pingcap/parser/mysql"
Expand All @@ -40,6 +41,7 @@ import (
"github.com/pingcap/tidb/store/mockstore/mocktikv"
"github.com/pingcap/tidb/table"
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/util/mock"
"github.com/pingcap/tidb/util/testkit"
)

Expand Down Expand Up @@ -587,6 +589,56 @@ func (s *testIntegrationSuite) TestChangingTableCharset(c *C) {

rs, err = tk.Exec("alter table t charset utf8mb4 collate utf8mb4_bin")
c.Assert(err, NotNil)

// Test change column charset when change table charset.
crazycs520 marked this conversation as resolved.
Show resolved Hide resolved
tk.MustExec("drop table t;")
tk.MustExec("create table t(a varchar(10) character set ascii) charset utf8")
tk.MustExec("alter table t convert to charset utf8mb4;")
checkCharset := func() {
tbl := testGetTableByName(c, s.ctx, "test", "t")
c.Assert(tbl, NotNil)
c.Assert(tbl.Meta().Charset, Equals, charset.CharsetUTF8MB4)
c.Assert(tbl.Meta().Collate, Equals, charset.CollationUTF8MB4)
for _, col := range tbl.Meta().Columns {
c.Assert(col.Charset, Equals, charset.CharsetUTF8MB4)
c.Assert(col.Collate, Equals, charset.CollationUTF8MB4)
}
}
checkCharset()
// Test when table charset is equal to target charset but column charset is not equal.
tk.MustExec("drop table t;")
tk.MustExec("create table t(a varchar(10) character set ascii) charset utf8mb4")
tk.MustExec("alter table t convert to charset utf8mb4;")
checkCharset()

// Mock table info with charset is "". Old TiDB maybe create table with charset is "".
mockCtx := mock.NewContext()
mockCtx.Store = s.store
err = mockCtx.NewTxn(context.Background())
c.Assert(err, IsNil)
txn, err := mockCtx.Txn(true)
c.Assert(err, IsNil)
mt := meta.NewMeta(txn)
db, ok := domain.GetDomain(s.ctx).InfoSchema().SchemaByName(model.NewCIStr("test"))
c.Assert(ok, IsTrue)
tbl := testGetTableByName(c, s.ctx, "test", "t")
tblInfo := tbl.Meta().Clone()
tblInfo.Charset = ""
tblInfo.Collate = ""
err = mt.UpdateTable(db.ID, tblInfo)
c.Assert(err, IsNil)
err = txn.Commit(context.Background())
c.Assert(err, IsNil)

// check table charset is ""
tk.MustExec("alter table t add column b varchar(10);") // load latest schema.
tbl = testGetTableByName(c, s.ctx, "test", "t")
c.Assert(tbl, NotNil)
c.Assert(tbl.Meta().Charset, Equals, "")
c.Assert(tbl.Meta().Collate, Equals, "")
// Test when table charset is "", this for compatibility.
tk.MustExec("alter table t convert to charset utf8mb4;")
checkCharset()
}

func (s *testIntegrationSuite) TestCaseInsensitiveCharsetAndCollate(c *C) {
Expand Down
66 changes: 49 additions & 17 deletions ddl/ddl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2426,12 +2426,9 @@ func (d *ddl) AlterTableCharsetAndCollate(ctx sessionctx.Context, ident ast.Iden
if err != nil {
return errors.Trace(infoschema.ErrTableNotExists.GenWithStackByArgs(ident.Schema, ident.Name))
}

origCharset := tb.Meta().Charset
origCollate := tb.Meta().Collate
if toCharset == "" {
// charset does not change.
toCharset = origCharset
toCharset = tb.Meta().Charset
zimulala marked this conversation as resolved.
Show resolved Hide resolved
}

if toCollate == "" {
zimulala marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -2442,22 +2439,14 @@ func (d *ddl) AlterTableCharsetAndCollate(ctx sessionctx.Context, ident ast.Iden
}
}

if origCharset == toCharset && origCollate == toCollate {
// nothing to do.
return nil
doNothing, err := checkAlterTableCharset(tb.Meta(), toCharset, toCollate)
if err != nil {
return err
}

if err = modifiableCharsetAndCollation(toCharset, toCollate, origCharset, origCollate); err != nil {
return errors.Trace(err)
if doNothing {
return nil
}

for _, col := range tb.Meta().Cols() {
if col.Tp == mysql.TypeVarchar {
if err = IsTooBigFieldLength(col.Flen, col.Name.O, toCharset); err != nil {
return errors.Trace(err)
}
}
}
job := &model.Job{
SchemaID: schema.ID,
TableID: tb.Meta().ID,
Expand All @@ -2470,6 +2459,49 @@ func (d *ddl) AlterTableCharsetAndCollate(ctx sessionctx.Context, ident ast.Iden
return errors.Trace(err)
}

func checkAlterTableCharset(tblInfo *model.TableInfo, toCharset, toCollate string) (bool, error) {
var err error
origCharset := tblInfo.Charset
origCollate := tblInfo.Collate
if origCharset == toCharset && origCollate == toCollate {
// nothing to do.
var doNothing = true
crazycs520 marked this conversation as resolved.
Show resolved Hide resolved
for _, col := range tblInfo.Columns {
if col.Charset == charset.CharsetBin {
continue
}
if col.Charset == toCharset && col.Collate == toCollate {
continue
}
doNothing = false
}
if doNothing {
return true, nil
crazycs520 marked this conversation as resolved.
Show resolved Hide resolved
}
}

if len(origCharset) == 0 {
// The table charset may be "", if the table is create in old TiDB version.
crazycs520 marked this conversation as resolved.
Show resolved Hide resolved
// This DDL will update the table charset to default charset.
// Use default charset or database charset?
// show create table is uses the default charset.
origCharset, origCollate = charset.GetDefaultCharsetAndCollate()
crazycs520 marked this conversation as resolved.
Show resolved Hide resolved
}

if err = modifiableCharsetAndCollation(toCharset, toCollate, origCharset, origCollate); err != nil {
return false, errors.Trace(err)
crazycs520 marked this conversation as resolved.
Show resolved Hide resolved
}

for _, col := range tblInfo.Columns {
if col.Tp == mysql.TypeVarchar {
if err = IsTooBigFieldLength(col.Flen, col.Name.O, toCharset); err != nil {
return false, errors.Trace(err)
}
}
}
return false, nil
crazycs520 marked this conversation as resolved.
Show resolved Hide resolved
}

// RenameIndex renames an index.
// In TiDB, indexes are case-insensitive (so index 'a' and 'A" are considered the same index),
// but index names are case-sensitive (we can rename index 'a' to 'A')
Expand Down
21 changes: 21 additions & 0 deletions ddl/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import (
"sync/atomic"

"github.com/pingcap/errors"
"github.com/pingcap/parser/charset"
"github.com/pingcap/parser/model"
"github.com/pingcap/parser/mysql"
"github.com/pingcap/tidb/ddl/util"
"github.com/pingcap/tidb/infoschema"
"github.com/pingcap/tidb/kv"
Expand Down Expand Up @@ -589,8 +591,27 @@ func onModifyTableCharsetAndCollate(t *meta.Meta, job *model.Job) (ver int64, _
return ver, errors.Trace(err)
}

// double check.
_, err = checkAlterTableCharset(tblInfo, toCharset, toCollate)
if err != nil {
job.State = model.JobStateCancelled
return ver, errors.Trace(err)
}

tblInfo.Charset = toCharset
tblInfo.Collate = toCollate
// update column charset.
for _, col := range tblInfo.Columns {
switch col.Tp {
case mysql.TypeString, mysql.TypeVarchar, mysql.TypeVarString, mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob, mysql.TypeEnum, mysql.TypeSet:
crazycs520 marked this conversation as resolved.
Show resolved Hide resolved
col.Charset = toCharset
col.Collate = toCollate
default:
col.Charset = charset.CharsetBin
col.Collate = charset.CharsetBin
}
}

ver, err = updateVersionAndTableInfo(t, job, tblInfo, true)
if err != nil {
return ver, errors.Trace(err)
Expand Down