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  }