github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/cdc/model/schema_storage_test.go (about) 1 // Copyright 2020 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package model 15 16 import ( 17 "testing" 18 19 "github.com/pingcap/tidb/pkg/parser/charset" 20 timodel "github.com/pingcap/tidb/pkg/parser/model" 21 "github.com/pingcap/tidb/pkg/parser/mysql" 22 parser_types "github.com/pingcap/tidb/pkg/parser/types" 23 "github.com/stretchr/testify/require" 24 ) 25 26 func TestHandleKeyPriority(t *testing.T) { 27 t.Parallel() 28 ftNull := parser_types.NewFieldType(mysql.TypeUnspecified) 29 ftNull.SetFlag(mysql.NotNullFlag) 30 31 ftNotNull := parser_types.NewFieldType(mysql.TypeUnspecified) 32 ftNotNull.SetFlag(mysql.NotNullFlag | mysql.MultipleKeyFlag) 33 34 tbl := timodel.TableInfo{ 35 Columns: []*timodel.ColumnInfo{ 36 { 37 Name: timodel.CIStr{O: "a"}, 38 FieldType: *ftNotNull, 39 State: timodel.StatePublic, 40 }, 41 { 42 Name: timodel.CIStr{O: "b"}, 43 FieldType: *ftNotNull, 44 State: timodel.StatePublic, 45 }, 46 { 47 Name: timodel.CIStr{O: "c"}, 48 FieldType: *ftNotNull, 49 State: timodel.StatePublic, 50 }, 51 { 52 Name: timodel.CIStr{O: "d"}, 53 FieldType: parser_types.FieldType{ 54 // test not null unique index 55 // Flag: mysql.NotNullFlag, 56 }, 57 State: timodel.StatePublic, 58 }, 59 { 60 Name: timodel.CIStr{O: "e"}, 61 FieldType: *ftNull, 62 State: timodel.StatePublic, 63 // test virtual generated column is not treated as unique key 64 GeneratedExprString: "as d", 65 GeneratedStored: false, 66 }, 67 }, 68 Indices: []*timodel.IndexInfo{ 69 { 70 ID: 10, 71 Name: timodel.CIStr{ 72 O: "a,b", 73 }, 74 Columns: []*timodel.IndexColumn{ 75 {Name: timodel.CIStr{O: "a"}, Offset: 0}, 76 {Name: timodel.CIStr{O: "b"}, Offset: 1}, 77 }, 78 Unique: true, 79 }, 80 { 81 ID: 9, 82 Name: timodel.CIStr{ 83 O: "c", 84 }, 85 Columns: []*timodel.IndexColumn{ 86 {Name: timodel.CIStr{O: "c"}, Offset: 2}, 87 }, 88 Unique: true, 89 }, 90 { 91 ID: 8, 92 Name: timodel.CIStr{ 93 O: "b", 94 }, 95 Columns: []*timodel.IndexColumn{ 96 {Name: timodel.CIStr{O: "b"}, Offset: 1}, 97 }, 98 Unique: true, 99 }, 100 { 101 ID: 7, 102 Name: timodel.CIStr{ 103 O: "d", 104 }, 105 Columns: []*timodel.IndexColumn{ 106 {Name: timodel.CIStr{O: "d"}, Offset: 3}, 107 }, 108 Unique: true, 109 }, 110 { 111 ID: 6, 112 Name: timodel.CIStr{ 113 O: "e", 114 }, 115 Columns: []*timodel.IndexColumn{ 116 {Name: timodel.CIStr{O: "e"}, Offset: 4}, 117 }, 118 Unique: true, 119 }, 120 }, 121 IsCommonHandle: false, 122 PKIsHandle: false, 123 } 124 info := WrapTableInfo(1, "", 0, &tbl) 125 require.Equal(t, int64(8), info.HandleIndexID) 126 } 127 128 func TestTableInfoGetterFuncs(t *testing.T) { 129 t.Parallel() 130 131 ftNull := parser_types.NewFieldType(mysql.TypeUnspecified) 132 ftNull.SetFlag(mysql.NotNullFlag) 133 134 ftNotNull := parser_types.NewFieldType(mysql.TypeUnspecified) 135 ftNotNull.SetFlag(mysql.NotNullFlag | mysql.MultipleKeyFlag) 136 137 ftNotNullBinCharset := parser_types.NewFieldType(mysql.TypeUnspecified) 138 ftNotNullBinCharset.SetFlag(mysql.NotNullFlag | mysql.MultipleKeyFlag) 139 ftNotNullBinCharset.SetCharset("binary") 140 141 tbl := timodel.TableInfo{ 142 ID: 1071, 143 Name: timodel.CIStr{O: "t1"}, 144 Columns: []*timodel.ColumnInfo{ 145 { 146 ID: 0, 147 Name: timodel.CIStr{O: "a"}, 148 FieldType: *ftNotNullBinCharset, 149 State: timodel.StatePublic, 150 }, 151 { 152 ID: 1, 153 Name: timodel.CIStr{O: "b"}, 154 FieldType: *ftNotNull, 155 State: timodel.StatePublic, 156 }, 157 { 158 ID: 2, 159 Name: timodel.CIStr{O: "c"}, 160 FieldType: *ftNull, 161 State: timodel.StatePublic, 162 }, 163 }, 164 Indices: []*timodel.IndexInfo{ 165 { 166 ID: 0, 167 Name: timodel.CIStr{ 168 O: "c", 169 }, 170 Columns: []*timodel.IndexColumn{ 171 {Name: timodel.CIStr{O: "c"}, Offset: 2}, 172 }, 173 Unique: true, 174 }, 175 }, 176 IsCommonHandle: false, 177 PKIsHandle: false, 178 Partition: &timodel.PartitionInfo{ 179 Enable: true, 180 }, 181 } 182 info := WrapTableInfo(1, "test", 0, &tbl) 183 184 col, exists := info.GetColumnInfo(2) 185 require.True(t, exists) 186 require.Equal(t, "c", col.Name.O) 187 _, exists = info.GetColumnInfo(4) 188 require.False(t, exists) 189 190 require.Equal(t, "TableInfo, ID: 1071, Name:test.t1, ColNum: 3, IdxNum: 1, PKIsHandle: false", info.String()) 191 192 require.Equal(t, "test", info.GetSchemaName()) 193 require.Equal(t, "t1", info.GetTableName()) 194 require.True(t, info.IsPartitionTable()) 195 196 handleColIDs, fts, colInfos := info.GetRowColInfos() 197 require.Equal(t, []int64{-1}, handleColIDs) 198 require.Equal(t, 3, len(fts)) 199 require.Equal(t, 3, len(colInfos)) 200 201 require.True(t, info.HasUniqueColumn()) 202 203 // check IsEligible 204 require.True(t, info.IsEligible(false)) 205 tbl = timodel.TableInfo{ 206 ID: 1073, 207 Name: timodel.CIStr{O: "t2"}, 208 Columns: []*timodel.ColumnInfo{ 209 { 210 ID: 0, 211 Name: timodel.CIStr{O: "a"}, 212 FieldType: parser_types.FieldType{}, 213 State: timodel.StatePublic, 214 }, 215 }, 216 Indices: []*timodel.IndexInfo{ 217 { 218 ID: 0, 219 Name: timodel.CIStr{O: "a"}, 220 Columns: []*timodel.IndexColumn{ 221 {Name: timodel.CIStr{O: "a"}, Offset: 0}, 222 }, 223 Unique: true, 224 }, 225 }, 226 IsCommonHandle: false, 227 PKIsHandle: false, 228 } 229 info = WrapTableInfo(1, "test", 0, &tbl) 230 require.False(t, info.IsEligible(false)) 231 require.True(t, info.IsEligible(true)) 232 233 // View is eligible. 234 tbl.View = &timodel.ViewInfo{} 235 info = WrapTableInfo(1, "test", 0, &tbl) 236 require.True(t, info.IsView()) 237 require.True(t, info.IsEligible(false)) 238 239 // Sequence is ineligible. 240 tbl.Sequence = &timodel.SequenceInfo{} 241 info = WrapTableInfo(1, "test", 0, &tbl) 242 require.True(t, info.IsSequence()) 243 require.False(t, info.IsEligible(false)) 244 require.False(t, info.IsEligible(true)) 245 } 246 247 func TestTableInfoClone(t *testing.T) { 248 t.Parallel() 249 ft := parser_types.NewFieldType(mysql.TypeUnspecified) 250 ft.SetFlag(mysql.NotNullFlag) 251 tbl := timodel.TableInfo{ 252 ID: 1071, 253 Name: timodel.CIStr{O: "t1"}, 254 Columns: []*timodel.ColumnInfo{ 255 { 256 ID: 0, 257 Name: timodel.CIStr{O: "c"}, 258 FieldType: *ft, 259 State: timodel.StatePublic, 260 }, 261 }, 262 Indices: []*timodel.IndexInfo{ 263 { 264 ID: 0, 265 Name: timodel.CIStr{ 266 O: "c", 267 }, 268 Columns: []*timodel.IndexColumn{ 269 {Name: timodel.CIStr{O: "c"}, Offset: 0}, 270 }, 271 Unique: true, 272 }, 273 }, 274 } 275 info := WrapTableInfo(10, "test", 0, &tbl) 276 cloned := info.Clone() 277 require.Equal(t, cloned.SchemaID, info.SchemaID) 278 cloned.SchemaID = 100 279 require.Equal(t, int64(10), info.SchemaID) 280 } 281 282 func TestIndexByName(t *testing.T) { 283 tableInfo := &TableInfo{ 284 TableInfo: &timodel.TableInfo{ 285 Indices: nil, 286 }, 287 } 288 names, offsets, ok := tableInfo.IndexByName("idx1") 289 require.False(t, ok) 290 require.Nil(t, names) 291 require.Nil(t, offsets) 292 293 tableInfo = &TableInfo{ 294 TableInfo: &timodel.TableInfo{ 295 Indices: []*timodel.IndexInfo{ 296 { 297 Name: timodel.CIStr{ 298 O: "idx1", 299 }, 300 Columns: []*timodel.IndexColumn{ 301 { 302 Name: timodel.CIStr{ 303 O: "col1", 304 }, 305 }, 306 }, 307 }, 308 }, 309 }, 310 } 311 312 names, offsets, ok = tableInfo.IndexByName("idx2") 313 require.False(t, ok) 314 require.Nil(t, names) 315 require.Nil(t, offsets) 316 317 names, offsets, ok = tableInfo.IndexByName("idx1") 318 require.True(t, ok) 319 require.Equal(t, []string{"col1"}, names) 320 require.Equal(t, []int{0}, offsets) 321 } 322 323 func TestColumnsByNames(t *testing.T) { 324 tableInfo := &TableInfo{ 325 TableInfo: &timodel.TableInfo{ 326 Columns: []*timodel.ColumnInfo{ 327 { 328 Name: timodel.CIStr{ 329 O: "col2", 330 }, 331 Offset: 1, 332 }, 333 { 334 Name: timodel.CIStr{ 335 O: "col1", 336 }, 337 Offset: 0, 338 }, 339 { 340 Name: timodel.CIStr{ 341 O: "col3", 342 }, 343 Offset: 2, 344 }, 345 }, 346 }, 347 } 348 349 names := []string{"col1", "col2", "col3"} 350 offsets, ok := tableInfo.OffsetsByNames(names) 351 require.True(t, ok) 352 require.Equal(t, []int{0, 1, 2}, offsets) 353 354 names = []string{"col2"} 355 offsets, ok = tableInfo.OffsetsByNames(names) 356 require.True(t, ok) 357 require.Equal(t, []int{1}, offsets) 358 359 names = []string{"col1", "col-not-found"} 360 offsets, ok = tableInfo.OffsetsByNames(names) 361 require.False(t, ok) 362 require.Nil(t, offsets) 363 } 364 365 func TestBuildTiDBTableInfoWithIntPrimaryKey(t *testing.T) { 366 columns := []*Column{{ 367 Name: "a1", 368 Type: mysql.TypeLong, 369 Flag: BinaryFlag | PrimaryKeyFlag | HandleKeyFlag, 370 }, { 371 Name: "a2", 372 Type: mysql.TypeVarchar, 373 Collation: charset.CollationUTF8, 374 }, { 375 Name: "a4", 376 Type: mysql.TypeTinyBlob, 377 Charset: charset.CharsetLatin1, 378 }} 379 tidbTableInfo := BuildTiDBTableInfo("t", columns, [][]int{{0}}) 380 tableInfo := WrapTableInfo(100, "test", 1000, tidbTableInfo) 381 require.Equal(t, "test", tableInfo.TableName.Schema) 382 require.Equal(t, "t", tableInfo.TableName.Table) 383 require.Equal(t, 3, len(tableInfo.columnsOffset)) 384 require.Equal(t, 1, len(tableInfo.indicesOffset)) 385 require.Equal(t, 3, len(tableInfo.Columns)) 386 387 require.Equal(t, tableInfo.Columns[0].ID, tableInfo.ForceGetColumnIDByName("a1")) 388 require.Equal(t, columns[0].Name, tableInfo.ForceGetColumnName(tableInfo.Columns[0].ID)) 389 require.Equal(t, columns[0].Type, tableInfo.ForceGetColumnInfo(tableInfo.Columns[0].ID).GetType()) 390 require.Equal(t, "binary", tableInfo.ForceGetColumnInfo(tableInfo.Columns[0].ID).GetCharset()) 391 require.Equal(t, mysql.UTF8MB4DefaultCollation, tableInfo.ForceGetColumnInfo(tableInfo.Columns[0].ID).GetCollate()) 392 require.Equal(t, columns[0].Flag, *tableInfo.ForceGetColumnFlagType(tableInfo.Columns[0].ID)) 393 394 require.Equal(t, columns[1].Name, tableInfo.ForceGetColumnName(tableInfo.Columns[1].ID)) 395 require.Equal(t, columns[1].Type, tableInfo.ForceGetColumnInfo(tableInfo.Columns[1].ID).GetType()) 396 require.Equal(t, mysql.UTF8MB4Charset, tableInfo.ForceGetColumnInfo(tableInfo.Columns[1].ID).GetCharset()) 397 require.Equal(t, charset.CollationUTF8, tableInfo.ForceGetColumnInfo(tableInfo.Columns[1].ID).GetCollate()) 398 require.Equal(t, columns[1].Flag, *tableInfo.ForceGetColumnFlagType(tableInfo.Columns[1].ID)) 399 400 require.Equal(t, columns[2].Name, tableInfo.ForceGetColumnName(tableInfo.Columns[2].ID)) 401 require.Equal(t, columns[2].Type, tableInfo.ForceGetColumnInfo(tableInfo.Columns[2].ID).GetType()) 402 require.Equal(t, charset.CharsetLatin1, tableInfo.ForceGetColumnInfo(tableInfo.Columns[2].ID).GetCharset()) 403 require.Equal(t, mysql.UTF8MB4DefaultCollation, tableInfo.ForceGetColumnInfo(tableInfo.Columns[2].ID).GetCollate()) 404 require.Equal(t, columns[2].Flag, *tableInfo.ForceGetColumnFlagType(tableInfo.Columns[2].ID)) 405 } 406 407 func TestBuildTiDBTableInfoWithCommonPrimaryKey(t *testing.T) { 408 columns := []*Column{{ 409 Name: "a1", 410 Type: mysql.TypeLong, 411 Flag: BinaryFlag | PrimaryKeyFlag | UniqueKeyFlag | HandleKeyFlag | MultipleKeyFlag, 412 }, { 413 Name: "a2", 414 Type: mysql.TypeTinyBlob, 415 Charset: charset.CharsetLatin1, 416 Flag: UniqueKeyFlag | UnsignedFlag | MultipleKeyFlag, 417 }, { 418 Name: "a4", 419 Type: mysql.TypeVarchar, 420 Flag: PrimaryKeyFlag | UniqueKeyFlag | HandleKeyFlag | MultipleKeyFlag, 421 }, { 422 Name: "a9", 423 Type: mysql.TypeLong, 424 Flag: NullableFlag | UnsignedFlag, 425 }} 426 tidbTableInfo := BuildTiDBTableInfo("t", columns, [][]int{{0, 2}, {0, 1}, {2}}) 427 tableInfo := WrapTableInfo(100, "test", 1000, tidbTableInfo) 428 require.Equal(t, "test", tableInfo.TableName.Schema) 429 require.Equal(t, "t", tableInfo.TableName.Table) 430 require.Equal(t, 4, len(tableInfo.columnsOffset)) 431 require.Equal(t, 3, len(tableInfo.indicesOffset)) 432 require.Equal(t, 4, len(tableInfo.Columns)) 433 434 require.Equal(t, tableInfo.Columns[0].ID, tableInfo.ForceGetColumnIDByName("a1")) 435 require.Equal(t, columns[0].Name, tableInfo.ForceGetColumnName(tableInfo.Columns[0].ID)) 436 require.Equal(t, columns[0].Type, tableInfo.ForceGetColumnInfo(tableInfo.Columns[0].ID).GetType()) 437 require.Equal(t, "binary", tableInfo.ForceGetColumnInfo(tableInfo.Columns[0].ID).GetCharset()) 438 require.Equal(t, mysql.UTF8MB4DefaultCollation, tableInfo.ForceGetColumnInfo(tableInfo.Columns[0].ID).GetCollate()) 439 require.Equal(t, columns[0].Flag, *tableInfo.ForceGetColumnFlagType(tableInfo.Columns[0].ID)) 440 441 require.Equal(t, columns[1].Name, tableInfo.ForceGetColumnName(tableInfo.Columns[1].ID)) 442 require.Equal(t, columns[1].Type, tableInfo.ForceGetColumnInfo(tableInfo.Columns[1].ID).GetType()) 443 require.Equal(t, charset.CharsetLatin1, tableInfo.ForceGetColumnInfo(tableInfo.Columns[1].ID).GetCharset()) 444 require.Equal(t, mysql.UTF8MB4DefaultCollation, tableInfo.ForceGetColumnInfo(tableInfo.Columns[1].ID).GetCollate()) 445 require.Equal(t, columns[1].Flag, *tableInfo.ForceGetColumnFlagType(tableInfo.Columns[1].ID)) 446 447 require.Equal(t, columns[2].Name, tableInfo.ForceGetColumnName(tableInfo.Columns[2].ID)) 448 require.Equal(t, columns[2].Type, tableInfo.ForceGetColumnInfo(tableInfo.Columns[2].ID).GetType()) 449 require.Equal(t, mysql.UTF8MB4Charset, tableInfo.ForceGetColumnInfo(tableInfo.Columns[2].ID).GetCharset()) 450 require.Equal(t, mysql.UTF8MB4DefaultCollation, tableInfo.ForceGetColumnInfo(tableInfo.Columns[2].ID).GetCollate()) 451 require.Equal(t, columns[2].Flag, *tableInfo.ForceGetColumnFlagType(tableInfo.Columns[2].ID)) 452 453 require.Equal(t, columns[3].Name, tableInfo.ForceGetColumnName(tableInfo.Columns[3].ID)) 454 require.Equal(t, columns[3].Type, tableInfo.ForceGetColumnInfo(tableInfo.Columns[3].ID).GetType()) 455 require.Equal(t, mysql.UTF8MB4Charset, tableInfo.ForceGetColumnInfo(tableInfo.Columns[3].ID).GetCharset()) 456 require.Equal(t, mysql.UTF8MB4DefaultCollation, tableInfo.ForceGetColumnInfo(tableInfo.Columns[3].ID).GetCollate()) 457 require.Equal(t, columns[3].Flag, *tableInfo.ForceGetColumnFlagType(tableInfo.Columns[3].ID)) 458 } 459 460 func TestBuildTiDBTableInfoWithUniqueKey(t *testing.T) { 461 columns := []*Column{{ 462 Name: "a1", 463 Type: mysql.TypeLong, 464 Flag: BinaryFlag | UniqueKeyFlag | HandleKeyFlag | MultipleKeyFlag, 465 }, { 466 Name: "a2", 467 Type: mysql.TypeTinyBlob, 468 Charset: charset.CharsetLatin1, 469 Flag: UniqueKeyFlag | MultipleKeyFlag, 470 }, { 471 Name: "a4", 472 Type: mysql.TypeVarchar, 473 Flag: UniqueKeyFlag | HandleKeyFlag | MultipleKeyFlag, 474 }, { 475 Name: "a9", 476 Type: mysql.TypeLong, 477 Flag: UnsignedFlag | UniqueKeyFlag | MultipleKeyFlag, 478 }} 479 tidbTableInfo := BuildTiDBTableInfo("t", columns, [][]int{{0, 2}, {1, 3}}) 480 tableInfo := WrapTableInfo(100, "test", 1000, tidbTableInfo) 481 require.Equal(t, "test", tableInfo.TableName.Schema) 482 require.Equal(t, "t", tableInfo.TableName.Table) 483 require.Equal(t, 4, len(tableInfo.columnsOffset)) 484 require.Equal(t, 2, len(tableInfo.indicesOffset)) 485 require.Equal(t, 4, len(tableInfo.Columns)) 486 487 require.Equal(t, tableInfo.Columns[0].ID, tableInfo.ForceGetColumnIDByName("a1")) 488 require.Equal(t, columns[0].Name, tableInfo.ForceGetColumnName(tableInfo.Columns[0].ID)) 489 require.Equal(t, columns[0].Type, tableInfo.ForceGetColumnInfo(tableInfo.Columns[0].ID).GetType()) 490 require.Equal(t, "binary", tableInfo.ForceGetColumnInfo(tableInfo.Columns[0].ID).GetCharset()) 491 require.Equal(t, mysql.UTF8MB4DefaultCollation, tableInfo.ForceGetColumnInfo(tableInfo.Columns[0].ID).GetCollate()) 492 require.Equal(t, columns[0].Flag, *tableInfo.ForceGetColumnFlagType(tableInfo.Columns[0].ID)) 493 494 require.Equal(t, columns[1].Name, tableInfo.ForceGetColumnName(tableInfo.Columns[1].ID)) 495 require.Equal(t, columns[1].Type, tableInfo.ForceGetColumnInfo(tableInfo.Columns[1].ID).GetType()) 496 require.Equal(t, charset.CharsetLatin1, tableInfo.ForceGetColumnInfo(tableInfo.Columns[1].ID).GetCharset()) 497 require.Equal(t, mysql.UTF8MB4DefaultCollation, tableInfo.ForceGetColumnInfo(tableInfo.Columns[1].ID).GetCollate()) 498 require.Equal(t, columns[1].Flag, *tableInfo.ForceGetColumnFlagType(tableInfo.Columns[1].ID)) 499 500 require.Equal(t, columns[2].Name, tableInfo.ForceGetColumnName(tableInfo.Columns[2].ID)) 501 require.Equal(t, columns[2].Type, tableInfo.ForceGetColumnInfo(tableInfo.Columns[2].ID).GetType()) 502 require.Equal(t, mysql.UTF8MB4Charset, tableInfo.ForceGetColumnInfo(tableInfo.Columns[2].ID).GetCharset()) 503 require.Equal(t, mysql.UTF8MB4DefaultCollation, tableInfo.ForceGetColumnInfo(tableInfo.Columns[2].ID).GetCollate()) 504 require.Equal(t, columns[2].Flag, *tableInfo.ForceGetColumnFlagType(tableInfo.Columns[2].ID)) 505 506 require.Equal(t, columns[3].Name, tableInfo.ForceGetColumnName(tableInfo.Columns[3].ID)) 507 require.Equal(t, columns[3].Type, tableInfo.ForceGetColumnInfo(tableInfo.Columns[3].ID).GetType()) 508 require.Equal(t, mysql.UTF8MB4Charset, tableInfo.ForceGetColumnInfo(tableInfo.Columns[3].ID).GetCharset()) 509 require.Equal(t, mysql.UTF8MB4DefaultCollation, tableInfo.ForceGetColumnInfo(tableInfo.Columns[3].ID).GetCollate()) 510 require.Equal(t, columns[3].Flag, *tableInfo.ForceGetColumnFlagType(tableInfo.Columns[3].ID)) 511 } 512 513 func TestBuildTiDBTableInfoWithoutVirtualColumns(t *testing.T) { 514 t.Parallel() 515 ftNull := parser_types.NewFieldType(mysql.TypeUnspecified) 516 ftNull.SetFlag(mysql.NotNullFlag) 517 518 ftNotNull := parser_types.NewFieldType(mysql.TypeUnspecified) 519 ftNotNull.SetFlag(mysql.NotNullFlag | mysql.MultipleKeyFlag) 520 521 tableInfo := timodel.TableInfo{ 522 Columns: []*timodel.ColumnInfo{ 523 { 524 Name: timodel.CIStr{O: "a"}, 525 FieldType: *ftNotNull, 526 State: timodel.StatePublic, 527 }, 528 { 529 Name: timodel.CIStr{O: "b"}, 530 FieldType: *ftNotNull, 531 State: timodel.StatePublic, 532 }, 533 { 534 Name: timodel.CIStr{O: "c"}, 535 FieldType: *ftNull, 536 State: timodel.StatePublic, 537 GeneratedExprString: "as d", 538 GeneratedStored: false, 539 }, 540 { 541 Name: timodel.CIStr{O: "d"}, 542 FieldType: *ftNotNull, 543 State: timodel.StatePublic, 544 }, 545 }, 546 Indices: []*timodel.IndexInfo{ 547 { 548 ID: 10, 549 Name: timodel.CIStr{ 550 O: "a,b", 551 }, 552 Columns: []*timodel.IndexColumn{ 553 {Name: timodel.CIStr{O: "a"}, Offset: 0}, 554 {Name: timodel.CIStr{O: "b"}, Offset: 1}, 555 }, 556 Unique: true, 557 }, 558 { 559 ID: 9, 560 Name: timodel.CIStr{ 561 O: "c", 562 }, 563 Columns: []*timodel.IndexColumn{ 564 {Name: timodel.CIStr{O: "c"}, Offset: 2}, 565 }, 566 Unique: true, 567 }, 568 { 569 ID: 8, 570 Name: timodel.CIStr{ 571 O: "b", 572 }, 573 Columns: []*timodel.IndexColumn{ 574 {Name: timodel.CIStr{O: "b"}, Offset: 1}, 575 }, 576 Unique: true, 577 }, 578 { 579 ID: 7, 580 Name: timodel.CIStr{ 581 O: "d", 582 }, 583 Columns: []*timodel.IndexColumn{ 584 {Name: timodel.CIStr{O: "d"}, Offset: 3}, 585 }, 586 Unique: true, 587 }, 588 }, 589 IsCommonHandle: false, 590 PKIsHandle: false, 591 } 592 infoWithourVirtualCols := BuildTiDBTableInfoWithoutVirtualColumns(&tableInfo) 593 require.Equal(t, 3, len(infoWithourVirtualCols.Columns)) 594 require.Equal(t, 0, infoWithourVirtualCols.Columns[0].Offset) 595 require.Equal(t, "a", infoWithourVirtualCols.Columns[0].Name.O) 596 require.Equal(t, 1, infoWithourVirtualCols.Columns[1].Offset) 597 require.Equal(t, "b", infoWithourVirtualCols.Columns[1].Name.O) 598 require.Equal(t, 2, infoWithourVirtualCols.Columns[2].Offset) 599 require.Equal(t, "d", infoWithourVirtualCols.Columns[2].Name.O) 600 }