From a46c12a31f94a3a2eb79497731b9d6813211c342 Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Wed, 9 Oct 2024 18:26:42 +0800 Subject: [PATCH 1/6] domain: fix play replay dump cannot save the table in the foreign key's reference Signed-off-by: Weizhen Wang --- pkg/domain/extract.go | 5 ++++- pkg/domain/plan_replayer_dump.go | 20 +++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/pkg/domain/extract.go b/pkg/domain/extract.go index 7bef58b6939ab..7f0032de93923 100644 --- a/pkg/domain/extract.go +++ b/pkg/domain/extract.go @@ -290,7 +290,10 @@ func (w *extractWorker) handleIsView(ctx context.Context, p *extractPlanPackage) if tne.err != nil { return tne.err } - r := tne.getTablesAndViews() + r, err := tne.getTablesAndViews() + if err != nil { + return err + } for t := range r { p.tables[t] = struct{}{} } diff --git a/pkg/domain/plan_replayer_dump.go b/pkg/domain/plan_replayer_dump.go index 29601e6d7f667..70f06fa8c05bd 100644 --- a/pkg/domain/plan_replayer_dump.go +++ b/pkg/domain/plan_replayer_dump.go @@ -97,7 +97,7 @@ type tableNameExtractor struct { err error } -func (tne *tableNameExtractor) getTablesAndViews() map[tableNamePair]struct{} { +func (tne *tableNameExtractor) getTablesAndViews() (map[tableNamePair]struct{}, error) { r := make(map[tableNamePair]struct{}) for tablePair := range tne.names { if tablePair.IsView { @@ -109,8 +109,22 @@ func (tne *tableNameExtractor) getTablesAndViews() map[tableNamePair]struct{} { if !ok { r[tablePair] = struct{}{} } + // if the table has a foreign key, we need to add the referenced table to the list + tblInfo, err := tne.is.TableByName(tne.ctx, model.NewCIStr(tablePair.DBName), model.NewCIStr(tablePair.TableName)) + if err != nil { + return nil, err + } + for _, fk := range tblInfo.Meta().ForeignKeys { + key := tableNamePair{ + DBName: fk.RefSchema.String(), + TableName: fk.RefTable.String(), + IsView: false, + } + r[key] = struct{}{} + } + } - return r + return r, nil } func (*tableNameExtractor) Enter(in ast.Node) (ast.Node, bool) { @@ -776,7 +790,7 @@ func extractTableNames(ctx context.Context, sctx sessionctx.Context, if tableExtractor.err != nil { return nil, tableExtractor.err } - return tableExtractor.getTablesAndViews(), nil + return tableExtractor.getTablesAndViews() } func getStatsForTable(do *Domain, pair tableNamePair, historyStatsTS uint64) (*util.JSONTable, []string, error) { From 6c06a9241ee05136cc91d3f2e5783777044430a2 Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Wed, 9 Oct 2024 18:32:38 +0800 Subject: [PATCH 2/6] update --- pkg/server/handler/optimizor/plan_replayer_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/server/handler/optimizor/plan_replayer_test.go b/pkg/server/handler/optimizor/plan_replayer_test.go index 34b19ed35f71d..7bb95a75b79ed 100644 --- a/pkg/server/handler/optimizor/plan_replayer_test.go +++ b/pkg/server/handler/optimizor/plan_replayer_test.go @@ -330,7 +330,8 @@ func prepareData4Issue43192(t *testing.T, client *testserverclient.TestServerCli tk.MustExec("create database planReplayer") tk.MustExec("use planReplayer") - tk.MustExec("create table t(a int, b int, INDEX ia (a), INDEX ib (b));") + tk.MustExec("CREATE TABLE authors (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(100) NOT NULL,email VARCHAR(100) UNIQUE NOT NULL);") + tk.MustExec("create table t(a int, b int, INDEX ia (a), INDEX ib (b), FOREIGN KEY (author_id) REFERENCES authors(id) ON DELETE CASCADE);") err = h.HandleDDLEvent(<-h.DDLEventCh()) require.NoError(t, err) 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)") From d73564882ee0db030b1f29d284114af64c9a063e Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Wed, 9 Oct 2024 18:59:01 +0800 Subject: [PATCH 3/6] update test --- pkg/domain/plan_replayer_dump.go | 4 +- .../handler/optimizor/plan_replayer_test.go | 76 +++++++++++++++++++ 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/pkg/domain/plan_replayer_dump.go b/pkg/domain/plan_replayer_dump.go index 70f06fa8c05bd..61cde8594ff2d 100644 --- a/pkg/domain/plan_replayer_dump.go +++ b/pkg/domain/plan_replayer_dump.go @@ -116,8 +116,8 @@ func (tne *tableNameExtractor) getTablesAndViews() (map[tableNamePair]struct{}, } for _, fk := range tblInfo.Meta().ForeignKeys { key := tableNamePair{ - DBName: fk.RefSchema.String(), - TableName: fk.RefTable.String(), + DBName: fk.RefSchema.L, + TableName: fk.RefTable.L, IsView: false, } r[key] = struct{}{} diff --git a/pkg/server/handler/optimizor/plan_replayer_test.go b/pkg/server/handler/optimizor/plan_replayer_test.go index 7bb95a75b79ed..747988f11a107 100644 --- a/pkg/server/handler/optimizor/plan_replayer_test.go +++ b/pkg/server/handler/optimizor/plan_replayer_test.go @@ -249,6 +249,55 @@ func prepareData4PlanReplayer(t *testing.T, client *testserverclient.TestServerC return filename, filename3 } +func TestIssue56458(t *testing.T) { + store := testkit.CreateMockStore(t) + dom, err := session.GetDomain(store) + require.NoError(t, err) + // 1. setup and prepare plan replayer files by manual command and capture + server, client := prepareServerAndClientForTest(t, store, dom) + defer server.Close() + + filename := prepareData4Issue56458(t, client, dom) + defer os.RemoveAll(replayer.GetPlanReplayerDirName()) + + // 2. check the contents of the plan replayer zip files. + var filesInReplayer []string + collectFileNameAndAssertFileSize := func(f *zip.File) { + // collect file name + filesInReplayer = append(filesInReplayer, f.Name) + } + + // 2-1. check the plan replayer file from manual command + resp0, err := client.FetchStatus(filepath.Join("/plan_replayer/dump/", filename)) + require.NoError(t, err) + defer func() { + require.NoError(t, resp0.Body.Close()) + }() + body, err := io.ReadAll(resp0.Body) + require.NoError(t, err) + forEachFileInZipBytes(t, body, collectFileNameAndAssertFileSize) + slices.Sort(filesInReplayer) + require.Equal(t, []string{ + "config.toml", + "debug_trace/debug_trace0.json", + "explain.txt", + "global_bindings.sql", + "meta.txt", + "schema/planreplayer.t.schema.txt", + "schema/planreplayer.v.schema.txt", + "schema/schema_meta.txt", + "session_bindings.sql", + "sql/sql0.sql", + "sql_meta.toml", + "stats/planreplayer.t.json", + "stats/planreplayer.v.json", + "statsMem/planreplayer.t.txt", + "statsMem/planreplayer.v.txt", + "table_tiflash_replica.txt", + "variables.toml", + }, filesInReplayer) +} + func TestIssue43192(t *testing.T) { store := testkit.CreateMockStore(t) dom, err := session.GetDomain(store) @@ -345,6 +394,33 @@ func prepareData4Issue43192(t *testing.T, client *testserverclient.TestServerCli return filename } +func prepareData4Issue56458(t *testing.T, client *testserverclient.TestServerClient, dom *domain.Domain) string { + h := dom.StatsHandle() + db, err := sql.Open("mysql", client.GetDSN()) + require.NoError(t, err, "Error connecting") + defer func() { + err := db.Close() + require.NoError(t, err) + }() + tk := testkit.NewDBTestKit(t, db) + + tk.MustExec("create database planReplayer") + tk.MustExec("use planReplayer") + tk.MustExec("CREATE TABLE v(id INT PRIMARY KEY AUTO_INCREMENT);") + 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);") + err = h.HandleDDLEvent(<-h.DDLEventCh()) + require.NoError(t, err) + 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)") + rows := tk.MustQuery("plan replayer dump explain select a, b from t where a in (1, 2, 3)") + require.True(t, rows.Next(), "unexpected data") + var filename string + require.NoError(t, rows.Scan(&filename)) + require.NoError(t, rows.Close()) + rows = tk.MustQuery("select @@tidb_last_plan_replayer_token") + require.True(t, rows.Next(), "unexpected data") + return filename +} + func forEachFileInZipBytes(t *testing.T, b []byte, fn func(file *zip.File)) { br := bytes.NewReader(b) z, err := zip.NewReader(br, int64(len(b))) From baa81173256f1a7de41188c5648431aaeeec2f84 Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Wed, 9 Oct 2024 18:59:55 +0800 Subject: [PATCH 4/6] update test --- pkg/server/handler/optimizor/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/server/handler/optimizor/BUILD.bazel b/pkg/server/handler/optimizor/BUILD.bazel index a267c4a2b323f..f1281d3456b1e 100644 --- a/pkg/server/handler/optimizor/BUILD.bazel +++ b/pkg/server/handler/optimizor/BUILD.bazel @@ -44,7 +44,7 @@ go_test( "statistics_handler_test.go", ], flaky = True, - shard_count = 5, + shard_count = 6, deps = [ ":optimizor", "//pkg/config", From 0e9761de047bd0a7dccf6d0feedf0f3afe763dce Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Wed, 9 Oct 2024 19:05:57 +0800 Subject: [PATCH 5/6] update test --- pkg/domain/plan_replayer_dump.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/domain/plan_replayer_dump.go b/pkg/domain/plan_replayer_dump.go index 61cde8594ff2d..5c311e989b64a 100644 --- a/pkg/domain/plan_replayer_dump.go +++ b/pkg/domain/plan_replayer_dump.go @@ -122,7 +122,6 @@ func (tne *tableNameExtractor) getTablesAndViews() (map[tableNamePair]struct{}, } r[key] = struct{}{} } - } return r, nil } From 6617f8ec6041af6b35a67c661f799fa9dc403599 Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Wed, 9 Oct 2024 19:57:14 +0800 Subject: [PATCH 6/6] update test --- pkg/server/handler/optimizor/plan_replayer_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/server/handler/optimizor/plan_replayer_test.go b/pkg/server/handler/optimizor/plan_replayer_test.go index 747988f11a107..5ddbc1e4baed1 100644 --- a/pkg/server/handler/optimizor/plan_replayer_test.go +++ b/pkg/server/handler/optimizor/plan_replayer_test.go @@ -379,8 +379,7 @@ func prepareData4Issue43192(t *testing.T, client *testserverclient.TestServerCli tk.MustExec("create database planReplayer") tk.MustExec("use planReplayer") - tk.MustExec("CREATE TABLE authors (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(100) NOT NULL,email VARCHAR(100) UNIQUE NOT NULL);") - tk.MustExec("create table t(a int, b int, INDEX ia (a), INDEX ib (b), FOREIGN KEY (author_id) REFERENCES authors(id) ON DELETE CASCADE);") + tk.MustExec("create table t(a int, b int, INDEX ia (a), INDEX ib (b));") err = h.HandleDDLEvent(<-h.DDLEventCh()) require.NoError(t, err) 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)")