github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/cdc/owner/ddl_sink_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 owner
    15  
    16  import (
    17  	"context"
    18  	"sync"
    19  	"sync/atomic"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/pingcap/errors"
    24  	"github.com/pingcap/tiflow/cdc/model"
    25  	"github.com/pingcap/tiflow/cdc/sink/ddlsink"
    26  	"github.com/pingcap/tiflow/pkg/config"
    27  	cerror "github.com/pingcap/tiflow/pkg/errors"
    28  	"github.com/pingcap/tiflow/pkg/retry"
    29  	"github.com/stretchr/testify/require"
    30  )
    31  
    32  type mockSink struct {
    33  	ddlsink.Sink
    34  	checkpointTs model.Ts
    35  	ddl          *model.DDLEvent
    36  	ddlMu        sync.Mutex
    37  	ddlError     error
    38  }
    39  
    40  func (m *mockSink) WriteDDLEvent(ctx context.Context, ddl *model.DDLEvent) error {
    41  	m.ddlMu.Lock()
    42  	defer m.ddlMu.Unlock()
    43  	time.Sleep(1 * time.Second)
    44  	m.ddl = ddl
    45  	return m.ddlError
    46  }
    47  
    48  func (m *mockSink) WriteCheckpointTs(ctx context.Context,
    49  	ts uint64, tables []*model.TableInfo,
    50  ) error {
    51  	atomic.StoreUint64(&m.checkpointTs, ts)
    52  	return nil
    53  }
    54  
    55  func (m *mockSink) Close() {}
    56  
    57  func (m *mockSink) GetDDL() *model.DDLEvent {
    58  	m.ddlMu.Lock()
    59  	defer m.ddlMu.Unlock()
    60  	return m.ddl
    61  }
    62  
    63  func newDDLSink4Test(reportErr func(err error), reportWarn func(err error)) (DDLSink, *mockSink) {
    64  	mockSink := &mockSink{}
    65  	ddlSink := newDDLSink(
    66  		model.DefaultChangeFeedID("changefeed-test"),
    67  		&model.ChangeFeedInfo{
    68  			Config: config.GetDefaultReplicaConfig(),
    69  		},
    70  		reportErr,
    71  		reportWarn)
    72  	ddlSink.(*ddlSinkImpl).sinkInitHandler = func(ctx context.Context, s *ddlSinkImpl) error {
    73  		s.sink = mockSink
    74  		return nil
    75  	}
    76  	return ddlSink, mockSink
    77  }
    78  
    79  func TestCheckpoint(t *testing.T) {
    80  	ddlSink, mSink := newDDLSink4Test(func(err error) {}, func(err error) {})
    81  
    82  	ctx, cancel := context.WithCancel(context.Background())
    83  	defer func() {
    84  		cancel()
    85  		ddlSink.close(ctx)
    86  	}()
    87  	ddlSink.run(ctx)
    88  
    89  	waitCheckpointGrowingUp := func(m *mockSink, targetTs model.Ts) error {
    90  		return retry.Do(ctx, func() error {
    91  			if targetTs != atomic.LoadUint64(&m.checkpointTs) {
    92  				return errors.New("targetTs!=checkpointTs")
    93  			}
    94  			return nil
    95  		}, retry.WithBackoffBaseDelay(100), retry.WithMaxTries(30))
    96  	}
    97  	ddlSink.emitCheckpointTs(1, nil)
    98  	require.Nil(t, waitCheckpointGrowingUp(mSink, 1))
    99  	ddlSink.emitCheckpointTs(10, nil)
   100  	require.Nil(t, waitCheckpointGrowingUp(mSink, 10))
   101  }
   102  
   103  func TestExecDDLEvents(t *testing.T) {
   104  	ddlSink, mSink := newDDLSink4Test(func(err error) {}, func(err error) {})
   105  
   106  	ctx, cancel := context.WithCancel(context.Background())
   107  	defer func() {
   108  		cancel()
   109  		ddlSink.close(ctx)
   110  	}()
   111  	ddlSink.run(ctx)
   112  
   113  	ddlEvents := []*model.DDLEvent{
   114  		{CommitTs: 1, Query: "create table t1(id int)"},
   115  		{CommitTs: 2, Query: "create table t2(id int)"},
   116  		{CommitTs: 3, Query: "create table t3(id int)"},
   117  	}
   118  
   119  	for _, event := range ddlEvents {
   120  		for {
   121  			done, err := ddlSink.emitDDLEvent(ctx, event)
   122  			require.Nil(t, err)
   123  			if done {
   124  				require.Equal(t, mSink.GetDDL(), event)
   125  				break
   126  			}
   127  		}
   128  	}
   129  }
   130  
   131  func TestExecDDLError(t *testing.T) {
   132  	var (
   133  		resultErr   error
   134  		resultErrMu sync.Mutex
   135  	)
   136  	readResultErr := func() error {
   137  		resultErrMu.Lock()
   138  		defer resultErrMu.Unlock()
   139  		return resultErr
   140  	}
   141  
   142  	reportFunc := func(err error) {
   143  		resultErrMu.Lock()
   144  		defer resultErrMu.Unlock()
   145  		resultErr = err
   146  	}
   147  
   148  	ddlSink, mSink := newDDLSink4Test(reportFunc, reportFunc)
   149  
   150  	ctx, cancel := context.WithCancel(context.Background())
   151  	defer func() {
   152  		cancel()
   153  		ddlSink.close(ctx)
   154  	}()
   155  
   156  	ddlSink.run(ctx)
   157  
   158  	mSink.ddlError = cerror.ErrExecDDLFailed.GenWithStackByArgs()
   159  	ddl2 := &model.DDLEvent{CommitTs: 2, Query: "create table t2(id int)"}
   160  	for {
   161  		done, err := ddlSink.emitDDLEvent(ctx, ddl2)
   162  		require.Nil(t, err)
   163  
   164  		if done || readResultErr() != nil {
   165  			require.Equal(t, mSink.GetDDL(), ddl2)
   166  			break
   167  		}
   168  	}
   169  	require.True(t, cerror.ErrExecDDLFailed.Equal(readResultErr()))
   170  }
   171  
   172  func TestAddSpecialComment(t *testing.T) {
   173  	testCase := []struct {
   174  		event  *model.DDLEvent
   175  		result string
   176  	}{
   177  		{
   178  			event: &model.DDLEvent{
   179  				Query: "create table t1 (id int ) shard_row_id_bits=2;",
   180  			},
   181  			result: "CREATE TABLE `t1` (`id` INT) /*T! SHARD_ROW_ID_BITS = 2 */",
   182  		},
   183  		{
   184  			event: &model.DDLEvent{
   185  				Query: "create table t1 (id int ) shard_row_id_bits=2 pre_split_regions=2;",
   186  			},
   187  			result: "CREATE TABLE `t1` (`id` INT) " +
   188  				"/*T! SHARD_ROW_ID_BITS = 2 */ /*T! PRE_SPLIT_REGIONS = 2 */",
   189  		},
   190  		{
   191  			event: &model.DDLEvent{
   192  				Query: "create table t1 (id int ) shard_row_id_bits=2     pre_split_regions=2;",
   193  			},
   194  			result: "CREATE TABLE `t1` (`id` INT) " +
   195  				"/*T! SHARD_ROW_ID_BITS = 2 */ /*T! PRE_SPLIT_REGIONS = 2 */",
   196  		},
   197  		{
   198  			event: &model.DDLEvent{
   199  				Query: "create table t1 (id int ) shard_row_id_bits=2 " +
   200  					"engine=innodb pre_split_regions=2;",
   201  			},
   202  			result: "CREATE TABLE `t1` (`id` INT) /*T! SHARD_ROW_ID_BITS = 2 */" +
   203  				" ENGINE = innodb /*T! PRE_SPLIT_REGIONS = 2 */",
   204  		},
   205  		{
   206  			event: &model.DDLEvent{
   207  				Query: "create table t1 (id int ) pre_split_regions=2 shard_row_id_bits=2;",
   208  			},
   209  			result: "CREATE TABLE `t1` (`id` INT) /*T! PRE_SPLIT_REGIONS = 2 */" +
   210  				" /*T! SHARD_ROW_ID_BITS = 2 */",
   211  		},
   212  		{
   213  			event: &model.DDLEvent{
   214  				Query: "create table t6 (id int ) " +
   215  					"shard_row_id_bits=2 shard_row_id_bits=3 pre_split_regions=2;",
   216  			},
   217  			result: "CREATE TABLE `t6` (`id` INT) /*T! SHARD_ROW_ID_BITS = 2 */ " +
   218  				"/*T! SHARD_ROW_ID_BITS = 3 */ /*T! PRE_SPLIT_REGIONS = 2 */",
   219  		},
   220  		{
   221  			event: &model.DDLEvent{
   222  				Query: "create table t1 (id int primary key auto_random(2));",
   223  			},
   224  			result: "CREATE TABLE `t1` (`id` INT PRIMARY KEY /*T![auto_rand] AUTO_RANDOM(2) */)",
   225  		},
   226  		{
   227  			event: &model.DDLEvent{
   228  				Query: "create table t1 (id int primary key auto_random);",
   229  			},
   230  			result: "CREATE TABLE `t1` (`id` INT PRIMARY KEY /*T![auto_rand] AUTO_RANDOM */)",
   231  		},
   232  		{
   233  			event: &model.DDLEvent{
   234  				Query: "create table t1 (id int auto_random ( 4 ) primary key);",
   235  			},
   236  			result: "CREATE TABLE `t1` (`id` INT /*T![auto_rand] AUTO_RANDOM(4) */ PRIMARY KEY)",
   237  		},
   238  		{
   239  			event: &model.DDLEvent{
   240  				Query: "create table t1 (id int  auto_random  (   4    ) primary key);",
   241  			},
   242  			result: "CREATE TABLE `t1` (`id` INT /*T![auto_rand] AUTO_RANDOM(4) */ PRIMARY KEY)",
   243  		},
   244  		{
   245  			event: &model.DDLEvent{
   246  				Query: "create table t1 (id int auto_random ( 3 ) primary key) " +
   247  					"auto_random_base = 100;",
   248  			},
   249  			result: "CREATE TABLE `t1` (`id` INT /*T![auto_rand] AUTO_RANDOM(3) */" +
   250  				" PRIMARY KEY) /*T![auto_rand_base] AUTO_RANDOM_BASE = 100 */",
   251  		},
   252  		{
   253  			event: &model.DDLEvent{
   254  				Query: "create table t1 (id int auto_random primary key) auto_random_base = 50;",
   255  			},
   256  			result: "CREATE TABLE `t1` (`id` INT /*T![auto_rand] AUTO_RANDOM */ PRIMARY KEY)" +
   257  				" /*T![auto_rand_base] AUTO_RANDOM_BASE = 50 */",
   258  		},
   259  		{
   260  			event: &model.DDLEvent{
   261  				Query: "create table t1 (id int auto_increment key) auto_id_cache 100;",
   262  			},
   263  			result: "CREATE TABLE `t1` (`id` INT AUTO_INCREMENT PRIMARY KEY) " +
   264  				"/*T![auto_id_cache] AUTO_ID_CACHE = 100 */",
   265  		},
   266  		{
   267  			event: &model.DDLEvent{
   268  				Query: "create table t1 (id int auto_increment unique) auto_id_cache 10;",
   269  			},
   270  			result: "CREATE TABLE `t1` (`id` INT AUTO_INCREMENT UNIQUE KEY) " +
   271  				"/*T![auto_id_cache] AUTO_ID_CACHE = 10 */",
   272  		},
   273  		{
   274  			event: &model.DDLEvent{
   275  				Query: "create table t1 (id int) auto_id_cache = 5;",
   276  			},
   277  			result: "CREATE TABLE `t1` (`id` INT) /*T![auto_id_cache] AUTO_ID_CACHE = 5 */",
   278  		},
   279  		{
   280  			event: &model.DDLEvent{
   281  				Query: "create table t1 (id int) auto_id_cache=5;",
   282  			},
   283  			result: "CREATE TABLE `t1` (`id` INT) /*T![auto_id_cache] AUTO_ID_CACHE = 5 */",
   284  		},
   285  		{
   286  			event: &model.DDLEvent{
   287  				Query: "create table t1 (id int) /*T![auto_id_cache] auto_id_cache=5 */ ;",
   288  			},
   289  			result: "CREATE TABLE `t1` (`id` INT) /*T![auto_id_cache] AUTO_ID_CACHE = 5 */",
   290  		},
   291  		{
   292  			event: &model.DDLEvent{
   293  				Query: "create table t1 (id int, a varchar(255), primary key (a, b) clustered);",
   294  			},
   295  			result: "CREATE TABLE `t1` (`id` INT,`a` VARCHAR(255),PRIMARY KEY(`a`, `b`)" +
   296  				" /*T![clustered_index] CLUSTERED */)",
   297  		},
   298  		{
   299  			event: &model.DDLEvent{
   300  				Query: "create table t1(id int, v int, primary key(a) clustered);",
   301  			},
   302  			result: "CREATE TABLE `t1` (`id` INT,`v` INT,PRIMARY KEY(`a`) " +
   303  				"/*T![clustered_index] CLUSTERED */)",
   304  		},
   305  		{
   306  			event: &model.DDLEvent{
   307  				Query: "create table t1(id int primary key clustered, v int);",
   308  			},
   309  			result: "CREATE TABLE `t1` (`id` INT PRIMARY KEY " +
   310  				"/*T![clustered_index] CLUSTERED */,`v` INT)",
   311  		},
   312  		{
   313  			event: &model.DDLEvent{
   314  				Query: "alter table t add primary key(a) clustered;",
   315  			},
   316  			result: "ALTER TABLE `t` ADD PRIMARY KEY(`a`) /*T![clustered_index] CLUSTERED */",
   317  		},
   318  		{
   319  			event: &model.DDLEvent{
   320  				Query: "create table t1 (id int, a varchar(255), primary key (a, b) nonclustered);",
   321  			},
   322  			result: "CREATE TABLE `t1` (`id` INT,`a` VARCHAR(255),PRIMARY KEY(`a`, `b`)" +
   323  				" /*T![clustered_index] NONCLUSTERED */)",
   324  		},
   325  		{
   326  			event: &model.DDLEvent{
   327  				Query: "create table t1 (id int, a varchar(255), primary key (a, b) " +
   328  					"/*T![clustered_index] nonclustered */);",
   329  			},
   330  			result: "CREATE TABLE `t1` (`id` INT,`a` VARCHAR(255),PRIMARY KEY(`a`, `b`)" +
   331  				" /*T![clustered_index] NONCLUSTERED */)",
   332  		},
   333  		{
   334  			event: &model.DDLEvent{
   335  				Query: "create table clustered_test(id int)",
   336  			},
   337  			result: "CREATE TABLE `clustered_test` (`id` INT)",
   338  		},
   339  		{
   340  			event: &model.DDLEvent{
   341  				Query: "create database clustered_test",
   342  			},
   343  			result: "CREATE DATABASE `clustered_test`",
   344  		},
   345  		{
   346  			event: &model.DDLEvent{
   347  				Query: "create database clustered",
   348  			},
   349  			result: "CREATE DATABASE `clustered`",
   350  		},
   351  		{
   352  			event: &model.DDLEvent{
   353  				Query: "create table clustered (id int)",
   354  			},
   355  			result: "CREATE TABLE `clustered` (`id` INT)",
   356  		},
   357  		{
   358  			event: &model.DDLEvent{
   359  				Query: "create table t1 (id int, a varchar(255) key clustered);",
   360  			},
   361  			result: "CREATE TABLE `t1` (" +
   362  				"`id` INT,`a` VARCHAR(255) PRIMARY KEY /*T![clustered_index] CLUSTERED */)",
   363  		},
   364  		{
   365  			event: &model.DDLEvent{
   366  				Query: "alter table t force auto_increment = 12;",
   367  			},
   368  			result: "ALTER TABLE `t` /*T![force_inc] FORCE */ AUTO_INCREMENT = 12",
   369  		},
   370  		{
   371  			event: &model.DDLEvent{
   372  				Query: "alter table t force, auto_increment = 12;",
   373  			},
   374  			result: "ALTER TABLE `t` FORCE /* AlterTableForce is not supported */ , " +
   375  				"AUTO_INCREMENT = 12",
   376  		},
   377  		{
   378  			event: &model.DDLEvent{
   379  				Query: "create table cdc_test (id varchar(10) primary key ,c1 varchar(10)) " +
   380  					"ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin" +
   381  					"/*!90000  SHARD_ROW_ID_BITS=4 PRE_SPLIT_REGIONS=3 */",
   382  			},
   383  			result: "CREATE TABLE `cdc_test` (`id` VARCHAR(10) PRIMARY KEY,`c1` VARCHAR(10)) " +
   384  				"ENGINE = InnoDB DEFAULT CHARACTER SET = UTF8MB4 DEFAULT COLLATE = UTF8MB4_BIN " +
   385  				"/*T! SHARD_ROW_ID_BITS = 4 */ /*T! PRE_SPLIT_REGIONS = 3 */",
   386  		},
   387  		{
   388  			event: &model.DDLEvent{
   389  				Query: "CREATE TABLE t1 (id BIGINT NOT NULL PRIMARY KEY auto_increment, " +
   390  					"b varchar(255)) PLACEMENT POLICY=placement1;",
   391  			},
   392  			result: "CREATE TABLE `t1` (`id` BIGINT NOT NULL PRIMARY KEY " +
   393  				"AUTO_INCREMENT,`b` VARCHAR(255)) ",
   394  		},
   395  		{
   396  			event: &model.DDLEvent{
   397  				Query: "CREATE TABLE `t1` (\n  `a` int(11) DEFAULT NULL\n) " +
   398  					"ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin " +
   399  					"/*T![placement] PLACEMENT POLICY=`p2` */",
   400  			},
   401  			result: "CREATE TABLE `t1` (`a` INT(11) DEFAULT NULL) " +
   402  				"ENGINE = InnoDB DEFAULT CHARACTER SET = UTF8MB4 DEFAULT COLLATE = UTF8MB4_BIN ",
   403  		},
   404  		{
   405  			event: &model.DDLEvent{
   406  				Query: "CREATE TABLE t4 (" +
   407  					"firstname VARCHAR(25) NOT NULL," +
   408  					"lastname VARCHAR(25) NOT NULL," +
   409  					"username VARCHAR(16) NOT NULL," +
   410  					"email VARCHAR(35)," +
   411  					"joined DATE NOT NULL) " +
   412  					"PARTITION BY RANGE( YEAR(joined) )" +
   413  					" (PARTITION p0 VALUES LESS THAN (1960) PLACEMENT POLICY=p1," +
   414  					"PARTITION p1 VALUES LESS THAN (1970),PARTITION p2 VALUES LESS THAN (1980)," +
   415  					"PARTITION p3 VALUES LESS THAN (1990),PARTITION p4 VALUES LESS THAN MAXVALUE);",
   416  			},
   417  			result: "CREATE TABLE `t4` (" +
   418  				"`firstname` VARCHAR(25) NOT NULL," +
   419  				"`lastname` VARCHAR(25) NOT NULL," +
   420  				"`username` VARCHAR(16) NOT NULL," +
   421  				"`email` VARCHAR(35)," +
   422  				"`joined` DATE NOT NULL) " +
   423  				"PARTITION BY RANGE (YEAR(`joined`)) " +
   424  				"(PARTITION `p0` VALUES LESS THAN (1960) ,PARTITION `p1` VALUES LESS THAN (1970)," +
   425  				"PARTITION `p2` VALUES LESS THAN (1980),PARTITION `p3` VALUES LESS THAN (1990)," +
   426  				"PARTITION `p4` VALUES LESS THAN (MAXVALUE))",
   427  		},
   428  		{
   429  			event: &model.DDLEvent{
   430  				Query: "ALTER TABLE t3 PLACEMENT POLICY=DEFAULT;",
   431  			},
   432  			result: "ALTER TABLE `t3`",
   433  		},
   434  		{
   435  			event: &model.DDLEvent{
   436  				Query: "ALTER TABLE t1 PLACEMENT POLICY=p10",
   437  			},
   438  			result: "ALTER TABLE `t1`",
   439  		},
   440  		{
   441  			event: &model.DDLEvent{
   442  				Query: "ALTER TABLE t1 PLACEMENT POLICY=p10, add d text(50)",
   443  			},
   444  			result: "ALTER TABLE `t1` ADD COLUMN `d` TEXT(50)",
   445  		},
   446  		{
   447  			event: &model.DDLEvent{
   448  				Query: "alter table tp PARTITION p1 placement policy p2",
   449  			},
   450  			result: "",
   451  		},
   452  		{
   453  			event: &model.DDLEvent{
   454  				Query: "alter table t add d text(50) PARTITION p1 placement policy p2",
   455  			},
   456  			result: "ALTER TABLE `t` ADD COLUMN `d` TEXT(50)",
   457  		},
   458  		{
   459  			event: &model.DDLEvent{
   460  				Query: "alter table tp set tiflash replica 1 PARTITION p1 placement policy p2",
   461  			},
   462  			result: "ALTER TABLE `tp` SET TIFLASH REPLICA 1",
   463  		},
   464  		{
   465  			event: &model.DDLEvent{
   466  				Query: "ALTER DATABASE TestResetPlacementDB PLACEMENT POLICY SET DEFAULT",
   467  			},
   468  			result: "",
   469  		},
   470  
   471  		{
   472  			event: &model.DDLEvent{
   473  				Query: "ALTER DATABASE TestResetPlacementDB PLACEMENT POLICY p1 charset utf8mb4",
   474  			},
   475  			result: "ALTER DATABASE `TestResetPlacementDB`  CHARACTER SET = utf8mb4",
   476  		},
   477  		{
   478  			event: &model.DDLEvent{
   479  				Query: "/*T![placement] ALTER DATABASE `db1` PLACEMENT POLICY = `p1` */",
   480  			},
   481  			result: "",
   482  		},
   483  		{
   484  			event: &model.DDLEvent{
   485  				Query: "ALTER PLACEMENT POLICY p3 PRIMARY_REGION='us-east-1' " +
   486  					"REGIONS='us-east-1,us-east-2,us-west-1';",
   487  			},
   488  			result: "",
   489  		},
   490  		{
   491  			event: &model.DDLEvent{
   492  				Query: "CREATE TABLE t1(t datetime) TTL=`t` + INTERVAL 1 DAY",
   493  			},
   494  			result: "CREATE TABLE `t1` (`t` DATETIME) " +
   495  				"/*T![ttl] TTL = `t` + INTERVAL 1 DAY */ /*T![ttl] TTL_ENABLE = 'OFF' */",
   496  		},
   497  		{
   498  			event: &model.DDLEvent{
   499  				Query: "CREATE TABLE t1(t datetime) TTL=`t` + INTERVAL 1 DAY TTL_ENABLE='ON'",
   500  			},
   501  			result: "CREATE TABLE `t1` (`t` DATETIME) " +
   502  				"/*T![ttl] TTL = `t` + INTERVAL 1 DAY */ /*T![ttl] TTL_ENABLE = 'OFF' */",
   503  		},
   504  		{
   505  			event: &model.DDLEvent{
   506  				Query: "ALTER TABLE t1 TTL=`t` + INTERVAL 1 DAY",
   507  			},
   508  			result: "ALTER TABLE `t1` " +
   509  				"/*T![ttl] TTL = `t` + INTERVAL 1 DAY */ /*T![ttl] TTL_ENABLE = 'OFF' */",
   510  		},
   511  		{
   512  			event: &model.DDLEvent{
   513  				Query: "ALTER TABLE t1 TTL=`t` + INTERVAL 1 DAY TTL_ENABLE='ON'",
   514  			},
   515  			result: "ALTER TABLE `t1` " +
   516  				"/*T![ttl] TTL = `t` + INTERVAL 1 DAY */ /*T![ttl] TTL_ENABLE = 'OFF' */",
   517  		},
   518  		{
   519  			event: &model.DDLEvent{
   520  				Query: "ALTER TABLE t1 TTL_ENABLE='ON'",
   521  			},
   522  			result: "ALTER TABLE `t1`",
   523  		},
   524  		{
   525  			event: &model.DDLEvent{
   526  				Query: "ALTER TABLE t1 TTL_ENABLE='OFF'",
   527  			},
   528  			result: "ALTER TABLE `t1`",
   529  		},
   530  		{
   531  			event: &model.DDLEvent{
   532  				Query: "ALTER TABLE t1 TTL_JOB_INTERVAL='7h'",
   533  			},
   534  			result: "ALTER TABLE `t1` /*T![ttl] TTL_JOB_INTERVAL = '7h' */",
   535  		},
   536  		{
   537  			event: &model.DDLEvent{
   538  				Query:   "alter table t add index j((cast(j->'$.number[*]' as signed array)))",
   539  				Charset: "utf8",
   540  				Collate: "utf8_bin",
   541  			},
   542  			result: "ALTER TABLE `t` ADD INDEX `j`((CAST(JSON_EXTRACT(`j`, _UTF8'$.number[*]') " +
   543  				"AS SIGNED ARRAY)))",
   544  		},
   545  		{
   546  			event: &model.DDLEvent{
   547  				Query: "alter table t add index j((cast(j->'$.number[*]' as signed array)))",
   548  			},
   549  			result: "ALTER TABLE `t` ADD INDEX `j`((CAST(JSON_EXTRACT(`j`, _UTF8MB4'$.number[*]') " +
   550  				"AS SIGNED ARRAY)))",
   551  		},
   552  	}
   553  
   554  	s := &ddlSinkImpl{}
   555  	s.info = &model.ChangeFeedInfo{
   556  		Config: config.GetDefaultReplicaConfig(),
   557  	}
   558  	for _, ca := range testCase {
   559  		re, err := s.addSpecialComment(ca.event)
   560  		require.Nil(t, err)
   561  		require.Equal(t, ca.result, re)
   562  	}
   563  	_, err := s.addSpecialComment(&model.DDLEvent{
   564  		Query: "alter table t force, auto_increment = 12;alter table t force, " +
   565  			"auto_increment = 12;",
   566  	})
   567  	require.NotNil(t, err)
   568  }