Skip to content

Commit 3418751

Browse files
authored
Merge pull request #3256 from dolthub/elian/9927
dolthub/dolt#9927: Fix double negation overflow with Literals
2 parents e24a6e8 + e71b727 commit 3418751

File tree

3 files changed

+110
-17
lines changed

3 files changed

+110
-17
lines changed

enginetest/queries/script_queries.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,89 @@ type ScriptTestAssertion struct {
122122
// Unlike other engine tests, ScriptTests must be self-contained. No other tables are created outside the definition of
123123
// the tests.
124124
var ScriptTests = []ScriptTest{
125+
{
126+
// https://github.com/dolthub/dolt/issues/9927
127+
// https://github.com/dolthub/dolt/issues/9053
128+
Name: "double negation of integer minimum values",
129+
Dialect: "mysql",
130+
SetUpScript: []string{
131+
"CREATE TABLE t0(c0 BIGINT);",
132+
"INSERT INTO t0(c0) VALUES (-9223372036854775808);",
133+
"CREATE TABLE t1(c0 INT);",
134+
"INSERT INTO t1(c0) VALUES (-2147483648);",
135+
"CREATE TABLE t2(c0 SMALLINT);",
136+
"INSERT INTO t2(c0) VALUES (-32768);",
137+
"CREATE TABLE t3(c0 TINYINT);",
138+
"INSERT INTO t3(c0) VALUES (-128);",
139+
},
140+
Assertions: []ScriptTestAssertion{
141+
{
142+
Query: "SELECT -(-128);",
143+
Expected: []sql.Row{{int16(128)}},
144+
ExpectedColumns: sql.Schema{{Name: "-(-128)", Type: types.Int64}},
145+
},
146+
{
147+
Query: "SELECT -(-32768);",
148+
Expected: []sql.Row{{int32(32768)}},
149+
ExpectedColumns: sql.Schema{{Name: "-(-32768)", Type: types.Int64}},
150+
},
151+
{
152+
Query: "SELECT -(-2147483648);",
153+
Expected: []sql.Row{{int64(2147483648)}},
154+
ExpectedColumns: sql.Schema{{Name: "-(-2147483648)", Type: types.Int64}},
155+
},
156+
{
157+
Query: "SELECT -(-9223372036854775808)",
158+
Expected: []sql.Row{{"9223372036854775808"}},
159+
ExpectedColumns: sql.Schema{{Name: "-(-9223372036854775808)", Type: types.InternalDecimalType}},
160+
},
161+
{
162+
Query: "SELECT -t0.c0 FROM t0;",
163+
ExpectedErr: sql.ErrValueOutOfRange,
164+
},
165+
{
166+
Query: "SELECT -t1.c0 FROM t1;",
167+
Expected: []sql.Row{{2147483648}},
168+
},
169+
{
170+
Query: "SELECT -t2.c0 FROM t2;",
171+
Expected: []sql.Row{{32768}},
172+
},
173+
{
174+
Query: "SELECT -t3.c0 FROM t3;",
175+
Expected: []sql.Row{{128}},
176+
},
177+
{
178+
Query: "SELECT -(-t1.c0 + 1) FROM t1;",
179+
Expected: []sql.Row{{-2147483649}},
180+
},
181+
{
182+
Query: "SELECT -(-(t2.c0 - 1)) FROM t2;",
183+
Expected: []sql.Row{{-32769}},
184+
},
185+
{
186+
Query: "SELECT -(-t3.c0 * 2) FROM t3;",
187+
Expected: []sql.Row{{-256}},
188+
},
189+
{
190+
Query: "SELECT -(-(-128));",
191+
Expected: []sql.Row{{int8(-128)}},
192+
},
193+
{
194+
Query: "SELECT -(-(-(-128)));",
195+
Expected: []sql.Row{{int16(128)}},
196+
},
197+
{
198+
Query: "SELECT -(-NULL);",
199+
Expected: []sql.Row{{nil}},
200+
},
201+
{
202+
Query: "SELECT -(-CAST(-128 AS SIGNED));",
203+
Expected: []sql.Row{{int64(-128)}},
204+
ExpectedColumns: sql.Schema{{Name: "-(-CAST(-128 AS SIGNED))", Type: types.Int64}},
205+
},
206+
},
207+
},
125208
{
126209
// https://github.com/dolthub/dolt/issues/9865
127210
Name: "Stored procedure containing a transaction does not return EOF",

sql/expression/arithmetic.go

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import (
2626
"github.com/dolthub/vitess/go/mysql"
2727
"github.com/dolthub/vitess/go/vt/sqlparser"
2828
"github.com/shopspring/decimal"
29-
errors "gopkg.in/src-d/go-errors.v1"
29+
"gopkg.in/src-d/go-errors.v1"
3030

3131
"github.com/dolthub/go-mysql-server/sql"
3232
"github.com/dolthub/go-mysql-server/sql/types"
@@ -705,25 +705,17 @@ func (e *UnaryMinus) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
705705
return -n, nil
706706
case float32:
707707
return -n, nil
708-
case int:
709-
return -n, nil
710708
case int8:
711-
if n == math.MinInt8 {
712-
return -int16(n), nil
713-
}
714-
return -n, nil
709+
return -int64(n), nil
715710
case int16:
716-
if n == math.MinInt16 {
717-
return -int32(n), nil
718-
}
719-
return -n, nil
711+
return -int64(n), nil
720712
case int32:
721-
if n == math.MinInt32 {
722-
return -int64(n), nil
723-
}
724-
return -n, nil
713+
return -int64(n), nil
725714
case int64:
726715
if n == math.MinInt64 {
716+
if _, ok := e.Child.(*Literal); ok {
717+
return decimal.NewFromInt(n).Neg(), nil
718+
}
727719
return nil, sql.ErrValueOutOfRange.New("BIGINT", fmt.Sprintf("%d", n))
728720
}
729721
return -n, nil
@@ -760,6 +752,17 @@ func (e *UnaryMinus) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
760752
// Type implements the sql.Expression interface.
761753
func (e *UnaryMinus) Type() sql.Type {
762754
typ := e.Child.Type()
755+
switch typ {
756+
case types.Int8, types.Int16, types.Int32:
757+
typ = types.Int64
758+
case types.Int64:
759+
if lit, ok := e.Child.(*Literal); ok {
760+
if lit.Value().(int64) == math.MinInt64 {
761+
typ = types.InternalDecimalType
762+
}
763+
}
764+
}
765+
763766
if !types.IsNumber(typ) {
764767
return types.Float64
765768
}
@@ -772,7 +775,7 @@ func (e *UnaryMinus) Type() sql.Type {
772775
return types.Int64
773776
}
774777

775-
return e.Child.Type()
778+
return typ
776779
}
777780

778781
// CollationCoercibility implements the interface sql.CollationCoercible.

sql/expression/arithmetic_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package expression
1616

1717
import (
1818
"fmt"
19+
"math"
1920
"testing"
2021
"time"
2122

@@ -568,7 +569,9 @@ func TestUnaryMinus(t *testing.T) {
568569
typ sql.Type
569570
expected interface{}
570571
}{
571-
{"int32", int32(1), types.Int32, int32(-1)},
572+
{"int8", int8(1), types.Int8, int64(-1)},
573+
{"int16", int16(1), types.Int16, int64(-1)},
574+
{"int32", int32(1), types.Int32, int64(-1)},
572575
{"uint32", uint32(1), types.Uint32, int32(-1)},
573576
{"int64", int64(1), types.Int64, int64(-1)},
574577
{"uint64", uint64(1), types.Uint64, int64(-1)},
@@ -577,6 +580,10 @@ func TestUnaryMinus(t *testing.T) {
577580
{"int text", "1", types.LongText, "-1"},
578581
{"float text", "1.2", types.LongText, "-1.2"},
579582
{"nil", nil, types.LongText, nil},
583+
{"minint8", int8(math.MinInt8), types.Int8, int64(128)},
584+
{"minint16", int16(math.MinInt16), types.Int16, int64(32768)},
585+
{"minint32", int32(math.MinInt32), types.Int32, int64(2147483648)},
586+
{"minint64", int64(math.MinInt64), types.Int64, "9223372036854775808"},
580587
}
581588

582589
for _, tt := range testCases {

0 commit comments

Comments
 (0)