From be112dc31d548db050aae1f6d0ebde1fd564e8e1 Mon Sep 17 00:00:00 2001 From: Yuanjia Zhang Date: Thu, 5 Jan 2023 11:20:20 +0800 Subject: [PATCH] planner: skip plan-cache for prepared queries with `INT in (Decimals...)` (#40312) close pingcap/tidb#40224 --- planner/core/expression_rewriter.go | 12 +++-------- planner/core/plan_cache_test.go | 32 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/planner/core/expression_rewriter.go b/planner/core/expression_rewriter.go index 5a8f8a2df9f35..a2d1f242a0ff6 100644 --- a/planner/core/expression_rewriter.go +++ b/planner/core/expression_rewriter.go @@ -1559,16 +1559,10 @@ func (er *expressionRewriter) inToExpression(lLen int, not bool, tp *types.Field if c, ok := args[i].(*expression.Constant); ok { var isExceptional bool if expression.MaybeOverOptimized4PlanCache(er.sctx, []expression.Expression{c}) { - if c.GetType().EvalType() == types.ETString { - // To keep the result be compatible with MySQL, refine `int non-constant str constant` - // here and skip this refine operation in all other cases for safety. - er.sctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: '%v' may be converted to INT", c.String())) - expression.RemoveMutableConst(er.sctx, []expression.Expression{c}) - } else { - continue + if c.GetType().EvalType() == types.ETInt { + continue // no need to refine it } - } else if !er.sctx.GetSessionVars().StmtCtx.UseCache { - // We should remove the mutable constant for correctness, because its value may be changed. + er.sctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: '%v' may be converted to INT", c.String())) expression.RemoveMutableConst(er.sctx, []expression.Expression{c}) } args[i], isExceptional = expression.RefineComparedConstant(er.sctx, *leftFt, c, opcode.EQ) diff --git a/planner/core/plan_cache_test.go b/planner/core/plan_cache_test.go index 0aa5c4e02d7cb..d7d47e55bc62e 100644 --- a/planner/core/plan_cache_test.go +++ b/planner/core/plan_cache_test.go @@ -385,6 +385,38 @@ func TestPlanCacheDiagInfo(t *testing.T) { tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 skip plan-cache: some parameters may be overwritten")) } +func TestIssue40224(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("create table t (a int, key(a))") + tk.MustExec("prepare st from 'select a from t where a in (?, ?)'") + tk.MustExec("set @a=1.0, @b=2.0") + tk.MustExec("execute st using @a, @b") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 skip plan-cache: '1.0' may be converted to INT")) + tk.MustExec("execute st using @a, @b") + tkProcess := tk.Session().ShowProcess() + ps := []*util.ProcessInfo{tkProcess} + tk.Session().SetSessionManager(&testkit.MockSessionManager{PS: ps}) + tk.MustQuery(fmt.Sprintf("explain for connection %d", tkProcess.ID)).CheckAt([]int{0}, + [][]interface{}{ + {"IndexReader_6"}, + {"└─IndexRangeScan_5"}, // range scan not full scan + }) + + tk.MustExec("set @a=1, @b=2") + tk.MustExec("execute st using @a, @b") + tk.MustQuery("show warnings").Check(testkit.Rows()) // no warning for INT values + tk.MustExec("execute st using @a, @b") + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) // cacheable for INT + tk.MustExec("execute st using @a, @b") + tk.MustQuery(fmt.Sprintf("explain for connection %d", tkProcess.ID)).CheckAt([]int{0}, + [][]interface{}{ + {"IndexReader_6"}, + {"└─IndexRangeScan_5"}, // range scan not full scan + }) +} + func TestIssue40225(t *testing.T) { store := testkit.CreateMockStore(t) tk := testkit.NewTestKit(t, store)