From cd1e02965e43a386758c44eff5a466c6c67151d8 Mon Sep 17 00:00:00 2001
From: Ti Chi Robot <ti-community-prow-bot@tidb.io>
Date: Tue, 28 May 2024 17:16:23 +0800
Subject: [PATCH] expression: fix wrong result when convert float to unsigned
 (#53590) (#53612)

close pingcap/tidb#41736
---
 expression/builtin_compare.go                 |  7 +++++
 sessionctx/stmtctx/stmtctx.go                 |  3 +-
 .../integrationtest/r/expression/cast.result  | 30 +++++++++++++++++++
 tests/integrationtest/t/expression/cast.test  | 13 ++++++++
 4 files changed, 52 insertions(+), 1 deletion(-)
 create mode 100644 tests/integrationtest/r/expression/cast.result
 create mode 100644 tests/integrationtest/t/expression/cast.test

diff --git a/expression/builtin_compare.go b/expression/builtin_compare.go
index e699bd2d06db1..ded05100747e2 100644
--- a/expression/builtin_compare.go
+++ b/expression/builtin_compare.go
@@ -1481,6 +1481,13 @@ func RefineComparedConstant(ctx sessionctx.Context, targetFieldType types.FieldT
 		targetFieldType = *types.NewFieldType(mysql.TypeLonglong)
 	}
 	var intDatum types.Datum
+
+	// To make sure return zero when underflow happens.
+	oriFlag := sc.IsRefineComparedConstant
+	sc.IsRefineComparedConstant = true
+	defer func() {
+		sc.IsRefineComparedConstant = oriFlag
+	}()
 	intDatum, err = dt.ConvertTo(sc, &targetFieldType)
 	if err != nil {
 		if terror.ErrorEqual(err, types.ErrOverflow) {
diff --git a/sessionctx/stmtctx/stmtctx.go b/sessionctx/stmtctx/stmtctx.go
index fc6c86fc11e3a..8e4b8813c9372 100644
--- a/sessionctx/stmtctx/stmtctx.go
+++ b/sessionctx/stmtctx/stmtctx.go
@@ -151,6 +151,7 @@ type StatementContext struct {
 	// IsDDLJobInQueue is used to mark whether the DDL job is put into the queue.
 	// If IsDDLJobInQueue is true, it means the DDL job is in the queue of storage, and it can be handled by the DDL worker.
 	IsDDLJobInQueue               bool
+	IsRefineComparedConstant      bool
 	DDLJobID                      int64
 	InInsertStmt                  bool
 	InUpdateStmt                  bool
@@ -1097,7 +1098,7 @@ func (sc *StatementContext) GetExecDetails() execdetails.ExecDetails {
 // This is the case for `insert`, `update`, `alter table`, `create table` and `load data infile` statements, when not in strict SQL mode.
 // see https://dev.mysql.com/doc/refman/5.7/en/out-of-range-and-overflow.html
 func (sc *StatementContext) ShouldClipToZero() bool {
-	return sc.InInsertStmt || sc.InLoadDataStmt || sc.InUpdateStmt || sc.InCreateOrAlterStmt || sc.IsDDLJobInQueue
+	return sc.InInsertStmt || sc.InLoadDataStmt || sc.InUpdateStmt || sc.InCreateOrAlterStmt || sc.IsDDLJobInQueue || sc.IsRefineComparedConstant
 }
 
 // ShouldIgnoreOverflowError indicates whether we should ignore the error when type conversion overflows,
diff --git a/tests/integrationtest/r/expression/cast.result b/tests/integrationtest/r/expression/cast.result
new file mode 100644
index 0000000000000..c7938cb727e72
--- /dev/null
+++ b/tests/integrationtest/r/expression/cast.result
@@ -0,0 +1,30 @@
+drop table if exists t0;
+create table t0(c0 tinyint(1) unsigned not null );
+insert into t0 values (1);
+select * from t0 where case 0 when t0.c0 > -1.194192591e9 then null else 1 end;
+c0
+1
+select t0.c0 > -1.194192591e9 from t0;
+t0.c0 > -1.194192591e9
+1
+select t0.c0 < -1.194192591e9 from t0;
+t0.c0 < -1.194192591e9
+0
+select -1.194192591e9 > t0.c0 from t0;
+-1.194192591e9 > t0.c0
+0
+select -1.194192591e9 < t0.c0 from t0;
+-1.194192591e9 < t0.c0
+1
+select t0.c0 > 1.194192591e9 from t0;
+t0.c0 > 1.194192591e9
+0
+select t0.c0 < 1.194192591e9 from t0;
+t0.c0 < 1.194192591e9
+1
+select 1.194192591e9 > t0.c0 from t0;
+1.194192591e9 > t0.c0
+1
+select 1.194192591e9 < t0.c0 from t0;
+1.194192591e9 < t0.c0
+0
diff --git a/tests/integrationtest/t/expression/cast.test b/tests/integrationtest/t/expression/cast.test
new file mode 100644
index 0000000000000..6876072d60365
--- /dev/null
+++ b/tests/integrationtest/t/expression/cast.test
@@ -0,0 +1,13 @@
+# TestNegFloatConvertToUnsigned
+drop table if exists t0;
+create table t0(c0 tinyint(1) unsigned not null );
+insert into t0 values (1);
+select * from t0 where case 0 when t0.c0 > -1.194192591e9 then null else 1 end;
+select t0.c0 > -1.194192591e9 from t0;
+select t0.c0 < -1.194192591e9 from t0;
+select -1.194192591e9 > t0.c0 from t0;
+select -1.194192591e9 < t0.c0 from t0;
+select t0.c0 > 1.194192591e9 from t0;
+select t0.c0 < 1.194192591e9 from t0;
+select 1.194192591e9 > t0.c0 from t0;
+select 1.194192591e9 < t0.c0 from t0;