diff --git a/pkg/bindinfo/BUILD.bazel b/pkg/bindinfo/BUILD.bazel index 671c7924bb0b9..fc3ba7b3b04bc 100644 --- a/pkg/bindinfo/BUILD.bazel +++ b/pkg/bindinfo/BUILD.bazel @@ -57,7 +57,7 @@ go_test( embed = [":bindinfo"], flaky = True, race = "on", - shard_count = 40, + shard_count = 41, deps = [ "//pkg/bindinfo/internal", "//pkg/config", diff --git a/pkg/bindinfo/handle.go b/pkg/bindinfo/handle.go index 4c7ad623c1fda..333874da35f30 100644 --- a/pkg/bindinfo/handle.go +++ b/pkg/bindinfo/handle.go @@ -99,6 +99,14 @@ const ( Prompt = "bindinfo" // BuiltinPseudoSQL4BindLock is used to simulate LOCK TABLE for mysql.bind_info. BuiltinPseudoSQL4BindLock = "builtin_pseudo_sql_for_bind_lock" + + // StmtRemoveDuplicatedPseudoBinding is used to remove duplicated pseudo binding. + // After using BR to sync bind_info between two clusters, the pseudo binding may be duplicated, and + // BR use this statement to remove duplicated rows, and this SQL should only be executed by BR. + StmtRemoveDuplicatedPseudoBinding = `DELETE FROM mysql.bind_info + WHERE original_sql='builtin_pseudo_sql_for_bind_lock' AND + _tidb_rowid NOT IN ( -- keep one arbitrary pseudo binding + SELECT _tidb_rowid FROM mysql.bind_info WHERE original_sql='builtin_pseudo_sql_for_bind_lock' limit 1)` ) type bindRecordUpdate struct { diff --git a/pkg/bindinfo/handle_test.go b/pkg/bindinfo/handle_test.go index 984fdb0189be7..a75e667cfdc8d 100644 --- a/pkg/bindinfo/handle_test.go +++ b/pkg/bindinfo/handle_test.go @@ -607,3 +607,37 @@ func TestReloadBindings(t *testing.T) { rows = tk.MustQuery("show global bindings").Rows() require.Equal(t, 0, len(rows)) } + +func TestRemoveDuplicatedPseudoBinding(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + + checkPseudoBinding := func(num int) { + tk.MustQuery(fmt.Sprintf("select count(1) from mysql.bind_info where original_sql='%s'", + bindinfo.BuiltinPseudoSQL4BindLock)).Check(testkit.Rows(fmt.Sprintf("%d", num))) + } + insertPseudoBinding := func() { + tk.MustExec(fmt.Sprintf(`INSERT INTO mysql.bind_info(original_sql, bind_sql, default_db, status, create_time, update_time, charset, collation, source) + VALUES ('%v', '%v', "mysql", '%v', "2000-01-01 00:00:00", "2000-01-01 00:00:00", "", "", '%v')`, + bindinfo.BuiltinPseudoSQL4BindLock, bindinfo.BuiltinPseudoSQL4BindLock, bindinfo.Builtin, bindinfo.Builtin)) + } + removeDuplicated := func() { + tk.MustExec(bindinfo.StmtRemoveDuplicatedPseudoBinding) + } + + checkPseudoBinding(1) + insertPseudoBinding() + checkPseudoBinding(2) + removeDuplicated() + checkPseudoBinding(1) + + insertPseudoBinding() + insertPseudoBinding() + insertPseudoBinding() + checkPseudoBinding(4) + removeDuplicated() + checkPseudoBinding(1) + removeDuplicated() + checkPseudoBinding(1) +}