Repository: pingcap/tidb (Go)

Issue:
Function NOT/IF returns incorrect result with decimal argument
## Bug Report

Please answer these questions before submitting your issue. Thanks!

1. What did you do?
If possible, provide a recipe for reproducing the error.

```mysql
select NOT 0.00000001000000000000, IF(0.00000001000000000000, 1, 0);
```

2. What did you expect to see?


```mysql
mysql> select NOT 0.00000001000000000000, IF(0.00000001000000000000, 1, 0);
+----------------------------+----------------------------------+
| NOT 0.00000001000000000000 | IF(0.00000001000000000000, 1, 0) |
+----------------------------+----------------------------------+
|                          0 |                                1 |
+----------------------------+----------------------------------+
1 row in set (0.00 sec)

```

3. What did you see instead?

```mysql
mysql> select NOT 0.00000001000000000000, IF(0.00000001000000000000, 1, 0);
+----------------------------+----------------------------------+
| NOT 0.00000001000000000000 | IF(0.00000001000000000000, 1, 0) |
+----------------------------+----------------------------------+
|                          1 |                                0 |
+----------------------------+----------------------------------+
1 row in set (0.00 sec)
```



4. What version of TiDB are you using (`tidb-server -V` or run `select tidb_version();` on TiDB)?

8c20289c7
wrong results when IF function along with float argument
## Bug Report

Please answer these questions before submitting your issue. Thanks!

1. What did you do?
If possible, provide a recipe for reproducing the error.
SELECT  IF(0.1, 1, 2) FROM t1;
2. What did you expect to see?
+---------------+
| IF(0.1, 1, 2) |
+---------------+
|             1 |
+---------------+
1 row in set (0.00 sec)


3. What did you see instead?
+---------------+
| IF(0.1, 1, 2) |
+---------------+
|             2 |
+---------------+
1 row in set (0.00 sec)

4. What version of TiDB are you using (`tidb-server -V` or run `select tidb_version();` on TiDB)?
Release Version: None
Git Commit Hash: None
Git Branch: None
UTC Build Time: None
GoVersion: None
Race Enabled: false
TiKV Min Version: 2.1.0-alpha.1-ff3dd160846b7d1aed9079c389fc188f7f5ea13e
Check Table Before Drop: false




Discussion:
Fixed by #12173 and #15016 

In tidb, almost all builtIn*Sig function use the result of `evalInt` to check true or false.
This is not ok when args is float64 which is less than 1, it will be convert to 0 by `evalInt`.
So we should replace `evalInt` with `evalReal`.(By the way,if the argis to small and is out of the float64 accuracy,such as 1e-1000, it should be converted to 0)

`evalInt` means this expression signature should return an `int` result. For this case, we should implement `evalInt`. But in order to get the correct result, we should calling `args[0].EvalReal()` instead of `args[0].EvalInt()`.
> `evalInt` means this expression signature should return an `int` result. For this case, we should implement `evalInt`. But in order to get the correct result, we should calling `args[0].EvalReal()` instead of `args[0].EvalInt()`.

Yes,I have fix the logic op https://github.com/pingcap/tidb/pull/11587,but many builtinfunc doesnt implement `evalReal`, so it may be difficult to handle.
`CASE` has a similar problem, I've created another issue https://github.com/pingcap/tidb/issues/15291



Patch:
diff --git a/expression/builtin_control.go b/expression/builtin_control.go
index 99f769d0adfc5..929236eec4ff3 100644
--- a/expression/builtin_control.go
+++ b/expression/builtin_control.go
@@ -475,6 +475,10 @@ func (c *ifFunctionClass) getFunction(ctx sessionctx.Context, args []Expression)
 	}
 	retTp := InferType4ControlFuncs(args[1].GetType(), args[2].GetType())
 	evalTps := retTp.EvalType()
+	args[0], err = wrapWithIsTrue(ctx, true, args[0])
+	if err != nil {
+		return nil, err
+	}
 	bf := newBaseBuiltinFuncWithTp(ctx, args, evalTps, types.ETInt, evalTps, evalTps)
 	retTp.Flag |= bf.tp.Flag
 	bf.tp = retTp


Test patch:
diff --git a/expression/builtin_control_test.go b/expression/builtin_control_test.go
index 5661e1992e5ec..5c4ee439e3177 100644
--- a/expression/builtin_control_test.go
+++ b/expression/builtin_control_test.go
@@ -78,6 +78,12 @@ func (s *testEvaluatorSuite) TestIf(c *C) {
 		{types.Duration{Duration: time.Duration(0)}, 1, 2, 2},
 		{types.NewDecFromStringForTest("1.2"), 1, 2, 1},
 		{jsonInt.GetMysqlJSON(), 1, 2, 1},
+		{0.1, 1, 2, 1},
+		{0.0, 1, 2, 2},
+		{types.NewDecFromStringForTest("0.1"), 1, 2, 1},
+		{types.NewDecFromStringForTest("0.0"), 1, 2, 2},
+		{"0.1", 1, 2, 1},
+		{"0.0", 1, 2, 2},
 	}
 
 	fc := funcs[ast.If]