github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/cdc/entry/schema_test.go (about)

     1  // Copyright 2021 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 entry
    15  
    16  import (
    17  	"context"
    18  	"encoding/json"
    19  	"fmt"
    20  	"sort"
    21  	"testing"
    22  
    23  	timodel "github.com/pingcap/tidb/pkg/parser/model"
    24  	"github.com/pingcap/tidb/pkg/parser/mysql"
    25  	"github.com/pingcap/tidb/pkg/parser/types"
    26  	"github.com/pingcap/tiflow/cdc/model"
    27  	"github.com/pingcap/tiflow/pkg/config"
    28  	"github.com/pingcap/tiflow/pkg/filter"
    29  	"github.com/pingcap/tiflow/pkg/util"
    30  	"github.com/stretchr/testify/require"
    31  	"github.com/tikv/client-go/v2/oracle"
    32  )
    33  
    34  func TestAllPhysicalTables(t *testing.T) {
    35  	helper := NewSchemaTestHelper(t)
    36  	defer helper.Close()
    37  	ver, err := helper.Storage().CurrentVersion(oracle.GlobalTxnScope)
    38  	require.Nil(t, err)
    39  	f, err := filter.NewFilter(config.GetDefaultReplicaConfig(), "")
    40  	require.Nil(t, err)
    41  	schema, err := NewSchemaStorage(helper.Storage(), ver.Ver,
    42  		false, dummyChangeFeedID, util.RoleTester, f)
    43  	require.Nil(t, err)
    44  	tableIDs, err := schema.AllPhysicalTables(context.Background(), ver.Ver)
    45  	require.Nil(t, err)
    46  	require.Len(t, tableIDs, 0)
    47  	// add normal table
    48  	job := helper.DDL2Job("create table test.t1(id int primary key)")
    49  	tableIDT1 := job.BinlogInfo.TableInfo.ID
    50  	require.Nil(t, schema.HandleDDLJob(job))
    51  	tableIDs, err = schema.AllPhysicalTables(context.Background(), job.BinlogInfo.FinishedTS)
    52  	require.Nil(t, err)
    53  	require.Equal(t, tableIDs, []model.TableID{tableIDT1})
    54  	// add ineligible table
    55  	job = helper.DDL2Job("create table test.t2(id int)")
    56  	require.Nil(t, schema.HandleDDLJob(job))
    57  	tableIDs, err = schema.AllPhysicalTables(context.Background(), job.BinlogInfo.FinishedTS)
    58  	require.Nil(t, err)
    59  	require.Equal(t, tableIDs, []model.TableID{tableIDT1})
    60  	// add partition table
    61  	job = helper.DDL2Job(`CREATE TABLE test.employees  (
    62  			id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    63  			fname VARCHAR(25) NOT NULL,
    64  			lname VARCHAR(25) NOT NULL,
    65  			store_id INT NOT NULL,
    66  			department_id INT NOT NULL
    67  		)
    68  
    69  		PARTITION BY RANGE(id)  (
    70  			PARTITION p0 VALUES LESS THAN (5),
    71  			PARTITION p1 VALUES LESS THAN (10),
    72  			PARTITION p2 VALUES LESS THAN (15),
    73  			PARTITION p3 VALUES LESS THAN (20)
    74  		)`)
    75  	require.Nil(t, schema.HandleDDLJob(job))
    76  	expectedTableIDs := []model.TableID{tableIDT1}
    77  	for _, p := range job.BinlogInfo.TableInfo.GetPartitionInfo().Definitions {
    78  		expectedTableIDs = append(expectedTableIDs, p.ID)
    79  	}
    80  	sortTableIDs := func(tableIDs []model.TableID) {
    81  		sort.Slice(tableIDs, func(i, j int) bool {
    82  			return tableIDs[i] < tableIDs[j]
    83  		})
    84  	}
    85  	sortTableIDs(expectedTableIDs)
    86  	tableIDs, err = schema.AllPhysicalTables(context.Background(), job.BinlogInfo.FinishedTS)
    87  	require.Nil(t, err)
    88  	sortTableIDs(tableIDs)
    89  	require.Equal(t, tableIDs, expectedTableIDs)
    90  }
    91  
    92  func TestAllTables(t *testing.T) {
    93  	helper := NewSchemaTestHelper(t)
    94  	defer helper.Close()
    95  	ver, err := helper.Storage().CurrentVersion(oracle.GlobalTxnScope)
    96  	require.Nil(t, err)
    97  	f, err := filter.NewFilter(config.GetDefaultReplicaConfig(), "")
    98  	require.Nil(t, err)
    99  	schema, err := NewSchemaStorage(helper.Storage(), ver.Ver,
   100  		false, dummyChangeFeedID, util.RoleTester, f)
   101  	require.Nil(t, err)
   102  	tableInfos, err := schema.AllTables(context.Background(), ver.Ver)
   103  	require.Nil(t, err)
   104  	require.Len(t, tableInfos, 0)
   105  	// add normal table
   106  	job := helper.DDL2Job("create table test.t1(id int primary key)")
   107  	require.Nil(t, schema.HandleDDLJob(job))
   108  	tableInfos, err = schema.AllTables(context.Background(), job.BinlogInfo.FinishedTS)
   109  	require.Nil(t, err)
   110  	require.Len(t, tableInfos, 1)
   111  	tableName := tableInfos[0].TableName
   112  	require.Equal(t, model.TableName{
   113  		Schema:  "test",
   114  		Table:   "t1",
   115  		TableID: 104,
   116  	}, tableName)
   117  	// add ineligible table
   118  	job = helper.DDL2Job("create table test.t2(id int)")
   119  	require.Nil(t, schema.HandleDDLJob(job))
   120  	tableInfos, err = schema.AllTables(context.Background(), job.BinlogInfo.FinishedTS)
   121  	require.Nil(t, err)
   122  	require.Len(t, tableInfos, 1)
   123  	tableName = tableInfos[0].TableName
   124  	require.Equal(t, model.TableName{
   125  		Schema:  "test",
   126  		Table:   "t1",
   127  		TableID: 104,
   128  	}, tableName)
   129  }
   130  
   131  func TestIsIneligibleTableID(t *testing.T) {
   132  	helper := NewSchemaTestHelper(t)
   133  	defer helper.Close()
   134  	ver, err := helper.Storage().CurrentVersion(oracle.GlobalTxnScope)
   135  	require.Nil(t, err)
   136  	f, err := filter.NewFilter(config.GetDefaultReplicaConfig(), "")
   137  	require.Nil(t, err)
   138  	schema, err := NewSchemaStorage(helper.Storage(), ver.Ver,
   139  		false, dummyChangeFeedID, util.RoleTester, f)
   140  	require.Nil(t, err)
   141  	// add normal table
   142  	job := helper.DDL2Job("create table test.t1(id int primary key)")
   143  	tableIDT1 := job.BinlogInfo.TableInfo.ID
   144  	require.Nil(t, schema.HandleDDLJob(job))
   145  	// add ineligible table
   146  	job = helper.DDL2Job("create table test.t2(id int)")
   147  	tableIDT2 := job.BinlogInfo.TableInfo.ID
   148  
   149  	require.Nil(t, schema.HandleDDLJob(job))
   150  	ctx := context.Background()
   151  	ignore, err := schema.IsIneligibleTable(ctx, tableIDT1, job.BinlogInfo.FinishedTS)
   152  	require.Nil(t, err)
   153  	require.False(t, ignore)
   154  
   155  	ignore, err = schema.IsIneligibleTable(ctx, tableIDT2, job.BinlogInfo.FinishedTS)
   156  	require.Nil(t, err)
   157  	require.True(t, ignore)
   158  
   159  	// test we get the right snapshot to check ineligible table
   160  	job = helper.DDL2Job("create table test.t3(id int)")
   161  	tableIDT3 := job.BinlogInfo.TableInfo.ID
   162  	snapshotTsWithoutPK := job.BinlogInfo.FinishedTS
   163  	require.Nil(t, schema.HandleDDLJob(job))
   164  	job = helper.DDL2Job("alter table test.t3 add primary key(id)")
   165  	snapshotTsWithPK := job.BinlogInfo.FinishedTS
   166  	require.Nil(t, schema.HandleDDLJob(job))
   167  	// tableIDT3 is ineligible at snapshotTsWithoutPK
   168  	ignore, err = schema.IsIneligibleTable(ctx, tableIDT3, snapshotTsWithoutPK)
   169  	require.Nil(t, err)
   170  	require.True(t, ignore)
   171  	// tableIDT3 is eligible at snapshotTsWithPK
   172  	ignore, err = schema.IsIneligibleTable(ctx, tableIDT3, snapshotTsWithPK)
   173  	require.Nil(t, err)
   174  	require.False(t, ignore)
   175  }
   176  
   177  func compareEvents(t *testing.T, e1, e2 *model.DDLEvent) {
   178  	require.Equal(t, e1.StartTs, e2.StartTs)
   179  	require.Equal(t, e1.CommitTs, e2.CommitTs)
   180  	require.Equal(t, e1.Query, e2.Query)
   181  	require.Equal(t, e1.TableInfo.TableName, e2.TableInfo.TableName)
   182  	require.Equal(t, len(e1.TableInfo.TableInfo.Columns), len(e2.TableInfo.TableInfo.Columns))
   183  	for idx, col := range e1.TableInfo.TableInfo.Columns {
   184  		require.Equal(t, col.Name, e2.TableInfo.Columns[idx].Name)
   185  		require.Equal(t, col.FieldType.GetType(), e2.TableInfo.Columns[idx].FieldType.GetType())
   186  	}
   187  }
   188  
   189  func TestBuildDDLEventsFromSingleTableDDL(t *testing.T) {
   190  	helper := NewSchemaTestHelper(t)
   191  	defer helper.Close()
   192  	ver, err := helper.Storage().CurrentVersion(oracle.GlobalTxnScope)
   193  	require.Nil(t, err)
   194  	f, err := filter.NewFilter(config.GetDefaultReplicaConfig(), "")
   195  	require.Nil(t, err)
   196  	schema, err := NewSchemaStorage(helper.Storage(), ver.Ver,
   197  		false, dummyChangeFeedID, util.RoleTester, f)
   198  	require.Nil(t, err)
   199  	// add normal table
   200  	ctx := context.Background()
   201  	job := helper.DDL2Job("create table test.t1(id int primary key)")
   202  	schema.AdvanceResolvedTs(job.BinlogInfo.FinishedTS - 1)
   203  	events, err := schema.BuildDDLEvents(ctx, job)
   204  	require.Nil(t, err)
   205  	require.Len(t, events, 1)
   206  	compareEvents(t, events[0], &model.DDLEvent{
   207  		StartTs:  job.StartTS,
   208  		CommitTs: job.BinlogInfo.FinishedTS,
   209  		Query:    "create table test.t1(id int primary key)",
   210  		Type:     timodel.ActionCreateTable,
   211  		TableInfo: &model.TableInfo{
   212  			TableName: model.TableName{
   213  				Schema:  "test",
   214  				Table:   "t1",
   215  				TableID: job.TableID,
   216  			},
   217  			TableInfo: &timodel.TableInfo{
   218  				Columns: []*timodel.ColumnInfo{
   219  					{Name: timodel.NewCIStr("id"), FieldType: *types.NewFieldType(mysql.TypeLong)},
   220  				},
   221  			},
   222  		},
   223  		PreTableInfo: nil,
   224  	})
   225  	require.Nil(t, schema.HandleDDLJob(job))
   226  	job = helper.DDL2Job("ALTER TABLE test.t1 ADD COLUMN c1 CHAR(16) NOT NULL")
   227  	schema.AdvanceResolvedTs(job.BinlogInfo.FinishedTS - 1)
   228  	events, err = schema.BuildDDLEvents(ctx, job)
   229  	require.Nil(t, err)
   230  	require.Len(t, events, 1)
   231  	compareEvents(t, events[0], &model.DDLEvent{
   232  		StartTs:  job.StartTS,
   233  		CommitTs: job.BinlogInfo.FinishedTS,
   234  		Query:    "ALTER TABLE test.t1 ADD COLUMN c1 CHAR(16) NOT NULL",
   235  		Type:     timodel.ActionAddColumn,
   236  		TableInfo: &model.TableInfo{
   237  			TableName: model.TableName{
   238  				Schema:  "test",
   239  				Table:   "t1",
   240  				TableID: job.TableID,
   241  			},
   242  			TableInfo: &timodel.TableInfo{
   243  				Columns: []*timodel.ColumnInfo{
   244  					{Name: timodel.NewCIStr("id"), FieldType: *types.NewFieldType(mysql.TypeLong)},
   245  					{Name: timodel.NewCIStr("c1"), FieldType: *types.NewFieldType(mysql.TypeString)},
   246  				},
   247  			},
   248  		},
   249  		PreTableInfo: &model.TableInfo{
   250  			TableName: model.TableName{
   251  				Schema:  "test",
   252  				Table:   "t1",
   253  				TableID: job.TableID,
   254  			},
   255  			TableInfo: &timodel.TableInfo{
   256  				Columns: []*timodel.ColumnInfo{
   257  					{Name: timodel.NewCIStr("id"), FieldType: *types.NewFieldType(mysql.TypeLong)},
   258  				},
   259  			},
   260  		},
   261  	})
   262  }
   263  
   264  func TestBuildDDLEventsFromRenameTablesDDL(t *testing.T) {
   265  	helper := NewSchemaTestHelper(t)
   266  	defer helper.Close()
   267  
   268  	ver, err := helper.Storage().CurrentVersion(oracle.GlobalTxnScope)
   269  	require.Nil(t, err)
   270  	f, err := filter.NewFilter(config.GetDefaultReplicaConfig(), "")
   271  	require.Nil(t, err)
   272  	schema, err := NewSchemaStorage(helper.Storage(), ver.Ver,
   273  		false, dummyChangeFeedID, util.RoleTester, f)
   274  	require.Nil(t, err)
   275  	ctx := context.Background()
   276  	job := helper.DDL2Job("create database test1")
   277  	schema.AdvanceResolvedTs(job.BinlogInfo.FinishedTS - 1)
   278  	events, err := schema.BuildDDLEvents(ctx, job)
   279  	require.Nil(t, err)
   280  	require.Len(t, events, 1)
   281  	require.Nil(t, schema.HandleDDLJob(job))
   282  	schemaID := job.SchemaID
   283  	// add test.t1
   284  	job = helper.DDL2Job("create table test1.t1(id int primary key)")
   285  	schema.AdvanceResolvedTs(job.BinlogInfo.FinishedTS - 1)
   286  	events, err = schema.BuildDDLEvents(ctx, job)
   287  	require.Nil(t, err)
   288  	require.Len(t, events, 1)
   289  	require.Nil(t, schema.HandleDDLJob(job))
   290  	t1TableID := job.TableID
   291  
   292  	// add test.t2
   293  	job = helper.DDL2Job("create table test1.t2(id int primary key)")
   294  	schema.AdvanceResolvedTs(job.BinlogInfo.FinishedTS - 1)
   295  	events, err = schema.BuildDDLEvents(ctx, job)
   296  	require.Nil(t, err)
   297  	require.Len(t, events, 1)
   298  	require.Nil(t, schema.HandleDDLJob(job))
   299  	t2TableID := job.TableID
   300  
   301  	// rename test.t1 and test.t2
   302  	job = helper.DDL2Job(
   303  		"rename table test1.t1 to test1.t10, test1.t2 to test1.t20")
   304  	oldSchemaIDs := []int64{schemaID, schemaID}
   305  	oldTableIDs := []int64{t1TableID, t2TableID}
   306  	newSchemaIDs := oldSchemaIDs
   307  	oldSchemaNames := []timodel.CIStr{
   308  		timodel.NewCIStr("test1"),
   309  		timodel.NewCIStr("test1"),
   310  	}
   311  	newTableNames := []timodel.CIStr{
   312  		timodel.NewCIStr("t10"),
   313  		timodel.NewCIStr("t20"),
   314  	}
   315  	args := []interface{}{
   316  		oldSchemaIDs, newSchemaIDs,
   317  		newTableNames, oldTableIDs, oldSchemaNames,
   318  	}
   319  	rawArgs, err := json.Marshal(args)
   320  	require.Nil(t, err)
   321  	// the RawArgs field in job fetched from tidb snapshot meta is incorrent,
   322  	// so we manually construct `job.RawArgs` to do the workaround.
   323  	job.RawArgs = rawArgs
   324  	schema.AdvanceResolvedTs(job.BinlogInfo.FinishedTS - 1)
   325  	events, err = schema.BuildDDLEvents(ctx, job)
   326  	require.Nil(t, err)
   327  	require.Len(t, events, 2)
   328  	fmt.Printf("events[0]:%+v\n", events[0])
   329  	fmt.Printf("events[1]:%+v\n", events[1])
   330  	compareEvents(t, events[0], &model.DDLEvent{
   331  		StartTs:  job.StartTS,
   332  		CommitTs: job.BinlogInfo.FinishedTS,
   333  		Query:    "RENAME TABLE `test1`.`t1` TO `test1`.`t10`",
   334  		Type:     timodel.ActionRenameTable,
   335  		TableInfo: &model.TableInfo{
   336  			TableName: model.TableName{
   337  				Schema:  "test1",
   338  				Table:   "t10",
   339  				TableID: t1TableID,
   340  			},
   341  			TableInfo: &timodel.TableInfo{
   342  				Columns: []*timodel.ColumnInfo{
   343  					{Name: timodel.NewCIStr("id"), FieldType: *types.NewFieldType(mysql.TypeLong)},
   344  				},
   345  			},
   346  		},
   347  		PreTableInfo: &model.TableInfo{
   348  			TableName: model.TableName{
   349  				Schema:  "test1",
   350  				Table:   "t1",
   351  				TableID: t1TableID,
   352  			},
   353  			TableInfo: &timodel.TableInfo{
   354  				Columns: []*timodel.ColumnInfo{
   355  					{Name: timodel.NewCIStr("id"), FieldType: *types.NewFieldType(mysql.TypeLong)},
   356  				},
   357  			},
   358  		},
   359  	})
   360  	compareEvents(t, events[1], &model.DDLEvent{
   361  		StartTs:  job.StartTS,
   362  		CommitTs: job.BinlogInfo.FinishedTS,
   363  		Query:    "RENAME TABLE `test1`.`t2` TO `test1`.`t20`",
   364  		Type:     timodel.ActionRenameTable,
   365  		TableInfo: &model.TableInfo{
   366  			TableName: model.TableName{
   367  				Schema:  "test1",
   368  				Table:   "t20",
   369  				TableID: t2TableID,
   370  			},
   371  			TableInfo: &timodel.TableInfo{
   372  				Columns: []*timodel.ColumnInfo{
   373  					{Name: timodel.NewCIStr("id"), FieldType: *types.NewFieldType(mysql.TypeLong)},
   374  				},
   375  			},
   376  		},
   377  		PreTableInfo: &model.TableInfo{
   378  			TableName: model.TableName{
   379  				Schema:  "test1",
   380  				Table:   "t2",
   381  				TableID: t2TableID,
   382  			},
   383  			TableInfo: &timodel.TableInfo{
   384  				Columns: []*timodel.ColumnInfo{
   385  					{Name: timodel.NewCIStr("id"), FieldType: *types.NewFieldType(mysql.TypeLong)},
   386  				},
   387  			},
   388  		},
   389  	})
   390  }
   391  
   392  func TestBuildDDLEventsFromDropTablesDDL(t *testing.T) {
   393  	helper := NewSchemaTestHelper(t)
   394  	defer helper.Close()
   395  
   396  	ver, err := helper.Storage().CurrentVersion(oracle.GlobalTxnScope)
   397  	require.Nil(t, err)
   398  	f, err := filter.NewFilter(config.GetDefaultReplicaConfig(), "")
   399  	require.Nil(t, err)
   400  	schema, err := NewSchemaStorage(helper.Storage(), ver.Ver,
   401  		false, dummyChangeFeedID, util.RoleTester, f)
   402  	require.Nil(t, err)
   403  	// add test.t1
   404  	ctx := context.Background()
   405  	job := helper.DDL2Job("create table test.t1(id int primary key)")
   406  	schema.AdvanceResolvedTs(job.BinlogInfo.FinishedTS - 1)
   407  	events, err := schema.BuildDDLEvents(ctx, job)
   408  	require.Nil(t, err)
   409  	require.Len(t, events, 1)
   410  	require.Nil(t, schema.HandleDDLJob(job))
   411  
   412  	// add test.t2
   413  	job = helper.DDL2Job("create table test.t2(id int primary key)")
   414  	schema.AdvanceResolvedTs(job.BinlogInfo.FinishedTS - 1)
   415  	events, err = schema.BuildDDLEvents(ctx, job)
   416  	require.Nil(t, err)
   417  	require.Len(t, events, 1)
   418  	require.Nil(t, schema.HandleDDLJob(job))
   419  
   420  	jobs := helper.DDL2Jobs("drop table test.t1, test.t2", 2)
   421  	t1DropJob := jobs[1]
   422  	t2DropJob := jobs[0]
   423  	schema.AdvanceResolvedTs(t1DropJob.BinlogInfo.FinishedTS - 1)
   424  	events, err = schema.BuildDDLEvents(ctx, t1DropJob)
   425  	require.Nil(t, err)
   426  	require.Len(t, events, 1)
   427  	require.Nil(t, schema.HandleDDLJob(t1DropJob))
   428  	compareEvents(t, events[0], &model.DDLEvent{
   429  		StartTs:  t1DropJob.StartTS,
   430  		CommitTs: t1DropJob.BinlogInfo.FinishedTS,
   431  		Query:    "DROP TABLE `test`.`t1`",
   432  		Type:     timodel.ActionDropTable,
   433  		PreTableInfo: &model.TableInfo{
   434  			TableName: model.TableName{
   435  				Schema:  "test",
   436  				Table:   "t1",
   437  				TableID: t1DropJob.TableID,
   438  			},
   439  			TableInfo: &timodel.TableInfo{
   440  				Columns: []*timodel.ColumnInfo{
   441  					{Name: timodel.NewCIStr("id"), FieldType: *types.NewFieldType(mysql.TypeLong)},
   442  				},
   443  			},
   444  		},
   445  		TableInfo: &model.TableInfo{
   446  			TableName: model.TableName{
   447  				Schema:  "test",
   448  				Table:   "t1",
   449  				TableID: t1DropJob.TableID,
   450  			},
   451  			TableInfo: &timodel.TableInfo{
   452  				Columns: []*timodel.ColumnInfo{
   453  					{Name: timodel.NewCIStr("id"), FieldType: *types.NewFieldType(mysql.TypeLong)},
   454  				},
   455  			},
   456  		},
   457  	})
   458  	schema.AdvanceResolvedTs(t2DropJob.BinlogInfo.FinishedTS - 1)
   459  	events, err = schema.BuildDDLEvents(ctx, t2DropJob)
   460  	require.Nil(t, err)
   461  	require.Len(t, events, 1)
   462  	require.Nil(t, schema.HandleDDLJob(t2DropJob))
   463  	compareEvents(t, events[0], &model.DDLEvent{
   464  		StartTs:  t2DropJob.StartTS,
   465  		CommitTs: t2DropJob.BinlogInfo.FinishedTS,
   466  		Query:    "DROP TABLE `test`.`t2`",
   467  		Type:     timodel.ActionDropTable,
   468  		PreTableInfo: &model.TableInfo{
   469  			TableName: model.TableName{
   470  				Schema:  "test",
   471  				Table:   "t2",
   472  				TableID: t2DropJob.TableID,
   473  			},
   474  			TableInfo: &timodel.TableInfo{
   475  				Columns: []*timodel.ColumnInfo{
   476  					{Name: timodel.NewCIStr("id"), FieldType: *types.NewFieldType(mysql.TypeLong)},
   477  				},
   478  			},
   479  		},
   480  		TableInfo: &model.TableInfo{
   481  			TableName: model.TableName{
   482  				Schema:  "test",
   483  				Table:   "t2",
   484  				TableID: t2DropJob.TableID,
   485  			},
   486  			TableInfo: &timodel.TableInfo{
   487  				Columns: []*timodel.ColumnInfo{
   488  					{Name: timodel.NewCIStr("id"), FieldType: *types.NewFieldType(mysql.TypeLong)},
   489  				},
   490  			},
   491  		},
   492  	})
   493  }
   494  
   495  func TestBuildDDLEventsFromDropViewsDDL(t *testing.T) {
   496  	helper := NewSchemaTestHelper(t)
   497  	defer helper.Close()
   498  
   499  	ver, err := helper.Storage().CurrentVersion(oracle.GlobalTxnScope)
   500  	require.Nil(t, err)
   501  	f, err := filter.NewFilter(config.GetDefaultReplicaConfig(), "")
   502  	require.Nil(t, err)
   503  	schema, err := NewSchemaStorage(helper.Storage(), ver.Ver,
   504  		false, dummyChangeFeedID, util.RoleTester, f)
   505  	require.Nil(t, err)
   506  	ctx := context.Background()
   507  	// add test.tb1
   508  	job := helper.DDL2Job("create table test.tb1(id int primary key)")
   509  	schema.AdvanceResolvedTs(job.BinlogInfo.FinishedTS - 1)
   510  	events, err := schema.BuildDDLEvents(ctx, job)
   511  	require.Nil(t, err)
   512  	require.Len(t, events, 1)
   513  	require.Nil(t, schema.HandleDDLJob(job))
   514  
   515  	// add test.tb2
   516  	job = helper.DDL2Job("create table test.tb2(id int primary key)")
   517  	schema.AdvanceResolvedTs(job.BinlogInfo.FinishedTS - 1)
   518  	events, err = schema.BuildDDLEvents(ctx, job)
   519  	require.Nil(t, err)
   520  	require.Len(t, events, 1)
   521  	require.Nil(t, schema.HandleDDLJob(job))
   522  
   523  	// add test.view1
   524  	job = helper.DDL2Job(
   525  		"create view test.view1 as select * from test.tb1 where id > 100")
   526  	schema.AdvanceResolvedTs(job.BinlogInfo.FinishedTS - 1)
   527  	events, err = schema.BuildDDLEvents(ctx, job)
   528  	require.Nil(t, err)
   529  	require.Len(t, events, 1)
   530  	require.Nil(t, schema.HandleDDLJob(job))
   531  
   532  	// add test.view2
   533  	job = helper.DDL2Job(
   534  		"create view test.view2 as select * from test.tb2 where id > 100")
   535  	schema.AdvanceResolvedTs(job.BinlogInfo.FinishedTS - 1)
   536  	events, err = schema.BuildDDLEvents(ctx, job)
   537  	require.Nil(t, err)
   538  	require.Len(t, events, 1)
   539  	require.Nil(t, schema.HandleDDLJob(job))
   540  
   541  	jobs := helper.DDL2Jobs("drop view test.view1, test.view2", 2)
   542  	view1DropJob := jobs[1]
   543  	view2DropJob := jobs[0]
   544  	schema.AdvanceResolvedTs(view1DropJob.BinlogInfo.FinishedTS - 1)
   545  	events, err = schema.BuildDDLEvents(ctx, view1DropJob)
   546  	require.Nil(t, err)
   547  	require.Len(t, events, 1)
   548  	require.Nil(t, schema.HandleDDLJob(view1DropJob))
   549  	compareEvents(t, events[0], &model.DDLEvent{
   550  		StartTs:  view1DropJob.StartTS,
   551  		CommitTs: view1DropJob.BinlogInfo.FinishedTS,
   552  		Query:    "DROP VIEW `test`.`view1`",
   553  		Type:     timodel.ActionDropView,
   554  		PreTableInfo: &model.TableInfo{
   555  			TableName: model.TableName{
   556  				Schema:  "test",
   557  				Table:   "view1",
   558  				TableID: view1DropJob.TableID,
   559  			},
   560  			TableInfo: &timodel.TableInfo{
   561  				Columns: []*timodel.ColumnInfo{
   562  					{Name: timodel.NewCIStr("id"), FieldType: *types.NewFieldType(mysql.TypeUnspecified)},
   563  				},
   564  			},
   565  		},
   566  		TableInfo: &model.TableInfo{
   567  			TableName: model.TableName{
   568  				Schema:  "test",
   569  				Table:   "view1",
   570  				TableID: view1DropJob.TableID,
   571  			},
   572  			TableInfo: &timodel.TableInfo{
   573  				Columns: []*timodel.ColumnInfo{
   574  					{Name: timodel.NewCIStr("id"), FieldType: *types.NewFieldType(mysql.TypeUnspecified)},
   575  				},
   576  			},
   577  		},
   578  	})
   579  	schema.AdvanceResolvedTs(view2DropJob.BinlogInfo.FinishedTS - 1)
   580  	events, err = schema.BuildDDLEvents(ctx, view2DropJob)
   581  	require.Nil(t, err)
   582  	require.Len(t, events, 1)
   583  	require.Nil(t, schema.HandleDDLJob(view2DropJob))
   584  	compareEvents(t, events[0], &model.DDLEvent{
   585  		StartTs:  view2DropJob.StartTS,
   586  		CommitTs: view2DropJob.BinlogInfo.FinishedTS,
   587  		Query:    "DROP VIEW `test`.`view2`",
   588  		Type:     timodel.ActionDropView,
   589  		PreTableInfo: &model.TableInfo{
   590  			TableName: model.TableName{
   591  				Schema:  "test",
   592  				Table:   "view2",
   593  				TableID: view2DropJob.TableID,
   594  			},
   595  			TableInfo: &timodel.TableInfo{
   596  				Columns: []*timodel.ColumnInfo{
   597  					{Name: timodel.NewCIStr("id"), FieldType: *types.NewFieldType(mysql.TypeUnspecified)},
   598  				},
   599  			},
   600  		},
   601  		TableInfo: &model.TableInfo{
   602  			TableName: model.TableName{
   603  				Schema:  "test",
   604  				Table:   "view2",
   605  				TableID: view2DropJob.TableID,
   606  			},
   607  			TableInfo: &timodel.TableInfo{
   608  				Columns: []*timodel.ColumnInfo{
   609  					{Name: timodel.NewCIStr("id"), FieldType: *types.NewFieldType(mysql.TypeUnspecified)},
   610  				},
   611  			},
   612  		},
   613  	})
   614  }