Skip to content

Commit

Permalink
ddl: check index key length when convert charset (#56964) (#57441)
Browse files Browse the repository at this point in the history
close #56930
  • Loading branch information
ti-chi-bot authored Nov 18, 2024
1 parent a276364 commit f00a584
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 0 deletions.
28 changes: 28 additions & 0 deletions ddl/ddl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -6041,6 +6041,10 @@ func checkAlterTableCharset(tblInfo *model.TableInfo, dbInfo *model.DBInfo, toCh
return doNothing, nil
}

if err = checkIndexLengthWithNewCharset(tblInfo, toCharset, toCollate); err != nil {
return doNothing, err
}

for _, col := range tblInfo.Columns {
if col.GetType() == mysql.TypeVarchar {
if err = types.IsVarcharTooBigFieldLength(col.GetFlen(), col.Name.O, toCharset); err != nil {
Expand All @@ -6064,6 +6068,30 @@ func checkAlterTableCharset(tblInfo *model.TableInfo, dbInfo *model.DBInfo, toCh
return doNothing, nil
}

func checkIndexLengthWithNewCharset(tblInfo *model.TableInfo, toCharset, toCollate string) error {
// Copy all columns and replace the charset and collate.
columns := make([]*model.ColumnInfo, 0, len(tblInfo.Columns))
for _, col := range tblInfo.Columns {
newCol := col.Clone()
if field_types.HasCharset(&newCol.FieldType) {
newCol.SetCharset(toCharset)
newCol.SetCollate(toCollate)
} else {
newCol.SetCharset(charset.CharsetBin)
newCol.SetCollate(charset.CharsetBin)
}
columns = append(columns, newCol)
}

for _, indexInfo := range tblInfo.Indices {
err := checkIndexPrefixLength(columns, indexInfo.Columns)
if err != nil {
return err
}
}
return nil
}

// 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
12 changes: 12 additions & 0 deletions ddl/ddl_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,3 +267,15 @@ func TestCreateDropCreateTable(t *testing.T) {
require.Less(t, create0TS, dropTS, "first create should finish before drop")
require.Less(t, dropTS, create1TS, "second create should finish after drop")
}

func TestFix56930(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t; create table posts (id int auto_increment primary key, title varchar(500) character set utf8, subtitle varchar(500) character set utf8, unique key(title, subtitle));")
tk.MustGetErrMsg("alter table posts convert to character set utf8mb4;", "[ddl:1071]Specified key was too long (4000 bytes); max key length is 3072 bytes")
tk.MustExec("drop table if exists t; create table t(a varchar(1000) character set utf8, primary key(a));")
tk.MustGetErrMsg("alter table t convert to character set utf8mb4;", "[ddl:1071]Specified key was too long (4000 bytes); max key length is 3072 bytes")
tk.MustExec("drop table if exists t; create table t(a varchar(1000) character set utf8, key(a));")
tk.MustGetErrMsg("alter table t convert to character set utf8mb4;", "[ddl:1071]Specified key was too long (4000 bytes); max key length is 3072 bytes")
}

0 comments on commit f00a584

Please sign in to comment.