diff --git a/expression/function_traits.go b/expression/function_traits.go index 4d6fa98da6a99..f2cafad69f8b5 100644 --- a/expression/function_traits.go +++ b/expression/function_traits.go @@ -28,6 +28,7 @@ var NonPreparedPlanCacheableOp = map[string]struct{}{ ast.EQ: {}, ast.LT: {}, ast.GT: {}, + ast.In: {}, } // UnCacheableFunctions stores functions which can not be cached to plan cache. diff --git a/planner/core/plan_cache_test.go b/planner/core/plan_cache_test.go index 12154de382e5d..3c2ebeaf3da84 100644 --- a/planner/core/plan_cache_test.go +++ b/planner/core/plan_cache_test.go @@ -455,7 +455,7 @@ func TestNonPreparedPlanCacheBasically(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, primary key(a), key(b), key(c, d))`) + tk.MustExec(`create table t (a int, b int, c int, d int, key(b), key(c, d))`) for i := 0; i < 20; i++ { tk.MustExec(fmt.Sprintf("insert into t values (%v, %v, %v, %v)", i, rand.Intn(20), rand.Intn(20), rand.Intn(20))) } @@ -468,6 +468,14 @@ func TestNonPreparedPlanCacheBasically(t *testing.T) { "select * from t where d>8", "select * from t where c=8 and d>10", "select * from t where a<12 and b<13 and c<12 and d>2", + "select * from t where a in (1, 2, 3)", + "select * from t where a<13 or b<15", + "select * from t where a<13 or b<15 and c=13", + "select * from t where a in (1, 2)", + "select * from t where a in (1, 2) and b in (1, 2, 3)", + "select * from t where a in (1, 2) and b < 15", + "select * from t where a between 1 and 10", + "select * from t where a between 1 and 10 and b < 15", } for _, query := range queries { diff --git a/planner/core/plan_cacheable_checker.go b/planner/core/plan_cacheable_checker.go index cfb38c28827a1..4c153cb25cf80 100644 --- a/planner/core/plan_cacheable_checker.go +++ b/planner/core/plan_cacheable_checker.go @@ -256,7 +256,7 @@ type nonPreparedPlanCacheableChecker struct { // Enter implements Visitor interface. func (checker *nonPreparedPlanCacheableChecker) Enter(in ast.Node) (out ast.Node, skipChildren bool) { switch node := in.(type) { - case *ast.SelectStmt, *ast.FieldList, *ast.SelectField, *ast.TableRefsClause, *ast.Join, + case *ast.SelectStmt, *ast.FieldList, *ast.SelectField, *ast.TableRefsClause, *ast.Join, *ast.BetweenExpr, *ast.TableSource, *ast.ColumnNameExpr, *ast.ColumnName, *driver.ValueExpr, *ast.PatternInExpr: return in, !checker.cacheable // skip child if un-cacheable case *ast.BinaryOperationExpr: diff --git a/planner/core/plan_cacheable_checker_test.go b/planner/core/plan_cacheable_checker_test.go index 5410890658fff..f174d97bc7697 100644 --- a/planner/core/plan_cacheable_checker_test.go +++ b/planner/core/plan_cacheable_checker_test.go @@ -291,6 +291,11 @@ func TestNonPreparedPlanCacheable(t *testing.T) { "select * from t where a in (1, 2, 3)", "select * from t where a<13 or b<15", "select * from t where a<13 or b<15 and c=13", + "select * from t where a in (1, 2)", + "select * from t where a in (1, 2) and b in (1, 2, 3)", + "select * from t where a in (1, 2) and b < 15", + "select * from t where a between 1 and 10", + "select * from t where a between 1 and 10 and b < 15", } unsupported := []string{ @@ -306,6 +311,9 @@ func TestNonPreparedPlanCacheable(t *testing.T) { "insert into t1(a, b) select a, b from t1", // insert into select "update t1 set a = 1 where b = 2", // update "delete from t1 where b = 1", // delete + "select * from t1 for update", // lock + "select * from t1 where a in (select a from t)", // uncorrelated sub-query + "select * from t1 where a in (select a from t where a > t1.a)", // correlated sub-query "select * from t where a+b=13", // '+' "select * from t where mod(a, 3)=1", // mod