Skip to content

Commit

Permalink
expression: fix the corner case of CAST int as unsigned real/decimal (p…
Browse files Browse the repository at this point in the history
  • Loading branch information
Deardrops authored and XiaTianliang committed Dec 21, 2019
1 parent e412e6b commit cf19bc0
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 5 deletions.
17 changes: 13 additions & 4 deletions expression/builtin_cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,9 +461,13 @@ func (b *builtinCastIntAsRealSig) evalReal(row chunk.Row) (res float64, isNull b
if isNull || err != nil {
return res, isNull, err
}
if !mysql.HasUnsignedFlag(b.tp.Flag) && !mysql.HasUnsignedFlag(b.args[0].GetType().Flag) {
if unsignedArgs0 := mysql.HasUnsignedFlag(b.args[0].GetType().Flag); !mysql.HasUnsignedFlag(b.tp.Flag) && !unsignedArgs0 {
res = float64(val)
} else if b.inUnion && val < 0 {
} else if b.inUnion && !unsignedArgs0 && val < 0 {
// Round up to 0 if the value is negative but the expression eval type is unsigned in `UNION` statement
// NOTE: the following expressions are equal (so choose the more efficient one):
// `b.inUnion && mysql.HasUnsignedFlag(b.tp.Flag) && !unsignedArgs0 && val < 0`
// `b.inUnion && !unsignedArgs0 && val < 0`
res = 0
} else {
// recall that, int to float is different from uint to float
Expand All @@ -487,9 +491,14 @@ func (b *builtinCastIntAsDecimalSig) evalDecimal(row chunk.Row) (res *types.MyDe
if isNull || err != nil {
return res, isNull, err
}
if !mysql.HasUnsignedFlag(b.tp.Flag) && !mysql.HasUnsignedFlag(b.args[0].GetType().Flag) {

if unsignedArgs0 := mysql.HasUnsignedFlag(b.args[0].GetType().Flag); !mysql.HasUnsignedFlag(b.tp.Flag) && !unsignedArgs0 {
res = types.NewDecFromInt(val)
} else if b.inUnion && val < 0 {
// Round up to 0 if the value is negative but the expression eval type is unsigned in `UNION` statement
// NOTE: the following expressions are equal (so choose the more efficient one):
// `b.inUnion && mysql.HasUnsignedFlag(b.tp.Flag) && !unsignedArgs0 && val < 0`
// `b.inUnion && !unsignedArgs0 && val < 0`
} else if b.inUnion && !unsignedArgs0 && val < 0 {
res = &types.MyDecimal{}
} else {
res = types.NewDecFromUint(uint64(val))
Expand Down
6 changes: 5 additions & 1 deletion expression/builtin_cast_vec.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,11 @@ func (b *builtinCastIntAsRealSig) vecEvalReal(input *chunk.Chunk, result *chunk.
}
if !hasUnsignedFlag0 && !hasUnsignedFlag1 {
rs[i] = float64(i64s[i])
} else if b.inUnion && i64s[i] < 0 {
} else if b.inUnion && !hasUnsignedFlag1 && i64s[i] < 0 {
// Round up to 0 if the value is negative but the expression eval type is unsigned in `UNION` statement
// NOTE: the following expressions are equal (so choose the more efficient one):
// `b.inUnion && hasUnsignedFlag0 && !hasUnsignedFlag1 && i64s[i] < 0`
// `b.inUnion && !hasUnsignedFlag1 && i64s[i] < 0`
rs[i] = 0
} else {
// recall that, int to float is different from uint to float
Expand Down
16 changes: 16 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2308,6 +2308,22 @@ func (s *testIntegrationSuite2) TestBuiltin(c *C) {
result.Check(testkit.Rows("9223372036854775808 9223372036854775808", "9223372036854775808 9223372036854775808"))
tk.MustExec(`drop table tb5;`)

// test builtinCastIntAsDecimalSig
tk.MustExec(`drop table if exists tb5`)
tk.MustExec(`create table tb5 (a decimal(65), b bigint(64) unsigned);`)
tk.MustExec(`insert into tb5 (a, b) values (9223372036854775808, 9223372036854775808);`)
result = tk.MustQuery(`select cast(b as decimal(64)) from tb5 union all select b from tb5;`)
result.Check(testkit.Rows("9223372036854775808", "9223372036854775808"))
tk.MustExec(`drop table tb5`)

// test builtinCastIntAsRealSig
tk.MustExec(`drop table if exists tb5`)
tk.MustExec(`create table tb5 (a bigint(64) unsigned, b double(64, 10));`)
tk.MustExec(`insert into tb5 (a, b) values (9223372036854775808, 9223372036854775808);`)
result = tk.MustQuery(`select a from tb5 where a = b union all select b from tb5;`)
result.Check(testkit.Rows("9223372036854776000", "9223372036854776000"))
tk.MustExec(`drop table tb5`)

// Test corner cases of cast string as datetime
result = tk.MustQuery(`select cast("170102034" as datetime);`)
result.Check(testkit.Rows("2017-01-02 03:04:00"))
Expand Down

0 comments on commit cf19bc0

Please sign in to comment.