vitess.io/vitess@v0.16.2/go/vt/schemadiff/table_test.go (about) 1 /* 2 Copyright 2022 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package schemadiff 18 19 import ( 20 "strings" 21 "testing" 22 23 "github.com/stretchr/testify/assert" 24 "github.com/stretchr/testify/require" 25 26 "vitess.io/vitess/go/vt/sqlparser" 27 ) 28 29 func TestCreateTableDiff(t *testing.T) { 30 tt := []struct { 31 name string 32 from string 33 to string 34 fromName string 35 toName string 36 diff string 37 diffs []string 38 cdiff string 39 cdiffs []string 40 isError bool 41 errorMsg string 42 autoinc int 43 rotation int 44 fulltext int 45 colrename int 46 constraint int 47 charset int 48 algorithm int 49 }{ 50 { 51 name: "identical", 52 from: "create table t (id int primary key)", 53 to: "create table t (id int primary key)", 54 }, 55 { 56 name: "identical 2", 57 from: "create table t (id int, primary key(id))", 58 to: "create table t (id int, primary key(id))", 59 }, 60 { 61 name: "identical, spacing", 62 from: "create table t (id int primary key)", 63 to: `create table t ( 64 id int primary key 65 )`, 66 }, 67 { 68 name: "column case change", 69 from: "create table t (id int not null, PRIMARY KEY(id))", 70 to: "create table t (Id int not null, primary key(id))", 71 diff: "alter table t modify column Id int not null", 72 cdiff: "ALTER TABLE `t` MODIFY COLUMN `Id` int NOT NULL", 73 }, 74 { 75 name: "identical, name change", 76 from: "create table t1 (id int PRIMARY KEY)", 77 to: "create table t2 (id int primary key)", 78 }, 79 { 80 name: "identical, case change", 81 from: "create table t (id int PRIMARY KEY)", 82 to: "create table t (id int primary key)", 83 }, 84 { 85 name: "identical, case change on target", 86 from: "create table t (id int primary key)", 87 to: "create table t (id int PRIMARY KEY)", 88 }, 89 { 90 name: "identical, case and qualifiers", 91 from: "CREATE table `t` (`id` int primary key)", 92 to: "create TABLE t (id int primary key)", 93 }, 94 { 95 name: "identical, case and qualifiers 2", 96 from: "CREATE table t (`id` int primary key)", 97 to: "create TABLE `t` (id int primary key)", 98 }, 99 { 100 name: "identical, case and column qualifiers", 101 from: "CREATE table t (`id` int primary key, i int not null default 0)", 102 to: "create TABLE t (id int primary key, `i` int not null default 0)", 103 }, 104 { 105 name: "added column", 106 from: "create table t1 (`id` int primary key)", 107 to: "create table t2 (id int primary key, `i` int not null default 0)", 108 diff: "alter table t1 add column i int not null default 0", 109 cdiff: "ALTER TABLE `t1` ADD COLUMN `i` int NOT NULL DEFAULT 0", 110 }, 111 { 112 name: "dropped column", 113 from: "create table t1 (id int primary key, `i` int not null default 0)", 114 to: "create table t2 (`id` int primary key)", 115 diff: "alter table t1 drop column i", 116 cdiff: "ALTER TABLE `t1` DROP COLUMN `i`", 117 fromName: "t1", 118 toName: "t2", 119 }, 120 { 121 name: "modified column", 122 from: "create table t1 (id int primary key, `i` int not null default 0)", 123 to: "create table t2 (id int primary key, `i` bigint unsigned default null)", 124 diff: "alter table t1 modify column i bigint unsigned", 125 cdiff: "ALTER TABLE `t1` MODIFY COLUMN `i` bigint unsigned", 126 }, 127 { 128 name: "added column, dropped column, modified column", 129 from: "create table t1 (id int primary key, `i` int not null default 0, c char(3) default '')", 130 to: "create table t2 (id int primary key, ts timestamp null, `i` bigint unsigned default null)", 131 diff: "alter table t1 drop column c, modify column i bigint unsigned, add column ts timestamp null after id", 132 cdiff: "ALTER TABLE `t1` DROP COLUMN `c`, MODIFY COLUMN `i` bigint unsigned, ADD COLUMN `ts` timestamp NULL AFTER `id`", 133 }, 134 // columns, rename 135 { 136 name: "rename mid column. consider different", 137 from: "create table t1 (id int primary key, i1 int not null, c char(3) default '')", 138 to: "create table t2 (id int primary key, i2 int not null, c char(3) default '')", 139 diff: "alter table t1 drop column i1, add column i2 int not null after id", 140 cdiff: "ALTER TABLE `t1` DROP COLUMN `i1`, ADD COLUMN `i2` int NOT NULL AFTER `id`", 141 }, 142 { 143 name: "rename mid column. statement", 144 from: "create table t1 (id int primary key, i1 int not null, c char(3) default '')", 145 to: "create table t2 (id int primary key, i2 int not null, c char(3) default '')", 146 colrename: ColumnRenameHeuristicStatement, 147 diff: "alter table t1 rename column i1 to i2", 148 cdiff: "ALTER TABLE `t1` RENAME COLUMN `i1` TO `i2`", 149 }, 150 { 151 name: "rename last column. statement", 152 from: "create table t1 (id int primary key, i1 int not null)", 153 to: "create table t2 (id int primary key, i2 int not null)", 154 colrename: ColumnRenameHeuristicStatement, 155 diff: "alter table t1 rename column i1 to i2", 156 cdiff: "ALTER TABLE `t1` RENAME COLUMN `i1` TO `i2`", 157 }, 158 { 159 name: "rename two columns. statement", 160 from: "create table t1 (id int primary key, i1 int not null, c char(3) default '', v1 varchar(32))", 161 to: "create table t2 (id int primary key, i2 int not null, c char(3) default '', v2 varchar(32))", 162 colrename: ColumnRenameHeuristicStatement, 163 diff: "alter table t1 rename column i1 to i2, rename column v1 to v2", 164 cdiff: "ALTER TABLE `t1` RENAME COLUMN `i1` TO `i2`, RENAME COLUMN `v1` TO `v2`", 165 }, 166 { 167 name: "rename mid column and add an index. statement", 168 from: "create table t1 (id int primary key, i1 int not null, c char(3) default '')", 169 to: "create table t2 (id int primary key, i2 int not null, c char(3) default '', key i2_idx(i2))", 170 colrename: ColumnRenameHeuristicStatement, 171 diff: "alter table t1 rename column i1 to i2, add key i2_idx (i2)", 172 cdiff: "ALTER TABLE `t1` RENAME COLUMN `i1` TO `i2`, ADD KEY `i2_idx` (`i2`)", 173 }, 174 { 175 // in a future iteration, this will generate a RENAME for both column, like in the previous test. Until then, we do not RENAME two successive columns 176 name: "rename two successive columns. statement", 177 from: "create table t1 (id int primary key, i1 int not null, v1 varchar(32))", 178 to: "create table t2 (id int primary key, i2 int not null, v2 varchar(32))", 179 colrename: ColumnRenameHeuristicStatement, 180 diff: "alter table t1 drop column i1, drop column v1, add column i2 int not null, add column v2 varchar(32)", 181 cdiff: "ALTER TABLE `t1` DROP COLUMN `i1`, DROP COLUMN `v1`, ADD COLUMN `i2` int NOT NULL, ADD COLUMN `v2` varchar(32)", 182 }, 183 // columns, reordering 184 { 185 name: "reorder column", 186 from: "create table t1 (id int primary key, a int, b int, c int, d int)", 187 to: "create table t2 (id int primary key, a int, c int, b int, d int)", 188 diff: "alter table t1 modify column c int after a", 189 cdiff: "ALTER TABLE `t1` MODIFY COLUMN `c` int AFTER `a`", 190 }, 191 { 192 name: "reorder column, far jump", 193 from: "create table t1 (id int primary key, a int, b int, c int, d int)", 194 to: "create table t2 (a int, b int, c int, d int, id int primary key)", 195 diff: "alter table t1 modify column id int after d", 196 cdiff: "ALTER TABLE `t1` MODIFY COLUMN `id` int AFTER `d`", 197 }, 198 { 199 name: "reorder column, far jump with case sentivity", 200 from: "create table t1 (id int primary key, a int, b int, c int, d int)", 201 to: "create table t2 (a int, B int, c int, d int, id int primary key)", 202 diff: "alter table t1 modify column B int, modify column id int after d", 203 cdiff: "ALTER TABLE `t1` MODIFY COLUMN `B` int, MODIFY COLUMN `id` int AFTER `d`", 204 }, 205 { 206 name: "reorder column, far jump, another reorder", 207 from: "create table t1 (id int primary key, a int, b int, c int, d int)", 208 to: "create table t2 (a int, c int, b int, d int, id int primary key)", 209 diff: "alter table t1 modify column c int after a, modify column id int after d", 210 cdiff: "ALTER TABLE `t1` MODIFY COLUMN `c` int AFTER `a`, MODIFY COLUMN `id` int AFTER `d`", 211 }, 212 { 213 name: "reorder column, far jump, another reorder 2", 214 from: "create table t1 (id int primary key, a int, b int, c int, d int)", 215 to: "create table t2 (c int, a int, b int, d int, id int primary key)", 216 diff: "alter table t1 modify column c int first, modify column id int after d", 217 cdiff: "ALTER TABLE `t1` MODIFY COLUMN `c` int FIRST, MODIFY COLUMN `id` int AFTER `d`", 218 }, 219 { 220 name: "reorder column, far jump, another reorder 3", 221 from: "create table t1 (id int primary key, a int, b int, c int, d int, e int, f int)", 222 to: "create table t2 (a int, c int, b int, d int, id int primary key, e int, f int)", 223 diff: "alter table t1 modify column c int after a, modify column id int after d", 224 cdiff: "ALTER TABLE `t1` MODIFY COLUMN `c` int AFTER `a`, MODIFY COLUMN `id` int AFTER `d`", 225 }, 226 { 227 name: "reorder column, far jump, another reorder, removed columns", 228 from: "create table t1 (id int primary key, a int, b int, c int, d int, e int, f int, g int)", 229 to: "create table t2 (a int, c int, f int, e int, id int primary key, g int)", 230 diff: "alter table t1 drop column b, drop column d, modify column f int after c, modify column id int after e", 231 cdiff: "ALTER TABLE `t1` DROP COLUMN `b`, DROP COLUMN `d`, MODIFY COLUMN `f` int AFTER `c`, MODIFY COLUMN `id` int AFTER `e`", 232 }, 233 { 234 name: "two reorders", 235 from: "create table t1 (id int primary key, a int, b int, c int, d int, e int, f int)", 236 to: "create table t2 (id int primary key, b int, a int, c int, e int, d int, f int)", 237 diff: "alter table t1 modify column b int after id, modify column e int after c", 238 cdiff: "ALTER TABLE `t1` MODIFY COLUMN `b` int AFTER `id`, MODIFY COLUMN `e` int AFTER `c`", 239 }, 240 { 241 name: "two reorders, added and removed columns", 242 from: "create table t1 (id int primary key, a int, b int, c int, d int, e int, f int)", 243 to: "create table t2 (g int, id int primary key, h int, b int, a int, i int, e int, d int, j int, f int, k int)", 244 diff: "alter table t1 drop column c, modify column b int after id, modify column e int after a, add column g int first, add column h int after id, add column i int after a, add column j int after d, add column k int", 245 cdiff: "ALTER TABLE `t1` DROP COLUMN `c`, MODIFY COLUMN `b` int AFTER `id`, MODIFY COLUMN `e` int AFTER `a`, ADD COLUMN `g` int FIRST, ADD COLUMN `h` int AFTER `id`, ADD COLUMN `i` int AFTER `a`, ADD COLUMN `j` int AFTER `d`, ADD COLUMN `k` int", 246 }, 247 { 248 name: "reorder column and change data type", 249 from: "create table t1 (id int primary key, a int, b int, c int, d int)", 250 to: "create table t2 (id int primary key, a int, c bigint, b int, d int)", 251 diff: "alter table t1 modify column c bigint after a", 252 cdiff: "ALTER TABLE `t1` MODIFY COLUMN `c` bigint AFTER `a`", 253 }, 254 { 255 name: "reorder column, first", 256 from: "create table t1 (id int primary key, a int, b int, c int, d int)", 257 to: "create table t2 (c int, id int primary key, a int, b int, d int)", 258 diff: "alter table t1 modify column c int first", 259 cdiff: "ALTER TABLE `t1` MODIFY COLUMN `c` int FIRST", 260 }, 261 { 262 name: "add multiple columns", 263 from: "create table t1 (id int primary key, a int)", 264 to: "create table t2 (id int primary key, a int, b int, c int, d int)", 265 diff: "alter table t1 add column b int, add column c int, add column d int", 266 cdiff: "ALTER TABLE `t1` ADD COLUMN `b` int, ADD COLUMN `c` int, ADD COLUMN `d` int", 267 }, 268 { 269 name: "added column in middle", 270 from: "create table t1 (id int primary key, a int, b int, c int, d int)", 271 to: "create table t2 (id int primary key, a int, b int, x int, c int, d int)", 272 diff: "alter table t1 add column x int after b", 273 cdiff: "ALTER TABLE `t1` ADD COLUMN `x` int AFTER `b`", 274 }, 275 { 276 name: "added multiple column in middle", 277 from: "create table t1 (id int primary key, a int)", 278 to: "create table t2 (w int, x int, id int primary key, y int, a int, z int)", 279 diff: "alter table t1 add column w int first, add column x int after w, add column y int after id, add column z int", 280 cdiff: "ALTER TABLE `t1` ADD COLUMN `w` int FIRST, ADD COLUMN `x` int AFTER `w`, ADD COLUMN `y` int AFTER `id`, ADD COLUMN `z` int", 281 }, 282 { 283 name: "added column first, reorder column", 284 from: "create table t1 (id int primary key, a int)", 285 to: "create table t2 (x int, a int, id int primary key)", 286 diff: "alter table t1 modify column a int first, add column x int first", 287 cdiff: "ALTER TABLE `t1` MODIFY COLUMN `a` int FIRST, ADD COLUMN `x` int FIRST", 288 }, 289 { 290 name: "added column in middle, add column on end, reorder column", 291 from: "create table t1 (id int primary key, a int, b int, c int, d int)", 292 to: "create table t2 (id int primary key, a int, b int, x int, d int, c int, y int)", 293 diff: "alter table t1 modify column d int after b, add column x int after b, add column y int", 294 cdiff: "ALTER TABLE `t1` MODIFY COLUMN `d` int AFTER `b`, ADD COLUMN `x` int AFTER `b`, ADD COLUMN `y` int", 295 }, 296 { 297 name: "added column in middle, add column on end, reorder column 2", 298 from: "create table t1 (id int primary key, a int, b int, c int, d int)", 299 to: "create table t2 (id int primary key, a int, c int, x int, b int, d int, y int)", 300 diff: "alter table t1 modify column c int after a, add column x int after c, add column y int", 301 cdiff: "ALTER TABLE `t1` MODIFY COLUMN `c` int AFTER `a`, ADD COLUMN `x` int AFTER `c`, ADD COLUMN `y` int", 302 }, 303 // keys 304 { 305 name: "added key", 306 from: "create table t1 (`id` int primary key, i int)", 307 to: "create table t2 (id int primary key, `i` int, key `i_idx` (i))", 308 diff: "alter table t1 add key i_idx (i)", 309 cdiff: "ALTER TABLE `t1` ADD KEY `i_idx` (`i`)", 310 }, 311 { 312 name: "added key without name", 313 from: "create table t1 (`id` int primary key, i int)", 314 to: "create table t2 (id int primary key, `i` int, key (i))", 315 diff: "alter table t1 add key i (i)", 316 cdiff: "ALTER TABLE `t1` ADD KEY `i` (`i`)", 317 }, 318 { 319 name: "added key without name, conflicting name", 320 from: "create table t1 (`id` int primary key, i int, key i(i))", 321 to: "create table t2 (id int primary key, `i` int, key i(i), key (i))", 322 diff: "alter table t1 add key i_2 (i)", 323 cdiff: "ALTER TABLE `t1` ADD KEY `i_2` (`i`)", 324 }, 325 { 326 name: "added key without name, conflicting name 2", 327 from: "create table t1 (`id` int primary key, i int, key i(i), key i_2(i))", 328 to: "create table t2 (id int primary key, `i` int, key i(i), key i_2(i), key (i))", 329 diff: "alter table t1 add key i_3 (i)", 330 cdiff: "ALTER TABLE `t1` ADD KEY `i_3` (`i`)", 331 }, 332 { 333 name: "added column and key", 334 from: "create table t1 (`id` int primary key)", 335 to: "create table t2 (id int primary key, `i` int, key `i_idx` (i))", 336 diff: "alter table t1 add column i int, add key i_idx (i)", 337 cdiff: "ALTER TABLE `t1` ADD COLUMN `i` int, ADD KEY `i_idx` (`i`)", 338 }, 339 { 340 name: "modify column primary key", 341 from: "create table t1 (`id` int)", 342 to: "create table t2 (id int primary key)", 343 diff: "alter table t1 add primary key (id)", 344 cdiff: "ALTER TABLE `t1` ADD PRIMARY KEY (`id`)", 345 }, 346 { 347 name: "added primary key", 348 from: "create table t1 (`id` int)", 349 to: "create table t2 (id int, primary key(id))", 350 diff: "alter table t1 add primary key (id)", 351 cdiff: "ALTER TABLE `t1` ADD PRIMARY KEY (`id`)", 352 }, 353 { 354 name: "dropped primary key", 355 from: "create table t1 (id int, primary key(id))", 356 to: "create table t2 (id int)", 357 diff: "alter table t1 drop primary key", 358 cdiff: "ALTER TABLE `t1` DROP PRIMARY KEY", 359 }, 360 { 361 name: "dropped key", 362 from: "create table t1 (`id` int primary key, i int, key i_idx(i))", 363 to: "create table t2 (`id` int primary key, i int)", 364 diff: "alter table t1 drop key i_idx", 365 cdiff: "ALTER TABLE `t1` DROP KEY `i_idx`", 366 }, 367 { 368 name: "dropped key 2", 369 from: "create table t1 (`id` int, i int, primary key (id), key i_idx(i))", 370 to: "create table t1 (`id` int, i int, primary key (id))", 371 diff: "alter table t1 drop key i_idx", 372 cdiff: "ALTER TABLE `t1` DROP KEY `i_idx`", 373 }, 374 { 375 name: "modified key", 376 from: "create table t1 (`id` int primary key, i int, key i_idx(i))", 377 to: "create table t2 (`id` int primary key, i int, key i_idx(i, id))", 378 diff: "alter table t1 drop key i_idx, add key i_idx (i, id)", 379 cdiff: "ALTER TABLE `t1` DROP KEY `i_idx`, ADD KEY `i_idx` (`i`, `id`)", 380 }, 381 { 382 name: "modified primary key", 383 from: "create table t1 (`id` int, i int, primary key(id), key i_idx(i))", 384 to: "create table t2 (`id` int, i int, primary key(id, i),key i_idx(`i`))", 385 diff: "alter table t1 drop primary key, add primary key (id, i)", 386 cdiff: "ALTER TABLE `t1` DROP PRIMARY KEY, ADD PRIMARY KEY (`id`, `i`)", 387 }, 388 { 389 name: "alternative primary key definition, no diff", 390 from: "create table t1 (`id` int primary key, i int)", 391 to: "create table t2 (`id` int, i int, primary key (id))", 392 }, 393 { 394 name: "reordered key, no diff", 395 from: "create table t1 (`id` int primary key, i int, key i_idx(i), key i2_idx(i, `id`))", 396 to: "create table t2 (`id` int primary key, i int, key i2_idx (`i`, id), key i_idx ( i ) )", 397 }, 398 { 399 name: "reordered key, no diff, 2", 400 from: "create table t1 (`id` int, i int, primary key(id), key i_idx(i), key i2_idx(i, `id`))", 401 to: "create table t2 (`id` int, i int, key i2_idx (`i`, id), key i_idx ( i ), primary key(id) )", 402 }, 403 { 404 name: "reordered key, no diff 3", 405 from: "CREATE TABLE `pets` (`id` int, `name` VARCHAR(255), `login` VARCHAR(255), PRIMARY KEY (`id`), KEY (`login`), KEY (`name`) )", 406 to: "CREATE TABLE `pets` (`id` int, `name` VARCHAR(255), `login` VARCHAR(255), PRIMARY KEY (`id`), KEY (`name`), KEY (`login`) )", 407 }, 408 { 409 name: "reordered key, no diff 4", 410 from: "CREATE TABLE `pets` (`id` int, `name` VARCHAR(255), `login` VARCHAR(255), PRIMARY KEY (`id`), KEY login (login, name), KEY (`login`), KEY (`name`) )", 411 to: "CREATE TABLE `pets` (`id` int, `name` VARCHAR(255), `login` VARCHAR(255), PRIMARY KEY (`id`), KEY (`name`), KEY (`login`), KEY login (login, name) )", 412 }, 413 { 414 name: "reordered key, add key", 415 from: "create table t1 (`id` int primary key, i int, key i_idx(i), key i2_idx(i, `id`))", 416 to: "create table t2 (`id` int primary key, i int, key i2_idx (`i`, id), key i_idx3(id), key i_idx ( i ) )", 417 diff: "alter table t1 add key i_idx3 (id)", 418 cdiff: "ALTER TABLE `t1` ADD KEY `i_idx3` (`id`)", 419 }, 420 { 421 name: "key made visible", 422 from: "create table t1 (`id` int primary key, i int, key i_idx(i) invisible)", 423 to: "create table t1 (`id` int primary key, i int, key i_idx(i))", 424 diff: "alter table t1 alter index i_idx visible", 425 cdiff: "ALTER TABLE `t1` ALTER INDEX `i_idx` VISIBLE", 426 }, 427 { 428 name: "key made invisible", 429 from: "create table t1 (`id` int primary key, i int, key i_idx(i))", 430 to: "create table t1 (`id` int primary key, i int, key i_idx(i) invisible)", 431 diff: "alter table t1 alter index i_idx invisible", 432 cdiff: "ALTER TABLE `t1` ALTER INDEX `i_idx` INVISIBLE", 433 }, 434 { 435 name: "key made invisible with different case", 436 from: "create table t1 (`id` int primary key, i int, key i_idx(i))", 437 to: "create table t1 (`id` int primary key, i int, key i_idx(i) INVISIBLE)", 438 diff: "alter table t1 alter index i_idx invisible", 439 cdiff: "ALTER TABLE `t1` ALTER INDEX `i_idx` INVISIBLE", 440 }, 441 // FULLTEXT keys 442 { 443 name: "add one fulltext key", 444 from: "create table t1 (id int primary key, name tinytext not null)", 445 to: "create table t1 (id int primary key, name tinytext not null, fulltext key name_ft(name))", 446 diff: "alter table t1 add fulltext key name_ft (`name`)", 447 cdiff: "ALTER TABLE `t1` ADD FULLTEXT KEY `name_ft` (`name`)", 448 }, 449 { 450 name: "add one fulltext key with explicit parser", 451 from: "create table t1 (id int primary key, name tinytext not null)", 452 to: "create table t1 (id int primary key, name tinytext not null, fulltext key name_ft(name) with parser ngram)", 453 diff: "alter table t1 add fulltext key name_ft (`name`) with parser ngram", 454 cdiff: "ALTER TABLE `t1` ADD FULLTEXT KEY `name_ft` (`name`) WITH PARSER ngram", 455 }, 456 { 457 name: "add one fulltext key and one normal key", 458 from: "create table t1 (id int primary key, name tinytext not null)", 459 to: "create table t1 (id int primary key, name tinytext not null, key name_idx(name(32)), fulltext key name_ft(name))", 460 diff: "alter table t1 add key name_idx (`name`(32)), add fulltext key name_ft (`name`)", 461 cdiff: "ALTER TABLE `t1` ADD KEY `name_idx` (`name`(32)), ADD FULLTEXT KEY `name_ft` (`name`)", 462 }, 463 { 464 name: "add two fulltext keys, distinct statements", 465 from: "create table t1 (id int primary key, name1 tinytext not null, name2 tinytext not null)", 466 to: "create table t1 (id int primary key, name1 tinytext not null, name2 tinytext not null, fulltext key name1_ft(name1), fulltext key name2_ft(name2))", 467 diffs: []string{"alter table t1 add fulltext key name1_ft (name1)", "alter table t1 add fulltext key name2_ft (name2)"}, 468 cdiffs: []string{"ALTER TABLE `t1` ADD FULLTEXT KEY `name1_ft` (`name1`)", "ALTER TABLE `t1` ADD FULLTEXT KEY `name2_ft` (`name2`)"}, 469 }, 470 { 471 name: "add two fulltext keys, unify statements", 472 from: "create table t1 (id int primary key, name1 tinytext not null, name2 tinytext not null)", 473 to: "create table t1 (id int primary key, name1 tinytext not null, name2 tinytext not null, fulltext key name1_ft(name1), fulltext key name2_ft(name2))", 474 fulltext: FullTextKeyUnifyStatements, 475 diff: "alter table t1 add fulltext key name1_ft (name1), add fulltext key name2_ft (name2)", 476 cdiff: "ALTER TABLE `t1` ADD FULLTEXT KEY `name1_ft` (`name1`), ADD FULLTEXT KEY `name2_ft` (`name2`)", 477 }, 478 { 479 name: "no fulltext diff", 480 from: "create table t1 (id int primary key, name tinytext not null, fulltext key name_ft(name) with parser ngram)", 481 to: "create table t1 (id int primary key, name tinytext not null, fulltext key name_ft(name) with parser ngram)", 482 }, 483 { 484 name: "no fulltext diff, 2", 485 from: "create table t1 (id int primary key, name tinytext not null, fulltext key name_ft(name) with parser ngram)", 486 to: "create table t1 (id int primary key, name tinytext not null, fulltext key name_ft(name) WITH PARSER `ngram`)", 487 }, 488 { 489 name: "no fulltext diff, 3", 490 from: "create table t1 (id int primary key, name tinytext not null, fulltext key name_ft(name) with parser ngram)", 491 to: "create table t1 (id int primary key, name tinytext not null, fulltext key name_ft(name) /*!50100 WITH PARSER `ngram` */)", 492 }, 493 { 494 name: "no fulltext diff", 495 from: "create table t1 (id int primary key, name tinytext not null, fulltext key name_ft(name) with parser ngram)", 496 to: "create table t1 (id int primary key, name tinytext not null, fulltext key name_ft(name) with parser NGRAM)", 497 }, 498 // CHECK constraints 499 { 500 name: "identical check constraints", 501 from: "create table t1 (id int primary key, i int, constraint `check1` CHECK ((`i` < 5)))", 502 to: "create table t2 (id int primary key, i int, constraint `check1` CHECK ((`i` < 5)))", 503 diff: "", 504 }, 505 { 506 name: "check constraints, different name, strict", 507 from: "create table t1 (id int primary key, i int, constraint `check1` CHECK ((`i` < 5)))", 508 to: "create table t2 (id int primary key, i int, constraint `chk_abc123` CHECK ((`i` < 5)))", 509 diff: "alter table t1 drop check check1, add constraint chk_abc123 check (i < 5)", 510 cdiff: "ALTER TABLE `t1` DROP CHECK `check1`, ADD CONSTRAINT `chk_abc123` CHECK (`i` < 5)", 511 constraint: ConstraintNamesStrict, 512 }, 513 { 514 name: "check constraints, different name, ignore vitess, non vitess names", 515 from: "create table t1 (id int primary key, i int, constraint `check1` CHECK ((`i` < 5)))", 516 to: "create table t2 (id int primary key, i int, constraint `chk_abc123` CHECK ((`i` < 5)))", 517 diff: "alter table t1 drop check check1, add constraint chk_abc123 check (i < 5)", 518 cdiff: "ALTER TABLE `t1` DROP CHECK `check1`, ADD CONSTRAINT `chk_abc123` CHECK (`i` < 5)", 519 constraint: ConstraintNamesIgnoreVitess, 520 }, 521 { 522 name: "check constraints, different name, ignore vitess, vitess names, no match", 523 from: "create table t1 (id int primary key, i int, constraint `check1` CHECK ((`i` < 5)))", 524 to: "create table t2 (id int primary key, i int, constraint `check2_7fp024p4rxvr858tsaggvf9dw` CHECK ((`i` < 5)))", 525 diff: "alter table t1 drop check check1, add constraint check2_7fp024p4rxvr858tsaggvf9dw check (i < 5)", 526 cdiff: "ALTER TABLE `t1` DROP CHECK `check1`, ADD CONSTRAINT `check2_7fp024p4rxvr858tsaggvf9dw` CHECK (`i` < 5)", 527 constraint: ConstraintNamesIgnoreVitess, 528 }, 529 { 530 name: "check constraints, different name, ignore vitess, vitess names match", 531 from: "create table t1 (id int primary key, i int, constraint `check2` CHECK ((`i` < 5)))", 532 to: "create table t2 (id int primary key, i int, constraint `check2_7fp024p4rxvr858tsaggvf9dw` CHECK ((`i` < 5)))", 533 diff: "", 534 constraint: ConstraintNamesIgnoreVitess, 535 }, 536 { 537 name: "check constraints, different name, ignore all", 538 from: "create table t1 (id int primary key, i int, constraint `check1` CHECK ((`i` < 5)))", 539 to: "create table t2 (id int primary key, i int, constraint `chk_abc123` CHECK ((`i` < 5)))", 540 diff: "", 541 constraint: ConstraintNamesIgnoreAll, 542 }, 543 { 544 name: "check constraints, different order", 545 from: "create table t1 (id int primary key, i int, constraint `check1` CHECK ((`i` < 5)), constraint `check2` CHECK ((`i` > 2)))", 546 to: "create table t2 (id int primary key, i int, constraint `check2` CHECK ((`i` > 2)), constraint `check1` CHECK ((`i` < 5)))", 547 diff: "", 548 }, 549 { 550 name: "check constraints, different names & order", 551 from: "create table t1 (id int primary key, i int, constraint `check1` CHECK ((`i` < 5)), constraint `check2` CHECK ((`i` > 2)))", 552 to: "create table t2 (id int primary key, i int, constraint `chk_123abc` CHECK ((`i` > 2)), constraint `chk_789def` CHECK ((`i` < 5)))", 553 diff: "", 554 constraint: ConstraintNamesIgnoreAll, 555 }, 556 { 557 name: "check constraints, add", 558 from: "create table t1 (id int primary key, i int, constraint `check1` CHECK ((`i` < 5)), constraint `check2` CHECK ((`i` > 2)))", 559 to: "create table t2 (id int primary key, i int, constraint `chk_123abc` CHECK ((`i` > 2)), constraint `check3` CHECK ((`i` != 3)), constraint `chk_789def` CHECK ((`i` < 5)))", 560 diff: "alter table t1 add constraint check3 check (i != 3)", 561 cdiff: "ALTER TABLE `t1` ADD CONSTRAINT `check3` CHECK (`i` != 3)", 562 constraint: ConstraintNamesIgnoreAll, 563 }, 564 { 565 name: "check constraints, remove", 566 from: "create table t1 (id int primary key, i int, constraint `chk_123abc` CHECK ((`i` > 2)), constraint `check3` CHECK ((`i` != 3)), constraint `chk_789def` CHECK ((`i` < 5)))", 567 to: "create table t2 (id int primary key, i int, constraint `check1` CHECK ((`i` < 5)), constraint `check2` CHECK ((`i` > 2)))", 568 diff: "alter table t1 drop check check3", 569 cdiff: "ALTER TABLE `t1` DROP CHECK `check3`", 570 constraint: ConstraintNamesIgnoreAll, 571 }, 572 { 573 name: "check constraints, remove, ignore vitess, no match", 574 from: "create table t1 (id int primary key, i int, constraint `chk_123abc` CHECK ((`i` > 2)), constraint `check3` CHECK ((`i` != 3)), constraint `chk_789def` CHECK ((`i` < 5)))", 575 to: "create table t2 (id int primary key, i int, constraint `check1` CHECK ((`i` < 5)), constraint `check2` CHECK ((`i` > 2)))", 576 diff: "alter table t1 drop check chk_123abc, drop check check3, drop check chk_789def, add constraint check1 check (i < 5), add constraint check2 check (i > 2)", 577 cdiff: "ALTER TABLE `t1` DROP CHECK `chk_123abc`, DROP CHECK `check3`, DROP CHECK `chk_789def`, ADD CONSTRAINT `check1` CHECK (`i` < 5), ADD CONSTRAINT `check2` CHECK (`i` > 2)", 578 constraint: ConstraintNamesIgnoreVitess, 579 }, 580 { 581 name: "check constraints, remove, ignore vitess, match", 582 from: "create table t1 (id int primary key, i int, constraint `check2_cukwabxd742sgycn96xj7n87g` CHECK ((`i` > 2)), constraint `check3` CHECK ((`i` != 3)), constraint `check1_19l09s37kbhj4axnzmi10e18k` CHECK ((`i` < 5)))", 583 to: "create table t2 (id int primary key, i int, constraint `check1` CHECK ((`i` < 5)), constraint `check2` CHECK ((`i` > 2)))", 584 diff: "alter table t1 drop check check3", 585 cdiff: "ALTER TABLE `t1` DROP CHECK `check3`", 586 constraint: ConstraintNamesIgnoreVitess, 587 }, 588 { 589 name: "check constraints, remove, strict", 590 from: "create table t1 (id int primary key, i int, constraint `chk_123abc` CHECK ((`i` > 2)), constraint `check3` CHECK ((`i` != 3)), constraint `chk_789def` CHECK ((`i` < 5)))", 591 to: "create table t2 (id int primary key, i int, constraint `check1` CHECK ((`i` < 5)), constraint `check2` CHECK ((`i` > 2)))", 592 diff: "alter table t1 drop check chk_123abc, drop check check3, drop check chk_789def, add constraint check1 check (i < 5), add constraint check2 check (i > 2)", 593 cdiff: "ALTER TABLE `t1` DROP CHECK `chk_123abc`, DROP CHECK `check3`, DROP CHECK `chk_789def`, ADD CONSTRAINT `check1` CHECK (`i` < 5), ADD CONSTRAINT `check2` CHECK (`i` > 2)", 594 constraint: ConstraintNamesStrict, 595 }, 596 // foreign keys 597 { 598 name: "drop foreign key", 599 from: "create table t1 (id int primary key, i int, key i_idex (i), constraint f foreign key (i) references parent(id))", 600 to: "create table t2 (id int primary key, i int, key i_idex (i))", 601 diff: "alter table t1 drop foreign key f", 602 cdiff: "ALTER TABLE `t1` DROP FOREIGN KEY `f`", 603 }, 604 { 605 name: "add foreign key", 606 from: "create table t1 (id int primary key, i int, key ix(i))", 607 to: "create table t2 (id int primary key, i int, key ix(i), constraint f foreign key (i) references parent(id))", 608 diff: "alter table t1 add constraint f foreign key (i) references parent (id)", 609 cdiff: "ALTER TABLE `t1` ADD CONSTRAINT `f` FOREIGN KEY (`i`) REFERENCES `parent` (`id`)", 610 }, 611 { 612 name: "add foreign key and index", 613 from: "create table t1 (id int primary key, i int)", 614 to: "create table t2 (id int primary key, i int, key ix(i), constraint f foreign key (i) references parent(id))", 615 diff: "alter table t1 add key ix (i), add constraint f foreign key (i) references parent (id)", 616 cdiff: "ALTER TABLE `t1` ADD KEY `ix` (`i`), ADD CONSTRAINT `f` FOREIGN KEY (`i`) REFERENCES `parent` (`id`)", 617 }, 618 { 619 name: "identical foreign key", 620 from: "create table t1 (id int primary key, i int, constraint f foreign key (i) references parent(id) on delete cascade)", 621 to: "create table t2 (id int primary key, i int, constraint f foreign key (i) references parent(id) on delete cascade)", 622 }, 623 { 624 name: "implicit foreign key indexes", 625 from: "create table t1 (id int primary key, i int, key f(i), constraint f foreign key (i) references parent(id) on delete cascade)", 626 to: "create table t2 (id int primary key, i int, constraint f foreign key (i) references parent(id) on delete cascade)", 627 }, 628 { 629 name: "implicit foreign key indexes 2", 630 from: "create table t1 (id int primary key, i int, constraint f foreign key (i) references parent(id) on delete cascade)", 631 to: "create table t2 (id int primary key, i int, key f(i), constraint f foreign key (i) references parent(id) on delete cascade)", 632 }, 633 { 634 name: "implicit unnamed foreign key indexes", 635 from: "create table t1 (id int primary key, i int, foreign key (i) references parent(id) on delete cascade)", 636 to: "create table t1 (id int primary key, i int, key i(i), constraint t1_ibfk_1 foreign key (i) references parent(id) on delete cascade)", 637 }, 638 { 639 name: "modify foreign key", 640 from: "create table t1 (id int primary key, i int, key ix(i), constraint f foreign key (i) references parent(id) on delete cascade)", 641 to: "create table t2 (id int primary key, i int, key ix(i), constraint f foreign key (i) references parent(id) on delete set null)", 642 diff: "alter table t1 drop foreign key f, add constraint f foreign key (i) references parent (id) on delete set null", 643 cdiff: "ALTER TABLE `t1` DROP FOREIGN KEY `f`, ADD CONSTRAINT `f` FOREIGN KEY (`i`) REFERENCES `parent` (`id`) ON DELETE SET NULL", 644 }, 645 { 646 name: "drop and add foreign key", 647 from: "create table t1 (id int primary key, i int, key ix(i), constraint f foreign key (i) references parent(id) on delete cascade)", 648 to: "create table t2 (id int primary key, i int, key ix(i), constraint f2 foreign key (i) references parent(id) on delete set null)", 649 diff: "alter table t1 drop foreign key f, add constraint f2 foreign key (i) references parent (id) on delete set null", 650 cdiff: "ALTER TABLE `t1` DROP FOREIGN KEY `f`, ADD CONSTRAINT `f2` FOREIGN KEY (`i`) REFERENCES `parent` (`id`) ON DELETE SET NULL", 651 }, 652 { 653 name: "ignore different foreign key order", 654 from: "create table t1 (id int primary key, i int, constraint f foreign key (i) references parent(id) on delete restrict, constraint f2 foreign key (i2) references parent2(id) on delete restrict)", 655 to: "create table t2 (id int primary key, i int, constraint f2 foreign key (i2) references parent2(id) on delete restrict, constraint f foreign key (i) references parent(id) on delete restrict)", 656 diff: "", 657 }, 658 { 659 name: "drop foreign key, but not implicit index", 660 from: "create table t1 (id int primary key, i int, constraint f foreign key (i) references parent(id) on delete cascade)", 661 to: "create table t2 (id int primary key, i int, key f(i))", 662 diff: "alter table t1 drop foreign key f", 663 cdiff: "ALTER TABLE `t1` DROP FOREIGN KEY `f`", 664 }, 665 // partitions 666 { 667 name: "identical partitioning", 668 from: "create table t1 (id int primary key) partition by hash (id) partitions 4", 669 to: "create table t1 (id int primary key, a int) partition by hash (id) partitions 4", 670 diff: "alter table t1 add column a int", 671 cdiff: "ALTER TABLE `t1` ADD COLUMN `a` int", 672 }, 673 { 674 name: "partitioning, column case", 675 from: "create table t1 (id int primary key) partition by hash (id) partitions 4", 676 to: "create table t1 (id int primary key, a int) partition by hash (ID) partitions 4", 677 diff: "alter table t1 add column a int \npartition by hash (ID) partitions 4", 678 cdiff: "ALTER TABLE `t1` ADD COLUMN `a` int \nPARTITION BY HASH (`ID`) PARTITIONS 4", 679 }, 680 { 681 name: "remove partitioning", 682 from: "create table t1 (id int primary key) partition by hash (id) partitions 4", 683 to: "create table t1 (id int primary key, a int)", 684 diff: "alter table t1 add column a int remove partitioning", 685 cdiff: "ALTER TABLE `t1` ADD COLUMN `a` int REMOVE PARTITIONING", 686 }, 687 { 688 name: "remove partitioning 2", 689 from: "create table t1 (id int primary key) partition by hash (id) partitions 4", 690 to: "create table t1 (id int primary key)", 691 diff: "alter table t1 remove partitioning", 692 cdiff: "ALTER TABLE `t1` REMOVE PARTITIONING", 693 }, 694 { 695 name: "change partitioning hash", 696 from: "create table t1 (id int primary key) partition by hash (id) partitions 4", 697 to: "create table t1 (id int primary key) partition by hash (id) partitions 5", 698 diff: "alter table t1 \npartition by hash (id) partitions 5", 699 cdiff: "ALTER TABLE `t1` \nPARTITION BY HASH (`id`) PARTITIONS 5", 700 }, 701 { 702 name: "change partitioning key", 703 from: "create table t1 (id int primary key) partition by key (id) partitions 2", 704 to: "create table t1 (id int primary key) partition by hash (id) partitions 5", 705 diff: "alter table t1 \npartition by hash (id) partitions 5", 706 cdiff: "ALTER TABLE `t1` \nPARTITION BY HASH (`id`) PARTITIONS 5", 707 }, 708 { 709 name: "change partitioning list", 710 from: "create table t1 (id int primary key) partition by key (id) partitions 2", 711 to: "create table t1 (id int primary key) partition by list (id) (partition p1 values in(11,21), partition p2 values in (12,22))", 712 diff: "alter table t1 \npartition by list (id)\n(partition p1 values in (11, 21),\n partition p2 values in (12, 22))", 713 cdiff: "ALTER TABLE `t1` \nPARTITION BY LIST (`id`)\n(PARTITION `p1` VALUES IN (11, 21),\n PARTITION `p2` VALUES IN (12, 22))", 714 }, 715 { 716 name: "change partitioning range: rotate", 717 from: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20), partition p3 values less than (30))", 718 to: "create table t1 (id int primary key) partition by range (id) (partition p2 values less than (20), partition p3 values less than (30), partition p4 values less than (40))", 719 diff: "alter table t1 \npartition by range (id)\n(partition p2 values less than (20),\n partition p3 values less than (30),\n partition p4 values less than (40))", 720 cdiff: "ALTER TABLE `t1` \nPARTITION BY RANGE (`id`)\n(PARTITION `p2` VALUES LESS THAN (20),\n PARTITION `p3` VALUES LESS THAN (30),\n PARTITION `p4` VALUES LESS THAN (40))", 721 }, 722 { 723 name: "change partitioning range: ignore rotate", 724 from: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20), partition p3 values less than (30))", 725 to: "create table t1 (id int primary key) partition by range (id) (partition p2 values less than (20), partition p3 values less than (30), partition p4 values less than (40))", 726 rotation: RangeRotationIgnore, 727 }, 728 { 729 name: "change partitioning range: statements, drop", 730 from: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20), partition p3 values less than (30))", 731 to: "create table t1 (id int primary key) partition by range (id) (partition p2 values less than (20), partition p3 values less than (30))", 732 rotation: RangeRotationDistinctStatements, 733 diff: "alter table t1 drop partition p1", 734 cdiff: "ALTER TABLE `t1` DROP PARTITION `p1`", 735 }, 736 { 737 name: "change partitioning range: statements, add", 738 from: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20))", 739 to: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20), partition p3 values less than (30))", 740 rotation: RangeRotationDistinctStatements, 741 diff: "alter table t1 add partition (partition p3 values less than (30))", 742 cdiff: "ALTER TABLE `t1` ADD PARTITION (PARTITION `p3` VALUES LESS THAN (30))", 743 }, 744 { 745 name: "change partitioning range: statements, multiple drops", 746 from: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20), partition p3 values less than (30))", 747 to: "create table t1 (id int primary key) partition by range (id) (partition p3 values less than (30))", 748 rotation: RangeRotationDistinctStatements, 749 diffs: []string{"alter table t1 drop partition p1", "alter table t1 drop partition p2"}, 750 cdiffs: []string{"ALTER TABLE `t1` DROP PARTITION `p1`", "ALTER TABLE `t1` DROP PARTITION `p2`"}, 751 }, 752 { 753 name: "change partitioning range: statements, multiple adds", 754 from: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10))", 755 to: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20), partition p3 values less than (30))", 756 rotation: RangeRotationDistinctStatements, 757 diffs: []string{"alter table t1 add partition (partition p2 values less than (20))", "alter table t1 add partition (partition p3 values less than (30))"}, 758 cdiffs: []string{"ALTER TABLE `t1` ADD PARTITION (PARTITION `p2` VALUES LESS THAN (20))", "ALTER TABLE `t1` ADD PARTITION (PARTITION `p3` VALUES LESS THAN (30))"}, 759 }, 760 { 761 name: "change partitioning range: statements, multiple, assorted", 762 from: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20), partition p3 values less than (30))", 763 to: "create table t1 (id int primary key) partition by range (id) (partition p2 values less than (20), partition p3 values less than (30), partition p4 values less than (40))", 764 rotation: RangeRotationDistinctStatements, 765 diffs: []string{"alter table t1 drop partition p1", "alter table t1 add partition (partition p4 values less than (40))"}, 766 cdiffs: []string{"ALTER TABLE `t1` DROP PARTITION `p1`", "ALTER TABLE `t1` ADD PARTITION (PARTITION `p4` VALUES LESS THAN (40))"}, 767 }, 768 { 769 name: "change partitioning range: mixed with nonpartition changes", 770 from: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20), partition p3 values less than (30))", 771 to: "create table t1 (id int primary key, i int) partition by range (id) (partition p3 values less than (30))", 772 rotation: RangeRotationDistinctStatements, 773 diffs: []string{"alter table t1 add column i int", "alter table t1 drop partition p1", "alter table t1 drop partition p2"}, 774 cdiffs: []string{"ALTER TABLE `t1` ADD COLUMN `i` int", "ALTER TABLE `t1` DROP PARTITION `p1`", "ALTER TABLE `t1` DROP PARTITION `p2`"}, 775 }, 776 { 777 name: "change partitioning range: single partition change, mixed with nonpartition changes", 778 from: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20))", 779 to: "create table t1 (id int primary key, i int) partition by range (id) (partition p2 values less than (20))", 780 rotation: RangeRotationDistinctStatements, 781 diffs: []string{"alter table t1 add column i int", "alter table t1 drop partition p1"}, 782 cdiffs: []string{"ALTER TABLE `t1` ADD COLUMN `i` int", "ALTER TABLE `t1` DROP PARTITION `p1`"}, 783 }, 784 { 785 name: "change partitioning range: mixed with nonpartition changes, full spec", 786 from: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20), partition p3 values less than (30))", 787 to: "create table t1 (id int primary key, i int) partition by range (id) (partition p3 values less than (30))", 788 rotation: RangeRotationFullSpec, 789 diff: "alter table t1 add column i int \npartition by range (id)\n(partition p3 values less than (30))", 790 cdiff: "ALTER TABLE `t1` ADD COLUMN `i` int \nPARTITION BY RANGE (`id`)\n(PARTITION `p3` VALUES LESS THAN (30))", 791 }, 792 { 793 name: "change partitioning range: ignore rotate, not a rotation", 794 from: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20), partition p3 values less than (30))", 795 to: "create table t1 (id int primary key) partition by range (id) (partition p2 values less than (25), partition p3 values less than (30), partition p4 values less than (40))", 796 rotation: RangeRotationIgnore, 797 diff: "alter table t1 \npartition by range (id)\n(partition p2 values less than (25),\n partition p3 values less than (30),\n partition p4 values less than (40))", 798 cdiff: "ALTER TABLE `t1` \nPARTITION BY RANGE (`id`)\n(PARTITION `p2` VALUES LESS THAN (25),\n PARTITION `p3` VALUES LESS THAN (30),\n PARTITION `p4` VALUES LESS THAN (40))", 799 }, 800 { 801 name: "change partitioning range: ignore rotate, not a rotation 2", 802 from: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20), partition p3 values less than (30))", 803 to: "create table t1 (id int primary key) partition by range (id) (partition p2 values less than (20), partition p3 values less than (35), partition p4 values less than (40))", 804 rotation: RangeRotationIgnore, 805 diff: "alter table t1 \npartition by range (id)\n(partition p2 values less than (20),\n partition p3 values less than (35),\n partition p4 values less than (40))", 806 cdiff: "ALTER TABLE `t1` \nPARTITION BY RANGE (`id`)\n(PARTITION `p2` VALUES LESS THAN (20),\n PARTITION `p3` VALUES LESS THAN (35),\n PARTITION `p4` VALUES LESS THAN (40))", 807 }, 808 { 809 name: "change partitioning range: ignore rotate, not a rotation 3", 810 from: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20), partition p3 values less than (30))", 811 to: "create table t1 (id int primary key) partition by range (id) (partition p2 values less than (20), partition pX values less than (30), partition p4 values less than (40))", 812 rotation: RangeRotationIgnore, 813 diff: "alter table t1 \npartition by range (id)\n(partition p2 values less than (20),\n partition pX values less than (30),\n partition p4 values less than (40))", 814 cdiff: "ALTER TABLE `t1` \nPARTITION BY RANGE (`id`)\n(PARTITION `p2` VALUES LESS THAN (20),\n PARTITION `pX` VALUES LESS THAN (30),\n PARTITION `p4` VALUES LESS THAN (40))", 815 }, 816 { 817 name: "change partitioning range: ignore rotate, not a rotation 4", 818 from: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20), partition p3 values less than (30))", 819 to: "create table t1 (id int primary key) partition by range (id) (partition pX values less than (20), partition p3 values less than (30), partition p4 values less than (40))", 820 rotation: RangeRotationIgnore, 821 diff: "alter table t1 \npartition by range (id)\n(partition pX values less than (20),\n partition p3 values less than (30),\n partition p4 values less than (40))", 822 cdiff: "ALTER TABLE `t1` \nPARTITION BY RANGE (`id`)\n(PARTITION `pX` VALUES LESS THAN (20),\n PARTITION `p3` VALUES LESS THAN (30),\n PARTITION `p4` VALUES LESS THAN (40))", 823 }, 824 { 825 name: "change partitioning range: ignore rotate, nothing shared", 826 from: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20), partition p3 values less than (30))", 827 to: "create table t1 (id int primary key) partition by range (id) (partition p4 values less than (40), partition p5 values less than (50), partition p6 values less than (60))", 828 rotation: RangeRotationIgnore, 829 diff: "alter table t1 \npartition by range (id)\n(partition p4 values less than (40),\n partition p5 values less than (50),\n partition p6 values less than (60))", 830 cdiff: "ALTER TABLE `t1` \nPARTITION BY RANGE (`id`)\n(PARTITION `p4` VALUES LESS THAN (40),\n PARTITION `p5` VALUES LESS THAN (50),\n PARTITION `p6` VALUES LESS THAN (60))", 831 }, 832 { 833 name: "change partitioning range: ignore rotate, no names shared, definitions shared", 834 from: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20), partition p3 values less than (30))", 835 to: "create table t1 (id int primary key) partition by range (id) (partition pA values less than (20), partition pB values less than (30), partition pC values less than (40))", 836 rotation: RangeRotationIgnore, 837 diff: "alter table t1 \npartition by range (id)\n(partition pA values less than (20),\n partition pB values less than (30),\n partition pC values less than (40))", 838 cdiff: "ALTER TABLE `t1` \nPARTITION BY RANGE (`id`)\n(PARTITION `pA` VALUES LESS THAN (20),\n PARTITION `pB` VALUES LESS THAN (30),\n PARTITION `pC` VALUES LESS THAN (40))", 839 }, 840 841 // 842 // table options 843 { 844 name: "same options, no diff 1", 845 from: "create table t1 (id int primary key) row_format=compressed", 846 to: "create table t1 (id int primary key) row_format=compressed", 847 }, 848 { 849 name: "same options, no diff 2", 850 from: "create table t1 (id int primary key) row_format=compressed, character set=utf8", 851 to: "create table t1 (id int primary key) row_format=compressed, character set=utf8", 852 }, 853 { 854 name: "same options, no diff 3", 855 from: "create table t1 (id int primary key) row_format=compressed, character set=utf8", 856 to: "create table t1 (id int primary key) row_format=compressed, charset=utf8", 857 }, 858 { 859 name: "reordered options, no diff", 860 from: "create table t1 (id int primary key) row_format=compressed character set=utf8", 861 to: "create table t1 (id int primary key) character set=utf8, row_format=compressed", 862 }, 863 { 864 name: "add table option 1", 865 from: "create table t1 (id int primary key)", 866 to: "create table t1 (id int primary key) row_format=compressed", 867 diff: "alter table t1 row_format COMPRESSED", 868 cdiff: "ALTER TABLE `t1` ROW_FORMAT COMPRESSED", 869 }, 870 { 871 name: "add table option 2", 872 from: "create table t1 (id int primary key) character set=utf8", 873 to: "create table t1 (id int primary key) character set=utf8, row_format=compressed", 874 diff: "alter table t1 row_format COMPRESSED", 875 cdiff: "ALTER TABLE `t1` ROW_FORMAT COMPRESSED", 876 }, 877 { 878 name: "add table option 3", 879 from: "create table t1 (id int primary key) character set=utf8", 880 to: "create table t1 (id int primary key) row_format=compressed, character set=utf8", 881 diff: "alter table t1 row_format COMPRESSED", 882 cdiff: "ALTER TABLE `t1` ROW_FORMAT COMPRESSED", 883 }, 884 { 885 name: "add table option 3", 886 from: "create table t1 (id int primary key) character set=utf8", 887 to: "create table t1 (id int primary key) row_format=compressed, character set=utf8, checksum=1", 888 diff: "alter table t1 row_format COMPRESSED checksum 1", 889 cdiff: "ALTER TABLE `t1` ROW_FORMAT COMPRESSED CHECKSUM 1", 890 }, 891 { 892 name: "modify table option 1", 893 from: "create table t1 (id int primary key) character set=utf8", 894 to: "create table t1 (id int primary key) character set=utf8mb4", 895 diff: "alter table t1 charset utf8mb4", 896 cdiff: "ALTER TABLE `t1` CHARSET utf8mb4", 897 }, 898 { 899 name: "modify table option 2", 900 from: "create table t1 (id int primary key) charset=utf8", 901 to: "create table t1 (id int primary key) character set=utf8mb4", 902 diff: "alter table t1 charset utf8mb4", 903 cdiff: "ALTER TABLE `t1` CHARSET utf8mb4", 904 }, 905 { 906 name: "modify table option 3", 907 from: "create table t1 (id int primary key) character set=utf8", 908 to: "create table t1 (id int primary key) charset=utf8mb4", 909 diff: "alter table t1 charset utf8mb4", 910 cdiff: "ALTER TABLE `t1` CHARSET utf8mb4", 911 }, 912 { 913 name: "modify table option 4", 914 from: "create table t1 (id int primary key) character set=utf8", 915 to: "create table t1 (id int primary key) row_format=compressed, character set=utf8mb4, checksum=1", 916 diff: "alter table t1 charset utf8mb4 row_format COMPRESSED checksum 1", 917 cdiff: "ALTER TABLE `t1` CHARSET utf8mb4 ROW_FORMAT COMPRESSED CHECKSUM 1", 918 }, 919 { 920 name: "remove table option 1", 921 from: "create table t1 (id int primary key) row_format=compressed", 922 to: "create table t1 (id int primary key) ", 923 diff: "alter table t1 row_format DEFAULT", 924 cdiff: "ALTER TABLE `t1` ROW_FORMAT DEFAULT", 925 }, 926 { 927 name: "remove table option 2", 928 from: "create table t1 (id int primary key) CHECKSUM=1", 929 to: "create table t1 (id int primary key) ", 930 diff: "alter table t1 checksum 0", 931 cdiff: "ALTER TABLE `t1` CHECKSUM 0", 932 }, 933 { 934 name: "remove table option 3", 935 from: "create table t1 (id int primary key) checksum=1", 936 to: "create table t1 (id int primary key) ", 937 diff: "alter table t1 checksum 0", 938 cdiff: "ALTER TABLE `t1` CHECKSUM 0", 939 }, 940 { 941 name: "remove table option 4", 942 from: "create table t1 (id int auto_increment primary key) KEY_BLOCK_SIZE=16 COMPRESSION='zlib'", 943 to: "create table t2 (id int auto_increment primary key)", 944 diff: "alter table t1 key_block_size 0 compression ''", 945 cdiff: "ALTER TABLE `t1` KEY_BLOCK_SIZE 0 COMPRESSION ''", 946 }, 947 { 948 name: "add, modify and remove table option", 949 from: "create table t1 (id int primary key) engine=innodb, charset=utf8, checksum=1", 950 to: "create table t1 (id int primary key) row_format=compressed, engine=innodb, charset=utf8mb4", 951 diff: "alter table t1 checksum 0 charset utf8mb4 row_format COMPRESSED", 952 cdiff: "ALTER TABLE `t1` CHECKSUM 0 CHARSET utf8mb4 ROW_FORMAT COMPRESSED", 953 }, 954 { 955 name: "ignore AUTO_INCREMENT addition", 956 from: "create table t1 (id int auto_increment primary key)", 957 to: "create table t2 (id int auto_increment primary key) AUTO_INCREMENT=300", 958 }, 959 { 960 name: "apply AUTO_INCREMENT addition", 961 from: "create table t1 (id int auto_increment primary key)", 962 to: "create table t2 (id int auto_increment primary key) AUTO_INCREMENT=300", 963 autoinc: AutoIncrementApplyHigher, 964 diff: "alter table t1 auto_increment 300", 965 cdiff: "ALTER TABLE `t1` AUTO_INCREMENT 300", 966 }, 967 { 968 name: "ignore AUTO_INCREMENT removal", 969 from: "create table t1 (id int auto_increment primary key) AUTO_INCREMENT=300", 970 to: "create table t2 (id int auto_increment primary key)", 971 }, 972 { 973 name: "ignore AUTO_INCREMENT removal 2", 974 from: "create table t1 (id int auto_increment primary key) AUTO_INCREMENT=300", 975 to: "create table t2 (id int auto_increment primary key)", 976 autoinc: AutoIncrementApplyHigher, 977 }, 978 { 979 name: "ignore AUTO_INCREMENT change", 980 from: "create table t1 (id int auto_increment primary key) AUTO_INCREMENT=100", 981 to: "create table t2 (id int auto_increment primary key) AUTO_INCREMENT=300", 982 }, 983 { 984 name: "apply AUTO_INCREMENT change", 985 from: "create table t1 (id int auto_increment primary key) AUTO_INCREMENT=100", 986 to: "create table t2 (id int auto_increment primary key) AUTO_INCREMENT=300", 987 autoinc: AutoIncrementApplyHigher, 988 diff: "alter table t1 auto_increment 300", 989 cdiff: "ALTER TABLE `t1` AUTO_INCREMENT 300", 990 }, 991 { 992 name: "ignore AUTO_INCREMENT decrease", 993 from: "create table t1 (id int auto_increment primary key) AUTO_INCREMENT=300", 994 to: "create table t2 (id int auto_increment primary key) AUTO_INCREMENT=100", 995 autoinc: AutoIncrementApplyHigher, 996 }, 997 { 998 name: "apply AUTO_INCREMENT decrease", 999 from: "create table t1 (id int auto_increment primary key) AUTO_INCREMENT=300", 1000 to: "create table t2 (id int auto_increment primary key) AUTO_INCREMENT=100", 1001 autoinc: AutoIncrementApplyAlways, 1002 diff: "alter table t1 auto_increment 100", 1003 cdiff: "ALTER TABLE `t1` AUTO_INCREMENT 100", 1004 }, 1005 { 1006 name: "apply table charset", 1007 from: "create table t (id int, primary key(id))", 1008 to: "create table t (id int, primary key(id)) DEFAULT CHARSET = utf8mb4", 1009 diff: "alter table t charset utf8mb4", 1010 cdiff: "ALTER TABLE `t` CHARSET utf8mb4", 1011 }, 1012 { 1013 name: "ignore empty table charset", 1014 from: "create table t (id int, primary key(id))", 1015 to: "create table t (id int, primary key(id)) DEFAULT CHARSET = utf8mb4", 1016 charset: TableCharsetCollateIgnoreEmpty, 1017 }, 1018 { 1019 name: "ignore empty table charset and collate", 1020 from: "create table t (id int, primary key(id))", 1021 to: "create table t (id int, primary key(id)) DEFAULT CHARSET = utf8mb4 COLLATE utf8mb4_0900_ai_ci", 1022 charset: TableCharsetCollateIgnoreEmpty, 1023 }, 1024 { 1025 name: "ignore empty table collate", 1026 from: "create table t (id int, primary key(id))", 1027 to: "create table t (id int, primary key(id)) COLLATE utf8mb4_0900_ai_ci", 1028 charset: TableCharsetCollateIgnoreEmpty, 1029 }, 1030 { 1031 name: "ignore empty table charset and collate in target", 1032 from: "create table t (id int, primary key(id)) DEFAULT CHARSET = utf8mb4 COLLATE utf8mb4_0900_ai_ci", 1033 to: "create table t (id int, primary key(id))", 1034 charset: TableCharsetCollateIgnoreEmpty, 1035 }, 1036 { 1037 name: "ignore dropped collate", 1038 from: "create table t (id int, primary key(id)) COLLATE utf8mb4_0900_ai_ci", 1039 to: "create table t (id int, primary key(id))", 1040 charset: TableCharsetCollateIgnoreEmpty, 1041 }, 1042 { 1043 name: "ignore table charset", 1044 from: "create table t (id int, primary key(id)) DEFAULT CHARSET = utf8", 1045 to: "create table t (id int, primary key(id)) DEFAULT CHARSET = utf8mb4", 1046 charset: TableCharsetCollateIgnoreAlways, 1047 }, 1048 { 1049 name: "change table charset", 1050 from: "create table t (id int, primary key(id)) DEFAULT CHARSET = utf8", 1051 to: "create table t (id int, primary key(id)) DEFAULT CHARSET = utf8mb4", 1052 diff: "alter table t charset utf8mb4", 1053 cdiff: "ALTER TABLE `t` CHARSET utf8mb4", 1054 }, 1055 { 1056 name: `change table charset and columns`, 1057 from: "create table t (id int primary key, t1 varchar(128) default null, t2 varchar(128) not null, t3 tinytext charset latin1, t4 tinytext charset latin1) default charset=utf8", 1058 to: "create table t (id int primary key, t1 varchar(128) not null, t2 varchar(128) not null, t3 tinytext, t4 tinytext charset latin1) default charset=utf8mb4", 1059 diff: "alter table t modify column t1 varchar(128) not null, modify column t2 varchar(128) not null, modify column t3 tinytext, charset utf8mb4", 1060 cdiff: "ALTER TABLE `t` MODIFY COLUMN `t1` varchar(128) NOT NULL, MODIFY COLUMN `t2` varchar(128) NOT NULL, MODIFY COLUMN `t3` tinytext, CHARSET utf8mb4", 1061 }, 1062 { 1063 name: "normalized unsigned attribute", 1064 from: "create table t1 (id int primary key)", 1065 to: "create table t1 (id int unsigned primary key)", 1066 diff: "alter table t1 modify column id int unsigned", 1067 cdiff: "ALTER TABLE `t1` MODIFY COLUMN `id` int unsigned", 1068 }, 1069 { 1070 name: "normalized ENGINE InnoDB value", 1071 from: "create table t1 (id int primary key) character set=utf8", 1072 to: "create table t1 (id int primary key) engine=innodb, character set=utf8", 1073 diff: "alter table t1 engine InnoDB", 1074 cdiff: "ALTER TABLE `t1` ENGINE InnoDB", 1075 }, 1076 { 1077 name: "normalized ENGINE MyISAM value", 1078 from: "create table t1 (id int primary key) character set=utf8", 1079 to: "create table t1 (id int primary key) engine=myisam, character set=utf8", 1080 diff: "alter table t1 engine MyISAM", 1081 cdiff: "ALTER TABLE `t1` ENGINE MyISAM", 1082 }, 1083 { 1084 name: "normalized ENGINE MEMORY value", 1085 from: "create table t1 (id int primary key) character set=utf8", 1086 to: "create table t1 (id int primary key) engine=memory, character set=utf8", 1087 diff: "alter table t1 engine MEMORY", 1088 cdiff: "ALTER TABLE `t1` ENGINE MEMORY", 1089 }, 1090 { 1091 name: "normalized CHARSET value", 1092 from: "create table t1 (id int primary key) engine=innodb", 1093 to: "create table t1 (id int primary key) engine=innodb, character set=UTF8MB4", 1094 diff: "alter table t1 charset utf8mb4", 1095 cdiff: "ALTER TABLE `t1` CHARSET utf8mb4", 1096 }, 1097 { 1098 name: "normalized CHARSET utf8 value", 1099 from: "create table t1 (id int primary key) engine=innodb", 1100 to: "create table t1 (id int primary key) engine=innodb, character set=UTF8", 1101 diff: "alter table t1 charset utf8mb3", 1102 cdiff: "ALTER TABLE `t1` CHARSET utf8mb3", 1103 }, 1104 { 1105 name: "normalized COLLATE value", 1106 from: "create table t1 (id int primary key) engine=innodb", 1107 to: "create table t1 (id int primary key) engine=innodb, collate=UTF8_BIN", 1108 diff: "alter table t1 collate utf8mb3_bin", 1109 cdiff: "ALTER TABLE `t1` COLLATE utf8mb3_bin", 1110 }, 1111 { 1112 name: "remove table comment", 1113 from: "create table t1 (id int primary key) comment='foo'", 1114 to: "create table t1 (id int primary key)", 1115 diff: "alter table t1 comment ''", 1116 cdiff: "ALTER TABLE `t1` COMMENT ''", 1117 }, 1118 // algorithm 1119 { 1120 name: "algorithm: COPY", 1121 from: "create table t1 (`id` int primary key)", 1122 to: "create table t2 (id int primary key, `i` int not null default 0)", 1123 diff: "alter table t1 add column i int not null default 0, algorithm = COPY", 1124 cdiff: "ALTER TABLE `t1` ADD COLUMN `i` int NOT NULL DEFAULT 0, ALGORITHM = COPY", 1125 algorithm: AlterTableAlgorithmStrategyCopy, 1126 }, 1127 { 1128 name: "algorithm: INPLACE", 1129 from: "create table t1 (`id` int primary key)", 1130 to: "create table t2 (id int primary key, `i` int not null default 0)", 1131 diff: "alter table t1 add column i int not null default 0, algorithm = INPLACE", 1132 cdiff: "ALTER TABLE `t1` ADD COLUMN `i` int NOT NULL DEFAULT 0, ALGORITHM = INPLACE", 1133 algorithm: AlterTableAlgorithmStrategyInplace, 1134 }, 1135 { 1136 name: "algorithm: INSTANT", 1137 from: "create table t1 (`id` int primary key)", 1138 to: "create table t2 (id int primary key, `i` int not null default 0)", 1139 diff: "alter table t1 add column i int not null default 0, algorithm = INSTANT", 1140 cdiff: "ALTER TABLE `t1` ADD COLUMN `i` int NOT NULL DEFAULT 0, ALGORITHM = INSTANT", 1141 algorithm: AlterTableAlgorithmStrategyInstant, 1142 }, 1143 } 1144 standardHints := DiffHints{} 1145 for _, ts := range tt { 1146 t.Run(ts.name, func(t *testing.T) { 1147 fromStmt, err := sqlparser.ParseStrictDDL(ts.from) 1148 require.NoError(t, err) 1149 fromCreateTable, ok := fromStmt.(*sqlparser.CreateTable) 1150 require.True(t, ok) 1151 1152 toStmt, err := sqlparser.ParseStrictDDL(ts.to) 1153 require.NoError(t, err) 1154 toCreateTable, ok := toStmt.(*sqlparser.CreateTable) 1155 require.True(t, ok) 1156 1157 c, err := NewCreateTableEntity(fromCreateTable) 1158 require.NoError(t, err) 1159 other, err := NewCreateTableEntity(toCreateTable) 1160 require.NoError(t, err) 1161 1162 hints := standardHints 1163 hints.AutoIncrementStrategy = ts.autoinc 1164 hints.RangeRotationStrategy = ts.rotation 1165 hints.ConstraintNamesStrategy = ts.constraint 1166 hints.ColumnRenameStrategy = ts.colrename 1167 hints.FullTextKeyStrategy = ts.fulltext 1168 hints.TableCharsetCollateStrategy = ts.charset 1169 hints.AlterTableAlgorithmStrategy = ts.algorithm 1170 alter, err := c.Diff(other, &hints) 1171 1172 require.Equal(t, len(ts.diffs), len(ts.cdiffs)) 1173 if ts.diff == "" && len(ts.diffs) > 0 { 1174 ts.diff = ts.diffs[0] 1175 ts.cdiff = ts.cdiffs[0] 1176 } 1177 switch { 1178 case ts.isError: 1179 require.Error(t, err) 1180 if ts.errorMsg != "" { 1181 assert.Contains(t, err.Error(), ts.errorMsg) 1182 } 1183 case ts.diff == "": 1184 assert.NoError(t, err) 1185 assert.True(t, alter.IsEmpty(), "expected empty diff, found changes") 1186 if !alter.IsEmpty() { 1187 t.Logf("statements[0]: %v", alter.StatementString()) 1188 t.Logf("c: %v", sqlparser.CanonicalString(c.CreateTable)) 1189 t.Logf("other: %v", sqlparser.CanonicalString(other.CreateTable)) 1190 } 1191 default: 1192 assert.NoError(t, err) 1193 require.NotNil(t, alter) 1194 assert.False(t, alter.IsEmpty(), "expected changes, found empty diff") 1195 1196 { 1197 diff := alter.StatementString() 1198 assert.Equal(t, ts.diff, diff) 1199 1200 if len(ts.diffs) > 0 { 1201 1202 allSubsequentDiffs := AllSubsequent(alter) 1203 require.Equal(t, len(ts.diffs), len(allSubsequentDiffs)) 1204 require.Equal(t, len(ts.cdiffs), len(allSubsequentDiffs)) 1205 for i := range ts.diffs { 1206 assert.Equal(t, ts.diffs[i], allSubsequentDiffs[i].StatementString()) 1207 assert.Equal(t, ts.cdiffs[i], allSubsequentDiffs[i].CanonicalStatementString()) 1208 } 1209 } 1210 // validate we can parse back the statement 1211 _, err := sqlparser.ParseStrictDDL(diff) 1212 assert.NoError(t, err) 1213 1214 // Validate "from/to" entities 1215 eFrom, eTo := alter.Entities() 1216 if ts.fromName != "" { 1217 assert.Equal(t, ts.fromName, eFrom.Name()) 1218 } 1219 if ts.toName != "" { 1220 assert.Equal(t, ts.toName, eTo.Name()) 1221 } 1222 1223 { // Validate "apply()" on "from" converges with "to" 1224 applied, err := c.Apply(alter) 1225 assert.NoError(t, err) 1226 require.NotNil(t, applied) 1227 appliedDiff, err := eTo.Diff(applied, &hints) 1228 require.NoError(t, err) 1229 assert.True(t, appliedDiff.IsEmpty(), "expected empty diff, found changes: %v.\nc=%v\n,alter=%v\n,eTo=%v\napplied=%v\n", 1230 appliedDiff.CanonicalStatementString(), 1231 c.Create().CanonicalStatementString(), 1232 alter.CanonicalStatementString(), 1233 eTo.Create().CanonicalStatementString(), 1234 applied.Create().CanonicalStatementString(), 1235 ) 1236 } 1237 } 1238 { 1239 cdiff := alter.CanonicalStatementString() 1240 assert.Equal(t, ts.cdiff, cdiff) 1241 _, err := sqlparser.ParseStrictDDL(cdiff) 1242 assert.NoError(t, err) 1243 } 1244 1245 } 1246 }) 1247 } 1248 } 1249 1250 func TestValidate(t *testing.T) { 1251 tt := []struct { 1252 name string 1253 from string 1254 to string 1255 alter string 1256 expectErr error 1257 }{ 1258 // columns 1259 { 1260 name: "add column", 1261 from: "create table t (id int primary key)", 1262 alter: "alter table t add column i int", 1263 to: "create table t (id int primary key, i int)", 1264 }, 1265 { 1266 name: "duplicate existing column", 1267 from: "create table t (id int primary key, id varchar(10))", 1268 alter: "alter table t add column i int", 1269 expectErr: &ApplyDuplicateColumnError{Table: "t", Column: "id"}, 1270 }, 1271 // keys 1272 { 1273 name: "add key", 1274 from: "create table t (id int primary key, i int)", 1275 alter: "alter table t add key i_idx(i)", 1276 to: "create table t (id int primary key, i int, key i_idx(i))", 1277 }, 1278 { 1279 name: "invalid table definition: primary key, same columns", 1280 from: "create table t (id int primary key, i int, primary key (id))", 1281 alter: "alter table t engine=innodb", 1282 expectErr: &DuplicateKeyNameError{Table: "t", Key: "PRIMARY"}, 1283 }, 1284 { 1285 name: "invalid table definition: primary key, different column", 1286 from: "create table t (id int primary key, i int, primary key (i))", 1287 alter: "alter table t engine=innodb", 1288 expectErr: &DuplicateKeyNameError{Table: "t", Key: "PRIMARY"}, 1289 }, 1290 { 1291 name: "add primary key", 1292 from: "create table t (id int, i int)", 1293 alter: "alter table t add primary key(id)", 1294 to: "create table t (id int, i int, primary key (id))", 1295 }, 1296 { 1297 name: "add primary key with existing key", 1298 from: "create table t (id int, i int, key i_idx (i))", 1299 alter: "alter table t add primary key(id)", 1300 to: "create table t (id int, i int, primary key (id), key i_idx (i))", 1301 }, 1302 { 1303 name: "modify into primary key", 1304 from: "create table t (id int, i int)", 1305 alter: "alter table t modify id int primary key", 1306 to: "create table t (id int, i int, primary key (id))", 1307 }, 1308 { 1309 name: "modify a primary key column", 1310 from: "create table t (id int primary key, i int)", 1311 alter: "alter table t modify id bigint primary key", 1312 to: "create table t (id bigint, i int, primary key (id))", 1313 }, 1314 { 1315 name: "modify a primary key column 2", 1316 from: "create table t (id int, i int, primary key (id))", 1317 alter: "alter table t modify id bigint primary key", 1318 to: "create table t (id bigint, i int, primary key (id))", 1319 }, 1320 { 1321 name: "fail modify another column to primary key", 1322 from: "create table t (id int primary key, i int)", 1323 alter: "alter table t modify i int primary key", 1324 expectErr: &DuplicateKeyNameError{Table: "t", Key: "PRIMARY"}, 1325 }, 1326 { 1327 name: "fail add another primary key column", 1328 from: "create table t (id int primary key, i int)", 1329 alter: "alter table t add column i2 int primary key", 1330 expectErr: &DuplicateKeyNameError{Table: "t", Key: "PRIMARY"}, 1331 }, 1332 { 1333 name: "fail add another primary key", 1334 from: "create table t (id int primary key, i int)", 1335 alter: "alter table t add primary key (i)", 1336 expectErr: &DuplicateKeyNameError{Table: "t", Key: "PRIMARY"}, 1337 }, 1338 { 1339 name: "add key, column case", 1340 from: "create table t (id int primary key, i int)", 1341 alter: "alter table t add key i_idx(I)", 1342 to: "create table t (id int primary key, i int, key i_idx(I))", 1343 }, 1344 { 1345 name: "add column and key", 1346 from: "create table t (id int primary key)", 1347 alter: "alter table t add column i int, add key i_idx(i)", 1348 to: "create table t (id int primary key, i int, key i_idx(i))", 1349 }, 1350 { 1351 name: "add key, missing column", 1352 from: "create table t (id int primary key, i int)", 1353 alter: "alter table t add key j_idx(j)", 1354 expectErr: &InvalidColumnInKeyError{Table: "t", Column: "j", Key: "j_idx"}, 1355 }, 1356 { 1357 name: "add key, missing column 2", 1358 from: "create table t (id int primary key, i int)", 1359 alter: "alter table t add key j_idx(j, i)", 1360 expectErr: &InvalidColumnInKeyError{Table: "t", Column: "j", Key: "j_idx"}, 1361 }, 1362 { 1363 name: "drop column, ok", 1364 from: "create table t (id int primary key, i int, i2 int, key i_idx(i))", 1365 alter: "alter table t drop column i2", 1366 to: "create table t (id int primary key, i int, key i_idx(i))", 1367 }, 1368 { 1369 name: "drop and add same column, ok", 1370 from: "create table t (id int primary key, i int, i2 int, key i_idx(i))", 1371 alter: "alter table t drop column i2, add column i2 bigint not null", 1372 to: "create table t (id int primary key, i int, i2 bigint not null, key i_idx(i))", 1373 }, 1374 { 1375 name: "drop column, affect keys", 1376 from: "create table t (id int primary key, i int, key i_idx(i))", 1377 alter: "alter table t drop column i", 1378 to: "create table t (id int primary key)", 1379 }, 1380 { 1381 name: "drop column, affect keys 2", 1382 from: "create table t (id int primary key, i int, i2 int, key i_idx(i, i2))", 1383 alter: "alter table t drop column i", 1384 to: "create table t (id int primary key, i2 int, key i_idx(i2))", 1385 }, 1386 { 1387 name: "drop column, affect keys 3", 1388 from: "create table t (id int primary key, i int, i2 int, key i_idx(i, i2))", 1389 alter: "alter table t drop column i2", 1390 to: "create table t (id int primary key, i int, key i_idx(i))", 1391 }, 1392 { 1393 name: "drop column, affect keys 4", 1394 from: "create table t (id int primary key, i int, i2 int, key some_key(id, i), key i_idx(i, i2))", 1395 alter: "alter table t drop column i2", 1396 to: "create table t (id int primary key, i int, key some_key(id, i), key i_idx(i))", 1397 }, 1398 { 1399 name: "drop column, affect keys 4, column case", 1400 from: "create table t (id int primary key, i int, i2 int, key some_key(id, i), key i_idx(i, I2))", 1401 alter: "alter table t drop column i2", 1402 to: "create table t (id int primary key, i int, key some_key(id, i), key i_idx(i))", 1403 }, 1404 { 1405 name: "drop column, affect keys with expression", 1406 from: "create table t (id int primary key, i int, key id_idx((IF(id, 0, 1))), key i_idx((IF(i,0,1))))", 1407 alter: "alter table t drop column i", 1408 expectErr: &InvalidColumnInKeyError{Table: "t", Column: "i", Key: "i_idx"}, 1409 }, 1410 { 1411 name: "drop column, affect keys with expression and multi expressions", 1412 from: "create table t (id int primary key, i int, key id_idx((IF(id, 0, 1))), key i_idx((IF(i,0,1)), (IF(id,2,3))))", 1413 alter: "alter table t drop column i", 1414 expectErr: &InvalidColumnInKeyError{Table: "t", Column: "i", Key: "i_idx"}, 1415 }, 1416 { 1417 name: "add multiple keys, multi columns, ok", 1418 from: "create table t (id int primary key, i1 int, i2 int, i3 int)", 1419 alter: "alter table t add key i12_idx(i1, i2), add key i32_idx(i3, i2), add key i21_idx(i2, i1)", 1420 to: "create table t (id int primary key, i1 int, i2 int, i3 int, key i12_idx(i1, i2), key i32_idx(i3, i2), key i21_idx(i2, i1))", 1421 }, 1422 { 1423 name: "add multiple keys, multi columns, missing column", 1424 from: "create table t (id int primary key, i1 int, i2 int, i4 int)", 1425 alter: "alter table t add key i12_idx(i1, i2), add key i32_idx(i3, i2), add key i21_idx(i2, i1)", 1426 expectErr: &InvalidColumnInKeyError{Table: "t", Column: "i3", Key: "i32_idx"}, 1427 }, 1428 { 1429 name: "multiple primary keys", 1430 from: "create table t (id int primary key, i1 int, i2 int, primary key (i1))", 1431 alter: "alter table t engine=innodb", 1432 expectErr: &DuplicateKeyNameError{Table: "t", Key: "PRIMARY"}, 1433 }, 1434 { 1435 name: "multiple primary keys for same column", 1436 from: "create table t (id int primary key, i1 int, i2 int, primary key (id))", 1437 alter: "alter table t engine=innodb", 1438 expectErr: &DuplicateKeyNameError{Table: "t", Key: "PRIMARY"}, 1439 }, 1440 // partitions 1441 { 1442 name: "drop column used by partitions", 1443 from: "create table t (id int, i int, primary key (id, i), unique key i_idx(i)) partition by hash (i) partitions 4", 1444 alter: "alter table t drop column i", 1445 expectErr: &InvalidColumnInPartitionError{Table: "t", Column: "i"}, 1446 }, 1447 { 1448 name: "drop column used by partitions, column case", 1449 from: "create table t (id int, i int, primary key (id, i), unique key i_idx(i)) partition by hash (I) partitions 4", 1450 alter: "alter table t drop column i", 1451 expectErr: &InvalidColumnInPartitionError{Table: "t", Column: "I"}, 1452 }, 1453 { 1454 name: "drop column used by partitions, function", 1455 from: "create table t (id int, i int, primary key (id, i), unique key i_idx(i)) partition by hash (abs(i)) partitions 4", 1456 alter: "alter table t drop column i", 1457 expectErr: &InvalidColumnInPartitionError{Table: "t", Column: "i"}, 1458 }, 1459 { 1460 name: "unique key covers all partitioned columns", 1461 from: "create table t (id int, i int, primary key (id, i)) partition by hash (i) partitions 4", 1462 alter: "alter table t add unique key i_idx(i)", 1463 to: "create table t (id int, i int, primary key (id, i), unique key i_idx(i)) partition by hash (i) partitions 4", 1464 }, 1465 { 1466 name: "unique key does not cover all partitioned columns", 1467 from: "create table t (id int, i int, primary key (id, i)) partition by hash (i) partitions 4", 1468 alter: "alter table t add unique key id_idx(id)", 1469 expectErr: &MissingPartitionColumnInUniqueKeyError{Table: "t", Column: "i", UniqueKey: "id_idx"}, 1470 }, 1471 { 1472 name: "add multiple keys, multi columns, missing column", 1473 from: "create table t (id int primary key, i1 int, i2 int, i4 int)", 1474 alter: "alter table t add key i12_idx(i1, i2), add key i32_idx((IF(i3 IS NULL, i2, i3)), i2), add key i21_idx(i2, i1)", 1475 expectErr: &InvalidColumnInKeyError{Table: "t", Column: "i3", Key: "i32_idx"}, 1476 }, 1477 // data types 1478 { 1479 name: "nullable timestamp", 1480 from: "create table t (id int primary key, t datetime)", 1481 alter: "alter table t modify column t timestamp null", 1482 to: "create table t (id int primary key, t timestamp null)", 1483 }, 1484 { 1485 name: "add range partition", 1486 from: "create table t (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20))", 1487 alter: "alter table t add partition (partition p3 values less than (30))", 1488 to: "create table t (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20), partition p3 values less than (30))", 1489 }, 1490 { 1491 name: "add range partition, duplicate", 1492 from: "create table t (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20))", 1493 alter: "alter table t add partition (partition p2 values less than (30))", 1494 expectErr: &ApplyDuplicatePartitionError{Table: "t", Partition: "p2"}, 1495 }, 1496 { 1497 name: "add range partition, duplicate", 1498 from: "create table t (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20))", 1499 alter: "alter table t add partition (partition P2 values less than (30))", 1500 expectErr: &ApplyDuplicatePartitionError{Table: "t", Partition: "P2"}, 1501 }, 1502 { 1503 name: "add range partition, no partitioning", 1504 from: "create table t (id int primary key)", 1505 alter: "alter table t add partition (partition p2 values less than (30))", 1506 expectErr: &ApplyNoPartitionsError{Table: "t"}, 1507 }, 1508 { 1509 name: "drop range partition", 1510 from: "create table t (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20))", 1511 alter: "alter table t drop partition p1", 1512 to: "create table t (id int primary key) partition by range (id) (partition p2 values less than (20))", 1513 }, 1514 { 1515 name: "drop range partition, not found", 1516 from: "create table t (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20))", 1517 alter: "alter table t drop partition p7", 1518 expectErr: &ApplyPartitionNotFoundError{Table: "t", Partition: "p7"}, 1519 }, 1520 { 1521 name: "duplicate existing partition name", 1522 from: "create table t1 (id int primary key) partition by range (id) (partition p1 values less than (10), partition p2 values less than (20), partition p2 values less than (30))", 1523 alter: "alter table t add column i int", 1524 expectErr: &ApplyDuplicatePartitionError{Table: "t1", Partition: "p2"}, 1525 }, 1526 { 1527 name: "change to visible with alter column", 1528 from: "create table t (id int, i int invisible, primary key (id))", 1529 alter: "alter table t alter column i set visible", 1530 to: "create table t (id int, i int, primary key (id))", 1531 }, 1532 { 1533 name: "change to invisible with alter column", 1534 from: "create table t (id int, i int, primary key (id))", 1535 alter: "alter table t alter column i set invisible", 1536 to: "create table t (id int, i int invisible, primary key (id))", 1537 }, 1538 { 1539 name: "remove default with alter column", 1540 from: "create table t (id int, i int default 0, primary key (id))", 1541 alter: "alter table t alter column i drop default", 1542 to: "create table t (id int, i int, primary key (id))", 1543 }, 1544 { 1545 name: "change default with alter column", 1546 from: "create table t (id int, i int, primary key (id))", 1547 alter: "alter table t alter column i set default 0", 1548 to: "create table t (id int, i int default 0, primary key (id))", 1549 }, 1550 { 1551 name: "change to visible with alter index", 1552 from: "create table t (id int primary key, i int, key i_idx(i) invisible)", 1553 alter: "alter table t alter index i_idx visible", 1554 to: "create table t (id int primary key, i int, key i_idx(i))", 1555 }, 1556 { 1557 name: "change to invisible with alter index", 1558 from: "create table t (id int primary key, i int, key i_idx(i))", 1559 alter: "alter table t alter index i_idx invisible", 1560 to: "create table t (id int primary key, i int, key i_idx(i) invisible)", 1561 }, 1562 { 1563 name: "drop column used by a generated column", 1564 from: "create table t (id int, i int, neg int as (0-i), primary key (id))", 1565 alter: "alter table t drop column i", 1566 expectErr: &InvalidColumnInGeneratedColumnError{Table: "t", Column: "i", GeneratedColumn: "neg"}, 1567 }, 1568 { 1569 name: "drop column used by a generated column, column case", 1570 from: "create table t (id int, i int, neg int as (0-I), primary key (id))", 1571 alter: "alter table t drop column I", 1572 expectErr: &InvalidColumnInGeneratedColumnError{Table: "t", Column: "I", GeneratedColumn: "neg"}, 1573 }, 1574 { 1575 name: "add generated column referencing nonexistent column", 1576 from: "create table t (id int, primary key (id))", 1577 alter: "alter table t add column neg int as (0-i)", 1578 expectErr: &InvalidColumnInGeneratedColumnError{Table: "t", Column: "i", GeneratedColumn: "neg"}, 1579 }, 1580 { 1581 name: "add generated column referencing existing column", 1582 from: "create table t (id int, i int not null default 0, primary key (id))", 1583 alter: "alter table t add column neg int as (0-i)", 1584 to: "create table t (id int, i int not null default 0, neg int as (0-i), primary key (id))", 1585 }, 1586 { 1587 name: "drop column used by a functional index", 1588 from: "create table t (id int, d datetime, primary key (id), key m ((month(d))))", 1589 alter: "alter table t drop column d", 1590 expectErr: &InvalidColumnInKeyError{Table: "t", Column: "d", Key: "m"}, 1591 }, 1592 { 1593 name: "add generated column referencing nonexistent column", 1594 from: "create table t (id int, primary key (id))", 1595 alter: "alter table t add index m ((month(d)))", 1596 expectErr: &InvalidColumnInKeyError{Table: "t", Column: "d", Key: "m"}, 1597 }, 1598 { 1599 name: "add functional index referencing existing column", 1600 from: "create table t (id int, d datetime, primary key (id))", 1601 alter: "alter table t add index m ((month(d)))", 1602 to: "create table t (id int, d datetime, primary key (id), key m ((month(d))))", 1603 }, 1604 // This case slightly diverges right now from MySQL behavior where a referenced column 1605 // gets normalized to the casing it has in the table definition. This version here 1606 // still works though. 1607 { 1608 name: "add functional index referencing existing column with different case", 1609 from: "create table t (id int, d datetime, primary key (id))", 1610 alter: "alter table t add index m ((month(D)))", 1611 to: "create table t (id int, d datetime, primary key (id), key m ((month(D))))", 1612 }, 1613 { 1614 name: "constraint check which only uses single drop column", 1615 from: "create table t (id int, d datetime, primary key (id), constraint unix_epoch check (d < '1970-01-01'))", 1616 alter: "alter table t drop column d", 1617 to: "create table t (id int, primary key (id))", 1618 }, 1619 { 1620 name: "constraint check which uses multiple dropped columns", 1621 from: "create table t (id int, d datetime, e datetime, primary key (id), constraint unix_epoch check (d < '1970-01-01' and e < '1970-01-01'))", 1622 alter: "alter table t drop column d, drop column e", 1623 expectErr: &InvalidColumnInCheckConstraintError{Table: "t", Constraint: "unix_epoch", Column: "d"}, 1624 }, 1625 { 1626 name: "constraint check which uses multiple dropped columns", 1627 from: "create table t (id int, d datetime, e datetime, primary key (id), constraint unix_epoch check (d < '1970-01-01' and e < '1970-01-01'))", 1628 alter: "alter table t drop column e", 1629 expectErr: &InvalidColumnInCheckConstraintError{Table: "t", Constraint: "unix_epoch", Column: "e"}, 1630 }, 1631 { 1632 name: "constraint check added", 1633 from: "create table t (id int, d datetime, e datetime, primary key (id))", 1634 alter: "alter table t add constraint unix_epoch check (d < '1970-01-01' and e < '1970-01-01')", 1635 to: "create table t (id int, d datetime, e datetime, primary key (id), constraint unix_epoch check (d < '1970-01-01' and e < '1970-01-01'))", 1636 }, 1637 { 1638 name: "constraint check added with invalid column", 1639 from: "create table t (id int, d datetime, e datetime, primary key (id))", 1640 alter: "alter table t add constraint unix_epoch check (d < '1970-01-01' and f < '1970-01-01')", 1641 expectErr: &InvalidColumnInCheckConstraintError{Table: "t", Constraint: "unix_epoch", Column: "f"}, 1642 }, 1643 { 1644 name: "constraint check added with camelcase column", 1645 from: "create table t (id int, dateT datetime, e datetime, primary key (id))", 1646 alter: "alter table t add constraint unix_epoch check (dateT < '1970-01-01')", 1647 to: "create table t (id int, dateT datetime, e datetime, primary key (id), constraint unix_epoch check (dateT < '1970-01-01'))", 1648 }, 1649 { 1650 name: "constraint check added with camelcase column", 1651 from: "create table t (id int, dateT datetime, e datetime, primary key (id), constraint unix_epoch check (dateT < '1970-01-01'))", 1652 alter: "alter table t drop column e", 1653 to: "create table t (id int, dateT datetime, primary key (id), constraint unix_epoch check (dateT < '1970-01-01'))", 1654 }, 1655 // Foreign keys 1656 { 1657 name: "existing foreign key, no such column", 1658 from: "create table t (id int primary key, i int, constraint f foreign key (z) references parent(id))", 1659 alter: "alter table t engine=innodb", 1660 expectErr: &InvalidColumnInForeignKeyConstraintError{Table: "t", Constraint: "f", Column: "z"}, 1661 }, 1662 { 1663 name: "add foreign key, no such column", 1664 from: "create table t (id int primary key, i int)", 1665 alter: "alter table t add constraint f foreign key (z) references parent(id)", 1666 expectErr: &InvalidColumnInForeignKeyConstraintError{Table: "t", Constraint: "f", Column: "z"}, 1667 }, 1668 { 1669 name: "mismatching column count in foreign key", 1670 from: "create table t (id int primary key, i int, constraint f foreign key (i) references parent(id, z))", 1671 alter: "alter table t engine=innodb", 1672 expectErr: &ForeignKeyColumnCountMismatchError{Table: "t", Constraint: "f", ColumnCount: 1, ReferencedTable: "parent", ReferencedColumnCount: 2}, 1673 }, 1674 { 1675 name: "change with constraints with uppercase columns", 1676 from: "CREATE TABLE `Machine` (id int primary key, `a` int, `B` int, CONSTRAINT `chk` CHECK (`B` >= `a`))", 1677 alter: "ALTER TABLE `Machine` MODIFY COLUMN `id` bigint primary key", 1678 to: "CREATE TABLE `Machine` (id bigint primary key, `a` int, `B` int, CONSTRAINT `chk` CHECK (`B` >= `a`))", 1679 }, 1680 { 1681 name: "add unnamed foreign key, implicitly add index", 1682 from: "create table t (id int primary key, i int)", 1683 alter: "alter table t add foreign key (i) references parent(id)", 1684 to: "create table t (id int primary key, i int, key i (i), constraint t_ibfk_1 foreign key (i) references parent(id))", 1685 }, 1686 { 1687 name: "add foreign key, implicitly add index", 1688 from: "create table t (id int primary key, i int)", 1689 alter: "alter table t add constraint f foreign key (i) references parent(id)", 1690 to: "create table t (id int primary key, i int, key f (i), constraint f foreign key (i) references parent(id))", 1691 }, 1692 { 1693 name: "add foreign key and index, no implicit index", 1694 from: "create table t (id int primary key, i int)", 1695 alter: "alter table t add key i_idx (i), add constraint f foreign key (i) references parent(id)", 1696 to: "create table t (id int primary key, i int, key i_idx (i), constraint f foreign key (i) references parent(id))", 1697 }, 1698 { 1699 name: "add foreign key and extended index, no implicit index", 1700 from: "create table t (id int primary key, i int)", 1701 alter: "alter table t add key i_id_idx (i, id), add constraint f foreign key (i) references parent(id)", 1702 to: "create table t (id int primary key, i int, key i_id_idx (i, id), constraint f foreign key (i) references parent(id))", 1703 }, 1704 { 1705 name: "add foreign key, implicitly add index, fail duplicate key name", 1706 from: "create table t (id int primary key, i int, key f(id, i))", 1707 alter: "alter table t add constraint f foreign key (i) references parent(id)", 1708 expectErr: &ApplyDuplicateKeyError{Table: "t", Key: "f"}, 1709 }, 1710 { 1711 name: "fail drop key leaving unindexed foreign key constraint", 1712 from: "create table t (id int primary key, i int, key i (i), constraint f foreign key (i) references parent(id))", 1713 alter: "alter table t drop key `i`", 1714 expectErr: &IndexNeededByForeignKeyError{Table: "t", Key: "i"}, 1715 }, 1716 { 1717 name: "drop key with alternative key for foreign key constraint, 1", 1718 from: "create table t (id int primary key, i int, key i (i), key i2 (i, id), constraint f foreign key (i) references parent(id))", 1719 alter: "alter table t drop key `i`", 1720 to: "create table t (id int primary key, i int, key i2 (i, id), constraint f foreign key (i) references parent(id))", 1721 }, 1722 { 1723 name: "drop key with alternative key for foreign key constraint, 2", 1724 from: "create table t (id int primary key, i int, key i (i), key i2 (i, id), constraint f foreign key (i) references parent(id))", 1725 alter: "alter table t drop key `i2`", 1726 to: "create table t (id int primary key, i int, key i (i), constraint f foreign key (i) references parent(id))", 1727 }, 1728 { 1729 name: "drop key with alternative key for foreign key constraint, 3", 1730 from: "create table t (id int primary key, i int, key i (i), key i2 (i), constraint f foreign key (i) references parent(id))", 1731 alter: "alter table t drop key `i`", 1732 to: "create table t (id int primary key, i int, key i2 (i), constraint f foreign key (i) references parent(id))", 1733 }, 1734 } 1735 hints := DiffHints{} 1736 for _, ts := range tt { 1737 t.Run(ts.name, func(t *testing.T) { 1738 stmt, err := sqlparser.ParseStrictDDL(ts.from) 1739 require.NoError(t, err) 1740 fromCreateTable, ok := stmt.(*sqlparser.CreateTable) 1741 require.True(t, ok) 1742 1743 stmt, err = sqlparser.ParseStrictDDL(ts.alter) 1744 require.NoError(t, err) 1745 alterTable, ok := stmt.(*sqlparser.AlterTable) 1746 require.True(t, ok) 1747 1748 from, err := NewCreateTableEntity(fromCreateTable) 1749 require.NoError(t, err) 1750 a := &AlterTableEntityDiff{from: from, alterTable: alterTable} 1751 applied, err := from.Apply(a) 1752 if ts.expectErr != nil { 1753 appliedCanonicalStatementString := "" 1754 if applied != nil { 1755 appliedCanonicalStatementString = applied.Create().CanonicalStatementString() 1756 } 1757 assert.Error(t, err) 1758 assert.EqualErrorf(t, err, ts.expectErr.Error(), "applied: %v", appliedCanonicalStatementString) 1759 } else { 1760 assert.NoError(t, err) 1761 assert.NotNil(t, applied) 1762 1763 c, ok := applied.(*CreateTableEntity) 1764 require.True(t, ok) 1765 applied = c.normalize() 1766 1767 stmt, err := sqlparser.ParseStrictDDL(ts.to) 1768 require.NoError(t, err) 1769 toCreateTable, ok := stmt.(*sqlparser.CreateTable) 1770 require.True(t, ok) 1771 1772 to, err := NewCreateTableEntity(toCreateTable) 1773 require.NoError(t, err) 1774 diff, err := applied.Diff(to, &hints) 1775 require.NoError(t, err) 1776 assert.Empty(t, diff, "diff found: %v.\napplied: %v\nto: %v", diff.CanonicalStatementString(), applied.Create().CanonicalStatementString(), to.Create().CanonicalStatementString()) 1777 } 1778 }) 1779 } 1780 } 1781 1782 func TestNormalize(t *testing.T) { 1783 tt := []struct { 1784 name string 1785 from string 1786 to string 1787 }{ 1788 { 1789 name: "basic table", 1790 from: "create table t (id int, i int, primary key (id))", 1791 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i` int,\n\tPRIMARY KEY (`id`)\n)", 1792 }, 1793 { 1794 name: "basic table, primary key", 1795 from: "create table t (id int primary key, i int)", 1796 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i` int,\n\tPRIMARY KEY (`id`)\n)", 1797 }, 1798 { 1799 name: "removes default null", 1800 from: "create table t (id int, i int default null, primary key (id))", 1801 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i` int,\n\tPRIMARY KEY (`id`)\n)", 1802 }, 1803 { 1804 name: "keeps not exist", 1805 from: "create table if not exists t (id int primary key, i int)", 1806 to: "CREATE TABLE IF NOT EXISTS `t` (\n\t`id` int,\n\t`i` int,\n\tPRIMARY KEY (`id`)\n)", 1807 }, 1808 { 1809 name: "timestamp null", 1810 from: "create table t (id int primary key, t timestamp null)", 1811 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`t` timestamp NULL,\n\tPRIMARY KEY (`id`)\n)", 1812 }, 1813 { 1814 name: "timestamp default null", 1815 from: "create table t (id int primary key, t timestamp default null)", 1816 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`t` timestamp NULL,\n\tPRIMARY KEY (`id`)\n)", 1817 }, 1818 { 1819 name: "uses lowercase type", 1820 from: "create table t (id INT primary key, i INT default null)", 1821 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i` int,\n\tPRIMARY KEY (`id`)\n)", 1822 }, 1823 { 1824 name: "removes default signed", 1825 from: "create table t (id int signed primary key, i int signed)", 1826 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i` int,\n\tPRIMARY KEY (`id`)\n)", 1827 }, 1828 { 1829 name: "does not remove tinyint(1) size", 1830 from: "create table t (id int primary key, i tinyint(1) default null)", 1831 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i` tinyint(1),\n\tPRIMARY KEY (`id`)\n)", 1832 }, 1833 { 1834 name: "removes other tinyint size", 1835 from: "create table t (id int primary key, i tinyint(2) default null)", 1836 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i` tinyint,\n\tPRIMARY KEY (`id`)\n)", 1837 }, 1838 { 1839 name: "removes int size", 1840 from: "create table t (id int primary key, i int(1) default null)", 1841 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i` int,\n\tPRIMARY KEY (`id`)\n)", 1842 }, 1843 { 1844 name: "removes bigint size", 1845 from: "create table t (id int primary key, i bigint(1) default null)", 1846 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i` bigint,\n\tPRIMARY KEY (`id`)\n)", 1847 }, 1848 { 1849 name: "keeps zerofill", 1850 from: "create table t (id int primary key, i int zerofill default null)", 1851 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i` int zerofill,\n\tPRIMARY KEY (`id`)\n)", 1852 }, 1853 { 1854 name: "removes int sizes case insensitive", 1855 from: "create table t (id int primary key, i INT(11) default null)", 1856 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i` int,\n\tPRIMARY KEY (`id`)\n)", 1857 }, 1858 { 1859 name: "removes float size with correct type", 1860 from: "create table t (id int primary key, f float(24) default null)", 1861 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`f` float,\n\tPRIMARY KEY (`id`)\n)", 1862 }, 1863 { 1864 name: "removes float size with correct type", 1865 from: "create table t (id int primary key, f float(25) default null)", 1866 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`f` double,\n\tPRIMARY KEY (`id`)\n)", 1867 }, 1868 { 1869 name: "normalizes real type to double", 1870 from: "create table t (id int primary key, f real default null)", 1871 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`f` double,\n\tPRIMARY KEY (`id`)\n)", 1872 }, 1873 { 1874 name: "normalizes float4 type to float", 1875 from: "create table t (id int primary key, f float4 default null)", 1876 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`f` float,\n\tPRIMARY KEY (`id`)\n)", 1877 }, 1878 { 1879 name: "normalizes float8 type to double", 1880 from: "create table t (id int primary key, f float8 default null)", 1881 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`f` double,\n\tPRIMARY KEY (`id`)\n)", 1882 }, 1883 { 1884 name: "removes matching charset", 1885 from: "create table t (id int signed primary key, v varchar(255) charset utf8mb4) charset utf8mb4", 1886 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`v` varchar(255),\n\tPRIMARY KEY (`id`)\n) CHARSET utf8mb4", 1887 }, 1888 { 1889 name: "removes matching case insensitive charset", 1890 from: "create table t (id int signed primary key, v varchar(255) charset UTF8MB4) charset utf8mb4", 1891 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`v` varchar(255),\n\tPRIMARY KEY (`id`)\n) CHARSET utf8mb4", 1892 }, 1893 { 1894 name: "removes matching collation if default", 1895 from: "create table t (id int signed primary key, v varchar(255) collate utf8mb4_0900_ai_ci) collate utf8mb4_0900_ai_ci", 1896 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`v` varchar(255),\n\tPRIMARY KEY (`id`)\n) COLLATE utf8mb4_0900_ai_ci", 1897 }, 1898 { 1899 name: "removes matching collation case insensitive if default", 1900 from: "create table t (id int signed primary key, v varchar(255) collate UTF8MB4_0900_AI_CI) collate utf8mb4_0900_ai_ci", 1901 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`v` varchar(255),\n\tPRIMARY KEY (`id`)\n) COLLATE utf8mb4_0900_ai_ci", 1902 }, 1903 { 1904 name: "removes matching charset & collation if default", 1905 from: "create table t (id int signed primary key, v varchar(255) charset utf8mb4 collate utf8mb4_0900_ai_ci) charset utf8mb4 collate utf8mb4_0900_ai_ci", 1906 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`v` varchar(255),\n\tPRIMARY KEY (`id`)\n) CHARSET utf8mb4,\n COLLATE utf8mb4_0900_ai_ci", 1907 }, 1908 { 1909 name: "sets collation for non default collation at table level", 1910 from: "create table t (id int signed primary key, v varchar(255) charset utf8mb4) charset utf8mb4 collate utf8mb4_0900_bin", 1911 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`v` varchar(255) COLLATE utf8mb4_0900_ai_ci,\n\tPRIMARY KEY (`id`)\n) CHARSET utf8mb4,\n COLLATE utf8mb4_0900_bin", 1912 }, 1913 { 1914 name: "does not add collation for a non default collation at table level", 1915 from: "create table t (id int signed primary key, v varchar(255)) charset utf8mb4 collate utf8mb4_0900_bin", 1916 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`v` varchar(255),\n\tPRIMARY KEY (`id`)\n) CHARSET utf8mb4,\n COLLATE utf8mb4_0900_bin", 1917 }, 1918 { 1919 name: "cleans up collation at the column level if it matches the tabel level and both are given", 1920 from: "create table t (id int signed primary key, v varchar(255) collate utf8mb4_0900_bin) charset utf8mb4 collate utf8mb4_0900_bin", 1921 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`v` varchar(255),\n\tPRIMARY KEY (`id`)\n) CHARSET utf8mb4,\n COLLATE utf8mb4_0900_bin", 1922 }, 1923 { 1924 name: "cleans up charset and collation at the column level if it matches the tabel level and both are given", 1925 from: "create table t (id int signed primary key, v varchar(255) charset utf8mb4 collate utf8mb4_0900_bin) charset utf8mb4 collate utf8mb4_0900_bin", 1926 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`v` varchar(255),\n\tPRIMARY KEY (`id`)\n) CHARSET utf8mb4,\n COLLATE utf8mb4_0900_bin", 1927 }, 1928 { 1929 name: "keeps existing collation even if default for non default collation at table level", 1930 from: "create table t (id int signed primary key, v varchar(255) charset utf8mb4 collate utf8mb4_0900_ai_ci) charset utf8mb4 collate utf8mb4_0900_bin", 1931 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`v` varchar(255) COLLATE utf8mb4_0900_ai_ci,\n\tPRIMARY KEY (`id`)\n) CHARSET utf8mb4,\n COLLATE utf8mb4_0900_bin", 1932 }, 1933 { 1934 name: "keeps existing collation even if another non default collation", 1935 from: "create table t (id int signed primary key, v varchar(255) charset utf8mb4 collate utf8mb4_german2_ci) charset utf8mb4 collate utf8mb4_0900_bin", 1936 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`v` varchar(255) COLLATE utf8mb4_german2_ci,\n\tPRIMARY KEY (`id`)\n) CHARSET utf8mb4,\n COLLATE utf8mb4_0900_bin", 1937 }, 1938 { 1939 name: "maps utf8 to utf8mb3", 1940 from: "create table t (id int signed primary key, v varchar(255) charset utf8 collate utf8_general_ci) charset utf8 collate utf8_general_ci", 1941 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`v` varchar(255),\n\tPRIMARY KEY (`id`)\n) CHARSET utf8mb3,\n COLLATE utf8mb3_general_ci", 1942 }, 1943 { 1944 name: "lowercase table options for charset and collation", 1945 from: "create table t (id int signed primary key, v varchar(255) charset utf8 collate utf8_general_ci) charset UTF8 collate UTF8_GENERAL_CI", 1946 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`v` varchar(255),\n\tPRIMARY KEY (`id`)\n) CHARSET utf8mb3,\n COLLATE utf8mb3_general_ci", 1947 }, 1948 { 1949 name: "drops existing collation if it matches table default at column level for non default charset", 1950 from: "create table t (id int signed primary key, v varchar(255) charset utf8mb3 collate utf8_unicode_ci) charset utf8mb3 collate utf8_unicode_ci", 1951 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`v` varchar(255),\n\tPRIMARY KEY (`id`)\n) CHARSET utf8mb3,\n COLLATE utf8mb3_unicode_ci", 1952 }, 1953 { 1954 name: "correct case table options for engine", 1955 from: "create table t (id int signed primary key) engine innodb", 1956 to: "CREATE TABLE `t` (\n\t`id` int,\n\tPRIMARY KEY (`id`)\n) ENGINE InnoDB", 1957 }, 1958 { 1959 name: "correct case for engine in partitions", 1960 from: "create table a (id int not null primary key) engine InnoDB, charset utf8mb4, collate utf8mb4_0900_ai_ci partition by range (`id`) (partition `p10` values less than(10) engine innodb)", 1961 to: "CREATE TABLE `a` (\n\t`id` int NOT NULL,\n\tPRIMARY KEY (`id`)\n) ENGINE InnoDB,\n CHARSET utf8mb4,\n COLLATE utf8mb4_0900_ai_ci\nPARTITION BY RANGE (`id`)\n(PARTITION `p10` VALUES LESS THAN (10) ENGINE InnoDB)", 1962 }, 1963 { 1964 name: "generates a name for a key with proper casing", 1965 from: "create table t (id int, I int, index i (i), index(I))", 1966 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`I` int,\n\tKEY `i` (`i`),\n\tKEY `I_2` (`I`)\n)", 1967 }, 1968 { 1969 name: "generates a name for checks", 1970 from: "create table t (id int NOT NULL, test int NOT NULL DEFAULT 0, PRIMARY KEY (id), CHECK ((test >= 0)))", 1971 to: "CREATE TABLE `t` (\n\t`id` int NOT NULL,\n\t`test` int NOT NULL DEFAULT 0,\n\tPRIMARY KEY (`id`),\n\tCONSTRAINT `t_chk_1` CHECK (`test` >= 0)\n)", 1972 }, 1973 { 1974 name: "generates a name for checks with proper casing", 1975 from: "create table t (id int NOT NULL, test int NOT NULL DEFAULT 0, PRIMARY KEY (id), CONSTRAINT t_CHK_1 CHECK (test >= 0), CHECK ((test >= 0)))", 1976 to: "CREATE TABLE `t` (\n\t`id` int NOT NULL,\n\t`test` int NOT NULL DEFAULT 0,\n\tPRIMARY KEY (`id`),\n\tCONSTRAINT `t_CHK_1` CHECK (`test` >= 0),\n\tCONSTRAINT `t_chk_2` CHECK (`test` >= 0)\n)", 1977 }, 1978 { 1979 name: "generates a name for foreign key constraints", 1980 from: "create table t1 (id int primary key, i int, key i_idx (i), foreign key (i) references parent(id))", 1981 to: "CREATE TABLE `t1` (\n\t`id` int,\n\t`i` int,\n\tPRIMARY KEY (`id`),\n\tKEY `i_idx` (`i`),\n\tCONSTRAINT `t1_ibfk_1` FOREIGN KEY (`i`) REFERENCES `parent` (`id`)\n)", 1982 }, 1983 { 1984 name: "creates an index for foreign key constraints", 1985 from: "create table t1 (id int primary key, i int, constraint f foreign key (i) references parent(id))", 1986 to: "CREATE TABLE `t1` (\n\t`id` int,\n\t`i` int,\n\tPRIMARY KEY (`id`),\n\tKEY `f` (`i`),\n\tCONSTRAINT `f` FOREIGN KEY (`i`) REFERENCES `parent` (`id`)\n)", 1987 }, 1988 { 1989 name: "creates an index for unnamed foreign key constraints", 1990 from: "create table t1 (id int primary key, i int, foreign key (i) references parent(id))", 1991 to: "CREATE TABLE `t1` (\n\t`id` int,\n\t`i` int,\n\tPRIMARY KEY (`id`),\n\tKEY `i` (`i`),\n\tCONSTRAINT `t1_ibfk_1` FOREIGN KEY (`i`) REFERENCES `parent` (`id`)\n)", 1992 }, 1993 { 1994 name: "does not add index since one already defined for foreign key constraint", 1995 from: "create table t1 (id int primary key, i int, key i_idx (i), foreign key (i) references parent(id))", 1996 to: "CREATE TABLE `t1` (\n\t`id` int,\n\t`i` int,\n\tPRIMARY KEY (`id`),\n\tKEY `i_idx` (`i`),\n\tCONSTRAINT `t1_ibfk_1` FOREIGN KEY (`i`) REFERENCES `parent` (`id`)\n)", 1997 }, 1998 { 1999 name: "uses KEY for indexes", 2000 from: "create table t (id int primary key, i1 int, index i1_idx(i1))", 2001 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i1` int,\n\tPRIMARY KEY (`id`),\n\tKEY `i1_idx` (`i1`)\n)", 2002 }, 2003 { 2004 name: "drops default index type", 2005 from: "create table t (id int primary key, i1 int, key i1_idx(i1) using btree)", 2006 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i1` int,\n\tPRIMARY KEY (`id`),\n\tKEY `i1_idx` (`i1`)\n)", 2007 }, 2008 { 2009 name: "does not drop non-default index type", 2010 from: "create table t (id int primary key, i1 int, key i1_idx(i1) using hash)", 2011 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i1` int,\n\tPRIMARY KEY (`id`),\n\tKEY `i1_idx` (`i1`) USING hash\n)", 2012 }, 2013 { 2014 name: "drops default index visibility", 2015 from: "create table t (id int primary key, i1 int, key i1_idx(i1) visible)", 2016 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i1` int,\n\tPRIMARY KEY (`id`),\n\tKEY `i1_idx` (`i1`)\n)", 2017 }, 2018 { 2019 name: "drops non-default index visibility", 2020 from: "create table t (id int primary key, i1 int, key i1_idx(i1) invisible)", 2021 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i1` int,\n\tPRIMARY KEY (`id`),\n\tKEY `i1_idx` (`i1`) INVISIBLE\n)", 2022 }, 2023 { 2024 name: "drops default column visibility", 2025 from: "create table t (id int primary key, i1 int visible)", 2026 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i1` int,\n\tPRIMARY KEY (`id`)\n)", 2027 }, 2028 { 2029 name: "drops non-default column visibility", 2030 from: "create table t (id int primary key, i1 int invisible)", 2031 to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i1` int INVISIBLE,\n\tPRIMARY KEY (`id`)\n)", 2032 }, 2033 } 2034 for _, ts := range tt { 2035 t.Run(ts.name, func(t *testing.T) { 2036 stmt, err := sqlparser.ParseStrictDDL(ts.from) 2037 require.NoError(t, err) 2038 fromCreateTable, ok := stmt.(*sqlparser.CreateTable) 2039 require.True(t, ok) 2040 2041 from, err := NewCreateTableEntity(fromCreateTable) 2042 require.NoError(t, err) 2043 assert.Equal(t, ts.to, sqlparser.CanonicalString(from)) 2044 }) 2045 } 2046 } 2047 2048 func TestIndexesCoveringForeignKeyColumns(t *testing.T) { 2049 sql := ` 2050 create table t ( 2051 id int, 2052 a int, 2053 b int, 2054 c int, 2055 d int, 2056 e int, 2057 z int, 2058 primary key (id), 2059 key ax (a), 2060 key abx (a, b), 2061 key bx (b), 2062 key bax (b, a), 2063 key abcdx (a, b, c, d), 2064 key dex (d, e) 2065 ) 2066 ` 2067 tt := []struct { 2068 columns []string 2069 indexes []string 2070 }{ 2071 {}, 2072 { 2073 columns: []string{"a"}, 2074 indexes: []string{"ax", "abx", "abcdx"}, 2075 }, 2076 { 2077 columns: []string{"b"}, 2078 indexes: []string{"bx", "bax"}, 2079 }, 2080 { 2081 columns: []string{"c"}, 2082 }, 2083 { 2084 columns: []string{"d"}, 2085 indexes: []string{"dex"}, 2086 }, 2087 { 2088 columns: []string{"e"}, 2089 }, 2090 { 2091 columns: []string{"z"}, 2092 }, 2093 { 2094 columns: []string{"a", "b"}, 2095 indexes: []string{"abx", "abcdx"}, 2096 }, 2097 { 2098 columns: []string{"A", "B"}, 2099 indexes: []string{"abx", "abcdx"}, 2100 }, 2101 { 2102 columns: []string{"a", "b", "c"}, 2103 indexes: []string{"abcdx"}, 2104 }, 2105 { 2106 columns: []string{"a", "b", "c", "d"}, 2107 indexes: []string{"abcdx"}, 2108 }, 2109 { 2110 columns: []string{"a", "b", "c", "d", "e"}, 2111 }, 2112 { 2113 columns: []string{"b", "a"}, 2114 indexes: []string{"bax"}, 2115 }, 2116 { 2117 columns: []string{"d", "e"}, 2118 indexes: []string{"dex"}, 2119 }, 2120 { 2121 columns: []string{"a", "e"}, 2122 }, 2123 } 2124 2125 stmt, err := sqlparser.ParseStrictDDL(sql) 2126 require.NoError(t, err) 2127 createTable, ok := stmt.(*sqlparser.CreateTable) 2128 require.True(t, ok) 2129 c, err := NewCreateTableEntity(createTable) 2130 require.NoError(t, err) 2131 tableColumns := map[string]sqlparser.IdentifierCI{} 2132 for _, col := range c.CreateTable.TableSpec.Columns { 2133 tableColumns[col.Name.Lowered()] = col.Name 2134 } 2135 for _, ts := range tt { 2136 name := strings.Join(ts.columns, ",") 2137 t.Run(name, func(t *testing.T) { 2138 columns := sqlparser.Columns{} 2139 for _, colName := range ts.columns { 2140 col, ok := tableColumns[strings.ToLower(colName)] 2141 require.True(t, ok) 2142 columns = append(columns, col) 2143 } 2144 2145 indexes := c.indexesCoveringForeignKeyColumns(columns) 2146 var indexesNames []string 2147 for _, index := range indexes { 2148 indexesNames = append(indexesNames, index.Info.Name.String()) 2149 } 2150 assert.Equal(t, ts.indexes, indexesNames) 2151 }) 2152 } 2153 }