github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/lightning/checkpoints/checkpoints_sql_test.go (about)

     1  package checkpoints_test
     2  
     3  import (
     4  	"context"
     5  	"database/sql"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/DATA-DOG/go-sqlmock"
    10  	. "github.com/pingcap/check"
    11  	"github.com/pingcap/errors"
    12  
    13  	"github.com/pingcap/br/pkg/lightning/checkpoints"
    14  	"github.com/pingcap/br/pkg/lightning/mydump"
    15  	"github.com/pingcap/br/pkg/lightning/verification"
    16  	"github.com/pingcap/br/pkg/version/build"
    17  )
    18  
    19  var _ = Suite(&cpSQLSuite{})
    20  
    21  type cpSQLSuite struct {
    22  	db   *sql.DB
    23  	mock sqlmock.Sqlmock
    24  	cpdb *checkpoints.MySQLCheckpointsDB
    25  }
    26  
    27  func (s *cpSQLSuite) SetUpTest(c *C) {
    28  	db, mock, err := sqlmock.New()
    29  	c.Assert(err, IsNil)
    30  	s.db = db
    31  	s.mock = mock
    32  
    33  	// 1. create the checkpoints database.
    34  	s.mock.
    35  		ExpectExec("CREATE DATABASE IF NOT EXISTS `mock-schema`").
    36  		WillReturnResult(sqlmock.NewResult(1, 1))
    37  	s.mock.
    38  		ExpectExec("CREATE TABLE IF NOT EXISTS `mock-schema`\\.task_v\\d+ .+").
    39  		WillReturnResult(sqlmock.NewResult(2, 1))
    40  	s.mock.
    41  		ExpectExec("CREATE TABLE IF NOT EXISTS `mock-schema`\\.table_v\\d+ .+").
    42  		WillReturnResult(sqlmock.NewResult(3, 1))
    43  	s.mock.
    44  		ExpectExec("CREATE TABLE IF NOT EXISTS `mock-schema`\\.engine_v\\d+ .+").
    45  		WillReturnResult(sqlmock.NewResult(4, 1))
    46  	s.mock.
    47  		ExpectExec("CREATE TABLE IF NOT EXISTS `mock-schema`\\.chunk_v\\d+ .+").
    48  		WillReturnResult(sqlmock.NewResult(5, 1))
    49  
    50  	cpdb, err := checkpoints.NewMySQLCheckpointsDB(context.Background(), s.db, "mock-schema")
    51  	c.Assert(err, IsNil)
    52  	c.Assert(s.mock.ExpectationsWereMet(), IsNil)
    53  	s.cpdb = cpdb
    54  }
    55  
    56  func (s *cpSQLSuite) TearDownTest(c *C) {
    57  	s.mock.ExpectClose()
    58  	c.Assert(s.cpdb.Close(), IsNil)
    59  	c.Assert(s.mock.ExpectationsWereMet(), IsNil)
    60  }
    61  
    62  func (s *cpSQLSuite) TestNormalOperations(c *C) {
    63  	ctx := context.Background()
    64  	cpdb := s.cpdb
    65  
    66  	// 2. initialize with checkpoint data.
    67  
    68  	s.mock.ExpectBegin()
    69  	initializeStmt := s.mock.ExpectPrepare(
    70  		"REPLACE INTO `mock-schema`\\.task_v\\d+")
    71  	initializeStmt.ExpectExec().
    72  		WithArgs(123, "/data", "local", "127.0.0.1:8287", "127.0.0.1", 4000, "127.0.0.1:2379", "/tmp/sorted-kv", build.ReleaseVersion).
    73  		WillReturnResult(sqlmock.NewResult(6, 1))
    74  	initializeStmt = s.mock.
    75  		ExpectPrepare("INSERT INTO `mock-schema`\\.table_v\\d+")
    76  	initializeStmt.ExpectExec().
    77  		WithArgs(123, "`db1`.`t1`", sqlmock.AnyArg(), int64(1)).
    78  		WillReturnResult(sqlmock.NewResult(7, 1))
    79  	initializeStmt.ExpectExec().
    80  		WithArgs(123, "`db1`.`t2`", sqlmock.AnyArg(), int64(2)).
    81  		WillReturnResult(sqlmock.NewResult(8, 1))
    82  	initializeStmt.ExpectExec().
    83  		WithArgs(123, "`db2`.`t3`", sqlmock.AnyArg(), int64(3)).
    84  		WillReturnResult(sqlmock.NewResult(9, 1))
    85  	s.mock.ExpectCommit()
    86  
    87  	s.mock.MatchExpectationsInOrder(false)
    88  	cfg := newTestConfig()
    89  	err := cpdb.Initialize(ctx, cfg, map[string]*checkpoints.TidbDBInfo{
    90  		"db1": {
    91  			Name: "db1",
    92  			Tables: map[string]*checkpoints.TidbTableInfo{
    93  				"t1": {Name: "t1", ID: 1},
    94  				"t2": {Name: "t2", ID: 2},
    95  			},
    96  		},
    97  		"db2": {
    98  			Name: "db2",
    99  			Tables: map[string]*checkpoints.TidbTableInfo{
   100  				"t3": {Name: "t3", ID: 3},
   101  			},
   102  		},
   103  	})
   104  	s.mock.MatchExpectationsInOrder(true)
   105  	c.Assert(err, IsNil)
   106  	c.Assert(s.mock.ExpectationsWereMet(), IsNil)
   107  
   108  	// 3. set some checkpoints
   109  
   110  	s.mock.ExpectBegin()
   111  	insertEngineStmt := s.mock.
   112  		ExpectPrepare("REPLACE INTO `mock-schema`\\.engine_v\\d+ .+")
   113  	insertEngineStmt.
   114  		ExpectExec().
   115  		WithArgs("`db1`.`t2`", 0, 30).
   116  		WillReturnResult(sqlmock.NewResult(8, 1))
   117  	insertEngineStmt.
   118  		ExpectExec().
   119  		WithArgs("`db1`.`t2`", -1, 30).
   120  		WillReturnResult(sqlmock.NewResult(9, 1))
   121  	insertChunkStmt := s.mock.
   122  		ExpectPrepare("REPLACE INTO `mock-schema`\\.chunk_v\\d+ .+")
   123  	insertChunkStmt.
   124  		ExpectExec().
   125  		WithArgs("`db1`.`t2`", 0, "/tmp/path/1.sql", 0, mydump.SourceTypeSQL, 0, "", 123, []byte("null"), 12, 102400, 1, 5000, 1234567890).
   126  		WillReturnResult(sqlmock.NewResult(10, 1))
   127  	s.mock.ExpectCommit()
   128  
   129  	s.mock.MatchExpectationsInOrder(false)
   130  	err = cpdb.InsertEngineCheckpoints(ctx, "`db1`.`t2`", map[int32]*checkpoints.EngineCheckpoint{
   131  		0: {
   132  			Status: checkpoints.CheckpointStatusLoaded,
   133  			Chunks: []*checkpoints.ChunkCheckpoint{{
   134  				Key: checkpoints.ChunkCheckpointKey{
   135  					Path:   "/tmp/path/1.sql",
   136  					Offset: 0,
   137  				},
   138  				FileMeta: mydump.SourceFileMeta{
   139  					Path:     "/tmp/path/1.sql",
   140  					Type:     mydump.SourceTypeSQL,
   141  					FileSize: 123,
   142  				},
   143  				Chunk: mydump.Chunk{
   144  					Offset:       12,
   145  					EndOffset:    102400,
   146  					PrevRowIDMax: 1,
   147  					RowIDMax:     5000,
   148  				},
   149  				Timestamp: 1234567890,
   150  			}},
   151  		},
   152  		-1: {
   153  			Status: checkpoints.CheckpointStatusLoaded,
   154  			Chunks: nil,
   155  		},
   156  	})
   157  	s.mock.MatchExpectationsInOrder(true)
   158  	c.Assert(err, IsNil)
   159  	c.Assert(s.mock.ExpectationsWereMet(), IsNil)
   160  
   161  	// 4. update some checkpoints
   162  
   163  	cpd := checkpoints.NewTableCheckpointDiff()
   164  	scm := checkpoints.StatusCheckpointMerger{
   165  		EngineID: 0,
   166  		Status:   checkpoints.CheckpointStatusImported,
   167  	}
   168  	scm.MergeInto(cpd)
   169  	scm = checkpoints.StatusCheckpointMerger{
   170  		EngineID: checkpoints.WholeTableEngineID,
   171  		Status:   checkpoints.CheckpointStatusAllWritten,
   172  	}
   173  	scm.MergeInto(cpd)
   174  	rcm := checkpoints.RebaseCheckpointMerger{
   175  		AllocBase: 132861,
   176  	}
   177  	rcm.MergeInto(cpd)
   178  	cksum := checkpoints.TableChecksumMerger{
   179  		Checksum: verification.MakeKVChecksum(4492, 686, 486070148910),
   180  	}
   181  	cksum.MergeInto(cpd)
   182  	ccm := checkpoints.ChunkCheckpointMerger{
   183  		EngineID: 0,
   184  		Key:      checkpoints.ChunkCheckpointKey{Path: "/tmp/path/1.sql", Offset: 0},
   185  		Checksum: verification.MakeKVChecksum(4491, 586, 486070148917),
   186  		Pos:      55904,
   187  		RowID:    681,
   188  	}
   189  	ccm.MergeInto(cpd)
   190  
   191  	s.mock.ExpectBegin()
   192  	s.mock.
   193  		ExpectPrepare("UPDATE `mock-schema`\\.chunk_v\\d+ SET pos = .+").
   194  		ExpectExec().
   195  		WithArgs(
   196  			55904, 681, 4491, 586, 486070148917, []byte("null"),
   197  			"`db1`.`t2`", 0, "/tmp/path/1.sql", 0,
   198  		).
   199  		WillReturnResult(sqlmock.NewResult(11, 1))
   200  	s.mock.
   201  		ExpectPrepare("UPDATE `mock-schema`\\.table_v\\d+ SET alloc_base = .+").
   202  		ExpectExec().
   203  		WithArgs(132861, "`db1`.`t2`").
   204  		WillReturnResult(sqlmock.NewResult(12, 1))
   205  	s.mock.
   206  		ExpectPrepare("UPDATE `mock-schema`\\.engine_v\\d+ SET status = .+").
   207  		ExpectExec().
   208  		WithArgs(120, "`db1`.`t2`", 0).
   209  		WillReturnResult(sqlmock.NewResult(13, 1))
   210  	s.mock.
   211  		ExpectPrepare("UPDATE `mock-schema`\\.table_v\\d+ SET status = .+").
   212  		ExpectExec().
   213  		WithArgs(60, "`db1`.`t2`").
   214  		WillReturnResult(sqlmock.NewResult(14, 1))
   215  	s.mock.
   216  		ExpectPrepare("UPDATE `mock-schema`\\.table_v\\d+ SET kv_bytes = .+").
   217  		ExpectExec().
   218  		WithArgs(4492, 686, 486070148910, "`db1`.`t2`").
   219  		WillReturnResult(sqlmock.NewResult(15, 1))
   220  
   221  	s.mock.ExpectCommit()
   222  
   223  	s.mock.MatchExpectationsInOrder(false)
   224  	cpdb.Update(map[string]*checkpoints.TableCheckpointDiff{"`db1`.`t2`": cpd})
   225  	s.mock.MatchExpectationsInOrder(true)
   226  	c.Assert(s.mock.ExpectationsWereMet(), IsNil)
   227  
   228  	// 5. get back the checkpoints
   229  
   230  	s.mock.ExpectBegin()
   231  	s.mock.
   232  		ExpectQuery("SELECT .+ FROM `mock-schema`\\.engine_v\\d+").
   233  		WithArgs("`db1`.`t2`").
   234  		WillReturnRows(
   235  			sqlmock.NewRows([]string{"engine_id", "status"}).
   236  				AddRow(0, 120).
   237  				AddRow(-1, 30),
   238  		)
   239  	s.mock.
   240  		ExpectQuery("SELECT (?s:.+) FROM `mock-schema`\\.chunk_v\\d+").
   241  		WithArgs("`db1`.`t2`").
   242  		WillReturnRows(
   243  			sqlmock.NewRows([]string{
   244  				"engine_id", "path", "offset", "type", "compression", "sort_key", "file_size", "columns",
   245  				"pos", "end_offset", "prev_rowid_max", "rowid_max",
   246  				"kvc_bytes", "kvc_kvs", "kvc_checksum", "unix_timestamp(create_time)",
   247  			}).
   248  				AddRow(
   249  					0, "/tmp/path/1.sql", 0, mydump.SourceTypeSQL, 0, "", 123, "[]",
   250  					55904, 102400, 681, 5000,
   251  					4491, 586, 486070148917, 1234567894,
   252  				),
   253  		)
   254  	s.mock.
   255  		ExpectQuery("SELECT .+ FROM `mock-schema`\\.table_v\\d+").
   256  		WithArgs("`db1`.`t2`").
   257  		WillReturnRows(
   258  			sqlmock.NewRows([]string{"status", "alloc_base", "table_id", "kv_bytes", "kv_kvs", "kv_checksum"}).
   259  				AddRow(60, 132861, int64(2), uint64(4492), uint64(686), uint64(486070148910)),
   260  		)
   261  	s.mock.ExpectCommit()
   262  
   263  	cp, err := cpdb.Get(ctx, "`db1`.`t2`")
   264  	c.Assert(err, IsNil)
   265  	c.Assert(cp, DeepEquals, &checkpoints.TableCheckpoint{
   266  		Status:    checkpoints.CheckpointStatusAllWritten,
   267  		AllocBase: 132861,
   268  		TableID:   int64(2),
   269  		Engines: map[int32]*checkpoints.EngineCheckpoint{
   270  			-1: {Status: checkpoints.CheckpointStatusLoaded},
   271  			0: {
   272  				Status: checkpoints.CheckpointStatusImported,
   273  				Chunks: []*checkpoints.ChunkCheckpoint{{
   274  					Key: checkpoints.ChunkCheckpointKey{
   275  						Path:   "/tmp/path/1.sql",
   276  						Offset: 0,
   277  					},
   278  					FileMeta: mydump.SourceFileMeta{
   279  						Path:     "/tmp/path/1.sql",
   280  						Type:     mydump.SourceTypeSQL,
   281  						FileSize: 123,
   282  					},
   283  					ColumnPermutation: []int{},
   284  					Chunk: mydump.Chunk{
   285  						Offset:       55904,
   286  						EndOffset:    102400,
   287  						PrevRowIDMax: 681,
   288  						RowIDMax:     5000,
   289  					},
   290  					Checksum:  verification.MakeKVChecksum(4491, 586, 486070148917),
   291  					Timestamp: 1234567894,
   292  				}},
   293  			},
   294  		},
   295  		Checksum: verification.MakeKVChecksum(4492, 686, 486070148910),
   296  	})
   297  	c.Assert(s.mock.ExpectationsWereMet(), IsNil)
   298  }
   299  
   300  func (s *cpSQLSuite) TestRemoveAllCheckpoints(c *C) {
   301  	s.mock.ExpectExec("DROP SCHEMA `mock-schema`").WillReturnResult(sqlmock.NewResult(0, 1))
   302  
   303  	ctx := context.Background()
   304  
   305  	err := s.cpdb.RemoveCheckpoint(ctx, "all")
   306  	c.Assert(err, IsNil)
   307  
   308  	s.mock.ExpectBegin()
   309  	s.mock.
   310  		ExpectQuery("SELECT .+ FROM `mock-schema`\\.engine_v\\d+").
   311  		WithArgs("`db1`.`t2`").
   312  		WillReturnRows(sqlmock.NewRows([]string{"engine_id", "status"}))
   313  	s.mock.
   314  		ExpectQuery("SELECT (?s:.+) FROM `mock-schema`\\.chunk_v\\d+").
   315  		WithArgs("`db1`.`t2`").
   316  		WillReturnRows(
   317  			sqlmock.NewRows([]string{
   318  				"engine_id", "path", "offset", "type", "compression", "sort_key", "file_size", "columns",
   319  				"pos", "end_offset", "prev_rowid_max", "rowid_max",
   320  				"kvc_bytes", "kvc_kvs", "kvc_checksum", "unix_timestamp(create_time)",
   321  			}))
   322  	s.mock.
   323  		ExpectQuery("SELECT .+ FROM `mock-schema`\\.table_v\\d+").
   324  		WithArgs("`db1`.`t2`").
   325  		WillReturnRows(sqlmock.NewRows([]string{"status", "alloc_base", "table_id"}))
   326  	s.mock.ExpectRollback()
   327  
   328  	cp, err := s.cpdb.Get(ctx, "`db1`.`t2`")
   329  	c.Assert(cp, IsNil)
   330  	c.Assert(errors.IsNotFound(err), IsTrue)
   331  }
   332  
   333  func (s *cpSQLSuite) TestRemoveOneCheckpoint(c *C) {
   334  	s.mock.ExpectBegin()
   335  	s.mock.
   336  		ExpectExec("DELETE FROM `mock-schema`\\.chunk_v\\d+ WHERE table_name = \\?").
   337  		WithArgs("`db1`.`t2`").
   338  		WillReturnResult(sqlmock.NewResult(0, 4))
   339  	s.mock.
   340  		ExpectExec("DELETE FROM `mock-schema`\\.engine_v\\d+ WHERE table_name = \\?").
   341  		WithArgs("`db1`.`t2`").
   342  		WillReturnResult(sqlmock.NewResult(0, 2))
   343  	s.mock.
   344  		ExpectExec("DELETE FROM `mock-schema`\\.table_v\\d+ WHERE table_name = \\?").
   345  		WithArgs("`db1`.`t2`").
   346  		WillReturnResult(sqlmock.NewResult(0, 1))
   347  	s.mock.ExpectCommit()
   348  
   349  	err := s.cpdb.RemoveCheckpoint(context.Background(), "`db1`.`t2`")
   350  	c.Assert(err, IsNil)
   351  }
   352  
   353  func (s *cpSQLSuite) TestIgnoreAllErrorCheckpoints(c *C) {
   354  	s.mock.ExpectBegin()
   355  	s.mock.
   356  		ExpectExec("UPDATE `mock-schema`\\.engine_v\\d+ SET status = 30 WHERE 'all' = \\? AND status <= 25").
   357  		WithArgs(sqlmock.AnyArg()).
   358  		WillReturnResult(sqlmock.NewResult(5, 3))
   359  	s.mock.
   360  		ExpectExec("UPDATE `mock-schema`\\.table_v\\d+ SET status = 30 WHERE 'all' = \\? AND status <= 25").
   361  		WithArgs(sqlmock.AnyArg()).
   362  		WillReturnResult(sqlmock.NewResult(6, 2))
   363  	s.mock.ExpectCommit()
   364  
   365  	err := s.cpdb.IgnoreErrorCheckpoint(context.Background(), "all")
   366  	c.Assert(err, IsNil)
   367  }
   368  
   369  func (s *cpSQLSuite) TestIgnoreOneErrorCheckpoint(c *C) {
   370  	s.mock.ExpectBegin()
   371  	s.mock.
   372  		ExpectExec("UPDATE `mock-schema`\\.engine_v\\d+ SET status = 30 WHERE table_name = \\? AND status <= 25").
   373  		WithArgs("`db1`.`t2`").
   374  		WillReturnResult(sqlmock.NewResult(5, 2))
   375  	s.mock.
   376  		ExpectExec("UPDATE `mock-schema`\\.table_v\\d+ SET status = 30 WHERE table_name = \\? AND status <= 25").
   377  		WithArgs("`db1`.`t2`").
   378  		WillReturnResult(sqlmock.NewResult(6, 1))
   379  	s.mock.ExpectCommit()
   380  
   381  	err := s.cpdb.IgnoreErrorCheckpoint(context.Background(), "`db1`.`t2`")
   382  	c.Assert(err, IsNil)
   383  }
   384  
   385  func (s *cpSQLSuite) TestDestroyAllErrorCheckpoints(c *C) {
   386  	s.mock.ExpectBegin()
   387  	s.mock.
   388  		ExpectQuery("SELECT (?s:.+)'all' = \\?").
   389  		WithArgs(sqlmock.AnyArg()).
   390  		WillReturnRows(
   391  			sqlmock.NewRows([]string{"table_name", "__min__", "__max__"}).
   392  				AddRow("`db1`.`t2`", -1, 0),
   393  		)
   394  	s.mock.
   395  		ExpectExec("DELETE FROM `mock-schema`\\.chunk_v\\d+ WHERE table_name IN .+ 'all' = \\?").
   396  		WithArgs(sqlmock.AnyArg()).
   397  		WillReturnResult(sqlmock.NewResult(0, 5))
   398  	s.mock.
   399  		ExpectExec("DELETE FROM `mock-schema`\\.engine_v\\d+ WHERE table_name IN .+ 'all' = \\?").
   400  		WithArgs(sqlmock.AnyArg()).
   401  		WillReturnResult(sqlmock.NewResult(0, 3))
   402  	s.mock.
   403  		ExpectExec("DELETE FROM `mock-schema`\\.table_v\\d+ WHERE 'all' = \\?").
   404  		WithArgs(sqlmock.AnyArg()).
   405  		WillReturnResult(sqlmock.NewResult(0, 2))
   406  	s.mock.ExpectCommit()
   407  
   408  	dtc, err := s.cpdb.DestroyErrorCheckpoint(context.Background(), "all")
   409  	c.Assert(err, IsNil)
   410  	c.Assert(dtc, DeepEquals, []checkpoints.DestroyedTableCheckpoint{{
   411  		TableName:   "`db1`.`t2`",
   412  		MinEngineID: -1,
   413  		MaxEngineID: 0,
   414  	}})
   415  }
   416  
   417  func (s *cpSQLSuite) TestDestroyOneErrorCheckpoints(c *C) {
   418  	s.mock.ExpectBegin()
   419  	s.mock.
   420  		ExpectQuery("SELECT (?s:.+)table_name = \\?").
   421  		WithArgs("`db1`.`t2`").
   422  		WillReturnRows(
   423  			sqlmock.NewRows([]string{"table_name", "__min__", "__max__"}).
   424  				AddRow("`db1`.`t2`", -1, 0),
   425  		)
   426  	s.mock.
   427  		ExpectExec("DELETE FROM `mock-schema`\\.chunk_v\\d+ WHERE .+table_name = \\?").
   428  		WithArgs("`db1`.`t2`").
   429  		WillReturnResult(sqlmock.NewResult(0, 4))
   430  	s.mock.
   431  		ExpectExec("DELETE FROM `mock-schema`\\.engine_v\\d+ WHERE .+table_name = \\?").
   432  		WithArgs("`db1`.`t2`").
   433  		WillReturnResult(sqlmock.NewResult(0, 2))
   434  	s.mock.
   435  		ExpectExec("DELETE FROM `mock-schema`\\.table_v\\d+ WHERE table_name = \\?").
   436  		WithArgs("`db1`.`t2`").
   437  		WillReturnResult(sqlmock.NewResult(0, 1))
   438  	s.mock.ExpectCommit()
   439  
   440  	dtc, err := s.cpdb.DestroyErrorCheckpoint(context.Background(), "`db1`.`t2`")
   441  	c.Assert(err, IsNil)
   442  	c.Assert(dtc, DeepEquals, []checkpoints.DestroyedTableCheckpoint{{
   443  		TableName:   "`db1`.`t2`",
   444  		MinEngineID: -1,
   445  		MaxEngineID: 0,
   446  	}})
   447  }
   448  
   449  func (s *cpSQLSuite) TestDump(c *C) {
   450  	ctx := context.Background()
   451  	t := time.Unix(1555555555, 0).UTC()
   452  
   453  	s.mock.
   454  		ExpectQuery("SELECT (?s:.+) FROM `mock-schema`\\.chunk_v\\d+").
   455  		WillReturnRows(
   456  			sqlmock.NewRows([]string{
   457  				"table_name", "path", "offset", "type", "compression", "sort_key", "file_size", "columns",
   458  				"pos", "end_offset", "prev_rowid_max", "rowid_max",
   459  				"kvc_bytes", "kvc_kvs", "kvc_checksum",
   460  				"create_time", "update_time",
   461  			}).AddRow(
   462  				"`db1`.`t2`", "/tmp/path/1.sql", 0, mydump.SourceTypeSQL, mydump.CompressionNone, "", 456, "[]",
   463  				55904, 102400, 681, 5000,
   464  				4491, 586, 486070148917,
   465  				t, t,
   466  			),
   467  		)
   468  
   469  	var csvBuilder strings.Builder
   470  	err := s.cpdb.DumpChunks(ctx, &csvBuilder)
   471  	c.Assert(err, IsNil)
   472  	c.Assert(csvBuilder.String(), Equals,
   473  		"table_name,path,offset,type,compression,sort_key,file_size,columns,pos,end_offset,prev_rowid_max,rowid_max,kvc_bytes,kvc_kvs,kvc_checksum,create_time,update_time\n"+
   474  			"`db1`.`t2`,/tmp/path/1.sql,0,3,0,,456,[],55904,102400,681,5000,4491,586,486070148917,2019-04-18 02:45:55 +0000 UTC,2019-04-18 02:45:55 +0000 UTC\n",
   475  	)
   476  
   477  	s.mock.
   478  		ExpectQuery("SELECT .+ FROM `mock-schema`\\.engine_v\\d+").
   479  		WillReturnRows(
   480  			sqlmock.NewRows([]string{"table_name", "engine_id", "status", "create_time", "update_time"}).
   481  				AddRow("`db1`.`t2`", -1, 30, t, t).
   482  				AddRow("`db1`.`t2`", 0, 120, t, t),
   483  		)
   484  
   485  	csvBuilder.Reset()
   486  	err = s.cpdb.DumpEngines(ctx, &csvBuilder)
   487  	c.Assert(err, IsNil)
   488  	c.Assert(csvBuilder.String(), Equals,
   489  		"table_name,engine_id,status,create_time,update_time\n"+
   490  			"`db1`.`t2`,-1,30,2019-04-18 02:45:55 +0000 UTC,2019-04-18 02:45:55 +0000 UTC\n"+
   491  			"`db1`.`t2`,0,120,2019-04-18 02:45:55 +0000 UTC,2019-04-18 02:45:55 +0000 UTC\n",
   492  	)
   493  
   494  	s.mock.
   495  		ExpectQuery("SELECT .+ FROM `mock-schema`\\.table_v\\d+").
   496  		WillReturnRows(
   497  			sqlmock.NewRows([]string{"task_id", "table_name", "hash", "status", "alloc_base", "create_time", "update_time"}).
   498  				AddRow(1555555555, "`db1`.`t2`", 0, 90, 132861, t, t),
   499  		)
   500  
   501  	csvBuilder.Reset()
   502  	err = s.cpdb.DumpTables(ctx, &csvBuilder)
   503  	c.Assert(err, IsNil)
   504  	c.Assert(csvBuilder.String(), Equals,
   505  		"task_id,table_name,hash,status,alloc_base,create_time,update_time\n"+
   506  			"1555555555,`db1`.`t2`,0,90,132861,2019-04-18 02:45:55 +0000 UTC,2019-04-18 02:45:55 +0000 UTC\n",
   507  	)
   508  }
   509  
   510  func (s *cpSQLSuite) TestMoveCheckpoints(c *C) {
   511  	ctx := context.Background()
   512  
   513  	s.mock.
   514  		ExpectExec("CREATE SCHEMA IF NOT EXISTS `mock-schema\\.12345678\\.bak`").
   515  		WillReturnResult(sqlmock.NewResult(1, 1))
   516  	s.mock.
   517  		ExpectExec("RENAME TABLE `mock-schema`\\.chunk_v\\d+ TO `mock-schema\\.12345678\\.bak`\\.chunk_v\\d+").
   518  		WillReturnResult(sqlmock.NewResult(0, 1))
   519  	s.mock.
   520  		ExpectExec("RENAME TABLE `mock-schema`\\.engine_v\\d+ TO `mock-schema\\.12345678\\.bak`\\.engine_v\\d+").
   521  		WillReturnResult(sqlmock.NewResult(0, 1))
   522  	s.mock.
   523  		ExpectExec("RENAME TABLE `mock-schema`\\.table_v\\d+ TO `mock-schema\\.12345678\\.bak`\\.table_v\\d+").
   524  		WillReturnResult(sqlmock.NewResult(0, 1))
   525  	s.mock.
   526  		ExpectExec("RENAME TABLE `mock-schema`\\.task_v\\d+ TO `mock-schema\\.12345678\\.bak`\\.task_v\\d+").
   527  		WillReturnResult(sqlmock.NewResult(0, 1))
   528  
   529  	err := s.cpdb.MoveCheckpoints(ctx, 12345678)
   530  	c.Assert(err, IsNil)
   531  }