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 }