diff --git a/pkg/bindinfo/BUILD.bazel b/pkg/bindinfo/BUILD.bazel index 17f2d6e9e36ea..13c5ec7c71009 100644 --- a/pkg/bindinfo/BUILD.bazel +++ b/pkg/bindinfo/BUILD.bazel @@ -53,7 +53,7 @@ go_test( srcs = [ "binding_cache_test.go", "binding_match_test.go", - "fuzzy_binding_test.go", + "cross_db_binding_test.go", "global_handle_test.go", "main_test.go", "optimize_test.go", diff --git a/pkg/bindinfo/binding.go b/pkg/bindinfo/binding.go index 42369778dcd60..21e245e286058 100644 --- a/pkg/bindinfo/binding.go +++ b/pkg/bindinfo/binding.go @@ -68,7 +68,7 @@ type Binding struct { SQLDigest string PlanDigest string - // TableNames records all schema and table names in this binding statement, which are used for fuzzy matching. + // TableNames records all schema and table names in this binding statement, which are used for cross-db matching. TableNames []*ast.TableName `json:"-"` } @@ -144,7 +144,7 @@ func prepareHints(sctx sessionctx.Context, binding *Binding) (rerr error) { return err } tableNames := CollectTableNames(bindingStmt) - isFuzzy := isFuzzyBinding(bindingStmt) + isFuzzy := isCrossDBBinding(bindingStmt) if isFuzzy { dbName = "*" // ues '*' for universal bindings } diff --git a/pkg/bindinfo/binding_cache.go b/pkg/bindinfo/binding_cache.go index 7e3211665daa5..f1368e84d3a7e 100644 --- a/pkg/bindinfo/binding_cache.go +++ b/pkg/bindinfo/binding_cache.go @@ -48,76 +48,76 @@ var GetBindingReturnNilAlways = stringutil.StringerStr("getBindingReturnNilAlway // LoadBindingNothing is only for test var LoadBindingNothing = stringutil.StringerStr("LoadBindingNothing") -// FuzzyBindingCache is based on BindingCache, and provide some more advanced features, like -// fuzzy matching, loading binding if cache miss automatically (TODO). -type FuzzyBindingCache interface { - // FuzzyMatchingBinding supports fuzzy matching on bindings. - FuzzyMatchingBinding(sctx sessionctx.Context, fuzzyDigest string, tableNames []*ast.TableName) (bindings Binding, isMatched bool) +// CrossDBBindingCache is based on BindingCache, and provide some more advanced features, like +// cross-db matching, loading binding if cache miss automatically (TODO). +type CrossDBBindingCache interface { + // MatchingBinding supports cross-db matching on bindings. + MatchingBinding(sctx sessionctx.Context, noDBDigest string, tableNames []*ast.TableName) (bindings Binding, isMatched bool) // Copy copies this cache. - Copy() (c FuzzyBindingCache, err error) + Copy() (c CrossDBBindingCache, err error) BindingCache } -type fuzzyBindingCache struct { +type crossDBBindingCache struct { BindingCache mu sync.RWMutex - // fuzzy2SQLDigests is used to support fuzzy matching. - // fuzzyDigest is the digest calculated after eliminating all DB names, e.g. `select * from test.t` -> `select * from t` -> fuzzyDigest. + // noDBDigest2SQLDigest is used to support cross-db matching. + // noDBDigest is the digest calculated after eliminating all DB names, e.g. `select * from test.t` -> `select * from t` -> noDBDigest. // sqlDigest is the digest where all DB names are kept, e.g. `select * from test.t` -> exactDigest. - fuzzy2SQLDigests map[string][]string // fuzzyDigest --> sqlDigests + noDBDigest2SQLDigest map[string][]string // noDBDigest --> sqlDigests - sql2FuzzyDigest map[string]string // sqlDigest --> fuzzyDigest + sqlDigest2noDBDigest map[string]string // sqlDigest --> noDBDigest // loadBindingFromStorageFunc is used to load binding from storage if cache miss. loadBindingFromStorageFunc func(sctx sessionctx.Context, sqlDigest string) (Bindings, error) } -func newFuzzyBindingCache(loadBindingFromStorageFunc func(sessionctx.Context, string) (Bindings, error)) FuzzyBindingCache { - return &fuzzyBindingCache{ +func newCrossDBBindingCache(loadBindingFromStorageFunc func(sessionctx.Context, string) (Bindings, error)) CrossDBBindingCache { + return &crossDBBindingCache{ BindingCache: newBindCache(), - fuzzy2SQLDigests: make(map[string][]string), - sql2FuzzyDigest: make(map[string]string), + noDBDigest2SQLDigest: make(map[string][]string), + sqlDigest2noDBDigest: make(map[string]string), loadBindingFromStorageFunc: loadBindingFromStorageFunc, } } -func (fbc *fuzzyBindingCache) shouldMetric() bool { - return fbc.loadBindingFromStorageFunc != nil // only metric for GlobalBindingCache, whose loadBindingFromStorageFunc is not nil. +func (cc *crossDBBindingCache) shouldMetric() bool { + return cc.loadBindingFromStorageFunc != nil // only metric for GlobalBindingCache, whose loadBindingFromStorageFunc is not nil. } -func (fbc *fuzzyBindingCache) FuzzyMatchingBinding(sctx sessionctx.Context, fuzzyDigest string, tableNames []*ast.TableName) (matchedBinding Binding, isMatched bool) { - matchedBinding, isMatched, missingSQLDigest := fbc.getFromMemory(sctx, fuzzyDigest, tableNames) +func (cc *crossDBBindingCache) MatchingBinding(sctx sessionctx.Context, noDBDigest string, tableNames []*ast.TableName) (matchedBinding Binding, isMatched bool) { + matchedBinding, isMatched, missingSQLDigest := cc.getFromMemory(sctx, noDBDigest, tableNames) if len(missingSQLDigest) == 0 { - if fbc.shouldMetric() && isMatched { + if cc.shouldMetric() && isMatched { metrics.BindingCacheHitCounter.Inc() } return } - if fbc.shouldMetric() { + if cc.shouldMetric() { metrics.BindingCacheMissCounter.Inc() } - if fbc.loadBindingFromStorageFunc == nil { + if cc.loadBindingFromStorageFunc == nil { return } - fbc.loadFromStore(sctx, missingSQLDigest) // loadFromStore's SetBinding has a Mutex inside, so it's safe to call it without lock - matchedBinding, isMatched, _ = fbc.getFromMemory(sctx, fuzzyDigest, tableNames) + cc.loadFromStore(sctx, missingSQLDigest) // loadFromStore's SetBinding has a Mutex inside, so it's safe to call it without lock + matchedBinding, isMatched, _ = cc.getFromMemory(sctx, noDBDigest, tableNames) return } -func (fbc *fuzzyBindingCache) getFromMemory(sctx sessionctx.Context, fuzzyDigest string, tableNames []*ast.TableName) (matchedBinding Binding, isMatched bool, missingSQLDigest []string) { - fbc.mu.RLock() - defer fbc.mu.RUnlock() - bindingCache := fbc.BindingCache +func (cc *crossDBBindingCache) getFromMemory(sctx sessionctx.Context, noDBDigest string, tableNames []*ast.TableName) (matchedBinding Binding, isMatched bool, missingSQLDigest []string) { + cc.mu.RLock() + defer cc.mu.RUnlock() + bindingCache := cc.BindingCache if bindingCache.Size() == 0 { return } leastWildcards := len(tableNames) + 1 - enableFuzzyBinding := sctx.GetSessionVars().EnableFuzzyBinding - for _, sqlDigest := range fbc.fuzzy2SQLDigests[fuzzyDigest] { + enableCrossDBBinding := sctx.GetSessionVars().EnableFuzzyBinding + for _, sqlDigest := range cc.noDBDigest2SQLDigest[noDBDigest] { bindings := bindingCache.GetBinding(sqlDigest) if intest.InTest { if sctx.Value(GetBindingReturnNil) != nil { @@ -131,9 +131,9 @@ func (fbc *fuzzyBindingCache) getFromMemory(sctx sessionctx.Context, fuzzyDigest } if bindings != nil { for _, binding := range bindings { - numWildcards, matched := fuzzyMatchBindingTableName(sctx.GetSessionVars().CurrentDB, tableNames, binding.TableNames) - if matched && numWildcards > 0 && sctx != nil && !enableFuzzyBinding { - continue // fuzzy binding is disabled, skip this binding + numWildcards, matched := crossDBMatchBindingTableName(sctx.GetSessionVars().CurrentDB, tableNames, binding.TableNames) + if matched && numWildcards > 0 && sctx != nil && !enableCrossDBBinding { + continue // cross-db binding is disabled, skip this binding } if matched && numWildcards < leastWildcards { matchedBinding = binding @@ -149,7 +149,7 @@ func (fbc *fuzzyBindingCache) getFromMemory(sctx sessionctx.Context, fuzzyDigest return matchedBinding, isMatched, missingSQLDigest } -func (fbc *fuzzyBindingCache) loadFromStore(sctx sessionctx.Context, missingSQLDigest []string) { +func (cc *crossDBBindingCache) loadFromStore(sctx sessionctx.Context, missingSQLDigest []string) { if intest.InTest && sctx.Value(LoadBindingNothing) != nil { return } @@ -159,7 +159,7 @@ func (fbc *fuzzyBindingCache) loadFromStore(sctx sessionctx.Context, missingSQLD for _, sqlDigest := range missingSQLDigest { start := time.Now() - bindings, err := fbc.loadBindingFromStorageFunc(sctx, sqlDigest) + bindings, err := cc.loadBindingFromStorageFunc(sctx, sqlDigest) if err != nil { logutil.BindLogger().Warn("failed to load binding from storage", zap.String("sqlDigest", sqlDigest), @@ -169,10 +169,10 @@ func (fbc *fuzzyBindingCache) loadFromStore(sctx sessionctx.Context, missingSQLD continue } // put binding into the cache - oldBinding := fbc.GetBinding(sqlDigest) + oldBinding := cc.GetBinding(sqlDigest) newBindings := removeDeletedBindings(merge(oldBinding, bindings)) if len(newBindings) > 0 { - err = fbc.SetBinding(sqlDigest, newBindings) + err = cc.SetBinding(sqlDigest, newBindings) if err != nil { // When the memory capacity of bing_cache is not enough, // there will be some memory-related errors in multiple places. @@ -183,72 +183,72 @@ func (fbc *fuzzyBindingCache) loadFromStore(sctx sessionctx.Context, missingSQLD } } -func (fbc *fuzzyBindingCache) SetBinding(sqlDigest string, bindings Bindings) (err error) { - fbc.mu.Lock() - defer fbc.mu.Unlock() +func (cc *crossDBBindingCache) SetBinding(sqlDigest string, bindings Bindings) (err error) { + cc.mu.Lock() + defer cc.mu.Unlock() - // prepare fuzzy digests for all bindings - fuzzyDigests := make([]string, 0, len(bindings)) + // prepare noDBDigests for all bindings + noDBDigests := make([]string, 0, len(bindings)) p := parser.New() for _, binding := range bindings { stmt, err := p.ParseOneStmt(binding.BindSQL, binding.Charset, binding.Collation) if err != nil { return err } - _, fuzzyDigest := norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - fuzzyDigests = append(fuzzyDigests, fuzzyDigest) + _, noDBDigest := norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + noDBDigests = append(noDBDigests, noDBDigest) } for i, binding := range bindings { - fbc.fuzzy2SQLDigests[fuzzyDigests[i]] = append(fbc.fuzzy2SQLDigests[fuzzyDigests[i]], binding.SQLDigest) - fbc.sql2FuzzyDigest[binding.SQLDigest] = fuzzyDigests[i] + cc.noDBDigest2SQLDigest[noDBDigests[i]] = append(cc.noDBDigest2SQLDigest[noDBDigests[i]], binding.SQLDigest) + cc.sqlDigest2noDBDigest[binding.SQLDigest] = noDBDigests[i] } - // NOTE: due to LRU eviction, the underlying BindingCache state might be inconsistent with fuzzy2SQLDigests and - // sql2FuzzyDigest, but it's acceptable, just return cache-miss in that case. - return fbc.BindingCache.SetBinding(sqlDigest, bindings) + // NOTE: due to LRU eviction, the underlying BindingCache state might be inconsistent with noDBDigest2SQLDigest and + // sqlDigest2noDBDigest, but it's acceptable, just return cache-miss in that case. + return cc.BindingCache.SetBinding(sqlDigest, bindings) } -func (fbc *fuzzyBindingCache) RemoveBinding(sqlDigest string) { - fbc.mu.Lock() - defer fbc.mu.Unlock() - fuzzyDigest, ok := fbc.sql2FuzzyDigest[sqlDigest] +func (cc *crossDBBindingCache) RemoveBinding(sqlDigest string) { + cc.mu.Lock() + defer cc.mu.Unlock() + noDBDigest, ok := cc.sqlDigest2noDBDigest[sqlDigest] if !ok { return } - digestList := fbc.fuzzy2SQLDigests[fuzzyDigest] + digestList := cc.noDBDigest2SQLDigest[noDBDigest] for i := range digestList { // remove sqlDigest from this list if digestList[i] == sqlDigest { digestList = append(digestList[:i], digestList[i+1:]...) break } } - fbc.fuzzy2SQLDigests[fuzzyDigest] = digestList - delete(fbc.sql2FuzzyDigest, sqlDigest) - fbc.BindingCache.RemoveBinding(sqlDigest) + cc.noDBDigest2SQLDigest[noDBDigest] = digestList + delete(cc.sqlDigest2noDBDigest, sqlDigest) + cc.BindingCache.RemoveBinding(sqlDigest) } -func (fbc *fuzzyBindingCache) Copy() (c FuzzyBindingCache, err error) { - fbc.mu.RLock() - defer fbc.mu.RUnlock() - bc, err := fbc.BindingCache.CopyBindingCache() +func (cc *crossDBBindingCache) Copy() (c CrossDBBindingCache, err error) { + cc.mu.RLock() + defer cc.mu.RUnlock() + bc, err := cc.BindingCache.CopyBindingCache() if err != nil { return nil, err } - sql2FuzzyDigest := make(map[string]string, len(fbc.sql2FuzzyDigest)) - for k, v := range fbc.sql2FuzzyDigest { - sql2FuzzyDigest[k] = v + sql2noDBDigest := make(map[string]string, len(cc.sqlDigest2noDBDigest)) + for k, v := range cc.sqlDigest2noDBDigest { + sql2noDBDigest[k] = v } - fuzzy2SQLDigests := make(map[string][]string, len(fbc.fuzzy2SQLDigests)) - for k, list := range fbc.fuzzy2SQLDigests { + noDBDigest2SQLDigest := make(map[string][]string, len(cc.noDBDigest2SQLDigest)) + for k, list := range cc.noDBDigest2SQLDigest { newList := make([]string, len(list)) copy(newList, list) - fuzzy2SQLDigests[k] = newList + noDBDigest2SQLDigest[k] = newList } - return &fuzzyBindingCache{ + return &crossDBBindingCache{ BindingCache: bc, - fuzzy2SQLDigests: fuzzy2SQLDigests, - sql2FuzzyDigest: sql2FuzzyDigest, - loadBindingFromStorageFunc: fbc.loadBindingFromStorageFunc, + noDBDigest2SQLDigest: noDBDigest2SQLDigest, + sqlDigest2noDBDigest: sql2noDBDigest, + loadBindingFromStorageFunc: cc.loadBindingFromStorageFunc, }, nil } diff --git a/pkg/bindinfo/binding_cache_test.go b/pkg/bindinfo/binding_cache_test.go index 12cf1a94bb32c..595ccf29a3610 100644 --- a/pkg/bindinfo/binding_cache_test.go +++ b/pkg/bindinfo/binding_cache_test.go @@ -26,58 +26,58 @@ import ( "github.com/stretchr/testify/require" ) -func bindingFuzzyDigest(t *testing.T, b Binding) string { +func bindingNoDBDigest(t *testing.T, b Binding) string { p := parser.New() stmt, err := p.ParseOneStmt(b.BindSQL, b.Charset, b.Collation) require.NoError(t, err) - _, fuzzyDigest := norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - return fuzzyDigest + _, noDBDigest := norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + return noDBDigest } func TestFuzzyBindingCache(t *testing.T) { - fbc := newFuzzyBindingCache(nil).(*fuzzyBindingCache) + fbc := newCrossDBBindingCache(nil).(*crossDBBindingCache) b1 := Binding{BindSQL: "SELECT * FROM db1.t1", SQLDigest: "b1"} - fDigest1 := bindingFuzzyDigest(t, b1) + fDigest1 := bindingNoDBDigest(t, b1) b2 := Binding{BindSQL: "SELECT * FROM db2.t1", SQLDigest: "b2"} b3 := Binding{BindSQL: "SELECT * FROM db2.t3", SQLDigest: "b3"} - fDigest3 := bindingFuzzyDigest(t, b3) + fDigest3 := bindingNoDBDigest(t, b3) - // add 3 bindings and b1 and b2 have the same fuzzy digest + // add 3 bindings and b1 and b2 have the same noDBDigest require.NoError(t, fbc.SetBinding(b1.SQLDigest, []Binding{b1})) require.NoError(t, fbc.SetBinding(b2.SQLDigest, []Binding{b2})) require.NoError(t, fbc.SetBinding(b3.SQLDigest, []Binding{b3})) - require.Equal(t, len(fbc.fuzzy2SQLDigests), 2) // b1 and b2 have the same fuzzy digest - require.Equal(t, len(fbc.fuzzy2SQLDigests[fDigest1]), 2) - require.Equal(t, len(fbc.fuzzy2SQLDigests[fDigest3]), 1) - require.Equal(t, len(fbc.sql2FuzzyDigest), 3) - _, ok := fbc.sql2FuzzyDigest[b1.SQLDigest] + require.Equal(t, len(fbc.noDBDigest2SQLDigest), 2) // b1 and b2 have the same noDBDigest + require.Equal(t, len(fbc.noDBDigest2SQLDigest[fDigest1]), 2) + require.Equal(t, len(fbc.noDBDigest2SQLDigest[fDigest3]), 1) + require.Equal(t, len(fbc.sqlDigest2noDBDigest), 3) + _, ok := fbc.sqlDigest2noDBDigest[b1.SQLDigest] require.True(t, ok) - _, ok = fbc.sql2FuzzyDigest[b2.SQLDigest] + _, ok = fbc.sqlDigest2noDBDigest[b2.SQLDigest] require.True(t, ok) - _, ok = fbc.sql2FuzzyDigest[b3.SQLDigest] + _, ok = fbc.sqlDigest2noDBDigest[b3.SQLDigest] require.True(t, ok) // remove b2 fbc.RemoveBinding(b2.SQLDigest) - require.Equal(t, len(fbc.fuzzy2SQLDigests), 2) - require.Equal(t, len(fbc.fuzzy2SQLDigests[fDigest1]), 1) - require.Equal(t, len(fbc.fuzzy2SQLDigests[fDigest3]), 1) - require.Equal(t, len(fbc.sql2FuzzyDigest), 2) - _, ok = fbc.sql2FuzzyDigest[b1.SQLDigest] + require.Equal(t, len(fbc.noDBDigest2SQLDigest), 2) + require.Equal(t, len(fbc.noDBDigest2SQLDigest[fDigest1]), 1) + require.Equal(t, len(fbc.noDBDigest2SQLDigest[fDigest3]), 1) + require.Equal(t, len(fbc.sqlDigest2noDBDigest), 2) + _, ok = fbc.sqlDigest2noDBDigest[b1.SQLDigest] require.True(t, ok) - _, ok = fbc.sql2FuzzyDigest[b2.SQLDigest] + _, ok = fbc.sqlDigest2noDBDigest[b2.SQLDigest] require.False(t, ok) // can't find b2 now - _, ok = fbc.sql2FuzzyDigest[b3.SQLDigest] + _, ok = fbc.sqlDigest2noDBDigest[b3.SQLDigest] require.True(t, ok) // test deep copy newCache, err := fbc.Copy() require.NoError(t, err) - newFBC := newCache.(*fuzzyBindingCache) - newFBC.fuzzy2SQLDigests[fDigest1] = nil - delete(newFBC.sql2FuzzyDigest, b1.SQLDigest) - require.Equal(t, len(fbc.fuzzy2SQLDigests[fDigest1]), 1) // no impact to the original cache - _, ok = fbc.sql2FuzzyDigest[b1.SQLDigest] + newFBC := newCache.(*crossDBBindingCache) + newFBC.noDBDigest2SQLDigest[fDigest1] = nil + delete(newFBC.sqlDigest2noDBDigest, b1.SQLDigest) + require.Equal(t, len(fbc.noDBDigest2SQLDigest[fDigest1]), 1) // no impact to the original cache + _, ok = fbc.sqlDigest2noDBDigest[b1.SQLDigest] require.True(t, ok) } diff --git a/pkg/bindinfo/binding_match.go b/pkg/bindinfo/binding_match.go index 82a2a7efe6183..c407c3b79a96a 100644 --- a/pkg/bindinfo/binding_match.go +++ b/pkg/bindinfo/binding_match.go @@ -31,11 +31,11 @@ var ( GetGlobalBindingHandle func(sctx sessionctx.Context) GlobalBindingHandle ) -// BindingMatchInfo records necessary information for fuzzy binding matching. +// BindingMatchInfo records necessary information for cross-db binding matching. // This is mainly for plan cache to avoid normalizing the same statement repeatedly. type BindingMatchInfo struct { - FuzzyDigest string - TableNames []*ast.TableName + NoDBDigest string + TableNames []*ast.TableName } // MatchSQLBindingForPlanCache matches binding for plan cache. @@ -64,29 +64,29 @@ func matchSQLBinding(sctx sessionctx.Context, stmtNode ast.StmtNode, info *Bindi } // record the normalization result into info to avoid repeat normalization next time. - var fuzzyDigest string + var noDBDigest string var tableNames []*ast.TableName - if info == nil || info.TableNames == nil || info.FuzzyDigest == "" { - _, fuzzyDigest = norm.NormalizeStmtForBinding(stmtNode, norm.WithFuzz(true)) + if info == nil || info.TableNames == nil || info.NoDBDigest == "" { + _, noDBDigest = norm.NormalizeStmtForBinding(stmtNode, norm.WithoutDB(true)) tableNames = CollectTableNames(stmtNode) if info != nil { - info.FuzzyDigest = fuzzyDigest + info.NoDBDigest = noDBDigest info.TableNames = tableNames } } else { - fuzzyDigest = info.FuzzyDigest + noDBDigest = info.NoDBDigest tableNames = info.TableNames } sessionHandle := sctx.Value(SessionBindInfoKeyType).(SessionBindingHandle) - if binding, matched := sessionHandle.MatchSessionBinding(sctx, fuzzyDigest, tableNames); matched { + if binding, matched := sessionHandle.MatchSessionBinding(sctx, noDBDigest, tableNames); matched { return binding, matched, metrics.ScopeSession } globalHandle := GetGlobalBindingHandle(sctx) if globalHandle == nil { return } - binding, matched = globalHandle.MatchGlobalBinding(sctx, fuzzyDigest, tableNames) + binding, matched = globalHandle.MatchGlobalBinding(sctx, noDBDigest, tableNames) if matched { return binding, matched, metrics.ScopeGlobal } @@ -94,7 +94,7 @@ func matchSQLBinding(sctx sessionctx.Context, stmtNode ast.StmtNode, info *Bindi return } -func fuzzyMatchBindingTableName(currentDB string, stmtTableNames, bindingTableNames []*ast.TableName) (numWildcards int, matched bool) { +func crossDBMatchBindingTableName(currentDB string, stmtTableNames, bindingTableNames []*ast.TableName) (numWildcards int, matched bool) { if len(stmtTableNames) != len(bindingTableNames) { return 0, false } @@ -107,7 +107,7 @@ func fuzzyMatchBindingTableName(currentDB string, stmtTableNames, bindingTableNa } if bindingTableNames[i].Schema.L == stmtTableNames[i].Schema.L || // exactly same, or (stmtTableNames[i].Schema.L == "" && bindingTableNames[i].Schema.L == strings.ToLower(currentDB)) || // equal to the current DB, or - bindingTableNames[i].Schema.L == "*" { // fuzzy match successfully + bindingTableNames[i].Schema.L == "*" { // cross-db match successfully continue } return 0, false @@ -115,8 +115,8 @@ func fuzzyMatchBindingTableName(currentDB string, stmtTableNames, bindingTableNa return numWildcards, true } -// isFuzzyBinding checks whether the stmtNode is a fuzzy binding. -func isFuzzyBinding(stmt ast.Node) bool { +// isCrossDBBinding checks whether the stmtNode is a cross-db binding. +func isCrossDBBinding(stmt ast.Node) bool { for _, t := range CollectTableNames(stmt) { if t.Schema.L == "*" { return true @@ -126,7 +126,7 @@ func isFuzzyBinding(stmt ast.Node) bool { } // CollectTableNames gets all table names from ast.Node. -// This function is mainly for binding fuzzy matching. +// This function is mainly for binding cross-db matching. // ** the return is read-only. // For example: // diff --git a/pkg/bindinfo/fuzzy_binding_test.go b/pkg/bindinfo/cross_db_binding_test.go similarity index 97% rename from pkg/bindinfo/fuzzy_binding_test.go rename to pkg/bindinfo/cross_db_binding_test.go index e3efa43f1a3f3..ef1e34f2dd971 100644 --- a/pkg/bindinfo/fuzzy_binding_test.go +++ b/pkg/bindinfo/cross_db_binding_test.go @@ -39,7 +39,7 @@ func showBinding(tk *testkit.TestKit, showStmt string) [][]any { return result } -func TestFuzzyBindingBasic(t *testing.T) { +func TestCrossDBBindingBasic(t *testing.T) { store := testkit.CreateMockStore(t) tk1 := testkit.NewTestKit(t, store) @@ -74,7 +74,7 @@ func TestFuzzyBindingBasic(t *testing.T) { } } -func TestFuzzyDuplicatedBinding(t *testing.T) { +func TestCrossDBDuplicatedBinding(t *testing.T) { store := testkit.CreateMockStore(t) tk := testkit.NewTestKit(t, store) tk.MustExec(`use test`) @@ -95,7 +95,7 @@ func TestFuzzyDuplicatedBinding(t *testing.T) { [][]any{{"select * from `*` . `t`", "SELECT /*+ use_index(`t` `b`)*/ * FROM `*`.`t`", "", "enabled", "manual", "a17da0a38af0f1d75229c5cd064d5222a610c5e5ef59436be5da1564c16f1013"}}) } -func TestFuzzyBindingPriority(t *testing.T) { +func TestCrossDBBindingPriority(t *testing.T) { store := testkit.CreateMockStore(t) tk := testkit.NewTestKit(t, store) @@ -138,7 +138,7 @@ func TestFuzzyBindingPriority(t *testing.T) { tk.MustQuery(`show warnings`).Check(testkit.Rows("Note 1105 Using the bindSQL: SELECT /*+ leading(`t1`, `t2`, `t3`, `t4`, `t5`)*/ * FROM ((((`*`.`t1`) JOIN `*`.`t2`) JOIN `*`.`t3`) JOIN `*`.`t4`) JOIN `*`.`t5`")) } -func TestCreateUpdateFuzzyBinding(t *testing.T) { +func TestCreateUpdateCrossDBBinding(t *testing.T) { store := testkit.CreateMockStore(t) tk := testkit.NewTestKit(t, store) @@ -170,7 +170,7 @@ func TestCreateUpdateFuzzyBinding(t *testing.T) { require.Equal(t, showBinding(tk, "show session bindings"), [][]any{}) } -func TestFuzzyBindingSwitch(t *testing.T) { +func TestCrossDBBindingSwitch(t *testing.T) { store := testkit.CreateMockStore(t) tk1 := testkit.NewTestKit(t, store) @@ -211,7 +211,7 @@ func TestFuzzyBindingSwitch(t *testing.T) { tk3.MustQuery(`show global variables like 'tidb_opt_enable_fuzzy_binding'`).Check(testkit.Rows("tidb_opt_enable_fuzzy_binding OFF")) } -func TestFuzzyBindingSetVar(t *testing.T) { +func TestCrossDBBindingSetVar(t *testing.T) { store := testkit.CreateMockStore(t) tk := testkit.NewTestKit(t, store) tk.MustExec(`use test`) @@ -235,7 +235,7 @@ func TestFuzzyBindingSetVar(t *testing.T) { tk.MustQuery(`select @@last_plan_from_binding`).Check(testkit.Rows("1")) } -func TestFuzzyBindingGC(t *testing.T) { +func TestCrossDBBindingGC(t *testing.T) { store := testkit.CreateMockStore(t) tk := testkit.NewTestKit(t, store) tk.MustExec(`use test`) @@ -257,7 +257,7 @@ func TestFuzzyBindingGC(t *testing.T) { tk.MustQuery(`select bind_sql, status from mysql.bind_info where source != 'builtin'`).Check(testkit.Rows()) // empty after GC } -func TestFuzzyBindingInList(t *testing.T) { +func TestCrossDBBindingInList(t *testing.T) { store := testkit.CreateMockStore(t) tk := testkit.NewTestKit(t, store) tk.MustExec(`create database test1`) @@ -297,7 +297,7 @@ func TestFuzzyBindingInList(t *testing.T) { } } -func TestFuzzyBindingPlanCache(t *testing.T) { +func TestCrossDBBindingPlanCache(t *testing.T) { store := testkit.CreateMockStore(t) tk := testkit.NewTestKit(t, store) tk.MustExec(`use test`) diff --git a/pkg/bindinfo/global_handle.go b/pkg/bindinfo/global_handle.go index dac1b4a868132..f661e92ff7d23 100644 --- a/pkg/bindinfo/global_handle.go +++ b/pkg/bindinfo/global_handle.go @@ -47,7 +47,7 @@ type GlobalBindingHandle interface { // Methods for create, get, drop global sql bindings. // MatchGlobalBinding returns the matched binding for this statement. - MatchGlobalBinding(sctx sessionctx.Context, fuzzyDigest string, tableNames []*ast.TableName) (matchedBinding Binding, isMatched bool) + MatchGlobalBinding(sctx sessionctx.Context, noDBDigest string, tableNames []*ast.TableName) (matchedBinding Binding, isMatched bool) // GetAllGlobalBindings returns all bind records in cache. GetAllGlobalBindings() (bindings Bindings) @@ -91,7 +91,7 @@ type GlobalBindingHandle interface { type globalBindingHandle struct { sPool util.SessionPool - fuzzyBindingCache atomic.Value + crossDBBindingCache atomic.Value // lastTaskTime records the last update time for the global sql bind cache. // This value is used to avoid reload duplicated bindings from storage. @@ -131,19 +131,19 @@ func NewGlobalBindingHandle(sPool util.SessionPool) GlobalBindingHandle { return handle } -func (h *globalBindingHandle) getCache() FuzzyBindingCache { - return h.fuzzyBindingCache.Load().(FuzzyBindingCache) +func (h *globalBindingHandle) getCache() CrossDBBindingCache { + return h.crossDBBindingCache.Load().(CrossDBBindingCache) } -func (h *globalBindingHandle) setCache(c FuzzyBindingCache) { +func (h *globalBindingHandle) setCache(c CrossDBBindingCache) { // TODO: update the global cache in-place instead of replacing it and remove this function. - h.fuzzyBindingCache.Store(c) + h.crossDBBindingCache.Store(c) } // Reset is to reset the BindHandle and clean old info. func (h *globalBindingHandle) Reset() { h.lastUpdateTime.Store(types.ZeroTimestamp) - h.setCache(newFuzzyBindingCache(h.LoadBindingsFromStorage)) + h.setCache(newCrossDBBindingCache(h.LoadBindingsFromStorage)) variable.RegisterStatistics(h) } @@ -159,11 +159,11 @@ func (h *globalBindingHandle) setLastUpdateTime(t types.Time) { func (h *globalBindingHandle) LoadFromStorageToCache(fullLoad bool) (err error) { var lastUpdateTime types.Time var timeCondition string - var newCache FuzzyBindingCache + var newCache CrossDBBindingCache if fullLoad { lastUpdateTime = types.ZeroTimestamp timeCondition = "" - newCache = newFuzzyBindingCache(h.LoadBindingsFromStorage) + newCache = newCrossDBBindingCache(h.LoadBindingsFromStorage) } else { lastUpdateTime = h.getLastUpdateTime() timeCondition = fmt.Sprintf("WHERE update_time>'%s'", lastUpdateTime.String()) @@ -411,8 +411,8 @@ func lockBindInfoTable(sctx sessionctx.Context) error { } // MatchGlobalBinding returns the matched binding for this statement. -func (h *globalBindingHandle) MatchGlobalBinding(sctx sessionctx.Context, fuzzyDigest string, tableNames []*ast.TableName) (matchedBinding Binding, isMatched bool) { - return h.getCache().FuzzyMatchingBinding(sctx, fuzzyDigest, tableNames) +func (h *globalBindingHandle) MatchGlobalBinding(sctx sessionctx.Context, noDBDigest string, tableNames []*ast.TableName) (matchedBinding Binding, isMatched bool) { + return h.getCache().MatchingBinding(sctx, noDBDigest, tableNames) } // GetAllGlobalBindings returns all bind records in cache. diff --git a/pkg/bindinfo/global_handle_test.go b/pkg/bindinfo/global_handle_test.go index 8268ca0ce3009..936b48d594d36 100644 --- a/pkg/bindinfo/global_handle_test.go +++ b/pkg/bindinfo/global_handle_test.go @@ -70,8 +70,8 @@ func TestBindingLastUpdateTime(t *testing.T) { stmt, err := parser.New().ParseOneStmt("select * from test . t0", "", "") require.NoError(t, err) - _, fuzzyDigest := norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - binding, matched := bindHandle.MatchGlobalBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest := norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + binding, matched := bindHandle.MatchGlobalBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.True(t, matched) updateTime := binding.UpdateTime.String() @@ -137,8 +137,8 @@ func TestBindParse(t *testing.T) { stmt, err := parser.New().ParseOneStmt("select * from test . t", "", "") require.NoError(t, err) - _, fuzzyDigest := norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - binding, matched := bindHandle.MatchGlobalBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest := norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + binding, matched := bindHandle.MatchGlobalBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.True(t, matched) require.Equal(t, "select * from `test` . `t`", binding.OriginalSQL) require.Equal(t, "select * from `test` . `t` use index(index_t)", binding.BindSQL) @@ -434,8 +434,8 @@ func TestGlobalBinding(t *testing.T) { stmt, _, _ := internal.UtilNormalizeWithDefaultDB(t, testSQL.querySQL) - _, fuzzyDigest := norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - binding, matched := dom.BindHandle().MatchGlobalBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest := norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + binding, matched := dom.BindHandle().MatchGlobalBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.True(t, matched) require.Equal(t, testSQL.originSQL, binding.OriginalSQL) require.Equal(t, testSQL.bindSQL, binding.BindSQL) @@ -467,8 +467,8 @@ func TestGlobalBinding(t *testing.T) { require.NoError(t, err) require.Equal(t, 1, len(bindHandle.GetAllGlobalBindings())) - _, fuzzyDigest = norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - binding, matched = dom.BindHandle().MatchGlobalBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest = norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + binding, matched = dom.BindHandle().MatchGlobalBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.True(t, matched) require.Equal(t, testSQL.originSQL, binding.OriginalSQL) require.Equal(t, testSQL.bindSQL, binding.BindSQL) @@ -482,16 +482,16 @@ func TestGlobalBinding(t *testing.T) { _, err = tk.Exec("drop global " + testSQL.dropSQL) require.Equal(t, uint64(1), tk.Session().AffectedRows()) require.NoError(t, err) - _, fuzzyDigest = norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - _, matched = dom.BindHandle().MatchGlobalBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest = norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + _, matched = dom.BindHandle().MatchGlobalBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.False(t, matched) // dropped bindHandle = bindinfo.NewGlobalBindingHandle(&mockSessionPool{tk.Session()}) err = bindHandle.LoadFromStorageToCache(true) require.NoError(t, err) require.Equal(t, 0, len(bindHandle.GetAllGlobalBindings())) - _, fuzzyDigest = norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - _, matched = dom.BindHandle().MatchGlobalBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest = norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + _, matched = dom.BindHandle().MatchGlobalBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.False(t, matched) // dropped rs, err = tk.Exec("show global bindings") diff --git a/pkg/bindinfo/norm/normalize.go b/pkg/bindinfo/norm/normalize.go index 4772c35cb3032..438ca24c78ead 100644 --- a/pkg/bindinfo/norm/normalize.go +++ b/pkg/bindinfo/norm/normalize.go @@ -24,15 +24,15 @@ import ( type option struct { specifiedDB string - fuzz bool + noDB bool } type optionFunc func(*option) -// WithFuzz specifies whether to eliminate schema names. -func WithFuzz(fuzz bool) optionFunc { +// WithoutDB specifies whether to eliminate schema names. +func WithoutDB(noDB bool) optionFunc { return func(user *option) { - user.fuzz = fuzz + user.noDB = noDB } } @@ -44,14 +44,14 @@ func WithSpecifiedDB(specifiedDB string) optionFunc { } // NormalizeStmtForBinding normalizes a statement for binding. -// when fuzz is false, schema names will be completed automatically: `select * from t` --> `select * from db . t`. -// when fuzz is true, schema names will be eliminated automatically: `select * from db . t` --> `select * from t`. +// when noDB is false, schema names will be completed automatically: `select * from t` --> `select * from db . t`. +// when noDB is true, schema names will be eliminated automatically: `select * from db . t` --> `select * from t`. func NormalizeStmtForBinding(stmtNode ast.StmtNode, options ...optionFunc) (normalizedStmt, exactSQLDigest string) { opt := &option{} for _, option := range options { option(opt) } - return normalizeStmt(stmtNode, opt.specifiedDB, opt.fuzz) + return normalizeStmt(stmtNode, opt.specifiedDB, opt.noDB) } // NormalizeStmtForBinding normalizes a statement for binding. @@ -59,12 +59,12 @@ func NormalizeStmtForBinding(stmtNode ast.StmtNode, options ...optionFunc) (norm // For normal bindings, DB name will be completed automatically: // // e.g. `select * from t where a in (1, 2, 3)` --> `select * from test.t where a in (...)` -func normalizeStmt(stmtNode ast.StmtNode, specifiedDB string, fuzzy bool) (normalizedStmt, sqlDigest string) { +func normalizeStmt(stmtNode ast.StmtNode, specifiedDB string, noDB bool) (normalizedStmt, sqlDigest string) { normalize := func(n ast.StmtNode) (normalizedStmt, sqlDigest string) { eraseLastSemicolon(n) var digest *parser.Digest var normalizedSQL string - if !fuzzy { + if !noDB { normalizedSQL = utilparser.RestoreWithDefaultDB(n, specifiedDB, n.Text()) } else { normalizedSQL = utilparser.RestoreWithoutDB(n) diff --git a/pkg/bindinfo/session_handle.go b/pkg/bindinfo/session_handle.go index 770b372fb4ef1..0436fa5c789e1 100644 --- a/pkg/bindinfo/session_handle.go +++ b/pkg/bindinfo/session_handle.go @@ -42,7 +42,7 @@ type SessionBindingHandle interface { DropSessionBinding(sqlDigests []string) error // MatchSessionBinding returns the matched binding for this statement. - MatchSessionBinding(sctx sessionctx.Context, fuzzyDigest string, tableNames []*ast.TableName) (matchedBinding Binding, isMatched bool) + MatchSessionBinding(sctx sessionctx.Context, noDBDigest string, tableNames []*ast.TableName) (matchedBinding Binding, isMatched bool) // GetAllSessionBindings return all bindings. GetAllSessionBindings() (bindings Bindings) @@ -55,13 +55,13 @@ type SessionBindingHandle interface { // sessionBindingHandle is used to handle all session sql bind operations. type sessionBindingHandle struct { - ch FuzzyBindingCache + ch CrossDBBindingCache } // NewSessionBindingHandle creates a new SessionBindingHandle. func NewSessionBindingHandle() SessionBindingHandle { sessionHandle := &sessionBindingHandle{} - sessionHandle.ch = newFuzzyBindingCache(nil) + sessionHandle.ch = newCrossDBBindingCache(nil) return sessionHandle } @@ -110,8 +110,8 @@ func (h *sessionBindingHandle) DropSessionBinding(sqlDigests []string) error { } // MatchSessionBinding returns the matched binding for this statement. -func (h *sessionBindingHandle) MatchSessionBinding(sctx sessionctx.Context, fuzzyDigest string, tableNames []*ast.TableName) (matchedBinding Binding, isMatched bool) { - matchedBinding, isMatched = h.ch.FuzzyMatchingBinding(sctx, fuzzyDigest, tableNames) +func (h *sessionBindingHandle) MatchSessionBinding(sctx sessionctx.Context, noDBDigest string, tableNames []*ast.TableName) (matchedBinding Binding, isMatched bool) { + matchedBinding, isMatched = h.ch.MatchingBinding(sctx, noDBDigest, tableNames) return } diff --git a/pkg/bindinfo/session_handle_test.go b/pkg/bindinfo/session_handle_test.go index ae1b4af53e08a..3d86eca9bb623 100644 --- a/pkg/bindinfo/session_handle_test.go +++ b/pkg/bindinfo/session_handle_test.go @@ -95,8 +95,8 @@ func TestSessionBinding(t *testing.T) { stmt, err := parser.New().ParseOneStmt(testSQL.originSQL, "", "") require.NoError(t, err) - _, fuzzyDigest := norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - binding, matched := handle.MatchSessionBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest := norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + binding, matched := handle.MatchSessionBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.True(t, matched) require.Equal(t, testSQL.originSQL, binding.OriginalSQL) require.Equal(t, testSQL.bindSQL, binding.BindSQL) @@ -132,8 +132,8 @@ func TestSessionBinding(t *testing.T) { _, err = tk.Exec("drop session " + testSQL.dropSQL) require.NoError(t, err) - _, fuzzyDigest = norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - _, matched = handle.MatchSessionBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest = norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + _, matched = handle.MatchSessionBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.False(t, matched) // dropped } } diff --git a/pkg/bindinfo/tests/bind_test.go b/pkg/bindinfo/tests/bind_test.go index 2c1a20754062c..e36e1879a25c3 100644 --- a/pkg/bindinfo/tests/bind_test.go +++ b/pkg/bindinfo/tests/bind_test.go @@ -301,8 +301,8 @@ func TestBindingSymbolList(t *testing.T) { stmt, err := parser.New().ParseOneStmt("select a, b from test . t where a = 1 limit 0, 1", "", "") require.NoError(t, err) - _, fuzzyDigest := norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - binding, matched := dom.BindHandle().MatchGlobalBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest := norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + binding, matched := dom.BindHandle().MatchGlobalBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.True(t, matched) require.Equal(t, "select `a` , `b` from `test` . `t` where `a` = ? limit ...", binding.OriginalSQL) require.Equal(t, "SELECT `a`,`b` FROM `test`.`t` USE INDEX (`ib`) WHERE `a` = 1 LIMIT 0,1", binding.BindSQL) @@ -346,8 +346,8 @@ func TestBindingInListWithSingleLiteral(t *testing.T) { stmt, err := parser.New().ParseOneStmt("select a, b from test . t where a in (1)", "", "") require.NoError(t, err) - _, fuzzyDigest := norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - binding, matched := dom.BindHandle().MatchGlobalBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest := norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + binding, matched := dom.BindHandle().MatchGlobalBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.True(t, matched) require.Equal(t, "select `a` , `b` from `test` . `t` where `a` in ( ... )", binding.OriginalSQL) require.Equal(t, "SELECT `a`,`b` FROM `test`.`t` USE INDEX (`ib`) WHERE `a` IN (1,2,3)", binding.BindSQL) @@ -382,8 +382,8 @@ func TestBestPlanInBaselines(t *testing.T) { stmt, _, _ := internal.UtilNormalizeWithDefaultDB(t, "select a, b from t where a = 1 limit 0, 1") - _, fuzzyDigest := norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - binding, matched := dom.BindHandle().MatchGlobalBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest := norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + binding, matched := dom.BindHandle().MatchGlobalBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.True(t, matched) require.Equal(t, "select `a` , `b` from `test` . `t` where `a` = ? limit ...", binding.OriginalSQL) require.Equal(t, "SELECT /*+ use_index(@`sel_1` `test`.`t` `ia`)*/ `a`,`b` FROM `test`.`t` WHERE `a` = 1 LIMIT 0,1", binding.BindSQL) @@ -429,8 +429,8 @@ func TestErrorBind(t *testing.T) { stmt, err := parser.New().ParseOneStmt("select * from test . t where i > ?", "", "") require.NoError(t, err) - _, fuzzyDigest := norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - binding, matched := dom.BindHandle().MatchGlobalBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest := norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + binding, matched := dom.BindHandle().MatchGlobalBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.True(t, matched) require.Equal(t, "select * from `test` . `t` where `i` > ?", binding.OriginalSQL) require.Equal(t, "SELECT * FROM `test`.`t` USE INDEX (`index_t`) WHERE `i` > 100", binding.BindSQL) @@ -476,40 +476,40 @@ func TestHintsSetID(t *testing.T) { // Verify the added Binding contains ID with restored query block. stmt, err := parser.New().ParseOneStmt("select * from t where a > ?", "", "") require.NoError(t, err) - _, fuzzyDigest := norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - binding, matched := dom.BindHandle().MatchGlobalBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest := norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + binding, matched := dom.BindHandle().MatchGlobalBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.True(t, matched) require.Equal(t, "select * from `test` . `t` where `a` > ?", binding.OriginalSQL) require.Equal(t, "use_index(@`sel_1` `test`.`t` `idx_a`)", binding.ID) internal.UtilCleanBindingEnv(tk, dom) tk.MustExec("create global binding for select * from t where a > 10 using select /*+ use_index(t, idx_a) */ * from t where a > 10") - _, fuzzyDigest = norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - binding, matched = dom.BindHandle().MatchGlobalBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest = norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + binding, matched = dom.BindHandle().MatchGlobalBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.True(t, matched) require.Equal(t, "select * from `test` . `t` where `a` > ?", binding.OriginalSQL) require.Equal(t, "use_index(@`sel_1` `test`.`t` `idx_a`)", binding.ID) internal.UtilCleanBindingEnv(tk, dom) tk.MustExec("create global binding for select * from t where a > 10 using select /*+ use_index(@sel_1 t, idx_a) */ * from t where a > 10") - _, fuzzyDigest = norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - binding, matched = dom.BindHandle().MatchGlobalBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest = norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + binding, matched = dom.BindHandle().MatchGlobalBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.True(t, matched) require.Equal(t, "select * from `test` . `t` where `a` > ?", binding.OriginalSQL) require.Equal(t, "use_index(@`sel_1` `test`.`t` `idx_a`)", binding.ID) internal.UtilCleanBindingEnv(tk, dom) tk.MustExec("create global binding for select * from t where a > 10 using select /*+ use_index(@qb1 t, idx_a) qb_name(qb1) */ * from t where a > 10") - _, fuzzyDigest = norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - binding, matched = dom.BindHandle().MatchGlobalBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest = norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + binding, matched = dom.BindHandle().MatchGlobalBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.True(t, matched) require.Equal(t, "select * from `test` . `t` where `a` > ?", binding.OriginalSQL) require.Equal(t, "use_index(@`sel_1` `test`.`t` `idx_a`)", binding.ID) internal.UtilCleanBindingEnv(tk, dom) tk.MustExec("create global binding for select * from t where a > 10 using select /*+ use_index(T, IDX_A) */ * from t where a > 10") - _, fuzzyDigest = norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - binding, matched = dom.BindHandle().MatchGlobalBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest = norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + binding, matched = dom.BindHandle().MatchGlobalBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.True(t, matched) require.Equal(t, "select * from `test` . `t` where `a` > ?", binding.OriginalSQL) require.Equal(t, "use_index(@`sel_1` `test`.`t` `idx_a`)", binding.ID) @@ -518,8 +518,8 @@ func TestHintsSetID(t *testing.T) { err = tk.ExecToErr("create global binding for select * from t using select /*+ non_exist_hint() */ * from t") require.True(t, terror.ErrorEqual(err, parser.ErrParse)) tk.MustExec("create global binding for select * from t where a > 10 using select * from t where a > 10") - _, fuzzyDigest = norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) - binding, matched = dom.BindHandle().MatchGlobalBinding(tk.Session(), fuzzyDigest, bindinfo.CollectTableNames(stmt)) + _, noDBDigest = norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) + binding, matched = dom.BindHandle().MatchGlobalBinding(tk.Session(), noDBDigest, bindinfo.CollectTableNames(stmt)) require.True(t, matched) require.Equal(t, "select * from `test` . `t` where `a` > ?", binding.OriginalSQL) require.Equal(t, "", binding.ID) @@ -841,7 +841,7 @@ func TestNormalizeStmtForBinding(t *testing.T) { } for _, test := range tests { stmt, _, _ := internal.UtilNormalizeWithDefaultDB(t, test.sql) - n, digest := norm.NormalizeStmtForBinding(stmt, norm.WithFuzz(true)) + n, digest := norm.NormalizeStmtForBinding(stmt, norm.WithoutDB(true)) require.Equal(t, test.normalized, n) require.Equal(t, test.digest, digest) }