From cea32e49355065442e35093b876cb114b1d83a4b Mon Sep 17 00:00:00 2001 From: qw4990 Date: Wed, 18 Jan 2023 14:28:39 +0800 Subject: [PATCH 1/4] fixup --- expression/builtin_compare.go | 37 ++++++++++++++------------------- planner/core/plan_cache_test.go | 19 +++++++++++++++++ 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/expression/builtin_compare.go b/expression/builtin_compare.go index dec5d06983679..e53a9765acf8f 100644 --- a/expression/builtin_compare.go +++ b/expression/builtin_compare.go @@ -1565,33 +1565,16 @@ func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Express arg0Type, arg1Type := args[0].GetType(), args[1].GetType() arg0IsInt := arg0Type.EvalType() == types.ETInt arg1IsInt := arg1Type.EvalType() == types.ETInt - arg0IsString := arg0Type.EvalType() == types.ETString - arg1IsString := arg1Type.EvalType() == types.ETString arg0, arg0IsCon := args[0].(*Constant) arg1, arg1IsCon := args[1].(*Constant) isExceptional, finalArg0, finalArg1 := false, args[0], args[1] isPositiveInfinite, isNegativeInfinite := false, false - if MaybeOverOptimized4PlanCache(ctx, args) { - // 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. - if (arg0IsInt && !arg0IsCon && arg1IsString && arg1IsCon) || (arg1IsInt && !arg1IsCon && arg0IsString && arg0IsCon) { - var reason error - if arg1IsString { - reason = errors.Errorf("skip plan-cache: '%v' may be converted to INT", arg1.String()) - } else { // arg0IsString - reason = errors.Errorf("skip plan-cache: '%v' may be converted to INT", arg0.String()) - } - ctx.GetSessionVars().StmtCtx.SetSkipPlanCache(reason) - RemoveMutableConst(ctx, args) - } else { - return args - } - } else if !ctx.GetSessionVars().StmtCtx.UseCache { - // We should remove the mutable constant for correctness, because its value may be changed. - RemoveMutableConst(ctx, args) - } // int non-constant [cmp] non-int constant if arg0IsInt && !arg0IsCon && !arg1IsInt && arg1IsCon { + if MaybeOverOptimized4PlanCache(ctx, []Expression{arg1}) { + ctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: '%v' may be converted to INT", arg1.String())) + } + arg1, isExceptional = RefineComparedConstant(ctx, *arg0Type, arg1, c.op) // Why check not null flag // eg: int_col > const_val(which is less than min_int32) @@ -1619,6 +1602,10 @@ func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Express } // non-int constant [cmp] int non-constant if arg1IsInt && !arg1IsCon && !arg0IsInt && arg0IsCon { + if MaybeOverOptimized4PlanCache(ctx, []Expression{arg0}) { + ctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: '%v' may be converted to INT", arg0.String())) + } + arg0, isExceptional = RefineComparedConstant(ctx, *arg1Type, arg0, symmetricOp[c.op]) if !isExceptional || (isExceptional && mysql.HasNotNullFlag(arg1Type.GetFlag())) { finalArg0 = arg0 @@ -1636,6 +1623,10 @@ func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Express } // int constant [cmp] year type if arg0IsCon && arg0IsInt && arg1Type.GetType() == mysql.TypeYear && !arg0.Value.IsNull() { + if MaybeOverOptimized4PlanCache(ctx, []Expression{arg0}) { + ctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: '%v' may be converted to INT", arg0.String())) + } + adjusted, failed := types.AdjustYear(arg0.Value.GetInt64(), false) if failed == nil { arg0.Value.SetInt64(adjusted) @@ -1644,6 +1635,10 @@ func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Express } // year type [cmp] int constant if arg1IsCon && arg1IsInt && arg0Type.GetType() == mysql.TypeYear && !arg1.Value.IsNull() { + if MaybeOverOptimized4PlanCache(ctx, []Expression{arg0}) { + ctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: '%v' may be converted to INT", arg0.String())) + } + adjusted, failed := types.AdjustYear(arg1.Value.GetInt64(), false) if failed == nil { arg1.Value.SetInt64(adjusted) diff --git a/planner/core/plan_cache_test.go b/planner/core/plan_cache_test.go index ba3e8962ff229..a2c75d99a9edd 100644 --- a/planner/core/plan_cache_test.go +++ b/planner/core/plan_cache_test.go @@ -371,3 +371,22 @@ func TestIssue40224(t *testing.T) { {"└─IndexRangeScan_5"}, // range scan not full scan }) } + +func TestIssue40679(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 * from t use index(a) where a < ?'") + tk.MustExec("set @a1=1.1") + tk.MustExec("execute st using @a1") + + tkProcess := tk.Session().ShowProcess() + ps := []*util.ProcessInfo{tkProcess} + tk.Session().SetSessionManager(&testkit.MockSessionManager{PS: ps}) + rows := tk.MustQuery(fmt.Sprintf("explain for connection %d", tkProcess.ID)).Rows() + require.True(t, strings.Contains(rows[1][0].(string), "RangeScan")) // RangeScan not FullScan + + tk.MustExec("execute st using @a1") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 skip plan-cache: '1.1' may be converted to INT")) +} From 6523b4cc7b1500e7c065ee0c70b286f2efd6c34e Mon Sep 17 00:00:00 2001 From: qw4990 Date: Wed, 18 Jan 2023 15:29:54 +0800 Subject: [PATCH 2/4] fixup --- expression/builtin_compare.go | 4 ++++ planner/core/expression_rewriter.go | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/expression/builtin_compare.go b/expression/builtin_compare.go index e53a9765acf8f..31c767b5b3571 100644 --- a/expression/builtin_compare.go +++ b/expression/builtin_compare.go @@ -1573,6 +1573,7 @@ func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Express if arg0IsInt && !arg0IsCon && !arg1IsInt && arg1IsCon { if MaybeOverOptimized4PlanCache(ctx, []Expression{arg1}) { ctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: '%v' may be converted to INT", arg1.String())) + RemoveMutableConst(ctx, args) } arg1, isExceptional = RefineComparedConstant(ctx, *arg0Type, arg1, c.op) @@ -1604,6 +1605,7 @@ func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Express if arg1IsInt && !arg1IsCon && !arg0IsInt && arg0IsCon { if MaybeOverOptimized4PlanCache(ctx, []Expression{arg0}) { ctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: '%v' may be converted to INT", arg0.String())) + RemoveMutableConst(ctx, args) } arg0, isExceptional = RefineComparedConstant(ctx, *arg1Type, arg0, symmetricOp[c.op]) @@ -1625,6 +1627,7 @@ func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Express if arg0IsCon && arg0IsInt && arg1Type.GetType() == mysql.TypeYear && !arg0.Value.IsNull() { if MaybeOverOptimized4PlanCache(ctx, []Expression{arg0}) { ctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: '%v' may be converted to INT", arg0.String())) + RemoveMutableConst(ctx, args) } adjusted, failed := types.AdjustYear(arg0.Value.GetInt64(), false) @@ -1637,6 +1640,7 @@ func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Express if arg1IsCon && arg1IsInt && arg0Type.GetType() == mysql.TypeYear && !arg1.Value.IsNull() { if MaybeOverOptimized4PlanCache(ctx, []Expression{arg0}) { ctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: '%v' may be converted to INT", arg0.String())) + RemoveMutableConst(ctx, args) } adjusted, failed := types.AdjustYear(arg1.Value.GetInt64(), false) diff --git a/planner/core/expression_rewriter.go b/planner/core/expression_rewriter.go index fcc81790cf074..051a25e0db581 100644 --- a/planner/core/expression_rewriter.go +++ b/planner/core/expression_rewriter.go @@ -1554,7 +1554,7 @@ func (er *expressionRewriter) inToExpression(lLen int, not bool, tp *types.Field continue // no need to refine it } 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}) + expression.RemoveMutableConst(er.sctx, args) } args[i], isExceptional = expression.RefineComparedConstant(er.sctx, *leftFt, c, opcode.EQ) if isExceptional { From 7df14727252b3b731a15caba5df81a3c8e2712c3 Mon Sep 17 00:00:00 2001 From: qw4990 Date: Sat, 28 Jan 2023 11:13:57 +0800 Subject: [PATCH 3/4] fixup --- expression/builtin_compare.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/expression/builtin_compare.go b/expression/builtin_compare.go index 31c767b5b3571..9e94cdeec184e 100644 --- a/expression/builtin_compare.go +++ b/expression/builtin_compare.go @@ -1626,7 +1626,7 @@ func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Express // int constant [cmp] year type if arg0IsCon && arg0IsInt && arg1Type.GetType() == mysql.TypeYear && !arg0.Value.IsNull() { if MaybeOverOptimized4PlanCache(ctx, []Expression{arg0}) { - ctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: '%v' may be converted to INT", arg0.String())) + ctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: '%v' may be converted to YEAR", arg0.String())) RemoveMutableConst(ctx, args) } @@ -1639,7 +1639,7 @@ func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Express // year type [cmp] int constant if arg1IsCon && arg1IsInt && arg0Type.GetType() == mysql.TypeYear && !arg1.Value.IsNull() { if MaybeOverOptimized4PlanCache(ctx, []Expression{arg0}) { - ctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: '%v' may be converted to INT", arg0.String())) + ctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: '%v' may be converted to YEAR", arg1.String())) RemoveMutableConst(ctx, args) } From 20460d2758616c3bd0c66ee094189671636057a4 Mon Sep 17 00:00:00 2001 From: qw4990 Date: Sat, 28 Jan 2023 11:15:23 +0800 Subject: [PATCH 4/4] fixup --- expression/builtin_compare.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expression/builtin_compare.go b/expression/builtin_compare.go index 9e94cdeec184e..bcb27a1233da7 100644 --- a/expression/builtin_compare.go +++ b/expression/builtin_compare.go @@ -1638,7 +1638,7 @@ func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Express } // year type [cmp] int constant if arg1IsCon && arg1IsInt && arg0Type.GetType() == mysql.TypeYear && !arg1.Value.IsNull() { - if MaybeOverOptimized4PlanCache(ctx, []Expression{arg0}) { + if MaybeOverOptimized4PlanCache(ctx, []Expression{arg1}) { ctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: '%v' may be converted to YEAR", arg1.String())) RemoveMutableConst(ctx, args) }