github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/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  	"github.com/pingcap/check"
    18  	timodel "github.com/pingcap/parser/model"
    19  	"github.com/pingcap/parser/mysql"
    20  	parser_types "github.com/pingcap/parser/types"
    21  	"github.com/pingcap/ticdc/pkg/util/testleak"
    22  )
    23  
    24  type schemaStorageSuite struct{}
    25  
    26  var _ = check.Suite(&schemaStorageSuite{})
    27  
    28  func (s *schemaStorageSuite) TestPKShouldBeInTheFirstPlaceWhenPKIsNotHandle(c *check.C) {
    29  	defer testleak.AfterTest(c)()
    30  	t := timodel.TableInfo{
    31  		Columns: []*timodel.ColumnInfo{
    32  			{
    33  				Name: timodel.CIStr{O: "group"},
    34  				FieldType: parser_types.FieldType{
    35  					Flag: mysql.NotNullFlag,
    36  				},
    37  				State: timodel.StatePublic,
    38  			},
    39  			{
    40  				Name: timodel.CIStr{O: "name"},
    41  				FieldType: parser_types.FieldType{
    42  					Flag: mysql.NotNullFlag,
    43  				},
    44  				State: timodel.StatePublic,
    45  			},
    46  			{
    47  				Name:  timodel.CIStr{O: "id"},
    48  				State: timodel.StatePublic,
    49  			},
    50  		},
    51  		Indices: []*timodel.IndexInfo{
    52  			{
    53  				Name: timodel.CIStr{
    54  					O: "group",
    55  				},
    56  				Columns: []*timodel.IndexColumn{
    57  					{
    58  						Name:   timodel.CIStr{O: "group"},
    59  						Offset: 0,
    60  					},
    61  				},
    62  				Unique: false,
    63  			},
    64  			{
    65  				Name: timodel.CIStr{
    66  					O: "name",
    67  				},
    68  				Columns: []*timodel.IndexColumn{
    69  					{
    70  						Name:   timodel.CIStr{O: "name"},
    71  						Offset: 0,
    72  					},
    73  				},
    74  				Unique: true,
    75  			},
    76  			{
    77  				Name: timodel.CIStr{
    78  					O: "PRIMARY",
    79  				},
    80  				Columns: []*timodel.IndexColumn{
    81  					{
    82  						Name:   timodel.CIStr{O: "id"},
    83  						Offset: 1,
    84  					},
    85  				},
    86  				Primary: true,
    87  			},
    88  		},
    89  		IsCommonHandle: true,
    90  		PKIsHandle:     false,
    91  	}
    92  	info := WrapTableInfo(1, "", 0, &t)
    93  	cols := info.GetUniqueKeys()
    94  	c.Assert(cols, check.DeepEquals, [][]string{
    95  		{"id"}, {"name"},
    96  	})
    97  }
    98  
    99  func (s *schemaStorageSuite) TestPKShouldBeInTheFirstPlaceWhenPKIsHandle(c *check.C) {
   100  	defer testleak.AfterTest(c)()
   101  	t := timodel.TableInfo{
   102  		Indices: []*timodel.IndexInfo{
   103  			{
   104  				Name: timodel.CIStr{
   105  					O: "uniq_job",
   106  				},
   107  				Columns: []*timodel.IndexColumn{
   108  					{Name: timodel.CIStr{O: "job"}},
   109  				},
   110  				Unique: true,
   111  			},
   112  		},
   113  		Columns: []*timodel.ColumnInfo{
   114  			{
   115  				Name: timodel.CIStr{
   116  					O: "job",
   117  				},
   118  				FieldType: parser_types.FieldType{
   119  					Flag: mysql.NotNullFlag,
   120  				},
   121  				State: timodel.StatePublic,
   122  			},
   123  			{
   124  				Name: timodel.CIStr{
   125  					O: "uid",
   126  				},
   127  				FieldType: parser_types.FieldType{
   128  					Flag: mysql.PriKeyFlag,
   129  				},
   130  				State: timodel.StatePublic,
   131  			},
   132  		},
   133  		PKIsHandle: true,
   134  	}
   135  	info := WrapTableInfo(1, "", 0, &t)
   136  	cols := info.GetUniqueKeys()
   137  	c.Assert(cols, check.DeepEquals, [][]string{
   138  		{"uid"}, {"job"},
   139  	})
   140  }
   141  
   142  func (s *schemaStorageSuite) TestUniqueKeyIsHandle(c *check.C) {
   143  	defer testleak.AfterTest(c)()
   144  	t := timodel.TableInfo{
   145  		Columns: []*timodel.ColumnInfo{
   146  			{
   147  				Name: timodel.CIStr{O: "group"},
   148  				FieldType: parser_types.FieldType{
   149  					Flag: mysql.NotNullFlag,
   150  				},
   151  				State: timodel.StatePublic,
   152  			},
   153  			{
   154  				Name: timodel.CIStr{O: "name"},
   155  				FieldType: parser_types.FieldType{
   156  					Flag: mysql.NotNullFlag,
   157  				},
   158  				State: timodel.StatePublic,
   159  			},
   160  		},
   161  		Indices: []*timodel.IndexInfo{
   162  			{
   163  				Name: timodel.CIStr{
   164  					O: "group",
   165  				},
   166  				Columns: []*timodel.IndexColumn{
   167  					{
   168  						Name:   timodel.CIStr{O: "group"},
   169  						Offset: 0,
   170  					},
   171  				},
   172  				Unique: false,
   173  			},
   174  			{
   175  				Name: timodel.CIStr{
   176  					O: "name",
   177  				},
   178  				Columns: []*timodel.IndexColumn{
   179  					{
   180  						Name:   timodel.CIStr{O: "name"},
   181  						Offset: 0,
   182  					},
   183  				},
   184  				Unique: true,
   185  			},
   186  		},
   187  		IsCommonHandle: false,
   188  		PKIsHandle:     false,
   189  	}
   190  	info := WrapTableInfo(1, "", 0, &t)
   191  	cols := info.GetUniqueKeys()
   192  	c.Assert(cols, check.DeepEquals, [][]string{{"name"}})
   193  }
   194  
   195  func (s *schemaStorageSuite) TestHandleKeyPriority(c *check.C) {
   196  	defer testleak.AfterTest(c)()
   197  	t := timodel.TableInfo{
   198  		Columns: []*timodel.ColumnInfo{
   199  			{
   200  				Name: timodel.CIStr{O: "a"},
   201  				FieldType: parser_types.FieldType{
   202  					Flag: mysql.NotNullFlag | mysql.MultipleKeyFlag,
   203  				},
   204  				State: timodel.StatePublic,
   205  			},
   206  			{
   207  				Name: timodel.CIStr{O: "b"},
   208  				FieldType: parser_types.FieldType{
   209  					Flag: mysql.NotNullFlag | mysql.MultipleKeyFlag,
   210  				},
   211  				State: timodel.StatePublic,
   212  			},
   213  			{
   214  				Name: timodel.CIStr{O: "c"},
   215  				FieldType: parser_types.FieldType{
   216  					Flag: mysql.NotNullFlag | mysql.UniqueKeyFlag,
   217  				},
   218  				State: timodel.StatePublic,
   219  			},
   220  			{
   221  				Name:      timodel.CIStr{O: "d"},
   222  				FieldType: parser_types.FieldType{
   223  					// test not null unique index
   224  					// Flag: mysql.NotNullFlag,
   225  				},
   226  				State: timodel.StatePublic,
   227  			},
   228  			{
   229  				Name: timodel.CIStr{O: "e"},
   230  				FieldType: parser_types.FieldType{
   231  					Flag: mysql.NotNullFlag,
   232  				},
   233  				State: timodel.StatePublic,
   234  				// test virtual generated column is not treated as unique key
   235  				GeneratedExprString: "as d",
   236  				GeneratedStored:     false,
   237  			},
   238  		},
   239  		Indices: []*timodel.IndexInfo{
   240  			{
   241  				ID: 10,
   242  				Name: timodel.CIStr{
   243  					O: "a,b",
   244  				},
   245  				Columns: []*timodel.IndexColumn{
   246  					{Name: timodel.CIStr{O: "a"}, Offset: 0},
   247  					{Name: timodel.CIStr{O: "b"}, Offset: 1},
   248  				},
   249  				Unique: true,
   250  			},
   251  			{
   252  				ID: 9,
   253  				Name: timodel.CIStr{
   254  					O: "c",
   255  				},
   256  				Columns: []*timodel.IndexColumn{
   257  					{Name: timodel.CIStr{O: "c"}, Offset: 2},
   258  				},
   259  				Unique: true,
   260  			},
   261  			{
   262  				ID: 8,
   263  				Name: timodel.CIStr{
   264  					O: "b",
   265  				},
   266  				Columns: []*timodel.IndexColumn{
   267  					{Name: timodel.CIStr{O: "b"}, Offset: 1},
   268  				},
   269  				Unique: true,
   270  			},
   271  			{
   272  				ID: 7,
   273  				Name: timodel.CIStr{
   274  					O: "d",
   275  				},
   276  				Columns: []*timodel.IndexColumn{
   277  					{Name: timodel.CIStr{O: "d"}, Offset: 3},
   278  				},
   279  				Unique: true,
   280  			},
   281  			{
   282  				ID: 6,
   283  				Name: timodel.CIStr{
   284  					O: "e",
   285  				},
   286  				Columns: []*timodel.IndexColumn{
   287  					{Name: timodel.CIStr{O: "e"}, Offset: 4},
   288  				},
   289  				Unique: true,
   290  			},
   291  		},
   292  		IsCommonHandle: false,
   293  		PKIsHandle:     false,
   294  	}
   295  	info := WrapTableInfo(1, "", 0, &t)
   296  	cols := info.GetUniqueKeys()
   297  	c.Assert(info.HandleIndexID, check.Equals, int64(8))
   298  	c.Assert(cols, check.DeepEquals, [][]string{{"a", "b"}, {"c"}, {"b"}})
   299  }
   300  
   301  func (s *schemaStorageSuite) TestTableInfoGetterFuncs(c *check.C) {
   302  	defer testleak.AfterTest(c)()
   303  	t := timodel.TableInfo{
   304  		ID:   1071,
   305  		Name: timodel.CIStr{O: "t1"},
   306  		Columns: []*timodel.ColumnInfo{
   307  			{
   308  				ID:   0,
   309  				Name: timodel.CIStr{O: "a"},
   310  				FieldType: parser_types.FieldType{
   311  					// test binary flag
   312  					Flag:    mysql.NotNullFlag | mysql.BinaryFlag,
   313  					Charset: "binary",
   314  				},
   315  				State: timodel.StatePublic,
   316  			},
   317  			{
   318  				ID:   1,
   319  				Name: timodel.CIStr{O: "b"},
   320  				FieldType: parser_types.FieldType{
   321  					// test unsigned flag
   322  					Flag: mysql.NotNullFlag | mysql.UnsignedFlag,
   323  				},
   324  				State: timodel.StatePublic,
   325  			},
   326  			{
   327  				ID:   2,
   328  				Name: timodel.CIStr{O: "c"},
   329  				FieldType: parser_types.FieldType{
   330  					Flag: mysql.NotNullFlag,
   331  				},
   332  				State: timodel.StatePublic,
   333  			},
   334  		},
   335  		Indices: []*timodel.IndexInfo{
   336  			{
   337  				ID: 0,
   338  				Name: timodel.CIStr{
   339  					O: "c",
   340  				},
   341  				Columns: []*timodel.IndexColumn{
   342  					{Name: timodel.CIStr{O: "c"}, Offset: 2},
   343  				},
   344  				Unique: true,
   345  			},
   346  		},
   347  		IsCommonHandle: false,
   348  		PKIsHandle:     false,
   349  	}
   350  	info := WrapTableInfo(1, "test", 0, &t)
   351  
   352  	col, exists := info.GetColumnInfo(2)
   353  	c.Assert(exists, check.IsTrue)
   354  	c.Assert(col.Name.O, check.Equals, "c")
   355  	_, exists = info.GetColumnInfo(4)
   356  	c.Assert(exists, check.IsFalse)
   357  
   358  	c.Assert(info.String(), check.Equals, "TableInfo, ID: 1071, Name:test.t1, ColNum: 3, IdxNum: 1, PKIsHandle: false")
   359  
   360  	idx, exists := info.GetIndexInfo(0)
   361  	c.Assert(exists, check.IsTrue)
   362  	c.Assert(idx.Name.O, check.Equals, "c")
   363  	_, exists = info.GetIndexInfo(1)
   364  	c.Assert(exists, check.IsFalse)
   365  
   366  	handleColIDs, fts, colInfos := info.GetRowColInfos()
   367  	c.Assert(handleColIDs, check.DeepEquals, []int64{-1})
   368  	c.Assert(len(fts), check.Equals, 3)
   369  	c.Assert(len(colInfos), check.Equals, 3)
   370  
   371  	c.Assert(info.IsColumnUnique(0), check.IsFalse)
   372  	c.Assert(info.IsColumnUnique(2), check.IsTrue)
   373  	c.Assert(info.ExistTableUniqueColumn(), check.IsTrue)
   374  
   375  	// check IsEligible
   376  	c.Assert(info.IsEligible(false), check.IsTrue)
   377  	t = timodel.TableInfo{
   378  		ID:   1073,
   379  		Name: timodel.CIStr{O: "t2"},
   380  		Columns: []*timodel.ColumnInfo{
   381  			{
   382  				ID:        0,
   383  				Name:      timodel.CIStr{O: "a"},
   384  				FieldType: parser_types.FieldType{},
   385  				State:     timodel.StatePublic,
   386  			},
   387  		},
   388  		Indices: []*timodel.IndexInfo{
   389  			{
   390  				ID:   0,
   391  				Name: timodel.CIStr{O: "a"},
   392  				Columns: []*timodel.IndexColumn{
   393  					{Name: timodel.CIStr{O: "a"}, Offset: 0},
   394  				},
   395  				Unique: true,
   396  			},
   397  		},
   398  		IsCommonHandle: false,
   399  		PKIsHandle:     false,
   400  	}
   401  	info = WrapTableInfo(1, "test", 0, &t)
   402  	c.Assert(info.IsEligible(false), check.IsFalse)
   403  	c.Assert(info.IsEligible(true), check.IsTrue)
   404  	t.View = &timodel.ViewInfo{}
   405  	info = WrapTableInfo(1, "test", 0, &t)
   406  	c.Assert(info.IsEligible(false), check.IsTrue)
   407  }
   408  
   409  func (s *schemaStorageSuite) TestTableInfoClone(c *check.C) {
   410  	defer testleak.AfterTest(c)()
   411  	t := timodel.TableInfo{
   412  		ID:   1071,
   413  		Name: timodel.CIStr{O: "t1"},
   414  		Columns: []*timodel.ColumnInfo{
   415  			{
   416  				ID:   0,
   417  				Name: timodel.CIStr{O: "c"},
   418  				FieldType: parser_types.FieldType{
   419  					Flag: mysql.NotNullFlag,
   420  				},
   421  				State: timodel.StatePublic,
   422  			},
   423  		},
   424  		Indices: []*timodel.IndexInfo{
   425  			{
   426  				ID: 0,
   427  				Name: timodel.CIStr{
   428  					O: "c",
   429  				},
   430  				Columns: []*timodel.IndexColumn{
   431  					{Name: timodel.CIStr{O: "c"}, Offset: 0},
   432  				},
   433  				Unique: true,
   434  			},
   435  		},
   436  	}
   437  	info := WrapTableInfo(10, "test", 0, &t)
   438  	cloned := info.Clone()
   439  	c.Assert(cloned.SchemaID, check.Equals, info.SchemaID)
   440  	cloned.SchemaID = 100
   441  	c.Assert(info.SchemaID, check.Equals, int64(10))
   442  }