Skip to content

Commit 7aeba7b

Browse files
committed
fix the issue that INSERT IGNORE doesn't lock the parent table
Signed-off-by: Yang Keao <[email protected]>
1 parent 83f040b commit 7aeba7b

File tree

2 files changed

+44
-4
lines changed

2 files changed

+44
-4
lines changed

pkg/executor/foreign_key.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ func (fkc *FKCheckExec) doCheck(ctx context.Context) error {
223223
fkc.stats = &FKCheckRuntimeStats{}
224224
defer fkc.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(fkc.ID(), fkc.stats)
225225
}
226-
if len(fkc.toBeCheckedKeys) == 0 && len(fkc.toBeCheckedPrefixKeys) == 0 {
226+
if len(fkc.toBeCheckedKeys) == 0 && len(fkc.toBeCheckedPrefixKeys) == 0 && len(fkc.toBeLockedKeys) == 0 {
227227
return nil
228228
}
229229
start := time.Now()
@@ -248,6 +248,7 @@ func (fkc *FKCheckExec) doCheck(ctx context.Context) error {
248248
if fkc.stats != nil {
249249
fkc.stats.Check = time.Since(start)
250250
}
251+
251252
if len(fkc.toBeLockedKeys) == 0 {
252253
return nil
253254
}
@@ -542,7 +543,7 @@ type fkCheckKey struct {
542543
isPrefix bool
543544
}
544545

545-
func (fkc FKCheckExec) checkRows(ctx context.Context, sc *stmtctx.StatementContext, txn kv.Transaction, rows []toBeCheckedRow) error {
546+
func (fkc *FKCheckExec) checkRows(ctx context.Context, sc *stmtctx.StatementContext, txn kv.Transaction, rows []toBeCheckedRow) error {
546547
if fkc.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl != nil {
547548
fkc.stats = &FKCheckRuntimeStats{}
548549
defer fkc.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(fkc.ID(), fkc.stats)

pkg/executor/test/fktest/foreign_key_test.go

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2088,8 +2088,8 @@ func TestExplainAnalyzeDMLWithFKInfo(t *testing.T) {
20882088
{
20892089
sql: "explain analyze insert ignore into t6 values (1,1,10)",
20902090
plan: "Insert_.* root time:.* loops:.* prepare:.* check_insert.* fk_check:.*" +
2091-
"├─Foreign_Key_Check.* 0 root table:t5 total:0s, foreign_keys:1 foreign_key:fk_1, check_exist N/A N/A.*" +
2092-
"├─Foreign_Key_Check.* 0 root table:t5, index:idx2 total:0s, foreign_keys:1 foreign_key:fk_2, check_exist N/A N/A.*" +
2091+
"├─Foreign_Key_Check.* 0 root table:t5 total:.*, lock:.*, foreign_keys:1 foreign_key:fk_1, check_exist N/A N/A.*" +
2092+
"├─Foreign_Key_Check.* 0 root table:t5, index:idx2 total:.*, lock:.*, foreign_keys:1 foreign_key:fk_2, check_exist N/A N/A.*" +
20932093
"└─Foreign_Key_Check.* 0 root table:t5, index:idx3 total:0s, foreign_keys:1 foreign_key:fk_3, check_exist N/A N/A",
20942094
},
20952095
{
@@ -2527,3 +2527,42 @@ func TestLockKeysInDML(t *testing.T) {
25272527
tk.MustQuery("SELECT * FROM t1").Check(testkit.Rows("1"))
25282528
tk.MustQuery("SELECT * FROM t2").Check(testkit.Rows("1"))
25292529
}
2530+
2531+
func TestLockKeysInInsertIgnore(t *testing.T) {
2532+
store := realtikvtest.CreateMockStoreAndSetup(t)
2533+
tk := testkit.NewTestKit(t, store)
2534+
tk.MustExec("use test")
2535+
tk.MustExec("create table t1 (id int primary key);")
2536+
tk.MustExec("create table t2 (id int primary key, foreign key fk (id) references t1(id));")
2537+
tk.MustExec("insert into t1 values (1)")
2538+
2539+
tk.MustExec("BEGIN")
2540+
tk.MustExec("INSERT IGNORE INTO t2 VALUES (1)")
2541+
2542+
var wg sync.WaitGroup
2543+
var tk2CommitTime time.Time
2544+
tk2StartTime := time.Now()
2545+
wg.Add(1)
2546+
go func() {
2547+
defer wg.Done()
2548+
2549+
tk2 := testkit.NewTestKit(t, store)
2550+
// unistore has a bug to handle the fair locking mechanism. We need to disable it to pass this test.
2551+
// Ref: https://github.com/pingcap/tidb/issues/56663
2552+
tk2.MustExec("set tidb_pessimistic_txn_fair_locking = 'OFF'")
2553+
tk2.MustExec("use test")
2554+
tk2.MustExec("BEGIN")
2555+
require.NotNil(t, tk2.ExecToErr("UPDATE t1 SET id = 2 WHERE id = 1"))
2556+
tk2.MustExec("COMMIT")
2557+
tk2CommitTime = time.Now()
2558+
}()
2559+
2560+
sleepDuration := 500 * time.Millisecond
2561+
time.Sleep(sleepDuration)
2562+
tk.MustExec("COMMIT")
2563+
wg.Wait()
2564+
2565+
require.Greater(t, tk2CommitTime.Sub(tk2StartTime), sleepDuration)
2566+
tk.MustQuery("SELECT * FROM t1").Check(testkit.Rows("1"))
2567+
tk.MustQuery("SELECT * FROM t2").Check(testkit.Rows("1"))
2568+
}

0 commit comments

Comments
 (0)