diff --git a/README.md b/README.md index 234721f..d6600de 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ The ddl-executor is a golang library that can parse and execute MySQL DDL statements. The library maintains schema structures in memory, for examples: creates a new schema structure when a CREATE statement executed, modifys a schema structure when a ALTER statement executed. -# What can it be used for ? +# What can it be used for? This library may be used for DDL analysis, binlog stream's schema tracking (like [`binlog_row_metadata=FULL`](https://dev.mysql.com/doc/refman/8.0/en/replication-options-binary-log.html#sysvar_binlog_row_metadata) in MySQL 8) and so on. # Usage @@ -45,7 +45,7 @@ This library use TiDB 's parser to parse MySQL statement to generate AST(abstrac * ALTER DATABASE -# What statements it supports ? +# What statements does it support? This library support 99% MySQL DDL statements.The ddl-executor can execute statements same as MySQL 5.7 identically, such as complicated statement like this: ``` # ----------------------------------------------- @@ -81,7 +81,7 @@ drop table t1; ``` > Those statements above come from MySQL' s test suit, and is part of our compatibility test cases. -# What statements it doesn't support ? +# What statements are not supported? Some DDL statement that are infrequent: * ALTER with 'convert charset': ALTER TABLE t1 CONVERT TO CHARACTER SET latin1; * ALTER with 'order by': ALTER TABLE t1 add column new_col int, ORDER BY payoutid, bandid; @@ -89,7 +89,7 @@ Some DDL statement that are infrequent: * CREATE TABLE with 'SELECT' clause; * Some others unfrequent statement we don't know now; -Those statements above will raise error when executing whit this library. +Those statements above will raise error when executing with this library. # Compatibility tests You can have a look on 'github.com/bytewatch/ddl-executor/compatibility_test', which is a cmd line tool to test compatibility between this library and MySQL. diff --git a/executor.go b/executor.go index 8777ed4..3c16c2e 100644 --- a/executor.go +++ b/executor.go @@ -498,49 +498,51 @@ func (o *Executor) enterDropIndexStmt(stmt *ast.DropIndexStmt) error { } func (o *Executor) enterRenameTableStmt(stmt *ast.RenameTableStmt) error { - oldDatabaseName := o.getSqlName(stmt.OldTable.Schema) - oldTableName := o.getSqlName(stmt.OldTable.Name) - newDatabaseName := o.getSqlName(stmt.NewTable.Schema) - newTableName := o.getSqlName(stmt.NewTable.Name) + for _, value := range stmt.TableToTables { + oldDatabaseName := o.getSqlName(value.OldTable.Schema) + oldTableName := o.getSqlName(value.OldTable.Name) + newDatabaseName := o.getSqlName(value.NewTable.Schema) + newTableName := o.getSqlName(value.NewTable.Name) - oldDatabaseDef, err := o.getSpecifiedOrDefaultDb(oldDatabaseName) - if err != nil { - return err - } - tableDef := oldDatabaseDef.cloneTable(oldTableName) - if tableDef == nil { - return ErrNoSuchTable.Gen(oldDatabaseDef.Name, oldTableName) - } - - if newDatabaseName == oldDatabaseName && newTableName == oldTableName { - // Nothing to do - return nil - } - - if newDatabaseName != oldDatabaseName { - // The new table name is in another database - newDatabaseDef, err := o.getSpecifiedOrDefaultDb(newDatabaseName) + oldDatabaseDef, err := o.getSpecifiedOrDefaultDb(oldDatabaseName) if err != nil { return err } + tableDef := oldDatabaseDef.cloneTable(oldTableName) + if tableDef == nil { + return ErrNoSuchTable.Gen(oldDatabaseDef.Name, oldTableName) + } - if newDatabaseDef.findTable(newTableName) != nil { - return ErrTableExists.Gen(newTableName) + if newDatabaseName == oldDatabaseName && newTableName == oldTableName { + // Nothing to do + continue } - oldDatabaseDef.dropTable(oldTableName) - tableDef.Name = newTableName - newDatabaseDef.setTable(newTableName, tableDef) + if newDatabaseName != oldDatabaseName { + // The new table name is in another database + newDatabaseDef, err := o.getSpecifiedOrDefaultDb(newDatabaseName) + if err != nil { + return err + } - } else { - // The new table name is still in the original database - if oldDatabaseDef.findTable(newTableName) != nil && - newTableName != oldTableName { - return ErrTableExists.Gen(newTableName) - } - oldDatabaseDef.dropTable(oldTableName) - tableDef.Name = newTableName - oldDatabaseDef.setTable(newTableName, tableDef) + if newDatabaseDef.findTable(newTableName) != nil { + return ErrTableExists.Gen(newTableName) + } + + oldDatabaseDef.dropTable(oldTableName) + tableDef.Name = newTableName + newDatabaseDef.setTable(newTableName, tableDef) + + } else { + // The new table name is still in the original database + if oldDatabaseDef.findTable(newTableName) != nil && + newTableName != oldTableName { + return ErrTableExists.Gen(newTableName) + } + oldDatabaseDef.dropTable(oldTableName) + tableDef.Name = newTableName + oldDatabaseDef.setTable(newTableName, tableDef) + } } return nil diff --git a/executor_test.go b/executor_test.go index 6065964..49c4081 100644 --- a/executor_test.go +++ b/executor_test.go @@ -64,7 +64,7 @@ func TestCreateTable(t *testing.T) { } expectedDef.Columns = append(expectedDef.Columns, &ColumnDef{ Name: "id", - Type: "int(10) unsigned", + Type: "int(11) unsigned", InnerType: TypeLong, Key: IndexType_PRI, Charset: "", @@ -181,7 +181,7 @@ func TestCreateTableWithLike(t *testing.T) { } expectedDef.Columns = append(expectedDef.Columns, &ColumnDef{ Name: "id", - Type: "int(10) unsigned", + Type: "int(11) unsigned", InnerType: TypeLong, Key: IndexType_PRI, Charset: "", @@ -220,7 +220,7 @@ func TestAlterTableAddColumn(t *testing.T) { } expectedDef.Columns = append(expectedDef.Columns, &ColumnDef{ Name: "id", - Type: "int(10) unsigned", + Type: "int(11) unsigned", InnerType: TypeLong, Key: IndexType_PRI, Charset: "", @@ -288,7 +288,7 @@ func TestAlterTableAddColumnWithPos(t *testing.T) { } expectedDef.Columns = append(expectedDef.Columns, &ColumnDef{ Name: "id", - Type: "int(10) unsigned", + Type: "int(11) unsigned", InnerType: TypeLong, Key: IndexType_PRI, Charset: "", @@ -347,7 +347,7 @@ func TestAlterTableDropColumn(t *testing.T) { } expectedDef.Columns = append(expectedDef.Columns, &ColumnDef{ Name: "id", - Type: "int(10) unsigned", + Type: "int(11) unsigned", InnerType: TypeLong, Key: IndexType_PRI, Charset: "", @@ -411,7 +411,7 @@ func TestAlterTableAddIndex(t *testing.T) { } expectedDef.Columns = append(expectedDef.Columns, &ColumnDef{ Name: "id", - Type: "int(10) unsigned", + Type: "int(11) unsigned", InnerType: TypeLong, Key: IndexType_PRI, Charset: "", @@ -490,7 +490,7 @@ func TestAlterTableAddIndexLowerCase(t *testing.T) { } expectedDef.Columns = append(expectedDef.Columns, &ColumnDef{ Name: "ID", - Type: "int(10) unsigned", + Type: "int(11) unsigned", InnerType: TypeLong, Key: IndexType_PRI, Charset: "", @@ -562,7 +562,7 @@ func TestAlterTableDropIndex(t *testing.T) { } expectedDef.Columns = append(expectedDef.Columns, &ColumnDef{ Name: "id", - Type: "int(10) unsigned", + Type: "int(11) unsigned", InnerType: TypeLong, Key: IndexType_MUL, Charset: "", @@ -626,7 +626,7 @@ func TestAlterTableModifyColumn(t *testing.T) { } expectedDef.Columns = append(expectedDef.Columns, &ColumnDef{ Name: "id", - Type: "int(10) unsigned", + Type: "int(11) unsigned", InnerType: TypeLong, Key: IndexType_NONE, Charset: "", @@ -694,7 +694,7 @@ func TestAlterTableModifyColumnWithPos(t *testing.T) { }) expectedDef.Columns = append(expectedDef.Columns, &ColumnDef{ Name: "id", - Type: "int(10) unsigned", + Type: "int(11) unsigned", InnerType: TypeLong, Key: IndexType_NONE, Charset: "", @@ -734,7 +734,7 @@ func TestAlterTableChangeColumn(t *testing.T) { } expectedDef.Columns = append(expectedDef.Columns, &ColumnDef{ Name: "id", - Type: "int(10) unsigned", + Type: "int(11) unsigned", InnerType: TypeLong, Key: IndexType_NONE, Charset: "", @@ -796,7 +796,7 @@ func TestAlterTableRenameTable(t *testing.T) { } expectedDef.Columns = append(expectedDef.Columns, &ColumnDef{ Name: "id", - Type: "int(10) unsigned", + Type: "int(11) unsigned", InnerType: TypeLong, Key: IndexType_MUL, Charset: "", @@ -885,7 +885,7 @@ func TestCreateIndex(t *testing.T) { } expectedDef.Columns = append(expectedDef.Columns, &ColumnDef{ Name: "id", - Type: "int(10) unsigned", + Type: "int(11) unsigned", InnerType: TypeLong, Key: IndexType_MUL, Charset: "", @@ -947,7 +947,7 @@ func TestRenameTable(t *testing.T) { } expectedDef.Columns = append(expectedDef.Columns, &ColumnDef{ Name: "id", - Type: "int(10) unsigned", + Type: "int(11) unsigned", InnerType: TypeLong, Key: IndexType_PRI, Charset: "", @@ -980,6 +980,76 @@ func TestRenameTable(t *testing.T) { } +func TestRenameTableMulti(t *testing.T) { + var err error + expectedDef := &TableDef{ + Name: "test2", + Database: "test", + Charset: "gbk", + } + expectedDef.Columns = append(expectedDef.Columns, &ColumnDef{ + Name: "id", + Type: "int(11) unsigned", + InnerType: TypeLong, + Key: IndexType_PRI, + Charset: "", + Unsigned: true, + Nullable: false, + }) + expectedDefTest4 := &TableDef{ + Name: "test4", + Database: "test", + Charset: "gbk", + } + expectedDefTest4.Columns = append(expectedDefTest4.Columns, &ColumnDef{ + Name: "id", + Type: "int(10) unsigned", + InnerType: TypeLong, + Key: IndexType_PRI, + Charset: "", + Unsigned: true, + Nullable: false, + }) + executor := NewExecutor(NewDefaultConfig()) + err = executor.Exec(` + create database test; + create table test.test1( + id int unsigned auto_increment, + primary key (id) + ) CHARACTER SET gbk; + create table test.test3( + id int(10) unsigned auto_increment, + primary key (id) + ) CHARACTER SET gbk;`) + require.Nil(t, err) + + err = executor.Exec(` + use test; + rename table test1 to test.test2, test3 to test4;`) + require.Nil(t, err) + + tableDef, err := executor.GetTableDef("test", "test1") + // It should be failed because test.test1 doesn't exist + require.NotNil(t, err) + + tableDef, err = executor.GetTableDef("test", "test3") + // It should be failed because test.test3 doesn't exist + require.NotNil(t, err) + + tableDef, err = executor.GetTableDef("test", "test2") + require.Nil(t, err) + + tableDef.Indices = nil + require.Equal(t, expectedDef, tableDef) + + tableDef, err = executor.GetTableDef("test", "test4") + require.Nil(t, err) + + tableDef.Indices = nil + require.Equal(t, expectedDefTest4, tableDef) + +} + func TestLowerCaseTableNames(t *testing.T) { var err error executor := NewExecutor(NewDefaultConfig()) @@ -1030,7 +1100,7 @@ func TestDropIndex(t *testing.T) { } expectedDef.Columns = append(expectedDef.Columns, &ColumnDef{ Name: "id", - Type: "int(10) unsigned", + Type: "int(11) unsigned", InnerType: TypeLong, Key: IndexType_NONE, Charset: "",