Skip to content

Commit

Permalink
planner: fix the issue that binding for in (?) cannot work for `in …
Browse files Browse the repository at this point in the history
…(?,?,?)` (pingcap#46896)

ref pingcap#44298
  • Loading branch information
qw4990 authored Sep 12, 2023
1 parent 5c205a7 commit 2db6c0a
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 7 deletions.
2 changes: 1 addition & 1 deletion bindinfo/tests/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ go_test(
],
flaky = True,
race = "on",
shard_count = 35,
shard_count = 37,
deps = [
"//bindinfo",
"//bindinfo/internal",
Expand Down
76 changes: 76 additions & 0 deletions bindinfo/tests/bind_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,82 @@ import (
"github.com/stretchr/testify/require"
)

func TestBindingInListEffect(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec(`create table t (a int, b int, c int, d int)`)

// binding created with `in (?)` can work for `in (?,?,?)`
tk.MustQuery(`select a from t where a in (1, 2, 3)`)
tk.MustQuery(`select @@last_plan_from_binding`).Check(testkit.Rows("0"))
tk.MustExec(`create binding for select a from t where a in (1) using select a from t where a in (1)`)
tk.MustQuery(`select a from t where a in (1, 2, 3)`)
tk.MustQuery(`select @@last_plan_from_binding`).Check(testkit.Rows("1"))
tk.MustQuery(`select a from t where a in (1, 2)`)
tk.MustQuery(`select @@last_plan_from_binding`).Check(testkit.Rows("1"))
tk.MustQuery(`select a from t where a in (1)`)
tk.MustQuery(`select @@last_plan_from_binding`).Check(testkit.Rows("1"))

// binding created with `in (?,?,?)` can work for `in (?)`
tk.MustQuery(`select b from t where b in (1)`)
tk.MustQuery(`select @@last_plan_from_binding`).Check(testkit.Rows("0"))
tk.MustExec(`create binding for select b from t where b in (1,2,3) using select b from t where b in (1,2,3)`)
tk.MustQuery(`select b from t where b in (1)`)
tk.MustQuery(`select @@last_plan_from_binding`).Check(testkit.Rows("1"))

// bindings with multiple in-lists can take effect
tk.MustQuery(`select * from t where a in (1) and b in (1) and c in (1)`)
tk.MustQuery(`select @@last_plan_from_binding`).Check(testkit.Rows("0"))
tk.MustExec(`create binding for select * from t where a in (1) and b in (1,2) and c in (1,2,3) using
select * from t where a in (1,2,3) and b in (1,2) and c in (1)`)
tk.MustQuery(`select * from t where a in (1) and b in (1) and c in (1)`)
tk.MustQuery(`select @@last_plan_from_binding`).Check(testkit.Rows("1"))
tk.MustQuery(`select * from t where a in (1) and b in (1,2) and c in (1,2,3)`)
tk.MustQuery(`select @@last_plan_from_binding`).Check(testkit.Rows("1"))
tk.MustQuery(`select * from t where a in (1,2,3) and b in (1,2) and c in (1)`)
tk.MustQuery(`select @@last_plan_from_binding`).Check(testkit.Rows("1"))
}

func TestBindingInListOperation(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec(`create table t (a int, b int, c int, d int)`)

// only 1 binding will be left
tk.MustExec(`create binding for select * from t where a in(1) using select * from t where a in(1)`)
tk.MustExec(`create binding for select * from t where a in(1,2) using select * from t where a in(1)`)
tk.MustExec(`create binding for select * from t where a in(1) using select * from t where a in(1,2)`)
tk.MustExec(`create binding for select * from t where a in(1,2) using select * from t where a in(1,2)`)
tk.MustExec(`create binding for select * from t where a in(1,2,3) using select * from t where a in(1,2,3)`)
require.Equal(t, 1, len(tk.MustQuery(`show bindings`).Rows()))
tk.MustExec(`drop binding for select * from t where a in(1)`)
require.Equal(t, 0, len(tk.MustQuery(`show bindings`).Rows()))

// create and drop
tk.MustExec(`create binding for select * from t where a in(1,2,3) using select * from t where a in(1)`)
require.Equal(t, 1, len(tk.MustQuery(`show bindings`).Rows()))
tk.MustExec(`drop binding for select * from t where a in(1)`)
require.Equal(t, 0, len(tk.MustQuery(`show bindings`).Rows()))
tk.MustExec(`create binding for select * from t where a in(1) using select * from t where a in(1)`)
require.Equal(t, 1, len(tk.MustQuery(`show bindings`).Rows()))
tk.MustExec(`drop binding for select * from t where a in(1,2,3)`)
require.Equal(t, 0, len(tk.MustQuery(`show bindings`).Rows()))
tk.MustExec(`create binding for select * from t where a in(1) using select * from t where a in(1)`)
require.Equal(t, 1, len(tk.MustQuery(`show bindings`).Rows()))
tk.MustExec(`drop binding for select * from t where a in(1,2,3,4,5,6,7,8,9,0,11,12)`)
require.Equal(t, 0, len(tk.MustQuery(`show bindings`).Rows()))

// create and set status
tk.MustExec(`create global binding for select * from t where a in(1,2,3) using select * from t where a in(1)`)
require.Equal(t, "enabled", tk.MustQuery(`show global bindings`).Rows()[0][3].(string))
tk.MustExec(`set binding disabled for select * from t where a in(1)`)
require.Equal(t, "disabled", tk.MustQuery(`show global bindings`).Rows()[0][3].(string))
tk.MustExec(`set binding enabled for select * from t where a in(1,2,3,4,5)`)
require.Equal(t, "enabled", tk.MustQuery(`show global bindings`).Rows()[0][3].(string))
}

func TestPrepareCacheWithBinding(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
Expand Down
8 changes: 4 additions & 4 deletions planner/core/planbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -1053,7 +1053,7 @@ func (b *PlanBuilder) buildDropBindPlan(v *ast.DropBindingStmt) (Plan, error) {
if v.OriginNode != nil {
p = &SQLBindPlan{
SQLBindOp: OpSQLBindDrop,
NormdOrigSQL: parser.Normalize(utilparser.RestoreWithDefaultDB(v.OriginNode, b.ctx.GetSessionVars().CurrentDB, v.OriginNode.Text())),
NormdOrigSQL: parser.NormalizeForBinding(utilparser.RestoreWithDefaultDB(v.OriginNode, b.ctx.GetSessionVars().CurrentDB, v.OriginNode.Text())),
IsGlobal: v.GlobalScope,
Db: utilparser.GetDefaultDB(v.OriginNode, b.ctx.GetSessionVars().CurrentDB),
}
Expand All @@ -1076,7 +1076,7 @@ func (b *PlanBuilder) buildSetBindingStatusPlan(v *ast.SetBindingStmt) (Plan, er
if v.OriginNode != nil {
p = &SQLBindPlan{
SQLBindOp: OpSetBindingStatus,
NormdOrigSQL: parser.Normalize(utilparser.RestoreWithDefaultDB(v.OriginNode, b.ctx.GetSessionVars().CurrentDB, v.OriginNode.Text())),
NormdOrigSQL: parser.NormalizeForBinding(utilparser.RestoreWithDefaultDB(v.OriginNode, b.ctx.GetSessionVars().CurrentDB, v.OriginNode.Text())),
Db: utilparser.GetDefaultDB(v.OriginNode, b.ctx.GetSessionVars().CurrentDB),
}
} else if v.SQLDigest != "" {
Expand Down Expand Up @@ -1169,7 +1169,7 @@ func (b *PlanBuilder) buildCreateBindPlanFromPlanDigest(v *ast.CreateBindingStmt
if err != nil {
return nil, errors.Errorf("binding failed: %v", err)
}
normdOrigSQL, sqlDigestWithDB := parser.NormalizeDigest(utilparser.RestoreWithDefaultDB(originNode, bindableStmt.Schema, bindableStmt.Query))
normdOrigSQL, sqlDigestWithDB := parser.NormalizeDigestForBinding(utilparser.RestoreWithDefaultDB(originNode, bindableStmt.Schema, bindableStmt.Query))
p := &SQLBindPlan{
SQLBindOp: OpSQLBindCreate,
NormdOrigSQL: normdOrigSQL,
Expand Down Expand Up @@ -1202,7 +1202,7 @@ func (b *PlanBuilder) buildCreateBindPlan(v *ast.CreateBindingStmt) (Plan, error
return nil, err
}

normdOrigSQL, sqlDigestWithDB := parser.NormalizeDigest(utilparser.RestoreWithDefaultDB(v.OriginNode, b.ctx.GetSessionVars().CurrentDB, v.OriginNode.Text()))
normdOrigSQL, sqlDigestWithDB := parser.NormalizeDigestForBinding(utilparser.RestoreWithDefaultDB(v.OriginNode, b.ctx.GetSessionVars().CurrentDB, v.OriginNode.Text()))
p := &SQLBindPlan{
SQLBindOp: OpSQLBindCreate,
NormdOrigSQL: normdOrigSQL,
Expand Down
4 changes: 2 additions & 2 deletions planner/core/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -547,8 +547,8 @@ func (p *preprocessor) checkBindGrammar(originNode, hintedNode ast.StmtNode, def
tn.DBInfo = dbInfo
}

originSQL := parser.Normalize(utilparser.RestoreWithDefaultDB(originNode, defaultDB, originNode.Text()))
hintedSQL := parser.Normalize(utilparser.RestoreWithDefaultDB(hintedNode, defaultDB, hintedNode.Text()))
originSQL := parser.NormalizeForBinding(utilparser.RestoreWithDefaultDB(originNode, defaultDB, originNode.Text()))
hintedSQL := parser.NormalizeForBinding(utilparser.RestoreWithDefaultDB(hintedNode, defaultDB, hintedNode.Text()))
if originSQL != hintedSQL {
p.err = errors.Errorf("hinted sql and origin sql don't match when hinted sql erase the hint info, after erase hint info, originSQL:%s, hintedSQL:%s", originSQL, hintedSQL)
}
Expand Down

0 comments on commit 2db6c0a

Please sign in to comment.