From 63fb86b4c83b6f227737e7bb813c20d2d37902a4 Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Mon, 26 Jun 2023 15:16:05 +0800 Subject: [PATCH] executor: fix issue of update with same foreign key value returns error (#44907) (#44928) close pingcap/tidb#44848 --- executor/fktest/BUILD.bazel | 2 +- executor/fktest/foreign_key_test.go | 12 ++++++++++++ executor/foreign_key.go | 24 ++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/executor/fktest/BUILD.bazel b/executor/fktest/BUILD.bazel index ebaf679ce1ae8..cbf2536c7a4d3 100644 --- a/executor/fktest/BUILD.bazel +++ b/executor/fktest/BUILD.bazel @@ -8,7 +8,7 @@ go_test( "main_test.go", ], flaky = True, - shard_count = 38, + shard_count = 39, deps = [ "//config", "//executor", diff --git a/executor/fktest/foreign_key_test.go b/executor/fktest/foreign_key_test.go index 4b0a21e0308d0..def9344c1c833 100644 --- a/executor/fktest/foreign_key_test.go +++ b/executor/fktest/foreign_key_test.go @@ -2865,3 +2865,15 @@ func TestForeignKeyAndSessionVariable(t *testing.T) { tk.MustQuery("select * from t1").Check(testkit.Rows()) tk.MustQuery("select * from t2").Check(testkit.Rows()) } + +func TestForeignKeyIssue44848(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("set @@foreign_key_checks=1") + tk.MustExec("use test") + tk.MustExec("create table b ( id int(11) NOT NULL AUTO_INCREMENT, f int(11) NOT NULL, PRIMARY KEY (id));") + tk.MustExec("create table a ( id int(11) NOT NULL AUTO_INCREMENT, b_id int(11) NOT NULL, PRIMARY KEY (id), CONSTRAINT fk_b_id FOREIGN KEY (b_id) REFERENCES b (id) ON DELETE CASCADE);") + tk.MustExec("insert b(id,f) values(1,1);") + tk.MustExec("insert a(id,b_id) values(1,1);") + tk.MustExec("update b set id=1,f=2 where id=1;") +} diff --git a/executor/foreign_key.go b/executor/foreign_key.go index 9908a72fd4b04..658808e714de2 100644 --- a/executor/foreign_key.go +++ b/executor/foreign_key.go @@ -34,6 +34,7 @@ import ( "github.com/pingcap/tidb/types" driver "github.com/pingcap/tidb/types/parser_driver" "github.com/pingcap/tidb/util/codec" + "github.com/pingcap/tidb/util/collate" "github.com/pingcap/tidb/util/execdetails" "github.com/pingcap/tidb/util/set" "github.com/tikv/client-go/v2/txnkv/txnsnapshot" @@ -161,6 +162,29 @@ func (fkc *FKCheckExec) insertRowNeedToCheck(sc *stmtctx.StatementContext, row [ } func (fkc *FKCheckExec) updateRowNeedToCheck(sc *stmtctx.StatementContext, oldRow, newRow []types.Datum) error { + newVals, err := fkc.fetchFKValues(newRow) + if err != nil { + return err + } + oldVals, err := fkc.fetchFKValues(oldRow) + if err != nil { + return err + } + if len(oldVals) == len(newVals) { + isSameValue := true + for i := range oldVals { + cmp, err := oldVals[i].Compare(sc, &newVals[i], collate.GetCollator(oldVals[i].Collation())) + if err != nil || cmp != 0 { + isSameValue = false + break + } + } + if isSameValue { + // If the old fk value and the new fk value are the same, no need to check. + return nil + } + } + if fkc.FK != nil { return fkc.addRowNeedToCheck(sc, newRow) } else if fkc.ReferredFK != nil {