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: fix the corner case of CAST int as unsigned real/decimal (#13637) #13756

Merged
merged 1 commit into from
Nov 27, 2019
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
17 changes: 13 additions & 4 deletions expression/builtin_cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,9 +462,13 @@ func (b *builtinCastIntAsRealSig) evalReal(row chunk.Row) (res float64, isNull b
if isNull || err != nil {
return res, isNull, errors.Trace(err)
}
if !mysql.HasUnsignedFlag(b.tp.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 @@ -488,9 +492,14 @@ func (b *builtinCastIntAsDecimalSig) evalDecimal(row chunk.Row) (res *types.MyDe
if isNull || err != nil {
return res, isNull, errors.Trace(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
16 changes: 16 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2108,6 +2108,22 @@ func (s *testIntegrationSuite) 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