github.com/XiaoMi/Gaea@v1.2.5/parser/ast/ddl_test.go (about)

     1  // Copyright 2017 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package ast_test
    15  
    16  import (
    17  	. "github.com/pingcap/check"
    18  
    19  	. "github.com/XiaoMi/Gaea/parser/ast"
    20  )
    21  
    22  var _ = Suite(&testDDLSuite{})
    23  
    24  type testDDLSuite struct {
    25  }
    26  
    27  func (ts *testDDLSuite) TestDDLVisitorCover(c *C) {
    28  	ce := &checkExpr{}
    29  	constraint := &Constraint{Keys: []*IndexColName{{Column: &ColumnName{}}, {Column: &ColumnName{}}}, Refer: &ReferenceDef{}, Option: &IndexOption{}}
    30  
    31  	alterTableSpec := &AlterTableSpec{Constraint: constraint, Options: []*TableOption{{}}, NewTable: &TableName{}, NewColumns: []*ColumnDef{{Name: &ColumnName{}}}, OldColumnName: &ColumnName{}, Position: &ColumnPosition{RelativeColumn: &ColumnName{}}}
    32  
    33  	stmts := []struct {
    34  		node             Node
    35  		expectedEnterCnt int
    36  		expectedLeaveCnt int
    37  	}{
    38  		{&CreateDatabaseStmt{}, 0, 0},
    39  		{&DropDatabaseStmt{}, 0, 0},
    40  		{&DropIndexStmt{Table: &TableName{}}, 0, 0},
    41  		{&DropTableStmt{Tables: []*TableName{{}, {}}}, 0, 0},
    42  		{&RenameTableStmt{OldTable: &TableName{}, NewTable: &TableName{}}, 0, 0},
    43  		{&TruncateTableStmt{Table: &TableName{}}, 0, 0},
    44  
    45  		// TODO: cover children
    46  		{&AlterTableStmt{Table: &TableName{}, Specs: []*AlterTableSpec{alterTableSpec}}, 0, 0},
    47  		{&CreateIndexStmt{Table: &TableName{}}, 0, 0},
    48  		{&CreateTableStmt{Table: &TableName{}, ReferTable: &TableName{}}, 0, 0},
    49  		{&CreateViewStmt{ViewName: &TableName{}, Select: &SelectStmt{}}, 0, 0},
    50  		{&AlterTableSpec{}, 0, 0},
    51  		{&ColumnDef{Name: &ColumnName{}, Options: []*ColumnOption{{Expr: ce}}}, 1, 1},
    52  		{&ColumnOption{Expr: ce}, 1, 1},
    53  		{&ColumnPosition{RelativeColumn: &ColumnName{}}, 0, 0},
    54  		{&Constraint{Keys: []*IndexColName{{Column: &ColumnName{}}, {Column: &ColumnName{}}}, Refer: &ReferenceDef{}, Option: &IndexOption{}}, 0, 0},
    55  		{&IndexColName{Column: &ColumnName{}}, 0, 0},
    56  		{&ReferenceDef{Table: &TableName{}, IndexColNames: []*IndexColName{{Column: &ColumnName{}}, {Column: &ColumnName{}}}, OnDelete: &OnDeleteOpt{}, OnUpdate: &OnUpdateOpt{}}, 0, 0},
    57  	}
    58  
    59  	for _, v := range stmts {
    60  		ce.reset()
    61  		v.node.Accept(checkVisitor{})
    62  		c.Check(ce.enterCnt, Equals, v.expectedEnterCnt)
    63  		c.Check(ce.leaveCnt, Equals, v.expectedLeaveCnt)
    64  		v.node.Accept(visitor1{})
    65  	}
    66  }
    67  
    68  func (ts *testDDLSuite) TestDDLIndexColNameRestore(c *C) {
    69  	testCases := []NodeRestoreTestCase{
    70  		{"world", "`world`"},
    71  		{"world(2)", "`world`(2)"},
    72  	}
    73  	extractNodeFunc := func(node Node) Node {
    74  		return node.(*CreateIndexStmt).IndexColNames[0]
    75  	}
    76  	RunNodeRestoreTest(c, testCases, "CREATE INDEX idx ON t (%s) USING HASH", extractNodeFunc)
    77  }
    78  
    79  func (ts *testDDLSuite) TestDDLOnDeleteRestore(c *C) {
    80  	testCases := []NodeRestoreTestCase{
    81  		{"on delete restrict", "ON DELETE RESTRICT"},
    82  		{"on delete CASCADE", "ON DELETE CASCADE"},
    83  		{"on delete SET NULL", "ON DELETE SET NULL"},
    84  		{"on delete no action", "ON DELETE NO ACTION"},
    85  	}
    86  	extractNodeFunc := func(node Node) Node {
    87  		return node.(*CreateTableStmt).Constraints[1].Refer.OnDelete
    88  	}
    89  	RunNodeRestoreTest(c, testCases, "CREATE TABLE child (id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id) %s)", extractNodeFunc)
    90  }
    91  
    92  func (ts *testDDLSuite) TestDDLOnUpdateRestore(c *C) {
    93  	testCases := []NodeRestoreTestCase{
    94  		{"ON UPDATE RESTRICT", "ON UPDATE RESTRICT"},
    95  		{"on update CASCADE", "ON UPDATE CASCADE"},
    96  		{"on update SET NULL", "ON UPDATE SET NULL"},
    97  		{"on update no action", "ON UPDATE NO ACTION"},
    98  	}
    99  	extractNodeFunc := func(node Node) Node {
   100  		return node.(*CreateTableStmt).Constraints[1].Refer.OnUpdate
   101  	}
   102  	RunNodeRestoreTest(c, testCases, "CREATE TABLE child ( id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE %s )", extractNodeFunc)
   103  }
   104  
   105  func (ts *testDDLSuite) TestDDLIndexOption(c *C) {
   106  	testCases := []NodeRestoreTestCase{
   107  		{"key_block_size=16", "KEY_BLOCK_SIZE=16"},
   108  		{"USING HASH", "USING HASH"},
   109  		{"comment 'hello'", "COMMENT 'hello'"},
   110  		{"key_block_size=16 USING HASH", "KEY_BLOCK_SIZE=16 USING HASH"},
   111  		{"USING HASH KEY_BLOCK_SIZE=16", "KEY_BLOCK_SIZE=16 USING HASH"},
   112  		{"USING HASH COMMENT 'foo'", "USING HASH COMMENT 'foo'"},
   113  		{"COMMENT 'foo'", "COMMENT 'foo'"},
   114  		{"key_block_size = 32 using hash comment 'hello'", "KEY_BLOCK_SIZE=32 USING HASH COMMENT 'hello'"},
   115  		{"key_block_size=32 using btree comment 'hello'", "KEY_BLOCK_SIZE=32 USING BTREE COMMENT 'hello'"},
   116  	}
   117  	extractNodeFunc := func(node Node) Node {
   118  		return node.(*CreateIndexStmt).IndexOption
   119  	}
   120  	RunNodeRestoreTest(c, testCases, "CREATE INDEX idx ON t (a) %s", extractNodeFunc)
   121  }
   122  
   123  func (ts *testDDLSuite) TestTableToTableRestore(c *C) {
   124  	testCases := []NodeRestoreTestCase{
   125  		{"t1 to t2", "`t1` TO `t2`"},
   126  	}
   127  	extractNodeFunc := func(node Node) Node {
   128  		return node.(*RenameTableStmt).TableToTables[0]
   129  	}
   130  	RunNodeRestoreTest(c, testCases, "rename table %s", extractNodeFunc)
   131  }
   132  
   133  func (ts *testDDLSuite) TestDDLReferenceDefRestore(c *C) {
   134  	testCases := []NodeRestoreTestCase{
   135  		{"REFERENCES parent(id) ON DELETE CASCADE ON UPDATE RESTRICT", "REFERENCES `parent`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT"},
   136  		{"REFERENCES parent(id) ON DELETE CASCADE", "REFERENCES `parent`(`id`) ON DELETE CASCADE"},
   137  		{"REFERENCES parent(id,hello) ON DELETE CASCADE", "REFERENCES `parent`(`id`, `hello`) ON DELETE CASCADE"},
   138  		{"REFERENCES parent(id,hello(12)) ON DELETE CASCADE", "REFERENCES `parent`(`id`, `hello`(12)) ON DELETE CASCADE"},
   139  		{"REFERENCES parent(id(8),hello(12)) ON DELETE CASCADE", "REFERENCES `parent`(`id`(8), `hello`(12)) ON DELETE CASCADE"},
   140  		{"REFERENCES parent(id)", "REFERENCES `parent`(`id`)"},
   141  	}
   142  	extractNodeFunc := func(node Node) Node {
   143  		return node.(*CreateTableStmt).Constraints[1].Refer
   144  	}
   145  	RunNodeRestoreTest(c, testCases, "CREATE TABLE child (id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) %s)", extractNodeFunc)
   146  }
   147  
   148  func (ts *testDDLSuite) TestDDLConstraintRestore(c *C) {
   149  	testCases := []NodeRestoreTestCase{
   150  		{"INDEX par_ind (parent_id)", "INDEX `par_ind`(`parent_id`)"},
   151  		{"INDEX par_ind (parent_id(6))", "INDEX `par_ind`(`parent_id`(6))"},
   152  		{"key par_ind (parent_id)", "INDEX `par_ind`(`parent_id`)"},
   153  		{"unique par_ind (parent_id)", "UNIQUE `par_ind`(`parent_id`)"},
   154  		{"unique key par_ind (parent_id)", "UNIQUE `par_ind`(`parent_id`)"},
   155  		{"unique index par_ind (parent_id)", "UNIQUE `par_ind`(`parent_id`)"},
   156  		{"fulltext key full_id (parent_id)", "FULLTEXT `full_id`(`parent_id`)"},
   157  		{"fulltext INDEX full_id (parent_id)", "FULLTEXT `full_id`(`parent_id`)"},
   158  		{"PRIMARY KEY (id)", "PRIMARY KEY(`id`)"},
   159  		{"PRIMARY KEY (id) key_block_size = 32 using hash comment 'hello'", "PRIMARY KEY(`id`) KEY_BLOCK_SIZE=32 USING HASH COMMENT 'hello'"},
   160  		{"CONSTRAINT FOREIGN KEY (parent_id(2),hello(4)) REFERENCES parent(id) ON DELETE CASCADE", "CONSTRAINT FOREIGN KEY (`parent_id`(2), `hello`(4)) REFERENCES `parent`(`id`) ON DELETE CASCADE"},
   161  		{"CONSTRAINT FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE ON UPDATE RESTRICT", "CONSTRAINT FOREIGN KEY (`parent_id`) REFERENCES `parent`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT"},
   162  		{"CONSTRAINT fk_123 FOREIGN KEY (parent_id(2),hello(4)) REFERENCES parent(id) ON DELETE CASCADE", "CONSTRAINT `fk_123` FOREIGN KEY (`parent_id`(2), `hello`(4)) REFERENCES `parent`(`id`) ON DELETE CASCADE"},
   163  		{"CONSTRAINT fk_123 FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE ON UPDATE RESTRICT", "CONSTRAINT `fk_123` FOREIGN KEY (`parent_id`) REFERENCES `parent`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT"},
   164  		{"FOREIGN KEY (parent_id(2),hello(4)) REFERENCES parent(id) ON DELETE CASCADE", "CONSTRAINT FOREIGN KEY (`parent_id`(2), `hello`(4)) REFERENCES `parent`(`id`) ON DELETE CASCADE"},
   165  		{"FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE ON UPDATE RESTRICT", "CONSTRAINT FOREIGN KEY (`parent_id`) REFERENCES `parent`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT"},
   166  	}
   167  	extractNodeFunc := func(node Node) Node {
   168  		return node.(*CreateTableStmt).Constraints[0]
   169  	}
   170  	RunNodeRestoreTest(c, testCases, "CREATE TABLE child (id INT, parent_id INT, %s)", extractNodeFunc)
   171  }
   172  
   173  func (ts *testDDLSuite) TestDDLColumnOptionRestore(c *C) {
   174  	testCases := []NodeRestoreTestCase{
   175  		{"primary key", "PRIMARY KEY"},
   176  		{"not null", "NOT NULL"},
   177  		{"null", "NULL"},
   178  		{"auto_increment", "AUTO_INCREMENT"},
   179  		{"DEFAULT 10", "DEFAULT 10"},
   180  		{"DEFAULT '10'", "DEFAULT '10'"},
   181  		{"DEFAULT 'hello'", "DEFAULT 'hello'"},
   182  		{"DEFAULT 1.1", "DEFAULT 1.1"},
   183  		{"DEFAULT NULL", "DEFAULT NULL"},
   184  		{"DEFAULT ''", "DEFAULT ''"},
   185  		{"DEFAULT TRUE", "DEFAULT TRUE"},
   186  		{"DEFAULT FALSE", "DEFAULT FALSE"},
   187  		{"UNIQUE KEY", "UNIQUE KEY"},
   188  		{"on update CURRENT_TIMESTAMP", "ON UPDATE CURRENT_TIMESTAMP()"},
   189  		{"comment 'hello'", "COMMENT 'hello'"},
   190  		{"generated always as(id + 1)", "GENERATED ALWAYS AS(`id`+1) VIRTUAL"},
   191  		{"generated always as(id + 1) virtual", "GENERATED ALWAYS AS(`id`+1) VIRTUAL"},
   192  		{"generated always as(id + 1) stored", "GENERATED ALWAYS AS(`id`+1) STORED"},
   193  		{"REFERENCES parent(id)", "REFERENCES `parent`(`id`)"},
   194  	}
   195  	extractNodeFunc := func(node Node) Node {
   196  		return node.(*CreateTableStmt).Cols[0].Options[0]
   197  	}
   198  	RunNodeRestoreTest(c, testCases, "CREATE TABLE child (id INT %s)", extractNodeFunc)
   199  }
   200  
   201  func (ts *testDDLSuite) TestDDLColumnDefRestore(c *C) {
   202  	testCases := []NodeRestoreTestCase{
   203  		// for type
   204  		{"id json", "`id` JSON"},
   205  		{"id time(5)", "`id` TIME(5)"},
   206  		{"id int(5) unsigned", "`id` INT(5) UNSIGNED"},
   207  		{"id int(5) UNSIGNED ZEROFILL", "`id` INT(5) UNSIGNED ZEROFILL"},
   208  		{"id float(12,3)", "`id` FLOAT(12,3)"},
   209  		{"id float", "`id` FLOAT"},
   210  		{"id double(22,3)", "`id` DOUBLE(22,3)"},
   211  		{"id double", "`id` DOUBLE"},
   212  		{"id tinyint(4)", "`id` TINYINT(4)"},
   213  		{"id smallint(6)", "`id` SMALLINT(6)"},
   214  		{"id mediumint(9)", "`id` MEDIUMINT(9)"},
   215  		{"id integer(11)", "`id` INT(11)"},
   216  		{"id bigint(20)", "`id` BIGINT(20)"},
   217  		{"id DATE", "`id` DATE"},
   218  		{"id DATETIME", "`id` DATETIME"},
   219  		{"id DECIMAL(4,2)", "`id` DECIMAL(4,2)"},
   220  		{"id char(1)", "`id` CHAR(1)"},
   221  		{"id varchar(10) BINARY", "`id` VARCHAR(10) BINARY"},
   222  		{"id binary(1)", "`id` BINARY(1)"},
   223  		{"id timestamp(2)", "`id` TIMESTAMP(2)"},
   224  		{"id timestamp", "`id` TIMESTAMP"},
   225  		{"id datetime(2)", "`id` DATETIME(2)"},
   226  		{"id date", "`id` DATE"},
   227  		{"id year", "`id` YEAR"},
   228  		{"id INT", "`id` INT"},
   229  		{"id INT NULL", "`id` INT NULL"},
   230  		{"id enum('a','b')", "`id` ENUM('a','b')"},
   231  		{"id enum('''a''','''b''')", "`id` ENUM('''a''','''b''')"},
   232  		{"id enum('a\\nb','a\\tb','a\\rb')", "`id` ENUM('a\nb','a\tb','a\rb')"},
   233  		{"id set('a','b')", "`id` SET('a','b')"},
   234  		{"id set('''a''','''b''')", "`id` SET('''a''','''b''')"},
   235  		{"id set('a\\nb','a''	\\r\\nb','a\\rb')", "`id` SET('a\nb','a''	\r\nb','a\rb')"},
   236  		{`id set("a'\nb","a'b\tc")`, "`id` SET('a''\nb','a''b\tc')"},
   237  		{"id TEXT CHARACTER SET UTF8 COLLATE UTF8_UNICODE_G", "`id` TEXT CHARACTER SET UTF8 COLLATE UTF8_UNICODE_G"},
   238  		{"id text character set UTF8", "`id` TEXT CHARACTER SET UTF8"},
   239  		{"id text charset UTF8", "`id` TEXT CHARACTER SET UTF8"},
   240  		{"id varchar(50) collate UTF8MB4_CZECH_CI", "`id` VARCHAR(50) COLLATE UTF8MB4_CZECH_CI"},
   241  		{"id varchar(50) collate utf8", "`id` VARCHAR(50) COLLATE utf8"},
   242  		{"c1 char(10) character set LATIN1 collate latin1_german1_ci", "`c1` CHAR(10) CHARACTER SET LATIN1 COLLATE latin1_german1_ci"},
   243  
   244  		{"id int(11) PRIMARY KEY", "`id` INT(11) PRIMARY KEY"},
   245  		{"id int(11) NOT NULL", "`id` INT(11) NOT NULL"},
   246  		{"id INT(11) NULL", "`id` INT(11) NULL"},
   247  		{"id INT(11) auto_increment", "`id` INT(11) AUTO_INCREMENT"},
   248  		{"id INT(11) DEFAULT 10", "`id` INT(11) DEFAULT 10"},
   249  		{"id INT(11) DEFAULT '10'", "`id` INT(11) DEFAULT '10'"},
   250  		{"id INT(11) DEFAULT 1.1", "`id` INT(11) DEFAULT 1.1"},
   251  		{"id INT(11) UNIQUE KEY", "`id` INT(11) UNIQUE KEY"},
   252  		{"id INT(11) on update CURRENT_TIMESTAMP", "`id` INT(11) ON UPDATE CURRENT_TIMESTAMP()"},
   253  		{"id INT(11) comment 'hello'", "`id` INT(11) COMMENT 'hello'"},
   254  		{"id INT(11) generated always as(id + 1)", "`id` INT(11) GENERATED ALWAYS AS(`id`+1) VIRTUAL"},
   255  		{"id INT(11) REFERENCES parent(id)", "`id` INT(11) REFERENCES `parent`(`id`)"},
   256  	}
   257  	extractNodeFunc := func(node Node) Node {
   258  		return node.(*CreateTableStmt).Cols[0]
   259  	}
   260  	RunNodeRestoreTest(c, testCases, "CREATE TABLE t (%s)", extractNodeFunc)
   261  }
   262  
   263  func (ts *testDDLSuite) TestDDLTruncateTableStmtRestore(c *C) {
   264  	testCases := []NodeRestoreTestCase{
   265  		{"truncate t1", "TRUNCATE TABLE `t1`"},
   266  		{"truncate table t1", "TRUNCATE TABLE `t1`"},
   267  		{"truncate a.t1", "TRUNCATE TABLE `a`.`t1`"},
   268  	}
   269  	extractNodeFunc := func(node Node) Node {
   270  		return node.(*TruncateTableStmt)
   271  	}
   272  	RunNodeRestoreTest(c, testCases, "%s", extractNodeFunc)
   273  }
   274  
   275  func (ts *testDDLSuite) TestColumnPositionRestore(c *C) {
   276  	testCases := []NodeRestoreTestCase{
   277  		{"", ""},
   278  		{"first", "FIRST"},
   279  		{"after b", "AFTER `b`"},
   280  	}
   281  	extractNodeFunc := func(node Node) Node {
   282  		return node.(*AlterTableStmt).Specs[0].Position
   283  	}
   284  	RunNodeRestoreTest(c, testCases, "alter table t add column a varchar(255) %s", extractNodeFunc)
   285  }
   286  
   287  func (ts *testDDLSuite) TestAlterTableSpecRestore(c *C) {
   288  	testCases := []NodeRestoreTestCase{
   289  		{"ENGINE innodb", "ENGINE = innodb"},
   290  		{"ENGINE = innodb", "ENGINE = innodb"},
   291  		{"ENGINE = 'innodb'", "ENGINE = innodb"},
   292  		{"DEFAULT CHARACTER SET utf8", "DEFAULT CHARACTER SET = UTF8"},
   293  		{"DEFAULT CHARACTER SET = utf8", "DEFAULT CHARACTER SET = UTF8"},
   294  		{"DEFAULT CHARSET utf8", "DEFAULT CHARACTER SET = UTF8"},
   295  		{"DEFAULT CHARSET = utf8", "DEFAULT CHARACTER SET = UTF8"},
   296  		{"DEFAULT COLLATE utf8_bin", "DEFAULT COLLATE = UTF8_BIN"},
   297  		{"DEFAULT COLLATE = utf8_bin", "DEFAULT COLLATE = UTF8_BIN"},
   298  		{"AUTO_INCREMENT 3", "AUTO_INCREMENT = 3"},
   299  		{"AUTO_INCREMENT = 6", "AUTO_INCREMENT = 6"},
   300  		{"COMMENT ''", "COMMENT = ''"},
   301  		{"COMMENT 'system role'", "COMMENT = 'system role'"},
   302  		{"COMMENT = 'system role'", "COMMENT = 'system role'"},
   303  		{"AVG_ROW_LENGTH 12", "AVG_ROW_LENGTH = 12"},
   304  		{"AVG_ROW_LENGTH = 6", "AVG_ROW_LENGTH = 6"},
   305  		{"connection 'abc'", "CONNECTION = 'abc'"},
   306  		{"CONNECTION = 'abc'", "CONNECTION = 'abc'"},
   307  		{"checksum 1", "CHECKSUM = 1"},
   308  		{"checksum = 0", "CHECKSUM = 0"},
   309  		{"PASSWORD '123456'", "PASSWORD = '123456'"},
   310  		{"PASSWORD = ''", "PASSWORD = ''"},
   311  		{"compression 'NONE'", "COMPRESSION = 'NONE'"},
   312  		{"compression = 'lz4'", "COMPRESSION = 'lz4'"},
   313  		{"key_block_size 1024", "KEY_BLOCK_SIZE = 1024"},
   314  		{"KEY_BLOCK_SIZE = 1024", "KEY_BLOCK_SIZE = 1024"},
   315  		{"max_rows 1000", "MAX_ROWS = 1000"},
   316  		{"max_rows = 1000", "MAX_ROWS = 1000"},
   317  		{"min_rows 1000", "MIN_ROWS = 1000"},
   318  		{"MIN_ROWS = 1000", "MIN_ROWS = 1000"},
   319  		{"DELAY_KEY_WRITE 1", "DELAY_KEY_WRITE = 1"},
   320  		{"DELAY_KEY_WRITE = 1000", "DELAY_KEY_WRITE = 1000"},
   321  		{"ROW_FORMAT default", "ROW_FORMAT = DEFAULT"},
   322  		{"ROW_FORMAT = default", "ROW_FORMAT = DEFAULT"},
   323  		{"ROW_FORMAT = fixed", "ROW_FORMAT = FIXED"},
   324  		{"ROW_FORMAT = compressed", "ROW_FORMAT = COMPRESSED"},
   325  		{"ROW_FORMAT = compact", "ROW_FORMAT = COMPACT"},
   326  		{"ROW_FORMAT = redundant", "ROW_FORMAT = REDUNDANT"},
   327  		{"ROW_FORMAT = dynamic", "ROW_FORMAT = DYNAMIC"},
   328  		{"shard_row_id_bits 1", "SHARD_ROW_ID_BITS = 1"},
   329  		{"shard_row_id_bits = 1", "SHARD_ROW_ID_BITS = 1"},
   330  		{"CONVERT TO CHARACTER SET utf8", "DEFAULT CHARACTER SET = UTF8"},
   331  		{"CONVERT TO CHARSET utf8", "DEFAULT CHARACTER SET = UTF8"},
   332  		{"CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin", "CONVERT TO CHARACTER SET UTF8 COLLATE UTF8_BIN"},
   333  		{"CONVERT TO CHARSET utf8 COLLATE utf8_bin", "CONVERT TO CHARACTER SET UTF8 COLLATE UTF8_BIN"},
   334  		{"ADD COLUMN (a SMALLINT UNSIGNED)", "ADD COLUMN (`a` SMALLINT UNSIGNED)"},
   335  		{"ADD COLUMN (a SMALLINT UNSIGNED, b varchar(255))", "ADD COLUMN (`a` SMALLINT UNSIGNED, `b` VARCHAR(255))"},
   336  		{"ADD COLUMN a SMALLINT UNSIGNED", "ADD COLUMN `a` SMALLINT UNSIGNED"},
   337  		{"ADD COLUMN a SMALLINT UNSIGNED FIRST", "ADD COLUMN `a` SMALLINT UNSIGNED FIRST"},
   338  		{"ADD COLUMN a SMALLINT UNSIGNED AFTER b", "ADD COLUMN `a` SMALLINT UNSIGNED AFTER `b`"},
   339  		{"ADD COLUMN name mediumtext CHARACTER SET UTF8MB4 COLLATE utf8mb4_unicode_ci NOT NULL", "ADD COLUMN `name` MEDIUMTEXT CHARACTER SET UTF8MB4 COLLATE utf8mb4_unicode_ci NOT NULL"},
   340  		{"ADD CONSTRAINT INDEX par_ind (parent_id)", "ADD INDEX `par_ind`(`parent_id`)"},
   341  		{"ADD CONSTRAINT INDEX par_ind (parent_id(6))", "ADD INDEX `par_ind`(`parent_id`(6))"},
   342  		{"ADD CONSTRAINT key par_ind (parent_id)", "ADD INDEX `par_ind`(`parent_id`)"},
   343  		{"ADD CONSTRAINT unique par_ind (parent_id)", "ADD UNIQUE `par_ind`(`parent_id`)"},
   344  		{"ADD CONSTRAINT unique key par_ind (parent_id)", "ADD UNIQUE `par_ind`(`parent_id`)"},
   345  		{"ADD CONSTRAINT unique index par_ind (parent_id)", "ADD UNIQUE `par_ind`(`parent_id`)"},
   346  		{"ADD CONSTRAINT fulltext key full_id (parent_id)", "ADD FULLTEXT `full_id`(`parent_id`)"},
   347  		{"ADD CONSTRAINT fulltext INDEX full_id (parent_id)", "ADD FULLTEXT `full_id`(`parent_id`)"},
   348  		{"ADD CONSTRAINT PRIMARY KEY (id)", "ADD PRIMARY KEY(`id`)"},
   349  		{"ADD CONSTRAINT PRIMARY KEY (id) key_block_size = 32 using hash comment 'hello'", "ADD PRIMARY KEY(`id`) KEY_BLOCK_SIZE=32 USING HASH COMMENT 'hello'"},
   350  		{"ADD CONSTRAINT FOREIGN KEY (parent_id(2),hello(4)) REFERENCES parent(id) ON DELETE CASCADE", "ADD CONSTRAINT FOREIGN KEY (`parent_id`(2), `hello`(4)) REFERENCES `parent`(`id`) ON DELETE CASCADE"},
   351  		{"ADD CONSTRAINT FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE ON UPDATE RESTRICT", "ADD CONSTRAINT FOREIGN KEY (`parent_id`) REFERENCES `parent`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT"},
   352  		{"ADD CONSTRAINT fk_123 FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE ON UPDATE RESTRICT", "ADD CONSTRAINT `fk_123` FOREIGN KEY (`parent_id`) REFERENCES `parent`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT"},
   353  		{"DROP COLUMN a", "DROP COLUMN `a`"},
   354  		{"DROP COLUMN a RESTRICT", "DROP COLUMN `a`"},
   355  		{"DROP COLUMN a CASCADE", "DROP COLUMN `a`"},
   356  		{"DROP PRIMARY KEY", "DROP PRIMARY KEY"},
   357  		{"drop index a", "DROP INDEX `a`"},
   358  		{"drop key a", "DROP INDEX `a`"},
   359  		{"drop FOREIGN key a", "DROP FOREIGN KEY `a`"},
   360  		{"MODIFY column a varchar(255)", "MODIFY COLUMN `a` VARCHAR(255)"},
   361  		{"modify COLUMN a varchar(255) FIRST", "MODIFY COLUMN `a` VARCHAR(255) FIRST"},
   362  		{"modify COLUMN a varchar(255) AFTER b", "MODIFY COLUMN `a` VARCHAR(255) AFTER `b`"},
   363  		{"change column a b VARCHAR(255)", "CHANGE COLUMN `a` `b` VARCHAR(255)"},
   364  		{"change COLUMN a b varchar(255) CHARACTER SET UTF8 BINARY", "CHANGE COLUMN `a` `b` VARCHAR(255) BINARY CHARACTER SET UTF8"},
   365  		{"CHANGE column a b varchar(255) FIRST", "CHANGE COLUMN `a` `b` VARCHAR(255) FIRST"},
   366  		{"change COLUMN a b varchar(255) AFTER c", "CHANGE COLUMN `a` `b` VARCHAR(255) AFTER `c`"},
   367  		{"RENAME db1.t1", "RENAME AS `db1`.`t1`"},
   368  		{"RENAME to db1.t1", "RENAME AS `db1`.`t1`"},
   369  		{"RENAME as t1", "RENAME AS `t1`"},
   370  		{"ALTER a SET DEFAULT 1", "ALTER COLUMN `a` SET DEFAULT 1"},
   371  		{"ALTER a DROP DEFAULT", "ALTER COLUMN `a` DROP DEFAULT"},
   372  		{"ALTER COLUMN a SET DEFAULT 1", "ALTER COLUMN `a` SET DEFAULT 1"},
   373  		{"ALTER COLUMN a DROP DEFAULT", "ALTER COLUMN `a` DROP DEFAULT"},
   374  		{"LOCK=NONE", "LOCK = NONE"},
   375  		{"LOCK=DEFAULT", "LOCK = DEFAULT"},
   376  		{"LOCK=SHARED", "LOCK = SHARED"},
   377  		{"LOCK=EXCLUSIVE", "LOCK = EXCLUSIVE"},
   378  		{"RENAME KEY a TO b", "RENAME INDEX `a` TO `b`"},
   379  		{"RENAME INDEX a TO b", "RENAME INDEX `a` TO `b`"},
   380  		{"ADD PARTITION", "ADD PARTITION"},
   381  		{"ADD PARTITION ( PARTITION P1 VALUES LESS THAN (2010))", "ADD PARTITION (PARTITION `P1` VALUES LESS THAN (2010))"},
   382  		{"ADD PARTITION ( PARTITION P2 VALUES LESS THAN MAXVALUE)", "ADD PARTITION (PARTITION `P2` VALUES LESS THAN (MAXVALUE))"},
   383  		{"ADD PARTITION (\nPARTITION P1 VALUES LESS THAN (2010),\nPARTITION P2 VALUES LESS THAN (2015),\nPARTITION P3 VALUES LESS THAN MAXVALUE)", "ADD PARTITION (PARTITION `P1` VALUES LESS THAN (2010), PARTITION `P2` VALUES LESS THAN (2015), PARTITION `P3` VALUES LESS THAN (MAXVALUE))"},
   384  		{"ADD PARTITION (PARTITION `p5` VALUES LESS THAN (2010) COMMENT 'AP_START \\' AP_END')", "ADD PARTITION (PARTITION `p5` VALUES LESS THAN (2010) COMMENT = 'AP_START '' AP_END')"},
   385  		{"ADD PARTITION (PARTITION `p5` VALUES LESS THAN (2010) COMMENT = 'xxx')", "ADD PARTITION (PARTITION `p5` VALUES LESS THAN (2010) COMMENT = 'xxx')"},
   386  		{"coalesce partition 3", "COALESCE PARTITION 3"},
   387  		{"drop partition p1", "DROP PARTITION `p1`"},
   388  		{"TRUNCATE PARTITION p0", "TRUNCATE PARTITION `p0`"},
   389  	}
   390  	extractNodeFunc := func(node Node) Node {
   391  		return node.(*AlterTableStmt).Specs[0]
   392  	}
   393  	RunNodeRestoreTest(c, testCases, "ALTER TABLE t %s", extractNodeFunc)
   394  }