diff --git a/pkg/executor/foreign_key.go b/pkg/executor/foreign_key.go index 0be34226d4756..5f0c7e701bbd8 100644 --- a/pkg/executor/foreign_key.go +++ b/pkg/executor/foreign_key.go @@ -223,7 +223,7 @@ func (fkc *FKCheckExec) doCheck(ctx context.Context) error { fkc.stats = &FKCheckRuntimeStats{} defer fkc.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(fkc.ID(), fkc.stats) } - if len(fkc.toBeCheckedKeys) == 0 && len(fkc.toBeCheckedPrefixKeys) == 0 { + if len(fkc.toBeCheckedKeys) == 0 && len(fkc.toBeCheckedPrefixKeys) == 0 && len(fkc.toBeLockedKeys) == 0 { return nil } start := time.Now() @@ -248,6 +248,7 @@ func (fkc *FKCheckExec) doCheck(ctx context.Context) error { if fkc.stats != nil { fkc.stats.Check = time.Since(start) } + if len(fkc.toBeLockedKeys) == 0 { return nil } @@ -542,7 +543,7 @@ type fkCheckKey struct { isPrefix bool } -func (fkc FKCheckExec) checkRows(ctx context.Context, sc *stmtctx.StatementContext, txn kv.Transaction, rows []toBeCheckedRow) error { +func (fkc *FKCheckExec) checkRows(ctx context.Context, sc *stmtctx.StatementContext, txn kv.Transaction, rows []toBeCheckedRow) error { if fkc.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl != nil { fkc.stats = &FKCheckRuntimeStats{} defer fkc.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(fkc.ID(), fkc.stats) diff --git a/pkg/executor/test/fktest/BUILD.bazel b/pkg/executor/test/fktest/BUILD.bazel index 0ff8067748db4..c538eb7ae46de 100644 --- a/pkg/executor/test/fktest/BUILD.bazel +++ b/pkg/executor/test/fktest/BUILD.bazel @@ -8,7 +8,7 @@ go_test( "main_test.go", ], flaky = True, - shard_count = 26, + shard_count = 27, deps = [ "//pkg/config", "//pkg/executor", diff --git a/pkg/executor/test/fktest/foreign_key_test.go b/pkg/executor/test/fktest/foreign_key_test.go index 141538238dc80..130cb8392797e 100644 --- a/pkg/executor/test/fktest/foreign_key_test.go +++ b/pkg/executor/test/fktest/foreign_key_test.go @@ -2088,8 +2088,8 @@ func TestExplainAnalyzeDMLWithFKInfo(t *testing.T) { { sql: "explain analyze insert ignore into t6 values (1,1,10)", plan: "Insert_.* root time:.* loops:.* prepare:.* check_insert.* fk_check:.*" + - "├─Foreign_Key_Check.* 0 root table:t5 total:0s, foreign_keys:1 foreign_key:fk_1, check_exist N/A N/A.*" + - "├─Foreign_Key_Check.* 0 root table:t5, index:idx2 total:0s, foreign_keys:1 foreign_key:fk_2, check_exist N/A N/A.*" + + "├─Foreign_Key_Check.* 0 root table:t5 total:.*, lock:.*, foreign_keys:1 foreign_key:fk_1, check_exist N/A N/A.*" + + "├─Foreign_Key_Check.* 0 root table:t5, index:idx2 total:.*, lock:.*, foreign_keys:1 foreign_key:fk_2, check_exist N/A N/A.*" + "└─Foreign_Key_Check.* 0 root table:t5, index:idx3 total:0s, foreign_keys:1 foreign_key:fk_3, check_exist N/A N/A", }, { @@ -2527,3 +2527,42 @@ func TestLockKeysInDML(t *testing.T) { tk.MustQuery("SELECT * FROM t1").Check(testkit.Rows("1")) tk.MustQuery("SELECT * FROM t2").Check(testkit.Rows("1")) } + +func TestLockKeysInInsertIgnore(t *testing.T) { + store := realtikvtest.CreateMockStoreAndSetup(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("create table t1 (id int primary key);") + tk.MustExec("create table t2 (id int primary key, foreign key fk (id) references t1(id));") + tk.MustExec("insert into t1 values (1)") + + tk.MustExec("BEGIN") + tk.MustExec("INSERT IGNORE INTO t2 VALUES (1)") + + var wg sync.WaitGroup + var tk2CommitTime time.Time + tk2StartTime := time.Now() + wg.Add(1) + go func() { + defer wg.Done() + + tk2 := testkit.NewTestKit(t, store) + // unistore has a bug to handle the fair locking mechanism. We need to disable it to pass this test. + // Ref: https://github.com/pingcap/tidb/issues/56663 + tk2.MustExec("set tidb_pessimistic_txn_fair_locking = 'OFF'") + tk2.MustExec("use test") + tk2.MustExec("BEGIN") + require.NotNil(t, tk2.ExecToErr("UPDATE t1 SET id = 2 WHERE id = 1")) + tk2.MustExec("COMMIT") + tk2CommitTime = time.Now() + }() + + sleepDuration := 500 * time.Millisecond + time.Sleep(sleepDuration) + tk.MustExec("COMMIT") + wg.Wait() + + require.Greater(t, tk2CommitTime.Sub(tk2StartTime), sleepDuration) + tk.MustQuery("SELECT * FROM t1").Check(testkit.Rows("1")) + tk.MustQuery("SELECT * FROM t2").Check(testkit.Rows("1")) +}