Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expression: disable int_col <cmp> non-int const folding for plan cache (#14120) #16184

Merged
merged 5 commits into from
Apr 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions expression/builtin_compare.go
Original file line number Diff line number Diff line change
Expand Up @@ -1090,8 +1090,9 @@ func tryToConvertConstantInt(ctx sessionctx.Context, targetFieldType *types.Fiel
if err != nil {
if terror.ErrorEqual(err, types.ErrOverflow) {
return &Constant{
Value: dt,
RetType: targetFieldType,
Value: dt,
RetType: targetFieldType,
DeferredExpr: con.DeferredExpr,
}, true
}
return con, false
Expand Down Expand Up @@ -1125,8 +1126,9 @@ func RefineComparedConstant(ctx sessionctx.Context, targetFieldType types.FieldT
if err != nil {
if terror.ErrorEqual(err, types.ErrOverflow) {
return &Constant{
Value: intDatum,
RetType: &targetFieldType,
Value: intDatum,
RetType: &targetFieldType,
DeferredExpr: con.DeferredExpr,
}, true
}
return con, false
Expand Down Expand Up @@ -1190,6 +1192,9 @@ func RefineComparedConstant(ctx sessionctx.Context, targetFieldType types.FieldT
// refineArgs will rewrite the arguments if the compare expression is `int column <cmp> non-int constant` or
// `non-int constant <cmp> int column`. E.g., `a < 1.1` will be rewritten to `a < 2`.
func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Expression) []Expression {
if ctx.GetSessionVars().StmtCtx.UseCache && ContainLazyConst(args) {
return args
}
arg0Type, arg1Type := args[0].GetType(), args[1].GetType()
arg0IsInt := arg0Type.EvalType() == types.ETInt
arg1IsInt := arg1Type.EvalType() == types.ETInt
Expand Down Expand Up @@ -1228,24 +1233,23 @@ func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Express
}
}
}

if isExceptional && (c.op == opcode.EQ || c.op == opcode.NullEQ) {
// This will always be false.
return []Expression{Zero.Clone(), One.Clone()}
return []Expression{Zero, One}
}
if isPositiveInfinite {
// If the op is opcode.LT, opcode.LE
// This will always be true.
// If the op is opcode.GT, opcode.GE
// This will always be false.
return []Expression{Zero.Clone(), One.Clone()}
return []Expression{Zero, One}
}
if isNegativeInfinite {
// If the op is opcode.GT, opcode.GE
// This will always be true.
// If the op is opcode.LT, opcode.LE
// This will always be false.
return []Expression{One.Clone(), Zero.Clone()}
return []Expression{One, Zero}
}

return []Expression{finalArg0, finalArg1}
Expand Down
36 changes: 36 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"bytes"
"context"
"fmt"
"math"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -4918,3 +4919,38 @@ func (s *testIntegrationSuite) TestValuesForBinaryLiteral(c *C) {
tk.MustQuery("select a=0 from testValuesBinary;").Check(testkit.Rows("1"))
tk.MustExec("drop table testValuesBinary;")
}

func (s *testIntegrationSuite) TestCacheRefineArgs(c *C) {
tk := testkit.NewTestKit(c, s.store)
orgEnable := plannercore.PreparedPlanCacheEnabled()
orgCapacity := plannercore.PreparedPlanCacheCapacity
orgMemGuardRatio := plannercore.PreparedPlanCacheMemoryGuardRatio
orgMaxMemory := plannercore.PreparedPlanCacheMaxMemory
defer func() {
plannercore.SetPreparedPlanCache(orgEnable)
plannercore.PreparedPlanCacheCapacity = orgCapacity
plannercore.PreparedPlanCacheMemoryGuardRatio = orgMemGuardRatio
plannercore.PreparedPlanCacheMaxMemory = orgMaxMemory
}()
plannercore.SetPreparedPlanCache(true)
plannercore.PreparedPlanCacheCapacity = 100
plannercore.PreparedPlanCacheMemoryGuardRatio = 0.1
// PreparedPlanCacheMaxMemory is set to MAX_UINT64 to make sure the cache
// behavior would not be effected by the uncertain memory utilization.
plannercore.PreparedPlanCacheMaxMemory.Store(math.MaxUint64)
tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec("create table t(col_int int)")
tk.MustExec("insert into t values(null)")
tk.MustExec("prepare stmt from 'SELECT ((col_int is true) = ?) AS res FROM t'")
tk.MustExec("set @p0='0.8'")
tk.MustQuery("execute stmt using @p0").Check(testkit.Rows("0"))
tk.MustExec("set @p0='0'")
tk.MustQuery("execute stmt using @p0").Check(testkit.Rows("1"))

tk.MustExec("delete from t")
tk.MustExec("insert into t values(1)")
tk.MustExec("prepare stmt from 'SELECT col_int < ? FROM t'")
tk.MustExec("set @p0='-184467440737095516167.1'")
tk.MustQuery("execute stmt using @p0").Check(testkit.Rows("0"))
}
17 changes: 17 additions & 0 deletions expression/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -703,3 +703,20 @@ func GetUint64FromConstant(expr Expression) (uint64, bool, bool) {
}
return 0, false, false
}

// ContainLazyConst checks if the expressions contain a lazy constant.
func ContainLazyConst(exprs []Expression) bool {
for _, expr := range exprs {
switch v := expr.(type) {
case *Constant:
if v.DeferredExpr != nil {
return true
}
case *ScalarFunction:
if ContainLazyConst(v.GetArgs()) {
return true
}
}
}
return false
}