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: add new scalar function IsTruthWithNull (#19621) #19903

Merged
merged 5 commits into from
Sep 21, 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
2 changes: 1 addition & 1 deletion executor/reload_expr_pushdown_blacklist.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ var funcName2Alias = map[string]string{
"case": ast.Case,
"regexp": ast.Regexp,
"is null": ast.IsNull,
"is true": ast.IsTruth,
"is true": ast.IsTruthWithoutNull,
"is false": ast.IsFalsity,
"values": ast.Values,
"bit_count": ast.BitCount,
Expand Down
73 changes: 37 additions & 36 deletions expression/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -764,41 +764,42 @@ var funcs = map[string]functionClass{
ast.GetLock: &lockFunctionClass{baseFunctionClass{ast.GetLock, 2, 2}},
ast.ReleaseLock: &releaseLockFunctionClass{baseFunctionClass{ast.ReleaseLock, 1, 1}},

ast.LogicAnd: &logicAndFunctionClass{baseFunctionClass{ast.LogicAnd, 2, 2}},
ast.LogicOr: &logicOrFunctionClass{baseFunctionClass{ast.LogicOr, 2, 2}},
ast.LogicXor: &logicXorFunctionClass{baseFunctionClass{ast.LogicXor, 2, 2}},
ast.GE: &compareFunctionClass{baseFunctionClass{ast.GE, 2, 2}, opcode.GE},
ast.LE: &compareFunctionClass{baseFunctionClass{ast.LE, 2, 2}, opcode.LE},
ast.EQ: &compareFunctionClass{baseFunctionClass{ast.EQ, 2, 2}, opcode.EQ},
ast.NE: &compareFunctionClass{baseFunctionClass{ast.NE, 2, 2}, opcode.NE},
ast.LT: &compareFunctionClass{baseFunctionClass{ast.LT, 2, 2}, opcode.LT},
ast.GT: &compareFunctionClass{baseFunctionClass{ast.GT, 2, 2}, opcode.GT},
ast.NullEQ: &compareFunctionClass{baseFunctionClass{ast.NullEQ, 2, 2}, opcode.NullEQ},
ast.Plus: &arithmeticPlusFunctionClass{baseFunctionClass{ast.Plus, 2, 2}},
ast.Minus: &arithmeticMinusFunctionClass{baseFunctionClass{ast.Minus, 2, 2}},
ast.Mod: &arithmeticModFunctionClass{baseFunctionClass{ast.Mod, 2, 2}},
ast.Div: &arithmeticDivideFunctionClass{baseFunctionClass{ast.Div, 2, 2}},
ast.Mul: &arithmeticMultiplyFunctionClass{baseFunctionClass{ast.Mul, 2, 2}},
ast.IntDiv: &arithmeticIntDivideFunctionClass{baseFunctionClass{ast.IntDiv, 2, 2}},
ast.BitNeg: &bitNegFunctionClass{baseFunctionClass{ast.BitNeg, 1, 1}},
ast.And: &bitAndFunctionClass{baseFunctionClass{ast.And, 2, 2}},
ast.LeftShift: &leftShiftFunctionClass{baseFunctionClass{ast.LeftShift, 2, 2}},
ast.RightShift: &rightShiftFunctionClass{baseFunctionClass{ast.RightShift, 2, 2}},
ast.UnaryNot: &unaryNotFunctionClass{baseFunctionClass{ast.UnaryNot, 1, 1}},
ast.Or: &bitOrFunctionClass{baseFunctionClass{ast.Or, 2, 2}},
ast.Xor: &bitXorFunctionClass{baseFunctionClass{ast.Xor, 2, 2}},
ast.UnaryMinus: &unaryMinusFunctionClass{baseFunctionClass{ast.UnaryMinus, 1, 1}},
ast.In: &inFunctionClass{baseFunctionClass{ast.In, 2, -1}},
ast.IsTruth: &isTrueOrFalseFunctionClass{baseFunctionClass{ast.IsTruth, 1, 1}, opcode.IsTruth, false},
ast.IsFalsity: &isTrueOrFalseFunctionClass{baseFunctionClass{ast.IsFalsity, 1, 1}, opcode.IsFalsity, false},
ast.Like: &likeFunctionClass{baseFunctionClass{ast.Like, 3, 3}},
ast.Regexp: &regexpFunctionClass{baseFunctionClass{ast.Regexp, 2, 2}},
ast.Case: &caseWhenFunctionClass{baseFunctionClass{ast.Case, 1, -1}},
ast.RowFunc: &rowFunctionClass{baseFunctionClass{ast.RowFunc, 2, -1}},
ast.SetVar: &setVarFunctionClass{baseFunctionClass{ast.SetVar, 2, 2}},
ast.GetVar: &getVarFunctionClass{baseFunctionClass{ast.GetVar, 1, 1}},
ast.BitCount: &bitCountFunctionClass{baseFunctionClass{ast.BitCount, 1, 1}},
ast.GetParam: &getParamFunctionClass{baseFunctionClass{ast.GetParam, 1, 1}},
ast.LogicAnd: &logicAndFunctionClass{baseFunctionClass{ast.LogicAnd, 2, 2}},
ast.LogicOr: &logicOrFunctionClass{baseFunctionClass{ast.LogicOr, 2, 2}},
ast.LogicXor: &logicXorFunctionClass{baseFunctionClass{ast.LogicXor, 2, 2}},
ast.GE: &compareFunctionClass{baseFunctionClass{ast.GE, 2, 2}, opcode.GE},
ast.LE: &compareFunctionClass{baseFunctionClass{ast.LE, 2, 2}, opcode.LE},
ast.EQ: &compareFunctionClass{baseFunctionClass{ast.EQ, 2, 2}, opcode.EQ},
ast.NE: &compareFunctionClass{baseFunctionClass{ast.NE, 2, 2}, opcode.NE},
ast.LT: &compareFunctionClass{baseFunctionClass{ast.LT, 2, 2}, opcode.LT},
ast.GT: &compareFunctionClass{baseFunctionClass{ast.GT, 2, 2}, opcode.GT},
ast.NullEQ: &compareFunctionClass{baseFunctionClass{ast.NullEQ, 2, 2}, opcode.NullEQ},
ast.Plus: &arithmeticPlusFunctionClass{baseFunctionClass{ast.Plus, 2, 2}},
ast.Minus: &arithmeticMinusFunctionClass{baseFunctionClass{ast.Minus, 2, 2}},
ast.Mod: &arithmeticModFunctionClass{baseFunctionClass{ast.Mod, 2, 2}},
ast.Div: &arithmeticDivideFunctionClass{baseFunctionClass{ast.Div, 2, 2}},
ast.Mul: &arithmeticMultiplyFunctionClass{baseFunctionClass{ast.Mul, 2, 2}},
ast.IntDiv: &arithmeticIntDivideFunctionClass{baseFunctionClass{ast.IntDiv, 2, 2}},
ast.BitNeg: &bitNegFunctionClass{baseFunctionClass{ast.BitNeg, 1, 1}},
ast.And: &bitAndFunctionClass{baseFunctionClass{ast.And, 2, 2}},
ast.LeftShift: &leftShiftFunctionClass{baseFunctionClass{ast.LeftShift, 2, 2}},
ast.RightShift: &rightShiftFunctionClass{baseFunctionClass{ast.RightShift, 2, 2}},
ast.UnaryNot: &unaryNotFunctionClass{baseFunctionClass{ast.UnaryNot, 1, 1}},
ast.Or: &bitOrFunctionClass{baseFunctionClass{ast.Or, 2, 2}},
ast.Xor: &bitXorFunctionClass{baseFunctionClass{ast.Xor, 2, 2}},
ast.UnaryMinus: &unaryMinusFunctionClass{baseFunctionClass{ast.UnaryMinus, 1, 1}},
ast.In: &inFunctionClass{baseFunctionClass{ast.In, 2, -1}},
ast.IsTruthWithoutNull: &isTrueOrFalseFunctionClass{baseFunctionClass{ast.IsTruthWithoutNull, 1, 1}, opcode.IsTruth, false},
ast.IsTruthWithNull: &isTrueOrFalseFunctionClass{baseFunctionClass{ast.IsTruthWithNull, 1, 1}, opcode.IsTruth, true},
ast.IsFalsity: &isTrueOrFalseFunctionClass{baseFunctionClass{ast.IsFalsity, 1, 1}, opcode.IsFalsity, false},
ast.Like: &likeFunctionClass{baseFunctionClass{ast.Like, 3, 3}},
ast.Regexp: &regexpFunctionClass{baseFunctionClass{ast.Regexp, 2, 2}},
ast.Case: &caseWhenFunctionClass{baseFunctionClass{ast.Case, 1, -1}},
ast.RowFunc: &rowFunctionClass{baseFunctionClass{ast.RowFunc, 2, -1}},
ast.SetVar: &setVarFunctionClass{baseFunctionClass{ast.SetVar, 2, 2}},
ast.GetVar: &getVarFunctionClass{baseFunctionClass{ast.GetVar, 1, 1}},
ast.BitCount: &bitCountFunctionClass{baseFunctionClass{ast.BitCount, 1, 1}},
ast.GetParam: &getParamFunctionClass{baseFunctionClass{ast.GetParam, 1, 1}},

// encryption and compression functions
ast.AesDecrypt: &aesDecryptFunctionClass{baseFunctionClass{ast.AesDecrypt, 2, 3}},
Expand Down Expand Up @@ -869,7 +870,7 @@ func IsFunctionSupported(name string) bool {
// GetBuiltinList returns a list of builtin functions
func GetBuiltinList() []string {
res := make([]string, 0, len(funcs))
notImplementedFunctions := []string{ast.RowFunc}
notImplementedFunctions := []string{ast.RowFunc, ast.IsTruthWithNull}
for funcName := range funcs {
skipFunc := false
// Skip not implemented functions
Expand Down
2 changes: 1 addition & 1 deletion expression/builtin_op_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ func (s *testEvaluatorSuite) TestIsTrueOrFalse(c *C) {
}

for _, tc := range testCases {
isTrueSig, err := funcs[ast.IsTruth].getFunction(s.ctx, s.datumsToConstants(types.MakeDatums(tc.args...)))
isTrueSig, err := funcs[ast.IsTruthWithoutNull].getFunction(s.ctx, s.datumsToConstants(types.MakeDatums(tc.args...)))
c.Assert(err, IsNil)
c.Assert(isTrueSig, NotNil)

Expand Down
2 changes: 1 addition & 1 deletion expression/builtin_op_vec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
)

var vecBuiltinOpCases = map[string][]vecExprBenchCase{
ast.IsTruth: {
ast.IsTruthWithoutNull: {
{retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETReal}},
{retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETDecimal}},
{retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETInt}},
Expand Down
15 changes: 12 additions & 3 deletions expression/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -878,7 +878,8 @@ func canFuncBePushed(sf *ScalarFunction, storeType kv.StoreType) bool {
ast.In,
ast.IsNull,
ast.Like,
ast.IsTruth,
ast.IsTruthWithoutNull,
ast.IsTruthWithNull,
ast.IsFalsity,

// arithmetical functions.
Expand Down Expand Up @@ -1197,15 +1198,23 @@ func wrapWithIsTrue(ctx sessionctx.Context, keepNull bool, arg Expression, wrapF
}
}
}
fc := &isTrueOrFalseFunctionClass{baseFunctionClass{ast.IsTruth, 1, 1}, opcode.IsTruth, keepNull}
var fc *isTrueOrFalseFunctionClass
if keepNull {
fc = &isTrueOrFalseFunctionClass{baseFunctionClass{ast.IsTruthWithNull, 1, 1}, opcode.IsTruth, keepNull}
} else {
fc = &isTrueOrFalseFunctionClass{baseFunctionClass{ast.IsTruthWithoutNull, 1, 1}, opcode.IsTruth, keepNull}
}
f, err := fc.getFunction(ctx, []Expression{arg})
if err != nil {
return nil, err
}
sf := &ScalarFunction{
FuncName: model.NewCIStr(ast.IsTruth),
FuncName: model.NewCIStr(ast.IsTruthWithoutNull),
Function: f,
RetType: f.getRetTp(),
}
if keepNull {
sf.FuncName = model.NewCIStr(ast.IsTruthWithNull)
}
return FoldConstant(sf), nil
}
23 changes: 23 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7048,3 +7048,26 @@ func (s *testIntegrationSuite) TestIssue19596(c *C) {
tk.MustExec("drop table if exists t;")
tk.MustGetErrMsg("create table t (a int) partition by range(a) (PARTITION p0 VALUES LESS THAN (a));", "[expression:1054]Unknown column 'a' in 'expression'")
}

func (s *testIntegrationSuite) TestIssue17476(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test")
tk.MustExec("DROP TABLE IF EXISTS `table_float`;")
tk.MustExec("DROP TABLE IF EXISTS `table_int_float_varchar`;")
tk.MustExec("CREATE TABLE `table_float` (`id_1` int(16) NOT NULL AUTO_INCREMENT,`col_float_1` float DEFAULT NULL,PRIMARY KEY (`id_1`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin AUTO_INCREMENT=97635;")
tk.MustExec("CREATE TABLE `table_int_float_varchar` " +
"(`id_6` int(16) NOT NULL AUTO_INCREMENT," +
"`col_int_6` int(16) DEFAULT NULL,`col_float_6` float DEFAULT NULL," +
"`col_varchar_6` varchar(511) DEFAULT NULL,PRIMARY KEY (`id_6`)," +
"KEY `vhyen` (`id_6`,`col_int_6`,`col_float_6`,`col_varchar_6`(1))," +
"KEY `zzylq` (`id_6`,`col_int_6`,`col_float_6`,`col_varchar_6`(1))) " +
"ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin AUTO_INCREMENT=90818;")

tk.MustExec("INSERT INTO `table_float` VALUES (1,NULL),(2,0.1),(3,0),(4,-0.1),(5,-0.1),(6,NULL),(7,0.5),(8,0),(9,0),(10,NULL),(11,1),(12,1.5),(13,NULL),(14,NULL);")
tk.MustExec("INSERT INTO `table_int_float_varchar` VALUES (1,0,0.1,'true'),(2,-1,1.5,'2020-02-02 02:02:00'),(3,NULL,1.5,NULL),(4,65535,0.1,'true'),(5,NULL,0.1,'1'),(6,-1,1.5,'2020-02-02 02:02:00'),(7,-1,NULL,''),(8,NULL,-0.1,NULL),(9,NULL,-0.1,'1'),(10,-1,NULL,''),(11,NULL,1.5,'false'),(12,-1,0,NULL),(13,0,-0.1,NULL),(14,-1,NULL,'-0'),(15,65535,-1,'1'),(16,NULL,0.5,NULL),(17,-1,NULL,NULL);")
tk.MustQuery(`select count(*) from table_float
JOIN table_int_float_varchar AS tmp3 ON (tmp3.col_varchar_6 AND NULL)
IS NULL WHERE col_int_6=0;`).Check(testkit.Rows("14"))
tk.MustQuery(`SELECT count(*) FROM (table_float JOIN table_int_float_varchar AS tmp3 ON (tmp3.col_varchar_6 AND NULL) IS NULL);`).Check(testkit.Rows("154"))
tk.MustQuery(`SELECT * FROM (table_int_float_varchar AS tmp3) WHERE (col_varchar_6 AND NULL) IS NULL AND col_int_6=0;`).Check(testkit.Rows("13 0 -0.1 <nil>"))
}
2 changes: 1 addition & 1 deletion expression/simple_rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ func (sr *simpleRewriter) notToExpression(hasNot bool, op string, tp *types.Fiel

func (sr *simpleRewriter) isTrueToScalarFunc(v *ast.IsTruthExpr) {
arg := sr.pop()
op := ast.IsTruth
op := ast.IsTruthWithoutNull
if v.True == 0 {
op = ast.IsFalsity
}
Expand Down
30 changes: 15 additions & 15 deletions expression/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,21 +356,21 @@ func timeZone2Duration(tz string) time.Duration {
}

var logicalOps = map[string]struct{}{
ast.LT: {},
ast.GE: {},
ast.GT: {},
ast.LE: {},
ast.EQ: {},
ast.NE: {},
ast.UnaryNot: {},
ast.LogicAnd: {},
ast.LogicOr: {},
ast.LogicXor: {},
ast.In: {},
ast.IsNull: {},
ast.IsTruth: {},
ast.IsFalsity: {},
ast.Like: {},
ast.LT: {},
ast.GE: {},
ast.GT: {},
ast.LE: {},
ast.EQ: {},
ast.NE: {},
ast.UnaryNot: {},
ast.LogicAnd: {},
ast.LogicOr: {},
ast.LogicXor: {},
ast.In: {},
ast.IsNull: {},
ast.IsTruthWithoutNull: {},
ast.IsFalsity: {},
ast.Like: {},
}

var oppositeOp = map[string]string{
Expand Down
8 changes: 4 additions & 4 deletions expression/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,29 +302,29 @@ func (s *testUtilSuite) TestPushDownNot(c *check.C) {
notFunc = newFunction(ast.UnaryNot, col)
notFunc = newFunction(ast.UnaryNot, notFunc)
ret = PushDownNot(ctx, notFunc)
c.Assert(ret.Equal(ctx, newFunction(ast.IsTruth, col)), check.IsTrue)
c.Assert(ret.Equal(ctx, newFunction(ast.IsTruthWithNull, col)), check.IsTrue)

// (not not (a+1)) should be optimized to (a+1 is true)
plusFunc := newFunction(ast.Plus, col, NewOne())
notFunc = newFunction(ast.UnaryNot, plusFunc)
notFunc = newFunction(ast.UnaryNot, notFunc)
ret = PushDownNot(ctx, notFunc)
c.Assert(ret.Equal(ctx, newFunction(ast.IsTruth, plusFunc)), check.IsTrue)
c.Assert(ret.Equal(ctx, newFunction(ast.IsTruthWithNull, plusFunc)), check.IsTrue)

// (not not not a) should be optimized to (not (a is true))
notFunc = newFunction(ast.UnaryNot, col)
notFunc = newFunction(ast.UnaryNot, notFunc)
notFunc = newFunction(ast.UnaryNot, notFunc)
ret = PushDownNot(ctx, notFunc)
c.Assert(ret.Equal(ctx, newFunction(ast.UnaryNot, newFunction(ast.IsTruth, col))), check.IsTrue)
c.Assert(ret.Equal(ctx, newFunction(ast.UnaryNot, newFunction(ast.IsTruthWithNull, col))), check.IsTrue)

// (not not not not a) should be optimized to (a is true)
notFunc = newFunction(ast.UnaryNot, col)
notFunc = newFunction(ast.UnaryNot, notFunc)
notFunc = newFunction(ast.UnaryNot, notFunc)
notFunc = newFunction(ast.UnaryNot, notFunc)
ret = PushDownNot(ctx, notFunc)
c.Assert(ret.Equal(ctx, newFunction(ast.IsTruth, col)), check.IsTrue)
c.Assert(ret.Equal(ctx, newFunction(ast.IsTruthWithNull, col)), check.IsTrue)
}

func (s *testUtilSuite) TestFilter(c *check.C) {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ require (
github.com/pingcap/goleveldb v0.0.0-20191226122134-f82aafb29989
github.com/pingcap/kvproto v0.0.0-20200818080353-7aaed8998596
github.com/pingcap/log v0.0.0-20200828042413-fce0951f1463
github.com/pingcap/parser v0.0.0-20200911054040-258297116c4b
github.com/pingcap/parser v0.0.0-20200921023559-ba9921b82da3
github.com/pingcap/sysutil v0.0.0-20200715082929-4c47bcac246a
github.com/pingcap/tidb-tools v4.0.6-0.20200828085514-03575b185007+incompatible
github.com/pingcap/tipb v0.0.0-20200618092958-4fad48b4c8c3
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -461,8 +461,8 @@ github.com/pingcap/parser v0.0.0-20200603032439-c4ecb4508d2f/go.mod h1:9v0Edh8Ib
github.com/pingcap/parser v0.0.0-20200623164729-3a18f1e5dceb/go.mod h1:vQdbJqobJAgFyiRNNtXahpMoGWwPEuWciVEK5A20NS0=
github.com/pingcap/parser v0.0.0-20200803072748-fdf66528323d/go.mod h1:vQdbJqobJAgFyiRNNtXahpMoGWwPEuWciVEK5A20NS0=
github.com/pingcap/parser v0.0.0-20200901062802-475ea5e2e0a7/go.mod h1:vQdbJqobJAgFyiRNNtXahpMoGWwPEuWciVEK5A20NS0=
github.com/pingcap/parser v0.0.0-20200911054040-258297116c4b h1:olNvO8UWo7Y+t2oWwB46cDj5pyqosgiQts5t8tZlbSc=
github.com/pingcap/parser v0.0.0-20200911054040-258297116c4b/go.mod h1:vQdbJqobJAgFyiRNNtXahpMoGWwPEuWciVEK5A20NS0=
github.com/pingcap/parser v0.0.0-20200921023559-ba9921b82da3 h1:7yYLV5EH94FuQWewlpTqn+k8y03JW0mOEs3ugQsMVBg=
github.com/pingcap/parser v0.0.0-20200921023559-ba9921b82da3/go.mod h1:vQdbJqobJAgFyiRNNtXahpMoGWwPEuWciVEK5A20NS0=
github.com/pingcap/pd/v4 v4.0.0-rc.1.0.20200422143320-428acd53eba2/go.mod h1:s+utZtXDznOiL24VK0qGmtoHjjXNsscJx3m1n8cC56s=
github.com/pingcap/pd/v4 v4.0.0-rc.2.0.20200520083007-2c251bd8f181/go.mod h1:q4HTx/bA8aKBa4S7L+SQKHvjRPXCRV0tA0yRw0qkZSA=
github.com/pingcap/pd/v4 v4.0.5-0.20200817114353-e465cafe8a91 h1:zCOWP+kIzM6ZsXdu2QoM/W6+3vFZj04MYboMP2Obc0E=
Expand Down
2 changes: 1 addition & 1 deletion planner/core/expression_rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -1249,7 +1249,7 @@ func (er *expressionRewriter) positionToScalarFunc(v *ast.PositionExpr) {

func (er *expressionRewriter) isTrueToScalarFunc(v *ast.IsTruthExpr) {
stkLen := len(er.ctxStack)
op := ast.IsTruth
op := ast.IsTruthWithoutNull
if v.True == 0 {
op = ast.IsFalsity
}
Expand Down
2 changes: 1 addition & 1 deletion util/ranger/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func (c *conditionChecker) checkScalarFunction(scalar *expression.ScalarFunction
}
case ast.IsNull:
return c.checkColumn(scalar.GetArgs()[0])
case ast.IsTruth, ast.IsFalsity:
case ast.IsTruthWithoutNull, ast.IsTruthWithNull, ast.IsFalsity:
if s, ok := scalar.GetArgs()[0].(*expression.Column); ok {
if s.RetType.EvalType() == types.ETString {
return false
Expand Down
23 changes: 8 additions & 15 deletions util/ranger/points.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/util/chunk"
"github.com/pingcap/tidb/util/collate"
"github.com/pingcap/tipb/go-tipb"
)

// Error instances.
Expand Down Expand Up @@ -498,9 +497,10 @@ func (r *builder) newBuildFromPatternLike(expr *expression.ScalarFunction) []poi

func (r *builder) buildFromNot(expr *expression.ScalarFunction) []point {
switch n := expr.FuncName.L; n {
case ast.IsTruth:
keepNull := r.isTrueKeepNull(expr)
return r.buildFromIsTrue(expr, 1, keepNull)
case ast.IsTruthWithoutNull:
return r.buildFromIsTrue(expr, 1, false)
case ast.IsTruthWithNull:
return r.buildFromIsTrue(expr, 1, true)
case ast.IsFalsity:
return r.buildFromIsFalse(expr, 1)
case ast.In:
Expand Down Expand Up @@ -555,9 +555,10 @@ func (r *builder) buildFromScalarFunc(expr *expression.ScalarFunction) []point {
return r.intersection(r.build(expr.GetArgs()[0]), r.build(expr.GetArgs()[1]))
case ast.LogicOr:
return r.union(r.build(expr.GetArgs()[0]), r.build(expr.GetArgs()[1]))
case ast.IsTruth:
keepNull := r.isTrueKeepNull(expr)
return r.buildFromIsTrue(expr, 0, keepNull)
case ast.IsTruthWithoutNull:
return r.buildFromIsTrue(expr, 0, false)
case ast.IsTruthWithNull:
return r.buildFromIsTrue(expr, 0, true)
case ast.IsFalsity:
return r.buildFromIsFalse(expr, 0)
case ast.In:
Expand Down Expand Up @@ -644,11 +645,3 @@ func (r *builder) merge(a, b []point, union bool) []point {
}
return mergedPoints[:curTail]
}

func (r *builder) isTrueKeepNull(expr *expression.ScalarFunction) bool {
switch expr.Function.PbCode() {
case tipb.ScalarFuncSig_DecimalIsTrueWithNull, tipb.ScalarFuncSig_RealIsTrueWithNull, tipb.ScalarFuncSig_IntIsTrueWithNull:
return true
}
return false
}