diff --git a/executor/explainfor_test.go b/executor/explainfor_test.go index 7b547d7caff8d..fc16cd93eea3f 100644 --- a/executor/explainfor_test.go +++ b/executor/explainfor_test.go @@ -613,9 +613,9 @@ func TestIssue28259(t *testing.T) { ps = []*util.ProcessInfo{tkProcess} tk.Session().SetSessionManager(&testkit.MockSessionManager{PS: ps}) res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10)) - require.Len(t, res.Rows(), 4) - require.Regexp(t, ".*Selection.*", res.Rows()[0][0]) - require.Regexp(t, ".*IndexFullScan.*", res.Rows()[3][0]) + require.Len(t, res.Rows(), 3) + require.Regexp(t, ".*Selection.*", res.Rows()[1][0]) + require.Regexp(t, ".*IndexFullScan.*", res.Rows()[2][0]) 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;") @@ -651,11 +651,9 @@ func TestIssue28259(t *testing.T) { ps = []*util.ProcessInfo{tkProcess} tk.Session().SetSessionManager(&testkit.MockSessionManager{PS: ps}) res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10)) - require.Len(t, res.Rows(), 5) - require.Regexp(t, ".*Selection.*", res.Rows()[1][0]) - require.Equal(t, "lt(test.t.b, 1), or(and(ge(test.t.a, 2), le(test.t.a, 1)), lt(test.t.a, 1))", res.Rows()[1][4]) - require.Regexp(t, ".*IndexReader.*", res.Rows()[2][0]) - require.Regexp(t, ".*IndexRangeScan.*", res.Rows()[4][0]) + require.Len(t, res.Rows(), 4) + require.Regexp(t, ".*Selection.*", res.Rows()[2][0]) + require.Regexp(t, ".*IndexRangeScan.*", res.Rows()[3][0]) 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;") @@ -698,12 +696,11 @@ func TestIssue28259(t *testing.T) { ps = []*util.ProcessInfo{tkProcess} tk.Session().SetSessionManager(&testkit.MockSessionManager{PS: ps}) res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10)) - require.Len(t, res.Rows(), 6) - require.Regexp(t, ".*Selection.*", res.Rows()[1][0]) - require.Regexp(t, ".*IndexLookUp.*", res.Rows()[2][0]) - require.Regexp(t, ".*IndexRangeScan.*", res.Rows()[3][0]) - require.Regexp(t, ".*Selection.*", res.Rows()[4][0]) - require.Regexp(t, ".*TableRowIDScan.*", res.Rows()[5][0]) + require.Len(t, res.Rows(), 5) + require.Regexp(t, ".*IndexLookUp.*", res.Rows()[1][0]) + require.Regexp(t, ".*IndexRangeScan.*", res.Rows()[2][0]) + require.Regexp(t, ".*Selection.*", res.Rows()[3][0]) + require.Regexp(t, ".*TableRowIDScan.*", res.Rows()[4][0]) 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;") @@ -946,7 +943,7 @@ func TestIndexMerge4PlanCache(t *testing.T) { 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;") diff --git a/executor/stale_txn_test.go b/executor/stale_txn_test.go index 62255326cbce0..9899fb0e1c8fd 100644 --- a/executor/stale_txn_test.go +++ b/executor/stale_txn_test.go @@ -533,19 +533,23 @@ func TestStalenessTransactionSchemaVer(t *testing.T) { tk.MustExec("alter table t add c int") // confirm schema changed + time.Sleep(time.Millisecond * 20) schemaVer2 := tk.Session().GetInfoSchema().SchemaMetaVersion() require.Less(t, schemaVer1, schemaVer2) // get the specific old schema tk.MustExec(fmt.Sprintf(`START TRANSACTION READ ONLY AS OF TIMESTAMP '%s'`, time1.Format("2006-1-2 15:04:05.000"))) + time.Sleep(time.Millisecond * 20) require.Equal(t, schemaVer1, tk.Session().GetInfoSchema().SchemaMetaVersion()) // schema changed back to the newest tk.MustExec("commit") + time.Sleep(time.Millisecond * 20) require.Equal(t, schemaVer2, tk.Session().GetInfoSchema().SchemaMetaVersion()) // select does not affect the infoschema tk.MustExec(fmt.Sprintf(`SELECT * from t AS OF TIMESTAMP '%s'`, time1.Format("2006-1-2 15:04:05.000"))) + time.Sleep(time.Millisecond * 20) require.Equal(t, schemaVer2, tk.Session().GetInfoSchema().SchemaMetaVersion()) } diff --git a/expression/expression.go b/expression/expression.go index df2d431e4f269..66b87da71aa65 100644 --- a/expression/expression.go +++ b/expression/expression.go @@ -795,7 +795,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 499f5c0bfea21..7d19897699c05 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 0dbcbaf2ad91a..71dd3cde99752 100644 --- a/planner/core/prepare_test.go +++ b/planner/core/prepare_test.go @@ -2212,7 +2212,7 @@ func TestPlanCachePointGetAndTableDual(t *testing.T) { 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)") diff --git a/util/ranger/detacher.go b/util/ranger/detacher.go index 116cc687b9ce2..b94b4aff6e1e1 100644 --- a/util/ranger/detacher.go +++ b/util/ranger/detacher.go @@ -540,9 +540,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 } @@ -565,9 +564,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 {