@@ -42,6 +42,7 @@ import (
42
42
"github.com/pingcap/tidb/pkg/session"
43
43
util2 "github.com/pingcap/tidb/pkg/statistics/handle/util"
44
44
"github.com/pingcap/tidb/pkg/testkit"
45
+ "github.com/pingcap/tidb/pkg/util/replayer"
45
46
"github.com/stretchr/testify/require"
46
47
"github.com/tikv/client-go/v2/oracle"
47
48
)
@@ -246,6 +247,177 @@ func prepareData4PlanReplayer(t *testing.T, client *testserverclient.TestServerC
246
247
return filename , filename3
247
248
}
248
249
250
+ func TestIssue56458 (t * testing.T ) {
251
+ store := testkit .CreateMockStore (t )
252
+ dom , err := session .GetDomain (store )
253
+ require .NoError (t , err )
254
+ // 1. setup and prepare plan replayer files by manual command and capture
255
+ server , client := prepareServerAndClientForTest (t , store , dom )
256
+ defer server .Close ()
257
+
258
+ filename := prepareData4Issue56458 (t , client , dom )
259
+ defer os .RemoveAll (replayer .GetPlanReplayerDirName ())
260
+
261
+ // 2. check the contents of the plan replayer zip files.
262
+ var filesInReplayer []string
263
+ collectFileNameAndAssertFileSize := func (f * zip.File ) {
264
+ // collect file name
265
+ filesInReplayer = append (filesInReplayer , f .Name )
266
+ }
267
+
268
+ // 2-1. check the plan replayer file from manual command
269
+ resp0 , err := client .FetchStatus (filepath .Join ("/plan_replayer/dump/" , filename ))
270
+ require .NoError (t , err )
271
+ defer func () {
272
+ require .NoError (t , resp0 .Body .Close ())
273
+ }()
274
+ body , err := io .ReadAll (resp0 .Body )
275
+ require .NoError (t , err )
276
+ forEachFileInZipBytes (t , body , collectFileNameAndAssertFileSize )
277
+ slices .Sort (filesInReplayer )
278
+ require .Equal (t , []string {
279
+ "config.toml" ,
280
+ "debug_trace/debug_trace0.json" ,
281
+ "explain.txt" ,
282
+ "global_bindings.sql" ,
283
+ "meta.txt" ,
284
+ "schema/planreplayer.t.schema.txt" ,
285
+ "schema/planreplayer.v.schema.txt" ,
286
+ "schema/schema_meta.txt" ,
287
+ "session_bindings.sql" ,
288
+ "sql/sql0.sql" ,
289
+ "sql_meta.toml" ,
290
+ "stats/planreplayer.t.json" ,
291
+ "stats/planreplayer.v.json" ,
292
+ "statsMem/planreplayer.t.txt" ,
293
+ "statsMem/planreplayer.v.txt" ,
294
+ "table_tiflash_replica.txt" ,
295
+ "variables.toml" ,
296
+ }, filesInReplayer )
297
+ }
298
+
299
+ func TestIssue43192 (t * testing.T ) {
300
+ store := testkit .CreateMockStore (t )
301
+ dom , err := session .GetDomain (store )
302
+ require .NoError (t , err )
303
+ // 1. setup and prepare plan replayer files by manual command and capture
304
+ server , client := prepareServerAndClientForTest (t , store , dom )
305
+ defer server .Close ()
306
+
307
+ filename := prepareData4Issue43192 (t , client , dom )
308
+ defer os .RemoveAll (replayer .GetPlanReplayerDirName ())
309
+
310
+ // 2. check the contents of the plan replayer zip files.
311
+ var filesInReplayer []string
312
+ collectFileNameAndAssertFileSize := func (f * zip.File ) {
313
+ // collect file name
314
+ filesInReplayer = append (filesInReplayer , f .Name )
315
+ }
316
+
317
+ // 2-1. check the plan replayer file from manual command
318
+ resp0 , err := client .FetchStatus (filepath .Join ("/plan_replayer/dump/" , filename ))
319
+ require .NoError (t , err )
320
+ defer func () {
321
+ require .NoError (t , resp0 .Body .Close ())
322
+ }()
323
+ body , err := io .ReadAll (resp0 .Body )
324
+ require .NoError (t , err )
325
+ forEachFileInZipBytes (t , body , collectFileNameAndAssertFileSize )
326
+ slices .Sort (filesInReplayer )
327
+ require .Equal (t , expectedFilesInReplayer , filesInReplayer )
328
+
329
+ // 3. check plan replayer load
330
+ // 3-1. write the plan replayer file from manual command to a file
331
+ path := "/tmp/plan_replayer.zip"
332
+ fp , err := os .Create (path )
333
+ require .NoError (t , err )
334
+ require .NotNil (t , fp )
335
+ defer func () {
336
+ require .NoError (t , fp .Close ())
337
+ require .NoError (t , os .Remove (path ))
338
+ }()
339
+
340
+ _ , err = io .Copy (fp , bytes .NewReader (body ))
341
+ require .NoError (t , err )
342
+ require .NoError (t , fp .Sync ())
343
+
344
+ // 3-2. connect to tidb and use PLAN REPLAYER LOAD to load this file
345
+ db , err := sql .Open ("mysql" , client .GetDSN (func (config * mysql.Config ) {
346
+ config .AllowAllFiles = true
347
+ }))
348
+ require .NoError (t , err , "Error connecting" )
349
+ defer func () {
350
+ err := db .Close ()
351
+ require .NoError (t , err )
352
+ }()
353
+ tk := testkit .NewDBTestKit (t , db )
354
+ tk .MustExec ("use planReplayer" )
355
+ tk .MustExec ("drop table planReplayer.t" )
356
+ tk .MustExec (`plan replayer load "/tmp/plan_replayer.zip"` )
357
+
358
+ // 3-3. check whether binding takes effect
359
+ tk .MustExec (`select a, b from t where a in (1, 2, 3)` )
360
+ rows := tk .MustQuery ("select @@last_plan_from_binding" )
361
+ require .True (t , rows .Next (), "unexpected data" )
362
+ var count int64
363
+ err = rows .Scan (& count )
364
+ require .NoError (t , err )
365
+ require .Equal (t , int64 (1 ), count )
366
+ }
367
+
368
+ func prepareData4Issue43192 (t * testing.T , client * testserverclient.TestServerClient , dom * domain.Domain ) string {
369
+ h := dom .StatsHandle ()
370
+ db , err := sql .Open ("mysql" , client .GetDSN ())
371
+ require .NoError (t , err , "Error connecting" )
372
+ defer func () {
373
+ err := db .Close ()
374
+ require .NoError (t , err )
375
+ }()
376
+ tk := testkit .NewDBTestKit (t , db )
377
+
378
+ tk .MustExec ("create database planReplayer" )
379
+ tk .MustExec ("use planReplayer" )
380
+ tk .MustExec ("create table t(a int, b int, INDEX ia (a), INDEX ib (b));" )
381
+ err = h .HandleDDLEvent (<- h .DDLEventCh ())
382
+ require .NoError (t , err )
383
+ tk .MustExec ("create global binding for select a, b from t where a in (1, 2, 3) using select a, b from t use index (ib) where a in (1, 2, 3)" )
384
+ rows := tk .MustQuery ("plan replayer dump explain select a, b from t where a in (1, 2, 3)" )
385
+ require .True (t , rows .Next (), "unexpected data" )
386
+ var filename string
387
+ require .NoError (t , rows .Scan (& filename ))
388
+ require .NoError (t , rows .Close ())
389
+ rows = tk .MustQuery ("select @@tidb_last_plan_replayer_token" )
390
+ require .True (t , rows .Next (), "unexpected data" )
391
+ return filename
392
+ }
393
+
394
+ func prepareData4Issue56458 (t * testing.T , client * testserverclient.TestServerClient , dom * domain.Domain ) string {
395
+ h := dom .StatsHandle ()
396
+ db , err := sql .Open ("mysql" , client .GetDSN ())
397
+ require .NoError (t , err , "Error connecting" )
398
+ defer func () {
399
+ err := db .Close ()
400
+ require .NoError (t , err )
401
+ }()
402
+ tk := testkit .NewDBTestKit (t , db )
403
+
404
+ tk .MustExec ("create database planReplayer" )
405
+ tk .MustExec ("use planReplayer" )
406
+ tk .MustExec ("CREATE TABLE v(id INT PRIMARY KEY AUTO_INCREMENT);" )
407
+ tk .MustExec ("create table t(a int, b int, INDEX ia (a), INDEX ib (b), author_id int, FOREIGN KEY (author_id) REFERENCES v(id) ON DELETE CASCADE);" )
408
+ err = h .HandleDDLEvent (<- h .DDLEventCh ())
409
+ require .NoError (t , err )
410
+ tk .MustExec ("create global binding for select a, b from t where a in (1, 2, 3) using select a, b from t use index (ib) where a in (1, 2, 3)" )
411
+ rows := tk .MustQuery ("plan replayer dump explain select a, b from t where a in (1, 2, 3)" )
412
+ require .True (t , rows .Next (), "unexpected data" )
413
+ var filename string
414
+ require .NoError (t , rows .Scan (& filename ))
415
+ require .NoError (t , rows .Close ())
416
+ rows = tk .MustQuery ("select @@tidb_last_plan_replayer_token" )
417
+ require .True (t , rows .Next (), "unexpected data" )
418
+ return filename
419
+ }
420
+
249
421
func forEachFileInZipBytes (t * testing.T , b []byte , fn func (file * zip.File )) {
250
422
br := bytes .NewReader (b )
251
423
z , err := zip .NewReader (br , int64 (len (b )))
0 commit comments