diff --git a/executor/explainfor_test.go b/executor/explainfor_test.go index 246262ac0a9ef..d962e6a8338f4 100644 --- a/executor/explainfor_test.go +++ b/executor/explainfor_test.go @@ -623,9 +623,9 @@ func (s *testPrepareSerialSuite) TestIssue28259(c *C) { ps = []*util.ProcessInfo{tkProcess} tk.Se.SetSessionManager(&mockSessionManager1{PS: ps}) res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10)) - c.Assert(len(res.Rows()), Equals, 4) - c.Assert(res.Rows()[0][0], Matches, ".*Selection.*") - c.Assert(res.Rows()[3][0], Matches, ".*IndexFullScan.*") + c.Assert(len(res.Rows()), Equals, 3) + c.Assert(res.Rows()[1][0], Matches, ".*Selection.*") + c.Assert(res.Rows()[2][0], Matches, ".*IndexFullScan.*") res = tk.MustQuery("explain format = 'brief' select col1 from UK_GCOL_VIRTUAL_18588 use index(UK_COL1) " + "where col1 between -1696020282760139948 and -2619168038882941276 or col1 < -4004648990067362699;") @@ -661,11 +661,9 @@ func (s *testPrepareSerialSuite) TestIssue28259(c *C) { ps = []*util.ProcessInfo{tkProcess} tk.Se.SetSessionManager(&mockSessionManager1{PS: ps}) res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10)) - c.Assert(len(res.Rows()), Equals, 5) - c.Assert(res.Rows()[1][0], Matches, ".*Selection.*") - c.Assert(res.Rows()[1][4], Equals, "lt(test.t.b, 1), or(and(ge(test.t.a, 2), le(test.t.a, 1)), lt(test.t.a, 1))") - c.Assert(res.Rows()[2][0], Matches, ".*IndexReader.*") - c.Assert(res.Rows()[4][0], Matches, ".*IndexRangeScan.*") + c.Assert(len(res.Rows()), Equals, 4) + c.Assert(res.Rows()[2][0], Matches, ".*Selection.*") + c.Assert(res.Rows()[3][0], Matches, ".*IndexRangeScan.*") res = tk.MustQuery("explain format = 'brief' select a from t use index(idx) " + "where (a between 0 and 2 or a < 2) and b < 1;") @@ -708,12 +706,11 @@ func (s *testPrepareSerialSuite) TestIssue28259(c *C) { ps = []*util.ProcessInfo{tkProcess} tk.Se.SetSessionManager(&mockSessionManager1{PS: ps}) res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10)) - c.Assert(len(res.Rows()), Equals, 6) - c.Assert(res.Rows()[1][0], Matches, ".*Selection.*") - c.Assert(res.Rows()[2][0], Matches, ".*IndexLookUp.*") - c.Assert(res.Rows()[3][0], Matches, ".*IndexRangeScan.*") - c.Assert(res.Rows()[4][0], Matches, ".*Selection.*") - c.Assert(res.Rows()[5][0], Matches, ".*TableRowIDScan.*") + c.Assert(len(res.Rows()), Equals, 5) + c.Assert(res.Rows()[1][0], Matches, ".*IndexLookUp.*") + c.Assert(res.Rows()[2][0], Matches, ".*IndexRangeScan.*") + c.Assert(res.Rows()[3][0], Matches, ".*Selection.*") + c.Assert(res.Rows()[4][0], Matches, ".*TableRowIDScan.*") res = tk.MustQuery("explain format = 'brief' select /*+ USE_INDEX(t, idx) */ a from t use index(idx) " + "where (a between 0 and 2 or a < 2) and b < 1;") @@ -952,7 +949,7 @@ func (s *testPrepareSerialSuite) TestIndexMerge4PlanCache(c *C) { tk.MustExec("prepare stmt from 'select /*+ use_index_merge(t1) */ * from t1 where c=? or (b=? and (a >= ? and a <= ?));';") tk.MustQuery("execute stmt using @a, @a, @b, @a").Check(testkit.Rows("10 10 10")) tk.MustQuery("execute stmt using @b, @b, @b, @b").Check(testkit.Rows("11 11 11")) - tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("1")) + tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0")) tk.MustExec("prepare stmt from 'select /*+ use_index_merge(t1) */ * from t1 where c=10 or (a >=? and a <= ?);';") tk.MustExec("set @a=9, @b=10, @c=11;") @@ -974,7 +971,7 @@ func (s *testPrepareSerialSuite) TestIndexMerge4PlanCache(c *C) { tk.MustExec("set @a=9, @b=10, @c=11;") tk.MustQuery("execute stmt using @c, @a;").Check(testkit.Rows("10 10 10")) tk.MustQuery("execute stmt using @a, @c;").Check(testkit.Rows("10 10 10", "11 11 11")) - tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("1")) + tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0")) tk.MustQuery("execute stmt using @a, @a;").Check(testkit.Rows("10 10 10")) tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("1")) diff --git a/expression/expression.go b/expression/expression.go index 0fc49b1adbc49..3566b2ccd84e3 100644 --- a/expression/expression.go +++ b/expression/expression.go @@ -794,7 +794,7 @@ func SplitDNFItems(onExpr Expression) []Expression { // If the Expression is a non-constant value, it means the result is unknown. func EvaluateExprWithNull(ctx sessionctx.Context, schema *Schema, expr Expression) Expression { if MaybeOverOptimized4PlanCache(ctx, []Expression{expr}) { - return expr + ctx.GetSessionVars().StmtCtx.SkipPlanCache = true } return evaluateExprWithNull(ctx, schema, expr) } diff --git a/expression/expression_test.go b/expression/expression_test.go index 0ae6cfdddd868..2459db13c9f0e 100644 --- a/expression/expression_test.go +++ b/expression/expression_test.go @@ -75,8 +75,9 @@ func TestEvaluateExprWithNullAndParameters(t *testing.T) { ltWithParam, err := newFunctionForTest(ctx, ast.LT, col0, param) require.NoError(t, err) res = EvaluateExprWithNull(ctx, schema, ltWithParam) - _, isScalarFunc := res.(*ScalarFunction) - require.True(t, isScalarFunc) // the expression with parameters is not evaluated + _, isConst := res.(*Constant) + require.True(t, isConst) // this expression is evaluated and skip-plan cache flag is set. + require.True(t, ctx.GetSessionVars().StmtCtx.SkipPlanCache) } func TestConstant(t *testing.T) { diff --git a/planner/core/prepare_test.go b/planner/core/prepare_test.go index ef2465195808d..047df5825f977 100644 --- a/planner/core/prepare_test.go +++ b/planner/core/prepare_test.go @@ -2058,7 +2058,7 @@ func (s *testPlanSerialSuite) TestPlanCachePointGetAndTableDual(c *C) { tk.MustQuery("execute s0 using @a0, @b0, @a0").Check(testkit.Rows()) tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) tk.MustQuery("execute s0 using @a0, @a0, @b0").Check(testkit.Rows("0000 7777 1")) - tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) tk.MustExec("create table t1(c1 varchar(20), c2 varchar(20), c3 bigint(20), primary key(c1, c2))") tk.MustExec("insert into t1 values('0000','7777',1)") @@ -2096,7 +2096,7 @@ func (s *testPlanSerialSuite) TestPlanCachePointGetAndTableDual(c *C) { tk.MustQuery("execute s3 using @b3,@a3").Check(testkit.Rows()) tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) tk.MustQuery("execute s3 using @a3,@b3").Check(testkit.Rows("2 1 1")) - tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) tk.MustExec("create table t4(c1 int primary key, c2 int, c3 int, key(c2))") tk.MustExec("insert into t4 values(2,1,1)") @@ -2112,7 +2112,7 @@ func (s *testPlanSerialSuite) TestPlanCachePointGetAndTableDual(c *C) { tk.MustQuery("execute s4 using @b4,@a4").Check(testkit.Rows()) tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) tk.MustQuery("execute s4 using @a4,@b4").Check(testkit.Rows("2 1 1")) - tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) } func (s *testPrepareSuite) TestIssue26873(c *C) { diff --git a/util/ranger/detacher.go b/util/ranger/detacher.go index b2ac1075f285d..58d472aadcf2e 100644 --- a/util/ranger/detacher.go +++ b/util/ranger/detacher.go @@ -537,9 +537,8 @@ func ExtractEqAndInCondition(sctx sessionctx.Context, conditions []expression.Ex points[offset] = rb.intersection(points[offset], rb.build(cond, collator), collator) if len(points[offset]) == 0 { // Early termination if false expression found if expression.MaybeOverOptimized4PlanCache(sctx, conditions) { - // cannot return an empty-range for plan-cache since the range may become non-empty as parameters change - // for safety, return the whole conditions in this case - return nil, conditions, nil, nil, false + // `a>@x and a<@y` --> `invalid-range if @x>=@y` + sctx.GetSessionVars().StmtCtx.SkipPlanCache = true } return nil, nil, nil, nil, true } @@ -562,9 +561,8 @@ func ExtractEqAndInCondition(sctx sessionctx.Context, conditions []expression.Ex accesses[i] = nil } else if len(points[i]) == 0 { // Early termination if false expression found if expression.MaybeOverOptimized4PlanCache(sctx, conditions) { - // cannot return an empty-range for plan-cache since the range may become non-empty as parameters change - // for safety, return the whole conditions in this case - return nil, conditions, nil, nil, false + // `a>@x and a<@y` --> `invalid-range if @x>=@y` + sctx.GetSessionVars().StmtCtx.SkipPlanCache = true } return nil, nil, nil, nil, true } else {