github.com/pingcap/tidb/parser@v0.0.0-20231013125129-93a834a6bf8d/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  	"testing"
    18  
    19  	. "github.com/pingcap/tidb/parser/ast"
    20  	"github.com/pingcap/tidb/parser/format"
    21  	"github.com/stretchr/testify/require"
    22  )
    23  
    24  func TestDDLVisitorCover(t *testing.T) {
    25  	ce := &checkExpr{}
    26  	constraint := &Constraint{Keys: []*IndexPartSpecification{{Column: &ColumnName{}}, {Column: &ColumnName{}}}, Refer: &ReferenceDef{}, Option: &IndexOption{}}
    27  
    28  	alterTableSpec := &AlterTableSpec{Constraint: constraint, Options: []*TableOption{{}}, NewTable: &TableName{}, NewColumns: []*ColumnDef{{Name: &ColumnName{}}}, OldColumnName: &ColumnName{}, Position: &ColumnPosition{RelativeColumn: &ColumnName{}}, AttributesSpec: &AttributesSpec{}}
    29  
    30  	stmts := []struct {
    31  		node             Node
    32  		expectedEnterCnt int
    33  		expectedLeaveCnt int
    34  	}{
    35  		{&CreateDatabaseStmt{}, 0, 0},
    36  		{&AlterDatabaseStmt{}, 0, 0},
    37  		{&DropDatabaseStmt{}, 0, 0},
    38  		{&DropIndexStmt{Table: &TableName{}}, 0, 0},
    39  		{&DropTableStmt{Tables: []*TableName{{}, {}}}, 0, 0},
    40  		{&RenameTableStmt{TableToTables: []*TableToTable{}}, 0, 0},
    41  		{&TruncateTableStmt{Table: &TableName{}}, 0, 0},
    42  
    43  		// TODO: cover children
    44  		{&AlterTableStmt{Table: &TableName{}, Specs: []*AlterTableSpec{alterTableSpec}}, 0, 0},
    45  		{&CreateIndexStmt{Table: &TableName{}}, 0, 0},
    46  		{&CreateTableStmt{Table: &TableName{}, ReferTable: &TableName{}}, 0, 0},
    47  		{&CreateViewStmt{ViewName: &TableName{}, Select: &SelectStmt{}}, 0, 0},
    48  		{&AlterTableSpec{}, 0, 0},
    49  		{&ColumnDef{Name: &ColumnName{}, Options: []*ColumnOption{{Expr: ce}}}, 1, 1},
    50  		{&ColumnOption{Expr: ce}, 1, 1},
    51  		{&ColumnPosition{RelativeColumn: &ColumnName{}}, 0, 0},
    52  		{&Constraint{Keys: []*IndexPartSpecification{{Column: &ColumnName{}}, {Column: &ColumnName{}}}, Refer: &ReferenceDef{}, Option: &IndexOption{}}, 0, 0},
    53  		{&IndexPartSpecification{Column: &ColumnName{}}, 0, 0},
    54  		{&ReferenceDef{Table: &TableName{}, IndexPartSpecifications: []*IndexPartSpecification{{Column: &ColumnName{}}, {Column: &ColumnName{}}}, OnDelete: &OnDeleteOpt{}, OnUpdate: &OnUpdateOpt{}}, 0, 0},
    55  		{&AlterTableSpec{NewConstraints: []*Constraint{constraint, constraint}}, 0, 0},
    56  		{&AlterTableSpec{NewConstraints: []*Constraint{constraint}, NewColumns: []*ColumnDef{{Name: &ColumnName{}}}}, 0, 0},
    57  	}
    58  
    59  	for _, v := range stmts {
    60  		ce.reset()
    61  		v.node.Accept(checkVisitor{})
    62  		require.Equal(t, v.expectedEnterCnt, ce.enterCnt)
    63  		require.Equal(t, v.expectedLeaveCnt, ce.leaveCnt)
    64  		v.node.Accept(visitor1{})
    65  	}
    66  }
    67  
    68  func TestDDLIndexColNameRestore(t *testing.T) {
    69  	testCases := []NodeRestoreTestCase{
    70  		{"(a + 1)", "(`a`+1)"},
    71  		{"(1 * 1 + (1 + 1))", "(1*1+(1+1))"},
    72  		{"((1 * 1 + (1 + 1)))", "((1*1+(1+1)))"},
    73  	}
    74  	extractNodeFunc := func(node Node) Node {
    75  		return node.(*CreateIndexStmt).IndexPartSpecifications[0]
    76  	}
    77  	runNodeRestoreTest(t, testCases, "CREATE INDEX idx ON t (%s) USING HASH", extractNodeFunc)
    78  }
    79  
    80  func TestDDLIndexExprRestore(t *testing.T) {
    81  	testCases := []NodeRestoreTestCase{
    82  		{"world", "`world`"},
    83  		{"world(2)", "`world`(2)"},
    84  	}
    85  	extractNodeFunc := func(node Node) Node {
    86  		return node.(*CreateIndexStmt).IndexPartSpecifications[0]
    87  	}
    88  	runNodeRestoreTest(t, testCases, "CREATE INDEX idx ON t (%s) USING HASH", extractNodeFunc)
    89  }
    90  
    91  func TestDDLOnDeleteRestore(t *testing.T) {
    92  	testCases := []NodeRestoreTestCase{
    93  		{"on delete restrict", "ON DELETE RESTRICT"},
    94  		{"on delete CASCADE", "ON DELETE CASCADE"},
    95  		{"on delete SET NULL", "ON DELETE SET NULL"},
    96  		{"on delete no action", "ON DELETE NO ACTION"},
    97  	}
    98  	extractNodeFunc := func(node Node) Node {
    99  		return node.(*CreateTableStmt).Constraints[1].Refer.OnDelete
   100  	}
   101  	runNodeRestoreTest(t, testCases, "CREATE TABLE child (id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id) %s)", extractNodeFunc)
   102  	runNodeRestoreTest(t, testCases, "CREATE TABLE child (id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id) on update CASCADE %s)", extractNodeFunc)
   103  	runNodeRestoreTest(t, testCases, "CREATE TABLE child (id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id) %s on update CASCADE)", extractNodeFunc)
   104  }
   105  
   106  func TestDDLOnUpdateRestore(t *testing.T) {
   107  	testCases := []NodeRestoreTestCase{
   108  		{"ON UPDATE RESTRICT", "ON UPDATE RESTRICT"},
   109  		{"on update CASCADE", "ON UPDATE CASCADE"},
   110  		{"on update SET NULL", "ON UPDATE SET NULL"},
   111  		{"on update no action", "ON UPDATE NO ACTION"},
   112  	}
   113  	extractNodeFunc := func(node Node) Node {
   114  		return node.(*CreateTableStmt).Constraints[1].Refer.OnUpdate
   115  	}
   116  	runNodeRestoreTest(t, 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)
   117  	runNodeRestoreTest(t, testCases, "CREATE TABLE child ( id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id) %s ON DELETE CASCADE)", extractNodeFunc)
   118  	runNodeRestoreTest(t, testCases, "CREATE TABLE child ( id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id)  %s )", extractNodeFunc)
   119  }
   120  
   121  func TestDDLIndexOption(t *testing.T) {
   122  	testCases := []NodeRestoreTestCase{
   123  		{"key_block_size=16", "KEY_BLOCK_SIZE=16"},
   124  		{"USING HASH", "USING HASH"},
   125  		{"comment 'hello'", "COMMENT 'hello'"},
   126  		{"key_block_size=16 USING HASH", "KEY_BLOCK_SIZE=16 USING HASH"},
   127  		{"USING HASH KEY_BLOCK_SIZE=16", "KEY_BLOCK_SIZE=16 USING HASH"},
   128  		{"USING HASH COMMENT 'foo'", "USING HASH COMMENT 'foo'"},
   129  		{"COMMENT 'foo'", "COMMENT 'foo'"},
   130  		{"key_block_size = 32 using hash comment 'hello'", "KEY_BLOCK_SIZE=32 USING HASH COMMENT 'hello'"},
   131  		{"key_block_size=32 using btree comment 'hello'", "KEY_BLOCK_SIZE=32 USING BTREE COMMENT 'hello'"},
   132  	}
   133  	extractNodeFunc := func(node Node) Node {
   134  		return node.(*CreateIndexStmt).IndexOption
   135  	}
   136  	runNodeRestoreTest(t, testCases, "CREATE INDEX idx ON t (a) %s", extractNodeFunc)
   137  }
   138  
   139  func TestTableToTableRestore(t *testing.T) {
   140  	testCases := []NodeRestoreTestCase{
   141  		{"t1 to t2", "`t1` TO `t2`"},
   142  	}
   143  	extractNodeFunc := func(node Node) Node {
   144  		return node.(*RenameTableStmt).TableToTables[0]
   145  	}
   146  	runNodeRestoreTest(t, testCases, "rename table %s", extractNodeFunc)
   147  }
   148  
   149  func TestDDLReferenceDefRestore(t *testing.T) {
   150  	testCases := []NodeRestoreTestCase{
   151  		{"REFERENCES parent(id) ON DELETE CASCADE ON UPDATE RESTRICT", "REFERENCES `parent`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT"},
   152  		{"REFERENCES parent(id) ON DELETE CASCADE", "REFERENCES `parent`(`id`) ON DELETE CASCADE"},
   153  		{"REFERENCES parent(id,hello) ON DELETE CASCADE", "REFERENCES `parent`(`id`, `hello`) ON DELETE CASCADE"},
   154  		{"REFERENCES parent(id,hello(12)) ON DELETE CASCADE", "REFERENCES `parent`(`id`, `hello`(12)) ON DELETE CASCADE"},
   155  		{"REFERENCES parent(id(8),hello(12)) ON DELETE CASCADE", "REFERENCES `parent`(`id`(8), `hello`(12)) ON DELETE CASCADE"},
   156  		{"REFERENCES parent(id)", "REFERENCES `parent`(`id`)"},
   157  		{"REFERENCES parent((id+1))", "REFERENCES `parent`((`id`+1))"},
   158  	}
   159  	extractNodeFunc := func(node Node) Node {
   160  		return node.(*CreateTableStmt).Constraints[1].Refer
   161  	}
   162  	runNodeRestoreTest(t, testCases, "CREATE TABLE child (id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) %s)", extractNodeFunc)
   163  }
   164  
   165  func TestDDLConstraintRestore(t *testing.T) {
   166  	testCases := []NodeRestoreTestCase{
   167  		{"INDEX par_ind (parent_id)", "INDEX `par_ind`(`parent_id`)"},
   168  		{"INDEX par_ind (parent_id(6))", "INDEX `par_ind`(`parent_id`(6))"},
   169  		{"INDEX expr_ind ((id + parent_id))", "INDEX `expr_ind`((`id`+`parent_id`))"},
   170  		{"INDEX expr_ind ((lower(id)))", "INDEX `expr_ind`((LOWER(`id`)))"},
   171  		{"key par_ind (parent_id)", "INDEX `par_ind`(`parent_id`)"},
   172  		{"key expr_ind ((lower(id)))", "INDEX `expr_ind`((LOWER(`id`)))"},
   173  		{"unique par_ind (parent_id)", "UNIQUE `par_ind`(`parent_id`)"},
   174  		{"unique key par_ind (parent_id)", "UNIQUE `par_ind`(`parent_id`)"},
   175  		{"unique index par_ind (parent_id)", "UNIQUE `par_ind`(`parent_id`)"},
   176  		{"unique expr_ind ((id + parent_id))", "UNIQUE `expr_ind`((`id`+`parent_id`))"},
   177  		{"unique expr_ind ((lower(id)))", "UNIQUE `expr_ind`((LOWER(`id`)))"},
   178  		{"unique key expr_ind ((id + parent_id))", "UNIQUE `expr_ind`((`id`+`parent_id`))"},
   179  		{"unique key expr_ind ((lower(id)))", "UNIQUE `expr_ind`((LOWER(`id`)))"},
   180  		{"unique index expr_ind ((id + parent_id))", "UNIQUE `expr_ind`((`id`+`parent_id`))"},
   181  		{"unique index expr_ind ((lower(id)))", "UNIQUE `expr_ind`((LOWER(`id`)))"},
   182  		{"fulltext key full_id (parent_id)", "FULLTEXT `full_id`(`parent_id`)"},
   183  		{"fulltext INDEX full_id (parent_id)", "FULLTEXT `full_id`(`parent_id`)"},
   184  		{"fulltext INDEX full_id ((parent_id+1))", "FULLTEXT `full_id`((`parent_id`+1))"},
   185  		{"PRIMARY KEY (id)", "PRIMARY KEY(`id`)"},
   186  		{"PRIMARY KEY (id) key_block_size = 32 using hash comment 'hello'", "PRIMARY KEY(`id`) KEY_BLOCK_SIZE=32 USING HASH COMMENT 'hello'"},
   187  		{"PRIMARY KEY ((id+1))", "PRIMARY KEY((`id`+1))"},
   188  		{"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"},
   189  		{"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"},
   190  		{"CONSTRAINT FOREIGN KEY (parent_id(2),hello(4)) REFERENCES parent((id+1)) ON DELETE CASCADE", "CONSTRAINT FOREIGN KEY (`parent_id`(2), `hello`(4)) REFERENCES `parent`((`id`+1)) ON DELETE CASCADE"},
   191  		{"CONSTRAINT FOREIGN KEY (parent_id) REFERENCES parent((id+1)) ON DELETE CASCADE ON UPDATE RESTRICT", "CONSTRAINT FOREIGN KEY (`parent_id`) REFERENCES `parent`((`id`+1)) ON DELETE CASCADE ON UPDATE RESTRICT"},
   192  		{"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"},
   193  		{"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"},
   194  		{"CONSTRAINT fk_123 FOREIGN KEY ((parent_id+1),hello(4)) REFERENCES parent(id) ON DELETE CASCADE", "CONSTRAINT `fk_123` FOREIGN KEY ((`parent_id`+1), `hello`(4)) REFERENCES `parent`(`id`) ON DELETE CASCADE"},
   195  		{"CONSTRAINT fk_123 FOREIGN KEY ((parent_id+1)) REFERENCES parent(id) ON DELETE CASCADE ON UPDATE RESTRICT", "CONSTRAINT `fk_123` FOREIGN KEY ((`parent_id`+1)) REFERENCES `parent`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT"},
   196  		{"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"},
   197  		{"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"},
   198  		{"FOREIGN KEY ((parent_id+1),hello(4)) REFERENCES parent(id) ON DELETE CASCADE", "CONSTRAINT FOREIGN KEY ((`parent_id`+1), `hello`(4)) REFERENCES `parent`(`id`) ON DELETE CASCADE"},
   199  		{"FOREIGN KEY ((parent_id+1)) REFERENCES parent(id) ON DELETE CASCADE ON UPDATE RESTRICT", "CONSTRAINT FOREIGN KEY ((`parent_id`+1)) REFERENCES `parent`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT"},
   200  	}
   201  	extractNodeFunc := func(node Node) Node {
   202  		return node.(*CreateTableStmt).Constraints[0]
   203  	}
   204  	runNodeRestoreTest(t, testCases, "CREATE TABLE child (id INT, parent_id INT, %s)", extractNodeFunc)
   205  
   206  	specialCommentCases := []NodeRestoreTestCase{
   207  		{"PRIMARY KEY (id) CLUSTERED", "PRIMARY KEY(`id`) /*T![clustered_index] CLUSTERED */"},
   208  		{"primary key (id) NONCLUSTERED", "PRIMARY KEY(`id`) /*T![clustered_index] NONCLUSTERED */"},
   209  		{"PRIMARY KEY (id) /*T![clustered_index] CLUSTERED */", "PRIMARY KEY(`id`) /*T![clustered_index] CLUSTERED */"},
   210  		{"primary key (id) /*T![clustered_index] NONCLUSTERED */", "PRIMARY KEY(`id`) /*T![clustered_index] NONCLUSTERED */"},
   211  	}
   212  	runNodeRestoreTestWithFlags(t, specialCommentCases,
   213  		"CREATE TABLE child (id INT, parent_id INT, %s)",
   214  		extractNodeFunc, format.DefaultRestoreFlags|format.RestoreTiDBSpecialComment)
   215  }
   216  
   217  func TestDDLColumnOptionRestore(t *testing.T) {
   218  	testCases := []NodeRestoreTestCase{
   219  		{"primary key", "PRIMARY KEY"},
   220  		{"not null", "NOT NULL"},
   221  		{"null", "NULL"},
   222  		{"auto_increment", "AUTO_INCREMENT"},
   223  		{"DEFAULT 10", "DEFAULT 10"},
   224  		{"DEFAULT '10'", "DEFAULT _UTF8MB4'10'"},
   225  		{"DEFAULT 'hello'", "DEFAULT _UTF8MB4'hello'"},
   226  		{"DEFAULT 1.1", "DEFAULT 1.1"},
   227  		{"DEFAULT NULL", "DEFAULT NULL"},
   228  		{"DEFAULT ''", "DEFAULT _UTF8MB4''"},
   229  		{"DEFAULT TRUE", "DEFAULT TRUE"},
   230  		{"DEFAULT FALSE", "DEFAULT FALSE"},
   231  		{"UNIQUE KEY", "UNIQUE KEY"},
   232  		{"on update CURRENT_TIMESTAMP", "ON UPDATE CURRENT_TIMESTAMP()"},
   233  		{"comment 'hello'", "COMMENT 'hello'"},
   234  		{"generated always as(id + 1)", "GENERATED ALWAYS AS(`id`+1) VIRTUAL"},
   235  		{"generated always as(id + 1) virtual", "GENERATED ALWAYS AS(`id`+1) VIRTUAL"},
   236  		{"generated always as(id + 1) stored", "GENERATED ALWAYS AS(`id`+1) STORED"},
   237  		{"REFERENCES parent(id)", "REFERENCES `parent`(`id`)"},
   238  		{"COLLATE utf8_bin", "COLLATE utf8_bin"},
   239  		{"STORAGE DEFAULT", "STORAGE DEFAULT"},
   240  		{"STORAGE DISK", "STORAGE DISK"},
   241  		{"STORAGE MEMORY", "STORAGE MEMORY"},
   242  		{"AUTO_RANDOM (3)", "AUTO_RANDOM(3)"},
   243  		{"AUTO_RANDOM", "AUTO_RANDOM"},
   244  	}
   245  	extractNodeFunc := func(node Node) Node {
   246  		return node.(*CreateTableStmt).Cols[0].Options[0]
   247  	}
   248  	runNodeRestoreTest(t, testCases, "CREATE TABLE child (id INT %s)", extractNodeFunc)
   249  }
   250  
   251  func TestGeneratedRestore(t *testing.T) {
   252  	testCases := []NodeRestoreTestCase{
   253  		{"generated always as(id + 1)", "GENERATED ALWAYS AS(`id`+1) VIRTUAL"},
   254  		{"generated always as(id + 1) virtual", "GENERATED ALWAYS AS(`id`+1) VIRTUAL"},
   255  		{"generated always as(id + 1) stored", "GENERATED ALWAYS AS(`id`+1) STORED"},
   256  		{"generated always as(lower(id)) stored", "GENERATED ALWAYS AS(LOWER(`id`)) STORED"},
   257  		{"generated always as(lower(child.id)) stored", "GENERATED ALWAYS AS(LOWER(`id`)) STORED"},
   258  	}
   259  	extractNodeFunc := func(node Node) Node {
   260  		return node.(*CreateTableStmt).Cols[0].Options[0]
   261  	}
   262  	runNodeRestoreTestWithFlagsStmtChange(t, testCases, "CREATE TABLE child (id INT %s)", extractNodeFunc,
   263  		format.DefaultRestoreFlags|format.RestoreWithoutSchemaName|format.RestoreWithoutTableName)
   264  }
   265  
   266  func TestDDLColumnDefRestore(t *testing.T) {
   267  	testCases := []NodeRestoreTestCase{
   268  		// for type
   269  		{"id json", "`id` JSON"},
   270  		{"id time(5)", "`id` TIME(5)"},
   271  		{"id int(5) unsigned", "`id` INT(5) UNSIGNED"},
   272  		{"id int(5) UNSIGNED ZEROFILL", "`id` INT(5) UNSIGNED ZEROFILL"},
   273  		{"id float(12,3)", "`id` FLOAT(12,3)"},
   274  		{"id float", "`id` FLOAT"},
   275  		{"id double(22,3)", "`id` DOUBLE(22,3)"},
   276  		{"id double", "`id` DOUBLE"},
   277  		{"id tinyint(4)", "`id` TINYINT(4)"},
   278  		{"id smallint(6)", "`id` SMALLINT(6)"},
   279  		{"id mediumint(9)", "`id` MEDIUMINT(9)"},
   280  		{"id integer(11)", "`id` INT(11)"},
   281  		{"id bigint(20)", "`id` BIGINT(20)"},
   282  		{"id DATE", "`id` DATE"},
   283  		{"id DATETIME", "`id` DATETIME"},
   284  		{"id DECIMAL(4,2)", "`id` DECIMAL(4,2)"},
   285  		{"id char(1)", "`id` CHAR(1)"},
   286  		{"id varchar(10) BINARY", "`id` VARCHAR(10) BINARY"},
   287  		{"id binary(1)", "`id` BINARY(1)"},
   288  		{"id timestamp(2)", "`id` TIMESTAMP(2)"},
   289  		{"id timestamp", "`id` TIMESTAMP"},
   290  		{"id datetime(2)", "`id` DATETIME(2)"},
   291  		{"id date", "`id` DATE"},
   292  		{"id year", "`id` YEAR"},
   293  		{"id INT", "`id` INT"},
   294  		{"id INT NULL", "`id` INT NULL"},
   295  		{"id enum('a','b')", "`id` ENUM('a','b')"},
   296  		{"id enum('''a''','''b''')", "`id` ENUM('''a''','''b''')"},
   297  		{"id enum('a\\nb','a\\tb','a\\rb')", "`id` ENUM('a\nb','a\tb','a\rb')"},
   298  		{"id enum('a','b') binary", "`id` ENUM('a','b') BINARY"},
   299  		{"id enum(0x61, 0b01100010)", "`id` ENUM('a','b')"},
   300  		{"id set('a','b')", "`id` SET('a','b')"},
   301  		{"id set('''a''','''b''')", "`id` SET('''a''','''b''')"},
   302  		{"id set('a\\nb','a''	\\r\\nb','a\\rb')", "`id` SET('a\nb','a''	\r\nb','a\rb')"},
   303  		{`id set("a'\nb","a'b\tc")`, "`id` SET('a''\nb','a''b\tc')"},
   304  		{"id set('a','b') binary", "`id` SET('a','b') BINARY"},
   305  		{"id set(0x61, 0b01100010)", "`id` SET('a','b')"},
   306  		{"id TEXT CHARACTER SET UTF8 COLLATE UTF8_UNICODE_CI", "`id` TEXT CHARACTER SET UTF8 COLLATE utf8_unicode_ci"},
   307  		{"id text character set UTF8", "`id` TEXT CHARACTER SET UTF8"},
   308  		{"id text charset UTF8", "`id` TEXT CHARACTER SET UTF8"},
   309  		{"id varchar(50) collate UTF8MB4_CZECH_CI", "`id` VARCHAR(50) COLLATE utf8mb4_czech_ci"},
   310  		{"id varchar(50) collate utf8_bin", "`id` VARCHAR(50) COLLATE utf8_bin"},
   311  		{"id varchar(50) collate utf8_unicode_ci collate utf8mb4_bin", "`id` VARCHAR(50) COLLATE utf8_unicode_ci COLLATE utf8mb4_bin"},
   312  		{"c1 char(10) character set LATIN1 collate latin1_german1_ci", "`c1` CHAR(10) CHARACTER SET LATIN1 COLLATE latin1_german1_ci"},
   313  
   314  		{"id int(11) PRIMARY KEY", "`id` INT(11) PRIMARY KEY"},
   315  		{"id int(11) NOT NULL", "`id` INT(11) NOT NULL"},
   316  		{"id INT(11) NULL", "`id` INT(11) NULL"},
   317  		{"id INT(11) auto_increment", "`id` INT(11) AUTO_INCREMENT"},
   318  		{"id INT(11) DEFAULT 10", "`id` INT(11) DEFAULT 10"},
   319  		{"id INT(11) DEFAULT '10'", "`id` INT(11) DEFAULT _UTF8MB4'10'"},
   320  		{"id INT(11) DEFAULT 1.1", "`id` INT(11) DEFAULT 1.1"},
   321  		{"id INT(11) UNIQUE KEY", "`id` INT(11) UNIQUE KEY"},
   322  		{"id INT(11) COLLATE ascii_bin", "`id` INT(11) COLLATE ascii_bin"},
   323  		{"id INT(11) collate ascii_bin collate utf8_bin", "`id` INT(11) COLLATE ascii_bin COLLATE utf8_bin"},
   324  		{"id INT(11) on update CURRENT_TIMESTAMP", "`id` INT(11) ON UPDATE CURRENT_TIMESTAMP()"},
   325  		{"id INT(11) comment 'hello'", "`id` INT(11) COMMENT 'hello'"},
   326  		{"id INT(11) generated always as(id + 1)", "`id` INT(11) GENERATED ALWAYS AS(`id`+1) VIRTUAL"},
   327  		{"id INT(11) REFERENCES parent(id)", "`id` INT(11) REFERENCES `parent`(`id`)"},
   328  
   329  		{"id bit", "`id` BIT(1)"},
   330  		{"id bit(1)", "`id` BIT(1)"},
   331  		{"id bit(64)", "`id` BIT(64)"},
   332  		{"id tinyint", "`id` TINYINT"},
   333  		{"id tinyint(255)", "`id` TINYINT(255)"},
   334  		{"id bool", "`id` TINYINT(1)"},
   335  		{"id boolean", "`id` TINYINT(1)"},
   336  		{"id smallint", "`id` SMALLINT"},
   337  		{"id smallint(255)", "`id` SMALLINT(255)"},
   338  		{"id mediumint", "`id` MEDIUMINT"},
   339  		{"id mediumint(255)", "`id` MEDIUMINT(255)"},
   340  		{"id int", "`id` INT"},
   341  		{"id int(255)", "`id` INT(255)"},
   342  		{"id integer", "`id` INT"},
   343  		{"id integer(255)", "`id` INT(255)"},
   344  		{"id bigint", "`id` BIGINT"},
   345  		{"id bigint(255)", "`id` BIGINT(255)"},
   346  		{"id decimal", "`id` DECIMAL"},
   347  		{"id decimal(10)", "`id` DECIMAL(10)"},
   348  		{"id decimal(10,0)", "`id` DECIMAL(10,0)"},
   349  		{"id decimal(65)", "`id` DECIMAL(65)"},
   350  		{"id decimal(65,30)", "`id` DECIMAL(65,30)"},
   351  		{"id dec(10,0)", "`id` DECIMAL(10,0)"},
   352  		{"id numeric(10,0)", "`id` DECIMAL(10,0)"},
   353  		{"id float(0)", "`id` FLOAT"},
   354  		{"id float(24)", "`id` FLOAT"},
   355  		{"id float(25)", "`id` DOUBLE"},
   356  		{"id float(53)", "`id` DOUBLE"},
   357  		{"id float(7,0)", "`id` FLOAT(7,0)"},
   358  		{"id float(25,0)", "`id` FLOAT(25,0)"},
   359  		{"id double(15,0)", "`id` DOUBLE(15,0)"},
   360  		{"id double precision(15,0)", "`id` DOUBLE(15,0)"},
   361  		{"id real(15,0)", "`id` DOUBLE(15,0)"},
   362  		{"id year(4)", "`id` YEAR(4)"},
   363  		{"id time", "`id` TIME"},
   364  		{"id char", "`id` CHAR"},
   365  		{"id char(0)", "`id` CHAR(0)"},
   366  		{"id char(255)", "`id` CHAR(255)"},
   367  		{"id national char(0)", "`id` CHAR(0)"},
   368  		{"id binary", "`id` BINARY"},
   369  		{"id varbinary(0)", "`id` VARBINARY(0)"},
   370  		{"id varbinary(65535)", "`id` VARBINARY(65535)"},
   371  		{"id tinyblob", "`id` TINYBLOB"},
   372  		{"id tinytext", "`id` TINYTEXT"},
   373  		{"id blob", "`id` BLOB"},
   374  		{"id blob(0)", "`id` BLOB(0)"},
   375  		{"id blob(65535)", "`id` BLOB(65535)"},
   376  		{"id text(0)", "`id` TEXT(0)"},
   377  		{"id text(65535)", "`id` TEXT(65535)"},
   378  		{"id mediumblob", "`id` MEDIUMBLOB"},
   379  		{"id mediumtext", "`id` MEDIUMTEXT"},
   380  		{"id longblob", "`id` LONGBLOB"},
   381  		{"id longtext", "`id` LONGTEXT"},
   382  		{"id json", "`id` JSON"},
   383  	}
   384  	extractNodeFunc := func(node Node) Node {
   385  		return node.(*CreateTableStmt).Cols[0]
   386  	}
   387  	runNodeRestoreTest(t, testCases, "CREATE TABLE t (%s)", extractNodeFunc)
   388  }
   389  
   390  func TestDDLTruncateTableStmtRestore(t *testing.T) {
   391  	testCases := []NodeRestoreTestCase{
   392  		{"truncate t1", "TRUNCATE TABLE `t1`"},
   393  		{"truncate table t1", "TRUNCATE TABLE `t1`"},
   394  		{"truncate a.t1", "TRUNCATE TABLE `a`.`t1`"},
   395  	}
   396  	extractNodeFunc := func(node Node) Node {
   397  		return node.(*TruncateTableStmt)
   398  	}
   399  	runNodeRestoreTest(t, testCases, "%s", extractNodeFunc)
   400  }
   401  
   402  func TestDDLDropTableStmtRestore(t *testing.T) {
   403  	testCases := []NodeRestoreTestCase{
   404  		{"drop table t1", "DROP TABLE `t1`"},
   405  		{"drop table if exists t1", "DROP TABLE IF EXISTS `t1`"},
   406  		{"drop temporary table t1", "DROP TEMPORARY TABLE `t1`"},
   407  		{"drop temporary table if exists t1", "DROP TEMPORARY TABLE IF EXISTS `t1`"},
   408  		{"DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `test`", "DROP TEMPORARY TABLE IF EXISTS `test`"},
   409  	}
   410  	extractNodeFunc := func(node Node) Node {
   411  		return node.(*DropTableStmt)
   412  	}
   413  	runNodeRestoreTest(t, testCases, "%s", extractNodeFunc)
   414  }
   415  
   416  func TestColumnPositionRestore(t *testing.T) {
   417  	testCases := []NodeRestoreTestCase{
   418  		{"", ""},
   419  		{"first", "FIRST"},
   420  		{"after b", "AFTER `b`"},
   421  	}
   422  	extractNodeFunc := func(node Node) Node {
   423  		return node.(*AlterTableStmt).Specs[0].Position
   424  	}
   425  	runNodeRestoreTest(t, testCases, "alter table t add column a varchar(255) %s", extractNodeFunc)
   426  }
   427  
   428  func TestAlterTableSpecRestore(t *testing.T) {
   429  	testCases := []NodeRestoreTestCase{
   430  		{"ENGINE innodb", "ENGINE = innodb"},
   431  		{"ENGINE = innodb", "ENGINE = innodb"},
   432  		{"ENGINE = 'innodb'", "ENGINE = innodb"},
   433  		{"ENGINE tokudb", "ENGINE = tokudb"},
   434  		{"ENGINE = tokudb", "ENGINE = tokudb"},
   435  		{"ENGINE = 'tokudb'", "ENGINE = tokudb"},
   436  		{"DEFAULT CHARACTER SET utf8", "DEFAULT CHARACTER SET = UTF8"},
   437  		{"DEFAULT CHARACTER SET = utf8", "DEFAULT CHARACTER SET = UTF8"},
   438  		{"DEFAULT CHARSET utf8", "DEFAULT CHARACTER SET = UTF8"},
   439  		{"DEFAULT CHARSET = utf8", "DEFAULT CHARACTER SET = UTF8"},
   440  		{"DEFAULT COLLATE utf8_bin", "DEFAULT COLLATE = UTF8_BIN"},
   441  		{"DEFAULT COLLATE = utf8_bin", "DEFAULT COLLATE = UTF8_BIN"},
   442  		{"AUTO_INCREMENT 3", "AUTO_INCREMENT = 3"},
   443  		{"AUTO_INCREMENT = 6", "AUTO_INCREMENT = 6"},
   444  		{"COMMENT ''", "COMMENT = ''"},
   445  		{"COMMENT 'system role'", "COMMENT = 'system role'"},
   446  		{"COMMENT = 'system role'", "COMMENT = 'system role'"},
   447  		{"AVG_ROW_LENGTH 12", "AVG_ROW_LENGTH = 12"},
   448  		{"AVG_ROW_LENGTH = 6", "AVG_ROW_LENGTH = 6"},
   449  		{"connection 'abc'", "CONNECTION = 'abc'"},
   450  		{"CONNECTION = 'abc'", "CONNECTION = 'abc'"},
   451  		{"checksum 1", "CHECKSUM = 1"},
   452  		{"checksum = 0", "CHECKSUM = 0"},
   453  		{"PASSWORD '123456'", "PASSWORD = '123456'"},
   454  		{"PASSWORD = ''", "PASSWORD = ''"},
   455  		{"compression 'NONE'", "COMPRESSION = 'NONE'"},
   456  		{"compression = 'lz4'", "COMPRESSION = 'lz4'"},
   457  		{"key_block_size 1024", "KEY_BLOCK_SIZE = 1024"},
   458  		{"KEY_BLOCK_SIZE = 1024", "KEY_BLOCK_SIZE = 1024"},
   459  		{"max_rows 1000", "MAX_ROWS = 1000"},
   460  		{"max_rows = 1000", "MAX_ROWS = 1000"},
   461  		{"min_rows 1000", "MIN_ROWS = 1000"},
   462  		{"MIN_ROWS = 1000", "MIN_ROWS = 1000"},
   463  		{"DELAY_KEY_WRITE 1", "DELAY_KEY_WRITE = 1"},
   464  		{"DELAY_KEY_WRITE = 1000", "DELAY_KEY_WRITE = 1000"},
   465  		{"ROW_FORMAT default", "ROW_FORMAT = DEFAULT"},
   466  		{"ROW_FORMAT = default", "ROW_FORMAT = DEFAULT"},
   467  		{"ROW_FORMAT = fixed", "ROW_FORMAT = FIXED"},
   468  		{"ROW_FORMAT = compressed", "ROW_FORMAT = COMPRESSED"},
   469  		{"ROW_FORMAT = compact", "ROW_FORMAT = COMPACT"},
   470  		{"ROW_FORMAT = redundant", "ROW_FORMAT = REDUNDANT"},
   471  		{"ROW_FORMAT = dynamic", "ROW_FORMAT = DYNAMIC"},
   472  		{"ROW_FORMAT tokudb_default", "ROW_FORMAT = TOKUDB_DEFAULT"},
   473  		{"ROW_FORMAT = tokudb_default", "ROW_FORMAT = TOKUDB_DEFAULT"},
   474  		{"ROW_FORMAT = tokudb_fast", "ROW_FORMAT = TOKUDB_FAST"},
   475  		{"ROW_FORMAT = tokudb_small", "ROW_FORMAT = TOKUDB_SMALL"},
   476  		{"ROW_FORMAT = tokudb_zlib", "ROW_FORMAT = TOKUDB_ZLIB"},
   477  		{"ROW_FORMAT = tokudb_zstd", "ROW_FORMAT = TOKUDB_ZSTD"},
   478  		{"ROW_FORMAT = tokudb_quicklz", "ROW_FORMAT = TOKUDB_QUICKLZ"},
   479  		{"ROW_FORMAT = tokudb_lzma", "ROW_FORMAT = TOKUDB_LZMA"},
   480  		{"ROW_FORMAT = tokudb_snappy", "ROW_FORMAT = TOKUDB_SNAPPY"},
   481  		{"ROW_FORMAT = tokudb_uncompressed", "ROW_FORMAT = TOKUDB_UNCOMPRESSED"},
   482  		{"shard_row_id_bits 1", "SHARD_ROW_ID_BITS = 1"},
   483  		{"shard_row_id_bits = 1", "SHARD_ROW_ID_BITS = 1"},
   484  		{"CONVERT TO CHARACTER SET utf8", "CONVERT TO CHARACTER SET UTF8"},
   485  		{"CONVERT TO CHARSET utf8", "CONVERT TO CHARACTER SET UTF8"},
   486  		{"CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin", "CONVERT TO CHARACTER SET UTF8 COLLATE UTF8_BIN"},
   487  		{"CONVERT TO CHARSET utf8 COLLATE utf8_bin", "CONVERT TO CHARACTER SET UTF8 COLLATE UTF8_BIN"},
   488  		{"ADD COLUMN (a SMALLINT UNSIGNED)", "ADD COLUMN (`a` SMALLINT UNSIGNED)"},
   489  		{"ADD COLUMN (a SMALLINT UNSIGNED, b varchar(255))", "ADD COLUMN (`a` SMALLINT UNSIGNED, `b` VARCHAR(255))"},
   490  		{"ADD COLUMN a SMALLINT UNSIGNED", "ADD COLUMN `a` SMALLINT UNSIGNED"},
   491  		{"ADD COLUMN a SMALLINT UNSIGNED FIRST", "ADD COLUMN `a` SMALLINT UNSIGNED FIRST"},
   492  		{"ADD COLUMN a SMALLINT UNSIGNED AFTER b", "ADD COLUMN `a` SMALLINT UNSIGNED AFTER `b`"},
   493  		{"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"},
   494  		{"ADD CONSTRAINT INDEX par_ind (parent_id)", "ADD INDEX `par_ind`(`parent_id`)"},
   495  		{"ADD CONSTRAINT INDEX par_ind (parent_id(6))", "ADD INDEX `par_ind`(`parent_id`(6))"},
   496  		{"ADD CONSTRAINT key par_ind (parent_id)", "ADD INDEX `par_ind`(`parent_id`)"},
   497  		{"ADD CONSTRAINT unique par_ind (parent_id)", "ADD UNIQUE `par_ind`(`parent_id`)"},
   498  		{"ADD CONSTRAINT unique key par_ind (parent_id)", "ADD UNIQUE `par_ind`(`parent_id`)"},
   499  		{"ADD CONSTRAINT unique index par_ind (parent_id)", "ADD UNIQUE `par_ind`(`parent_id`)"},
   500  		{"ADD CONSTRAINT fulltext key full_id (parent_id)", "ADD FULLTEXT `full_id`(`parent_id`)"},
   501  		{"ADD CONSTRAINT fulltext INDEX full_id (parent_id)", "ADD FULLTEXT `full_id`(`parent_id`)"},
   502  		{"ADD CONSTRAINT PRIMARY KEY (id)", "ADD PRIMARY KEY(`id`)"},
   503  		{"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'"},
   504  		{"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"},
   505  		{"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"},
   506  		{"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"},
   507  		{"DROP COLUMN a", "DROP COLUMN `a`"},
   508  		{"DROP COLUMN a RESTRICT", "DROP COLUMN `a`"},
   509  		{"DROP COLUMN a CASCADE", "DROP COLUMN `a`"},
   510  		{"DROP PRIMARY KEY", "DROP PRIMARY KEY"},
   511  		{"drop index a", "DROP INDEX `a`"},
   512  		{"drop key a", "DROP INDEX `a`"},
   513  		{"drop FOREIGN key a", "DROP FOREIGN KEY `a`"},
   514  		{"MODIFY column a varchar(255)", "MODIFY COLUMN `a` VARCHAR(255)"},
   515  		{"modify COLUMN a varchar(255) FIRST", "MODIFY COLUMN `a` VARCHAR(255) FIRST"},
   516  		{"modify COLUMN a varchar(255) AFTER b", "MODIFY COLUMN `a` VARCHAR(255) AFTER `b`"},
   517  		{"change column a b VARCHAR(255)", "CHANGE COLUMN `a` `b` VARCHAR(255)"},
   518  		{"change COLUMN a b varchar(255) CHARACTER SET UTF8 BINARY", "CHANGE COLUMN `a` `b` VARCHAR(255) BINARY CHARACTER SET UTF8"},
   519  		{"CHANGE column a b varchar(255) FIRST", "CHANGE COLUMN `a` `b` VARCHAR(255) FIRST"},
   520  		{"change COLUMN a b varchar(255) AFTER c", "CHANGE COLUMN `a` `b` VARCHAR(255) AFTER `c`"},
   521  		{"RENAME db1.t1", "RENAME AS `db1`.`t1`"},
   522  		{"RENAME to db1.t1", "RENAME AS `db1`.`t1`"},
   523  		{"RENAME as t1", "RENAME AS `t1`"},
   524  		{"ALTER a SET DEFAULT 1", "ALTER COLUMN `a` SET DEFAULT 1"},
   525  		{"ALTER a DROP DEFAULT", "ALTER COLUMN `a` DROP DEFAULT"},
   526  		{"ALTER COLUMN a SET DEFAULT 1", "ALTER COLUMN `a` SET DEFAULT 1"},
   527  		{"ALTER COLUMN a DROP DEFAULT", "ALTER COLUMN `a` DROP DEFAULT"},
   528  		{"LOCK=NONE", "LOCK = NONE"},
   529  		{"LOCK=DEFAULT", "LOCK = DEFAULT"},
   530  		{"LOCK=SHARED", "LOCK = SHARED"},
   531  		{"LOCK=EXCLUSIVE", "LOCK = EXCLUSIVE"},
   532  		{"RENAME KEY a TO b", "RENAME INDEX `a` TO `b`"},
   533  		{"RENAME INDEX a TO b", "RENAME INDEX `a` TO `b`"},
   534  		{"ADD PARTITION", "ADD PARTITION"},
   535  		{"ADD PARTITION ( PARTITION P1 VALUES LESS THAN (2010))", "ADD PARTITION (PARTITION `P1` VALUES LESS THAN (2010))"},
   536  		{"ADD PARTITION ( PARTITION P2 VALUES LESS THAN MAXVALUE)", "ADD PARTITION (PARTITION `P2` VALUES LESS THAN (MAXVALUE))"},
   537  		{"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))"},
   538  		{"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')"},
   539  		{"ADD PARTITION (PARTITION `p5` VALUES LESS THAN (2010) COMMENT = 'xxx')", "ADD PARTITION (PARTITION `p5` VALUES LESS THAN (2010) COMMENT = 'xxx')"},
   540  		{"coalesce partition 3", "COALESCE PARTITION 3"},
   541  		{"drop partition p1", "DROP PARTITION `p1`"},
   542  		{"TRUNCATE PARTITION p0", "TRUNCATE PARTITION `p0`"},
   543  		{"add stats_extended s1 cardinality(a,b)", "ADD STATS_EXTENDED `s1` CARDINALITY(`a`, `b`)"},
   544  		{"add stats_extended if not exists s1 cardinality(a,b)", "ADD STATS_EXTENDED IF NOT EXISTS `s1` CARDINALITY(`a`, `b`)"},
   545  		{"add stats_extended s1 correlation(a,b)", "ADD STATS_EXTENDED `s1` CORRELATION(`a`, `b`)"},
   546  		{"add stats_extended if not exists s1 correlation(a,b)", "ADD STATS_EXTENDED IF NOT EXISTS `s1` CORRELATION(`a`, `b`)"},
   547  		{"add stats_extended s1 dependency(a,b)", "ADD STATS_EXTENDED `s1` DEPENDENCY(`a`, `b`)"},
   548  		{"add stats_extended if not exists s1 dependency(a,b)", "ADD STATS_EXTENDED IF NOT EXISTS `s1` DEPENDENCY(`a`, `b`)"},
   549  		{"drop stats_extended s1", "DROP STATS_EXTENDED `s1`"},
   550  		{"drop stats_extended if exists s1", "DROP STATS_EXTENDED IF EXISTS `s1`"},
   551  		{"placement policy p1", "PLACEMENT POLICY = `p1`"},
   552  		{"placement policy p1 comment='aaa'", "PLACEMENT POLICY = `p1` COMMENT = 'aaa'"},
   553  		{"partition p0 placement policy p1", "PARTITION `p0` PLACEMENT POLICY = `p1`"},
   554  	}
   555  	extractNodeFunc := func(node Node) Node {
   556  		return node.(*AlterTableStmt).Specs[0]
   557  	}
   558  	runNodeRestoreTest(t, testCases, "ALTER TABLE t %s", extractNodeFunc)
   559  }
   560  
   561  func TestAlterTableWithSpecialCommentRestore(t *testing.T) {
   562  	testCases := []NodeRestoreTestCase{
   563  		{"placement policy p1", "/*T![placement] PLACEMENT POLICY = `p1` */"},
   564  		{"placement policy p1 comment='aaa'", "/*T![placement] PLACEMENT POLICY = `p1` */ COMMENT = 'aaa'"},
   565  		{"partition p0 placement policy p1", "/*T![placement] PARTITION `p0` PLACEMENT POLICY = `p1` */"},
   566  	}
   567  
   568  	extractNodeFunc := func(node Node) Node {
   569  		return node.(*AlterTableStmt).Specs[0]
   570  	}
   571  	runNodeRestoreTestWithFlags(t, testCases, "ALTER TABLE t %s", extractNodeFunc, format.DefaultRestoreFlags|format.RestoreTiDBSpecialComment)
   572  }
   573  
   574  func TestAlterTableOptionRestore(t *testing.T) {
   575  	testCases := []NodeRestoreTestCase{
   576  		{"ALTER TABLE t ROW_FORMAT = COMPRESSED KEY_BLOCK_SIZE = 8", "ALTER TABLE `t` ROW_FORMAT = COMPRESSED KEY_BLOCK_SIZE = 8"},
   577  		{"ALTER TABLE t ROW_FORMAT = COMPRESSED, KEY_BLOCK_SIZE = 8", "ALTER TABLE `t` ROW_FORMAT = COMPRESSED, KEY_BLOCK_SIZE = 8"},
   578  	}
   579  	extractNodeFunc := func(node Node) Node {
   580  		return node
   581  	}
   582  	runNodeRestoreTest(t, testCases, "%s", extractNodeFunc)
   583  }
   584  
   585  func TestAdminRepairTableRestore(t *testing.T) {
   586  	testCases := []NodeRestoreTestCase{
   587  		{"ADMIN REPAIR TABLE t CREATE TABLE t (a int)", "ADMIN REPAIR TABLE `t` CREATE TABLE `t` (`a` INT)"},
   588  		{"ADMIN REPAIR TABLE t CREATE TABLE t (a char(1), b int)", "ADMIN REPAIR TABLE `t` CREATE TABLE `t` (`a` CHAR(1),`b` INT)"},
   589  		{"ADMIN REPAIR TABLE t CREATE TABLE t (a TINYINT UNSIGNED)", "ADMIN REPAIR TABLE `t` CREATE TABLE `t` (`a` TINYINT UNSIGNED)"},
   590  	}
   591  	extractNodeFunc := func(node Node) Node {
   592  		return node
   593  	}
   594  	runNodeRestoreTest(t, testCases, "%s", extractNodeFunc)
   595  }
   596  
   597  func TestSequenceRestore(t *testing.T) {
   598  	testCases := []NodeRestoreTestCase{
   599  		{"create sequence seq", "CREATE SEQUENCE `seq`"},
   600  		{"create sequence if not exists seq", "CREATE SEQUENCE IF NOT EXISTS `seq`"},
   601  		{"create sequence if not exists seq", "CREATE SEQUENCE IF NOT EXISTS `seq`"},
   602  		{"create sequence if not exists seq increment 1", "CREATE SEQUENCE IF NOT EXISTS `seq` INCREMENT BY 1"},
   603  		{"create sequence if not exists seq increment = 1", "CREATE SEQUENCE IF NOT EXISTS `seq` INCREMENT BY 1"},
   604  		{"create sequence if not exists seq minvalue 1", "CREATE SEQUENCE IF NOT EXISTS `seq` MINVALUE 1"},
   605  		{"create sequence if not exists seq minvalue = 1", "CREATE SEQUENCE IF NOT EXISTS `seq` MINVALUE 1"},
   606  		{"create sequence if not exists seq nominvalue", "CREATE SEQUENCE IF NOT EXISTS `seq` NO MINVALUE"},
   607  		{"create sequence if not exists seq no minvalue", "CREATE SEQUENCE IF NOT EXISTS `seq` NO MINVALUE"},
   608  		{"create sequence if not exists seq maxvalue 1", "CREATE SEQUENCE IF NOT EXISTS `seq` MAXVALUE 1"},
   609  		{"create sequence if not exists seq maxvalue = 1", "CREATE SEQUENCE IF NOT EXISTS `seq` MAXVALUE 1"},
   610  		{"create sequence if not exists seq nomaxvalue", "CREATE SEQUENCE IF NOT EXISTS `seq` NO MAXVALUE"},
   611  		{"create sequence if not exists seq no maxvalue", "CREATE SEQUENCE IF NOT EXISTS `seq` NO MAXVALUE"},
   612  		{"create sequence if not exists seq start 1", "CREATE SEQUENCE IF NOT EXISTS `seq` START WITH 1"},
   613  		{"create sequence if not exists seq start with 1", "CREATE SEQUENCE IF NOT EXISTS `seq` START WITH 1"},
   614  		{"create sequence if not exists seq cache 1", "CREATE SEQUENCE IF NOT EXISTS `seq` CACHE 1"},
   615  		{"create sequence if not exists seq nocache", "CREATE SEQUENCE IF NOT EXISTS `seq` NOCACHE"},
   616  		{"create sequence if not exists seq no cache", "CREATE SEQUENCE IF NOT EXISTS `seq` NOCACHE"},
   617  		{"create sequence if not exists seq cycle", "CREATE SEQUENCE IF NOT EXISTS `seq` CYCLE"},
   618  		{"create sequence if not exists seq nocycle", "CREATE SEQUENCE IF NOT EXISTS `seq` NOCYCLE"},
   619  		{"create sequence if not exists seq no cycle", "CREATE SEQUENCE IF NOT EXISTS `seq` NOCYCLE"},
   620  		{"create sequence seq increment 1 minvalue 0 maxvalue 1000", "CREATE SEQUENCE `seq` INCREMENT BY 1 MINVALUE 0 MAXVALUE 1000"},
   621  		{"create sequence seq minvalue 0 maxvalue 1000 increment 1", "CREATE SEQUENCE `seq` MINVALUE 0 MAXVALUE 1000 INCREMENT BY 1"},
   622  		{"create sequence seq cache = 1 minvalue 0 maxvalue -1000", "CREATE SEQUENCE `seq` CACHE 1 MINVALUE 0 MAXVALUE -1000"},
   623  		{"create sequence seq increment -1 minvalue 0 maxvalue -1000", "CREATE SEQUENCE `seq` INCREMENT BY -1 MINVALUE 0 MAXVALUE -1000"},
   624  		{"create sequence seq nocycle nocache maxvalue 1000 cache 1", "CREATE SEQUENCE `seq` NOCYCLE NOCACHE MAXVALUE 1000 CACHE 1"},
   625  		{"create sequence seq increment -1 no minvalue no maxvalue cache = 1", "CREATE SEQUENCE `seq` INCREMENT BY -1 NO MINVALUE NO MAXVALUE CACHE 1"},
   626  		{"create sequence if not exists seq increment 1 minvalue 0 nomaxvalue cache 100 nocycle", "CREATE SEQUENCE IF NOT EXISTS `seq` INCREMENT BY 1 MINVALUE 0 NO MAXVALUE CACHE 100 NOCYCLE"},
   627  
   628  		// test drop sequence
   629  		{"drop sequence seq", "DROP SEQUENCE `seq`"},
   630  		{"drop sequence seq, seq2", "DROP SEQUENCE `seq`, `seq2`"},
   631  		{"drop sequence if exists seq, seq2", "DROP SEQUENCE IF EXISTS `seq`, `seq2`"},
   632  		{"drop sequence if exists seq", "DROP SEQUENCE IF EXISTS `seq`"},
   633  		{"drop sequence sequence", "DROP SEQUENCE `sequence`"},
   634  	}
   635  	extractNodeFunc := func(node Node) Node {
   636  		return node
   637  	}
   638  	runNodeRestoreTest(t, testCases, "%s", extractNodeFunc)
   639  }
   640  
   641  func TestDropIndexRestore(t *testing.T) {
   642  	sourceSQL := "drop index if exists idx on t"
   643  	cases := []struct {
   644  		flags     format.RestoreFlags
   645  		expectSQL string
   646  	}{
   647  		{format.DefaultRestoreFlags, "DROP INDEX IF EXISTS `idx` ON `t`"},
   648  		{format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment, "DROP INDEX /*T! IF EXISTS  */`idx` ON `t`"},
   649  	}
   650  
   651  	extractNodeFunc := func(node Node) Node {
   652  		return node
   653  	}
   654  
   655  	for _, ca := range cases {
   656  		testCases := []NodeRestoreTestCase{
   657  			{sourceSQL, ca.expectSQL},
   658  		}
   659  		runNodeRestoreTestWithFlags(t, testCases, "%s", extractNodeFunc, ca.flags)
   660  	}
   661  }
   662  
   663  func TestAlterDatabaseRestore(t *testing.T) {
   664  	sourceSQL1 := "alter database db1 charset='ascii'"
   665  	sourceSQL2 := "alter database db1 collate='ascii_bin'"
   666  	sourceSQL3 := "alter database db1 placement policy p1"
   667  	sourceSQL4 := "alter database db1 placement policy p1 charset='ascii'"
   668  
   669  	cases := []struct {
   670  		sourceSQL string
   671  		flags     format.RestoreFlags
   672  		expectSQL string
   673  	}{
   674  		{sourceSQL1, format.DefaultRestoreFlags, "ALTER DATABASE `db1` CHARACTER SET = ascii"},
   675  		{sourceSQL1, format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment, "ALTER DATABASE `db1` CHARACTER SET = ascii"},
   676  		{sourceSQL2, format.DefaultRestoreFlags, "ALTER DATABASE `db1` COLLATE = ascii_bin"},
   677  		{sourceSQL2, format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment, "ALTER DATABASE `db1` COLLATE = ascii_bin"},
   678  		{sourceSQL3, format.DefaultRestoreFlags, "ALTER DATABASE `db1` PLACEMENT POLICY = `p1`"},
   679  		{sourceSQL3, format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment, "/*T![placement] ALTER DATABASE `db1` PLACEMENT POLICY = `p1` */"},
   680  		{sourceSQL4, format.DefaultRestoreFlags, "ALTER DATABASE `db1` PLACEMENT POLICY = `p1` CHARACTER SET = ascii"},
   681  		{sourceSQL4, format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment, "ALTER DATABASE `db1` /*T![placement] PLACEMENT POLICY = `p1` */ CHARACTER SET = ascii"},
   682  	}
   683  
   684  	extractNodeFunc := func(node Node) Node {
   685  		return node
   686  	}
   687  
   688  	for _, ca := range cases {
   689  		testCases := []NodeRestoreTestCase{
   690  			{ca.sourceSQL, ca.expectSQL},
   691  		}
   692  		runNodeRestoreTestWithFlags(t, testCases, "%s", extractNodeFunc, ca.flags)
   693  	}
   694  }
   695  
   696  func TestCreatePlacementPolicyRestore(t *testing.T) {
   697  	sourceSQL1 := "create placement policy p1 primary_region=\"r1\" regions='r1,r2' followers=1"
   698  	sourceSQL2 := "create placement policy if not exists p1 primary_region=\"r1\" regions='r1,r2' followers=1"
   699  	sourceSQL3 := "create or replace placement policy p1 followers=1"
   700  	cases := []struct {
   701  		sourceSQL string
   702  		flags     format.RestoreFlags
   703  		expectSQL string
   704  	}{
   705  		{sourceSQL1, format.DefaultRestoreFlags, "CREATE PLACEMENT POLICY `p1` PRIMARY_REGION = 'r1' REGIONS = 'r1,r2' FOLLOWERS = 1"},
   706  		{sourceSQL1, format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment, "/*T![placement] CREATE PLACEMENT POLICY `p1` PRIMARY_REGION = 'r1' REGIONS = 'r1,r2' FOLLOWERS = 1 */"},
   707  		{sourceSQL2, format.DefaultRestoreFlags, "CREATE PLACEMENT POLICY IF NOT EXISTS `p1` PRIMARY_REGION = 'r1' REGIONS = 'r1,r2' FOLLOWERS = 1"},
   708  		{sourceSQL2, format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment, "/*T![placement] CREATE PLACEMENT POLICY IF NOT EXISTS `p1` PRIMARY_REGION = 'r1' REGIONS = 'r1,r2' FOLLOWERS = 1 */"},
   709  		{sourceSQL3, format.DefaultRestoreFlags, "CREATE OR REPLACE PLACEMENT POLICY `p1` FOLLOWERS = 1"},
   710  		{sourceSQL3, format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment, "/*T![placement] CREATE OR REPLACE PLACEMENT POLICY `p1` FOLLOWERS = 1 */"},
   711  	}
   712  
   713  	extractNodeFunc := func(node Node) Node {
   714  		return node
   715  	}
   716  
   717  	for _, ca := range cases {
   718  		testCases := []NodeRestoreTestCase{
   719  			{ca.sourceSQL, ca.expectSQL},
   720  		}
   721  		runNodeRestoreTestWithFlags(t, testCases, "%s", extractNodeFunc, ca.flags)
   722  	}
   723  }
   724  
   725  func TestAlterPlacementPolicyRestore(t *testing.T) {
   726  	sourceSQL := "alter placement policy p1 primary_region=\"r1\" regions='r1,r2' followers=1"
   727  	cases := []struct {
   728  		flags     format.RestoreFlags
   729  		expectSQL string
   730  	}{
   731  		{format.DefaultRestoreFlags, "ALTER PLACEMENT POLICY `p1` PRIMARY_REGION = 'r1' REGIONS = 'r1,r2' FOLLOWERS = 1"},
   732  		{format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment, "/*T![placement] ALTER PLACEMENT POLICY `p1` PRIMARY_REGION = 'r1' REGIONS = 'r1,r2' FOLLOWERS = 1 */"},
   733  	}
   734  
   735  	extractNodeFunc := func(node Node) Node {
   736  		return node
   737  	}
   738  
   739  	for _, ca := range cases {
   740  		testCases := []NodeRestoreTestCase{
   741  			{sourceSQL, ca.expectSQL},
   742  		}
   743  		runNodeRestoreTestWithFlags(t, testCases, "%s", extractNodeFunc, ca.flags)
   744  	}
   745  }
   746  
   747  func TestDropPlacementPolicyRestore(t *testing.T) {
   748  	sourceSQL1 := "drop placement policy p1"
   749  	sourceSQL2 := "drop placement policy if exists p1"
   750  	cases := []struct {
   751  		sourceSQL string
   752  		flags     format.RestoreFlags
   753  		expectSQL string
   754  	}{
   755  		{sourceSQL1, format.DefaultRestoreFlags, "DROP PLACEMENT POLICY `p1`"},
   756  		{sourceSQL1, format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment, "/*T![placement] DROP PLACEMENT POLICY `p1` */"},
   757  		{sourceSQL2, format.DefaultRestoreFlags, "DROP PLACEMENT POLICY IF EXISTS `p1`"},
   758  		{sourceSQL2, format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment, "/*T![placement] DROP PLACEMENT POLICY IF EXISTS `p1` */"},
   759  	}
   760  
   761  	extractNodeFunc := func(node Node) Node {
   762  		return node
   763  	}
   764  
   765  	for _, ca := range cases {
   766  		testCases := []NodeRestoreTestCase{
   767  			{ca.sourceSQL, ca.expectSQL},
   768  		}
   769  		runNodeRestoreTestWithFlags(t, testCases, "%s", extractNodeFunc, ca.flags)
   770  	}
   771  }
   772  
   773  func TestRemovePlacementRestore(t *testing.T) {
   774  	f := format.DefaultRestoreFlags | format.SkipPlacementRuleForRestore
   775  	cases := []struct {
   776  		sourceSQL string
   777  		expectSQL string
   778  	}{
   779  		{
   780  			"CREATE TABLE t1 (id BIGINT NOT NULL PRIMARY KEY auto_increment, b varchar(255)) PLACEMENT POLICY=placement1;",
   781  			"CREATE TABLE `t1` (`id` BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,`b` VARCHAR(255)) ",
   782  		},
   783  		{
   784  			"CREATE TABLE `t1` (\n  `a` int(11) DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin /*T![placement] PLACEMENT POLICY=`p2` */",
   785  			"CREATE TABLE `t1` (`a` INT(11) DEFAULT NULL) ENGINE = InnoDB DEFAULT CHARACTER SET = UTF8MB4 DEFAULT COLLATE = UTF8MB4_BIN ",
   786  		},
   787  		{
   788  			"CREATE TABLE t4 (firstname VARCHAR(25) NOT NULL,lastname VARCHAR(25) NOT NULL,username VARCHAR(16) NOT NULL,email VARCHAR(35),joined DATE NOT NULL) PARTITION BY RANGE( YEAR(joined) ) (PARTITION p0 VALUES LESS THAN (1960) PLACEMENT POLICY=p1,PARTITION p1 VALUES LESS THAN (1970),PARTITION p2 VALUES LESS THAN (1980),PARTITION p3 VALUES LESS THAN (1990),PARTITION p4 VALUES LESS THAN MAXVALUE);",
   789  			"CREATE TABLE `t4` (`firstname` VARCHAR(25) NOT NULL,`lastname` VARCHAR(25) NOT NULL,`username` VARCHAR(16) NOT NULL,`email` VARCHAR(35),`joined` DATE NOT NULL) PARTITION BY RANGE (YEAR(`joined`)) (PARTITION `p0` VALUES LESS THAN (1960) ,PARTITION `p1` VALUES LESS THAN (1970),PARTITION `p2` VALUES LESS THAN (1980),PARTITION `p3` VALUES LESS THAN (1990),PARTITION `p4` VALUES LESS THAN (MAXVALUE))",
   790  		},
   791  		{
   792  			"ALTER TABLE t3 PLACEMENT POLICY=DEFAULT;",
   793  			"ALTER TABLE `t3`",
   794  		},
   795  		{
   796  			"ALTER TABLE t1 PLACEMENT POLICY=p10",
   797  			"ALTER TABLE `t1`",
   798  		},
   799  		{
   800  			"ALTER TABLE t1 PLACEMENT POLICY=p10, add d text(50)",
   801  			"ALTER TABLE `t1` ADD COLUMN `d` TEXT(50)",
   802  		},
   803  		{
   804  			"alter table tp PARTITION p1 placement policy p2",
   805  			"",
   806  		},
   807  		{
   808  			"alter table t add d text(50) PARTITION p1 placement policy p2",
   809  			"ALTER TABLE `t` ADD COLUMN `d` TEXT(50)",
   810  		},
   811  		{
   812  			"alter table tp set tiflash replica 1 PARTITION p1 placement policy p2",
   813  			"ALTER TABLE `tp` SET TIFLASH REPLICA 1",
   814  		},
   815  		{
   816  			"ALTER DATABASE TestResetPlacementDB PLACEMENT POLICY SET DEFAULT",
   817  			"",
   818  		},
   819  
   820  		{
   821  			"ALTER DATABASE TestResetPlacementDB PLACEMENT POLICY p1 charset utf8mb4",
   822  			"ALTER DATABASE `TestResetPlacementDB`  CHARACTER SET = utf8mb4",
   823  		},
   824  		{
   825  			"/*T![placement] ALTER DATABASE `db1` PLACEMENT POLICY = `p1` */",
   826  			"",
   827  		},
   828  		{
   829  			"ALTER PLACEMENT POLICY p3 PRIMARY_REGION='us-east-1' REGIONS='us-east-1,us-east-2,us-west-1';",
   830  			"",
   831  		},
   832  	}
   833  
   834  	extractNodeFunc := func(node Node) Node {
   835  		return node
   836  	}
   837  
   838  	for _, ca := range cases {
   839  		testCases := []NodeRestoreTestCase{
   840  			{ca.sourceSQL, ca.expectSQL},
   841  		}
   842  		runNodeRestoreTestWithFlagsStmtChange(t, testCases, "%s", extractNodeFunc, f)
   843  	}
   844  }
   845  
   846  func TestFlashBackDatabaseRestore(t *testing.T) {
   847  	testCases := []NodeRestoreTestCase{
   848  		{"flashback database M", "FLASHBACK DATABASE `M`"},
   849  		{"flashback schema M", "FLASHBACK DATABASE `M`"},
   850  		{"flashback database M to n", "FLASHBACK DATABASE `M` TO `n`"},
   851  		{"flashback schema M to N", "FLASHBACK DATABASE `M` TO `N`"},
   852  	}
   853  	extractNodeFunc := func(node Node) Node {
   854  		return node
   855  	}
   856  	runNodeRestoreTest(t, testCases, "%s", extractNodeFunc)
   857  }
   858  
   859  func TestTableOptionTTLRestore(t *testing.T) {
   860  	sourceSQL1 := "create table t (created_at datetime) ttl = created_at + INTERVAL 1 YEAR"
   861  	sourceSQL2 := "alter table t ttl_enable = 'OFF'"
   862  	sourceSQL3 := "alter table t remove ttl"
   863  	cases := []struct {
   864  		sourceSQL string
   865  		flags     format.RestoreFlags
   866  		expectSQL string
   867  	}{
   868  		{sourceSQL1, format.DefaultRestoreFlags, "CREATE TABLE `t` (`created_at` DATETIME) TTL = `created_at` + INTERVAL 1 YEAR"},
   869  		{sourceSQL1, format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment, "CREATE TABLE `t` (`created_at` DATETIME) /*T![ttl] TTL = `created_at` + INTERVAL 1 YEAR */"},
   870  		{sourceSQL2, format.DefaultRestoreFlags, "ALTER TABLE `t` TTL_ENABLE = 'OFF'"},
   871  		{sourceSQL2, format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment, "ALTER TABLE `t` /*T![ttl] TTL_ENABLE = 'OFF' */"},
   872  		{sourceSQL3, format.DefaultRestoreFlags, "ALTER TABLE `t` REMOVE TTL"},
   873  		{sourceSQL3, format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment, "ALTER TABLE `t` /*T![ttl] REMOVE TTL */"},
   874  	}
   875  
   876  	extractNodeFunc := func(node Node) Node {
   877  		return node
   878  	}
   879  
   880  	for _, ca := range cases {
   881  		testCases := []NodeRestoreTestCase{
   882  			{ca.sourceSQL, ca.expectSQL},
   883  		}
   884  		runNodeRestoreTestWithFlags(t, testCases, "%s", extractNodeFunc, ca.flags)
   885  	}
   886  }
   887  
   888  func TestTableOptionTTLRestoreWithTTLEnableOffFlag(t *testing.T) {
   889  	sourceSQL1 := "create table t (created_at datetime) ttl = created_at + INTERVAL 1 YEAR"
   890  	sourceSQL2 := "alter table t ttl_enable = 'ON'"
   891  	sourceSQL3 := "alter table t remove ttl"
   892  	sourceSQL4 := "create table t (created_at datetime) ttl = created_at + INTERVAL 1 YEAR ttl_enable = 'ON'"
   893  	sourceSQL5 := "alter table t ttl_enable = 'ON' placement policy p1"
   894  	cases := []struct {
   895  		sourceSQL string
   896  		flags     format.RestoreFlags
   897  		expectSQL string
   898  	}{
   899  		{sourceSQL1, format.DefaultRestoreFlags | format.RestoreWithTTLEnableOff, "CREATE TABLE `t` (`created_at` DATETIME) TTL = `created_at` + INTERVAL 1 YEAR TTL_ENABLE = 'OFF'"},
   900  		{sourceSQL1, format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment | format.RestoreWithTTLEnableOff, "CREATE TABLE `t` (`created_at` DATETIME) /*T![ttl] TTL = `created_at` + INTERVAL 1 YEAR */ /*T![ttl] TTL_ENABLE = 'OFF' */"},
   901  		{sourceSQL2, format.DefaultRestoreFlags | format.RestoreWithTTLEnableOff, "ALTER TABLE `t`"},
   902  		{sourceSQL2, format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment | format.RestoreWithTTLEnableOff, "ALTER TABLE `t`"},
   903  		{sourceSQL3, format.DefaultRestoreFlags | format.RestoreWithTTLEnableOff, "ALTER TABLE `t` REMOVE TTL"},
   904  		{sourceSQL3, format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment | format.RestoreWithTTLEnableOff, "ALTER TABLE `t` /*T![ttl] REMOVE TTL */"},
   905  		{sourceSQL4, format.DefaultRestoreFlags | format.RestoreWithTTLEnableOff, "CREATE TABLE `t` (`created_at` DATETIME) TTL = `created_at` + INTERVAL 1 YEAR TTL_ENABLE = 'OFF'"},
   906  		{sourceSQL4, format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment | format.RestoreWithTTLEnableOff, "CREATE TABLE `t` (`created_at` DATETIME) /*T![ttl] TTL = `created_at` + INTERVAL 1 YEAR */ /*T![ttl] TTL_ENABLE = 'OFF' */"},
   907  		{sourceSQL5, format.DefaultRestoreFlags | format.RestoreTiDBSpecialComment | format.RestoreWithTTLEnableOff, "ALTER TABLE `t` /*T![placement] PLACEMENT POLICY = `p1` */"},
   908  	}
   909  
   910  	extractNodeFunc := func(node Node) Node {
   911  		return node
   912  	}
   913  
   914  	for _, ca := range cases {
   915  		testCases := []NodeRestoreTestCase{
   916  			{ca.sourceSQL, ca.expectSQL},
   917  		}
   918  		runNodeRestoreTestWithFlagsStmtChange(t, testCases, "%s", extractNodeFunc, ca.flags)
   919  	}
   920  }