Skip to content

Commit 1f32c8e

Browse files
authored
domain: fix the issue where defining FKs in a circular manner causes an infinite loop (#60987)
close #60985
1 parent eeafa7d commit 1f32c8e

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

pkg/domain/plan_replayer_dump.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ func findFK(is infoschema.InfoSchema, dbName, tableName string, tableMap map[tab
129129
TableName: fk.RefTable.L,
130130
IsView: false,
131131
}
132+
// Skip already visited tables to prevent infinite recursion in case of circular foreign key definitions.
133+
if _, ok := tableMap[key]; ok {
134+
continue
135+
}
132136
tableMap[key] = struct{}{}
133137
err := findFK(is, key.DBName, key.TableName, tableMap)
134138
if err != nil {

pkg/server/handler/optimizor/plan_replayer_test.go

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,16 +290,25 @@ func TestPlanReplayerWithMultiForeignKey(t *testing.T) {
290290
"explain.txt",
291291
"global_bindings.sql",
292292
"meta.txt",
293+
"schema/planreplayer.a.schema.txt",
294+
"schema/planreplayer.b.schema.txt",
295+
"schema/planreplayer.c.schema.txt",
293296
"schema/planreplayer.t.schema.txt",
294297
"schema/planreplayer.v.schema.txt",
295298
"schema/planreplayer2.t.schema.txt",
296299
"schema/schema_meta.txt",
297300
"session_bindings.sql",
298301
"sql/sql0.sql",
299302
"sql_meta.toml",
303+
"stats/planreplayer.a.json",
304+
"stats/planreplayer.b.json",
305+
"stats/planreplayer.c.json",
300306
"stats/planreplayer.t.json",
301307
"stats/planreplayer.v.json",
302308
"stats/planreplayer2.t.json",
309+
"statsMem/planreplayer.a.txt",
310+
"statsMem/planreplayer.b.txt",
311+
"statsMem/planreplayer.c.txt",
303312
"statsMem/planreplayer.t.txt",
304313
"statsMem/planreplayer.v.txt",
305314
"statsMem/planreplayer2.t.txt",
@@ -334,9 +343,14 @@ func TestPlanReplayerWithMultiForeignKey(t *testing.T) {
334343
}()
335344
tk := testkit.NewDBTestKit(t, db)
336345
tk.MustExec("use planReplayer")
346+
tk.MustExec(`SET FOREIGN_KEY_CHECKS = 0;`)
337347
tk.MustExec("drop table planReplayer.t")
338348
tk.MustExec("drop table planReplayer2.t")
339349
tk.MustExec("drop table planReplayer.v")
350+
tk.MustExec("drop table planReplayer.a")
351+
tk.MustExec("drop table planReplayer.b")
352+
tk.MustExec("drop table planReplayer.c")
353+
tk.MustExec(`SET FOREIGN_KEY_CHECKS = 1;`)
340354
tk.MustExec(fmt.Sprintf(`plan replayer load "%s"`, path))
341355

342356
// 3-3. check whether binding takes effect
@@ -458,7 +472,7 @@ func prepareData4Issue56458(t *testing.T, client *testserverclient.TestServerCli
458472
require.NoError(t, err)
459473
}()
460474
tk := testkit.NewDBTestKit(t, db)
461-
475+
tk.MustExec(`SET FOREIGN_KEY_CHECKS = 0;`)
462476
tk.MustExec("create database planReplayer")
463477
tk.MustExec("create database planReplayer2")
464478
tk.MustExec("use planReplayer")
@@ -473,10 +487,35 @@ func prepareData4Issue56458(t *testing.T, client *testserverclient.TestServerCli
473487
tk.MustExec("create table planReplayer2.t(a int, b int, INDEX ia (a), INDEX ib (b), author_id int, FOREIGN KEY (author_id) REFERENCES planReplayer.v(id) ON DELETE CASCADE);")
474488
err = statstestutil.HandleNextDDLEventWithTxn(h)
475489
require.NoError(t, err)
476-
tk.MustExec("create table t(a int, b int, INDEX ia (a), INDEX ib (b), author_id int, FOREIGN KEY (author_id) REFERENCES planReplayer2.t(a) ON DELETE CASCADE) placement policy p;")
490+
tk.MustExec("create table t(a int, b int, INDEX ia (a), INDEX ib (b), author_id int, b_id int, FOREIGN KEY (b_id) REFERENCES B(id),FOREIGN KEY (author_id) REFERENCES planReplayer2.t(a) ON DELETE CASCADE) placement policy p;")
477491
err = statstestutil.HandleNextDDLEventWithTxn(h)
478492
require.NoError(t, err)
479-
493+
// defining FKs in a circular manner
494+
tk.MustExec(`CREATE TABLE A (
495+
id INT AUTO_INCREMENT PRIMARY KEY,
496+
name VARCHAR(50) NOT NULL,
497+
b_id INT,
498+
FOREIGN KEY (b_id) REFERENCES B(id)
499+
);`)
500+
err = statstestutil.HandleNextDDLEventWithTxn(h)
501+
require.NoError(t, err)
502+
tk.MustExec(`CREATE TABLE B (
503+
id INT AUTO_INCREMENT PRIMARY KEY,
504+
name VARCHAR(50) NOT NULL,
505+
c_id INT,
506+
FOREIGN KEY (c_id) REFERENCES C(id)
507+
);`)
508+
err = statstestutil.HandleNextDDLEventWithTxn(h)
509+
require.NoError(t, err)
510+
tk.MustExec(`CREATE TABLE C(
511+
id INT AUTO_INCREMENT PRIMARY KEY,
512+
name VARCHAR(50) NOT NULL,
513+
a_id INT,
514+
FOREIGN KEY (a_id) REFERENCES A(id)
515+
);`)
516+
err = statstestutil.HandleNextDDLEventWithTxn(h)
517+
require.NoError(t, err)
518+
tk.MustExec(`SET FOREIGN_KEY_CHECKS = 1;`)
480519
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)")
481520
rows := tk.MustQuery("plan replayer dump explain select a, b from t where a in (1, 2, 3)")
482521
require.True(t, rows.Next(), "unexpected data")

0 commit comments

Comments
 (0)