Skip to content

Commit 1eb0c8c

Browse files
authored
domain: fix play replay dump cannot save the table in the foreign key's reference (#56512)
close #56458
1 parent c43d058 commit 1eb0c8c

File tree

4 files changed

+97
-5
lines changed

4 files changed

+97
-5
lines changed

pkg/domain/extract.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,10 @@ func (w *extractWorker) handleIsView(ctx context.Context, p *extractPlanPackage)
290290
if tne.err != nil {
291291
return tne.err
292292
}
293-
r := tne.getTablesAndViews()
293+
r, err := tne.getTablesAndViews()
294+
if err != nil {
295+
return err
296+
}
294297
for t := range r {
295298
p.tables[t] = struct{}{}
296299
}

pkg/domain/plan_replayer_dump.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ type tableNameExtractor struct {
9797
err error
9898
}
9999

100-
func (tne *tableNameExtractor) getTablesAndViews() map[tableNamePair]struct{} {
100+
func (tne *tableNameExtractor) getTablesAndViews() (map[tableNamePair]struct{}, error) {
101101
r := make(map[tableNamePair]struct{})
102102
for tablePair := range tne.names {
103103
if tablePair.IsView {
@@ -109,8 +109,21 @@ func (tne *tableNameExtractor) getTablesAndViews() map[tableNamePair]struct{} {
109109
if !ok {
110110
r[tablePair] = struct{}{}
111111
}
112+
// if the table has a foreign key, we need to add the referenced table to the list
113+
tblInfo, err := tne.is.TableByName(tne.ctx, model.NewCIStr(tablePair.DBName), model.NewCIStr(tablePair.TableName))
114+
if err != nil {
115+
return nil, err
116+
}
117+
for _, fk := range tblInfo.Meta().ForeignKeys {
118+
key := tableNamePair{
119+
DBName: fk.RefSchema.L,
120+
TableName: fk.RefTable.L,
121+
IsView: false,
122+
}
123+
r[key] = struct{}{}
124+
}
112125
}
113-
return r
126+
return r, nil
114127
}
115128

116129
func (*tableNameExtractor) Enter(in ast.Node) (ast.Node, bool) {
@@ -776,7 +789,7 @@ func extractTableNames(ctx context.Context, sctx sessionctx.Context,
776789
if tableExtractor.err != nil {
777790
return nil, tableExtractor.err
778791
}
779-
return tableExtractor.getTablesAndViews(), nil
792+
return tableExtractor.getTablesAndViews()
780793
}
781794

782795
func getStatsForTable(do *Domain, pair tableNamePair, historyStatsTS uint64) (*util.JSONTable, []string, error) {

pkg/server/handler/optimizor/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ go_test(
4444
"statistics_handler_test.go",
4545
],
4646
flaky = True,
47-
shard_count = 5,
47+
shard_count = 6,
4848
deps = [
4949
":optimizor",
5050
"//pkg/config",

pkg/server/handler/optimizor/plan_replayer_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,55 @@ func prepareData4PlanReplayer(t *testing.T, client *testserverclient.TestServerC
249249
return filename, filename3
250250
}
251251

252+
func TestIssue56458(t *testing.T) {
253+
store := testkit.CreateMockStore(t)
254+
dom, err := session.GetDomain(store)
255+
require.NoError(t, err)
256+
// 1. setup and prepare plan replayer files by manual command and capture
257+
server, client := prepareServerAndClientForTest(t, store, dom)
258+
defer server.Close()
259+
260+
filename := prepareData4Issue56458(t, client, dom)
261+
defer os.RemoveAll(replayer.GetPlanReplayerDirName())
262+
263+
// 2. check the contents of the plan replayer zip files.
264+
var filesInReplayer []string
265+
collectFileNameAndAssertFileSize := func(f *zip.File) {
266+
// collect file name
267+
filesInReplayer = append(filesInReplayer, f.Name)
268+
}
269+
270+
// 2-1. check the plan replayer file from manual command
271+
resp0, err := client.FetchStatus(filepath.Join("/plan_replayer/dump/", filename))
272+
require.NoError(t, err)
273+
defer func() {
274+
require.NoError(t, resp0.Body.Close())
275+
}()
276+
body, err := io.ReadAll(resp0.Body)
277+
require.NoError(t, err)
278+
forEachFileInZipBytes(t, body, collectFileNameAndAssertFileSize)
279+
slices.Sort(filesInReplayer)
280+
require.Equal(t, []string{
281+
"config.toml",
282+
"debug_trace/debug_trace0.json",
283+
"explain.txt",
284+
"global_bindings.sql",
285+
"meta.txt",
286+
"schema/planreplayer.t.schema.txt",
287+
"schema/planreplayer.v.schema.txt",
288+
"schema/schema_meta.txt",
289+
"session_bindings.sql",
290+
"sql/sql0.sql",
291+
"sql_meta.toml",
292+
"stats/planreplayer.t.json",
293+
"stats/planreplayer.v.json",
294+
"statsMem/planreplayer.t.txt",
295+
"statsMem/planreplayer.v.txt",
296+
"table_tiflash_replica.txt",
297+
"variables.toml",
298+
}, filesInReplayer)
299+
}
300+
252301
func TestIssue43192(t *testing.T) {
253302
store := testkit.CreateMockStore(t)
254303
dom, err := session.GetDomain(store)
@@ -344,6 +393,33 @@ func prepareData4Issue43192(t *testing.T, client *testserverclient.TestServerCli
344393
return filename
345394
}
346395

396+
func prepareData4Issue56458(t *testing.T, client *testserverclient.TestServerClient, dom *domain.Domain) string {
397+
h := dom.StatsHandle()
398+
db, err := sql.Open("mysql", client.GetDSN())
399+
require.NoError(t, err, "Error connecting")
400+
defer func() {
401+
err := db.Close()
402+
require.NoError(t, err)
403+
}()
404+
tk := testkit.NewDBTestKit(t, db)
405+
406+
tk.MustExec("create database planReplayer")
407+
tk.MustExec("use planReplayer")
408+
tk.MustExec("CREATE TABLE v(id INT PRIMARY KEY AUTO_INCREMENT);")
409+
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);")
410+
err = h.HandleDDLEvent(<-h.DDLEventCh())
411+
require.NoError(t, err)
412+
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)")
413+
rows := tk.MustQuery("plan replayer dump explain select a, b from t where a in (1, 2, 3)")
414+
require.True(t, rows.Next(), "unexpected data")
415+
var filename string
416+
require.NoError(t, rows.Scan(&filename))
417+
require.NoError(t, rows.Close())
418+
rows = tk.MustQuery("select @@tidb_last_plan_replayer_token")
419+
require.True(t, rows.Next(), "unexpected data")
420+
return filename
421+
}
422+
347423
func forEachFileInZipBytes(t *testing.T, b []byte, fn func(file *zip.File)) {
348424
br := bytes.NewReader(b)
349425
z, err := zip.NewReader(br, int64(len(b)))

0 commit comments

Comments
 (0)