Skip to content

Commit 4889374

Browse files
authored
types: fix issue that we can insert negative value to unsinged float column sometimes (#47946) (#47983)
close #47945
1 parent 934a298 commit 4889374

File tree

4 files changed

+24
-7
lines changed

4 files changed

+24
-7
lines changed

pkg/executor/insert_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,3 +1593,16 @@ func TestInsertLockUnchangedKeys(t *testing.T) {
15931593
}
15941594
}
15951595
}
1596+
1597+
// see issue: https://github.com/pingcap/tidb/issues/47945
1598+
func TestUnsignedDecimalFloatInsertNegative(t *testing.T) {
1599+
store := testkit.CreateMockStore(t)
1600+
tk := testkit.NewTestKit(t, store)
1601+
tk.MustExec(`use test`)
1602+
tk.MustExec("create table tf(a float(1, 0) unsigned)")
1603+
err := tk.ExecToErr("insert into tf values('-100')")
1604+
require.EqualError(t, err, "[types:1264]Out of range value for column 'a' at row 1")
1605+
tk.MustExec("set @@sql_mode=''")
1606+
tk.MustExec("insert into tf values('-100')")
1607+
tk.MustQuery("select * from tf").Check(testkit.Rows("0"))
1608+
}

pkg/expression/builtin_cast.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1419,7 +1419,7 @@ func (b *builtinCastStringAsRealSig) evalReal(row chunk.Row) (res float64, isNul
14191419
if b.inUnion && mysql.HasUnsignedFlag(b.tp.GetFlag()) && res < 0 {
14201420
res = 0
14211421
}
1422-
res, err = types.ProduceFloatWithSpecifiedTp(res, b.tp, sc)
1422+
res, err = types.ProduceFloatWithSpecifiedTp(res, b.tp)
14231423
return res, false, err
14241424
}
14251425

pkg/expression/builtin_cast_vec.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1692,7 +1692,7 @@ func (b *builtinCastStringAsRealSig) vecEvalReal(input *chunk.Chunk, result *chu
16921692
if b.inUnion && mysql.HasUnsignedFlag(b.tp.GetFlag()) && res < 0 {
16931693
res = 0
16941694
}
1695-
res, err = types.ProduceFloatWithSpecifiedTp(res, b.tp, sc)
1695+
res, err = types.ProduceFloatWithSpecifiedTp(res, b.tp)
16961696
if err != nil {
16971697
return err
16981698
}

pkg/types/datum.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -980,7 +980,7 @@ func (d *Datum) convertToFloat(sc *stmtctx.StatementContext, target *FieldType)
980980
default:
981981
return invalidConv(d, target.GetType())
982982
}
983-
f, err1 := ProduceFloatWithSpecifiedTp(f, target, sc)
983+
f, err1 := ProduceFloatWithSpecifiedTp(f, target)
984984
if err == nil && err1 != nil {
985985
err = err1
986986
}
@@ -993,7 +993,7 @@ func (d *Datum) convertToFloat(sc *stmtctx.StatementContext, target *FieldType)
993993
}
994994

995995
// ProduceFloatWithSpecifiedTp produces a new float64 according to `flen` and `decimal`.
996-
func ProduceFloatWithSpecifiedTp(f float64, target *FieldType, sc *stmtctx.StatementContext) (_ float64, err error) {
996+
func ProduceFloatWithSpecifiedTp(f float64, target *FieldType) (_ float64, err error) {
997997
if math.IsNaN(f) {
998998
return 0, overflow(f, target.GetType())
999999
}
@@ -1004,13 +1004,17 @@ func ProduceFloatWithSpecifiedTp(f float64, target *FieldType, sc *stmtctx.State
10041004
// If no D is set, we will handle it like origin float whether M is set or not.
10051005
if target.GetFlen() != UnspecifiedLength && target.GetDecimal() != UnspecifiedLength {
10061006
f, err = TruncateFloat(f, target.GetFlen(), target.GetDecimal())
1007-
if err = sc.HandleOverflow(err, err); err != nil {
1008-
return f, errors.Trace(err)
1009-
}
10101007
}
10111008
if mysql.HasUnsignedFlag(target.GetFlag()) && f < 0 {
10121009
return 0, overflow(f, target.GetType())
10131010
}
1011+
1012+
if err != nil {
1013+
// We must return the error got from TruncateFloat after checking whether the target is unsigned to make sure
1014+
// the returned float is not negative when the target type is unsigned.
1015+
return f, errors.Trace(err)
1016+
}
1017+
10141018
if target.GetType() == mysql.TypeFloat && (f > math.MaxFloat32 || f < -math.MaxFloat32) {
10151019
if f > 0 {
10161020
return math.MaxFloat32, overflow(f, target.GetType())

0 commit comments

Comments
 (0)