Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
5da8887
Implemented Multiply() along with appropricate functions in arithmeti…
Aug 27, 2019
c969702
Fixed runtime error in Multiply()
Aug 28, 2019
4dfa6a5
Fixed error checking for overflow of integer multiplication
Aug 30, 2019
2172ab9
Changed error checking in uintTimesUintWithError() in arithmetic.go
Sep 3, 2019
95a52bd
Fixed error checking for uintTimesIntWithError() in arithmetic.go
Sep 6, 2019
a52ce84
Completed error checking for uintTimesIntWithError()
Sep 6, 2019
e68a3c5
Fixed error checking for multiplication of uint*int and uint*int
Sep 11, 2019
7ebf526
Merge remote-tracking branch 'origin/master' into rk-newmult
Sep 12, 2019
9f9c2e0
sqltypes: Subtract functionality
Aug 13, 2019
eeebadb
Fixed code coverage in arithmetic.go
Aug 27, 2019
32fa645
Fixed spacing between // and comment
Aug 27, 2019
9214c94
Fixed comment spacing and cleaned up code
Aug 27, 2019
9afca1c
Fixed error print statements
Aug 27, 2019
8975b47
Implemented Multiply() along with appropricate functions in arithmeti…
Aug 27, 2019
ba19e18
Fixed runtime error in Multiply()
Aug 28, 2019
e2558a6
Fixed error checking for overflow of integer multiplication
Aug 30, 2019
52b0974
Changed error checking in uintTimesUintWithError() in arithmetic.go
Sep 3, 2019
bdb6bf8
Fixed error checking for uintTimesIntWithError() in arithmetic.go
Sep 6, 2019
ffd573a
Completed error checking for uintTimesIntWithError()
Sep 6, 2019
cb9c05e
Fixed error checking for multiplication of uint*int and uint*int
Sep 11, 2019
0cf6371
fix docker pre-fetch of go modules
morgo Sep 6, 2019
c5c67ad
making sure fresh state works before turning off query service during…
figocia Sep 6, 2019
ea327d7
Improve errror when capabiility detect fails
morgo Sep 5, 2019
297345f
maintainers: add morgo and systay
sougou Sep 9, 2019
00b4593
Merge branch 'rk-newmult' of github.com:planetscale/vitess into rk-ne…
Sep 12, 2019
5a18b06
Merge remote-tracking branch 'origin/master' into rk-newmult
Sep 12, 2019
d0fed7b
Merge remote-tracking branch 'origin/master' into rk-newmult
Sep 13, 2019
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
74 changes: 74 additions & 0 deletions go/sqltypes/arithmetic.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,28 @@ func Subtract(v1, v2 Value) (Value, error) {
return castFromNumeric(lresult, lresult.typ), nil
}

// Multiply takes two values and multiplies it together
func Multiply(v1, v2 Value) (Value, error) {
if v1.IsNull() || v2.IsNull() {
return NULL, nil
}

lv1, err := newNumeric(v1)
if err != nil {
return NULL, err
}
lv2, err := newNumeric(v2)
if err != nil {
return NULL, err
}
lresult, err := multiplyNumericWithError(lv1, lv2)
if err != nil {
return NULL, err
}

return castFromNumeric(lresult, lresult.typ), nil
}

// NullsafeAdd adds two Values in a null-safe manner. A null value
// is treated as 0. If both values are null, then a null is returned.
// If both values are not null, a numeric value is built
Expand Down Expand Up @@ -430,6 +452,24 @@ func subtractNumericWithError(v1, v2 numeric) (numeric, error) {
panic("unreachable")
}

func multiplyNumericWithError(v1, v2 numeric) (numeric, error) {
v1, v2 = prioritize(v1, v2)
switch v1.typ {
case Int64:
return intTimesIntWithError(v1.ival, v2.ival)
case Uint64:
switch v2.typ {
case Int64:
return uintTimesIntWithError(v1.uval, v2.ival)
case Uint64:
return uintTimesUintWithError(v1.uval, v2.uval)
}
case Float64:
return floatTimesAny(v1.fval, v2), nil
}
panic("unreachable")
}

// prioritize reorders the input parameters
// to be Float64, Uint64, Int64.
func prioritize(v1, v2 numeric) (altv1, altv2 numeric) {
Expand Down Expand Up @@ -477,6 +517,14 @@ func intMinusIntWithError(v1, v2 int64) (numeric, error) {
return numeric{typ: Int64, ival: result}, nil
}

func intTimesIntWithError(v1, v2 int64) (numeric, error) {
result := v1 * v2
if v1 != 0 && result/v1 != v2 {
return numeric{}, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "BIGINT value is out of range in %v * %v", v1, v2)
}
return numeric{typ: Int64, ival: result}, nil
}

func intMinusUintWithError(v1 int64, v2 uint64) (numeric, error) {
if v1 < 0 || v1 < int64(v2) {
return numeric{}, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "BIGINT UNSIGNED value is out of range in %v - %v", v1, v2)
Expand Down Expand Up @@ -508,6 +556,13 @@ func uintMinusIntWithError(v1 uint64, v2 int64) (numeric, error) {
return uintMinusUintWithError(v1, uint64(v2))
}

func uintTimesIntWithError(v1 uint64, v2 int64) (numeric, error) {
if v2 < 0 || int64(v1) < 0 {
return numeric{}, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "BIGINT UNSIGNED value is out of range in %v * %v", v1, v2)
}
return uintTimesUintWithError(v1, uint64(v2))
}

func uintPlusUint(v1, v2 uint64) numeric {
result := v1 + v2
if result < v2 {
Expand All @@ -529,6 +584,15 @@ func uintMinusUintWithError(v1, v2 uint64) (numeric, error) {
if v2 > v1 {
return numeric{}, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "BIGINT UNSIGNED value is out of range in %v - %v", v1, v2)
}

return numeric{typ: Uint64, uval: result}, nil
}

func uintTimesUintWithError(v1, v2 uint64) (numeric, error) {
result := v1 * v2
if result < v2 || result < v1 {
return numeric{}, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "BIGINT UNSIGNED value is out of range in %v * %v", v1, v2)
}
return numeric{typ: Uint64, uval: result}, nil
}

Expand All @@ -552,6 +616,16 @@ func floatMinusAny(v1 float64, v2 numeric) numeric {
return numeric{typ: Float64, fval: v1 - v2.fval}
}

func floatTimesAny(v1 float64, v2 numeric) numeric {
switch v2.typ {
case Int64:
v2.fval = float64(v2.ival)
case Uint64:
v2.fval = float64(v2.uval)
}
return numeric{typ: Float64, fval: v1 * v2.fval}
}

func anyMinusFloat(v1 numeric, v2 float64) numeric {
switch v1.typ {
case Int64:
Expand Down
99 changes: 99 additions & 0 deletions go/sqltypes/arithmetic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,105 @@ import (
"vitess.io/vitess/go/vt/vterrors"
)

func TestMultiply(t *testing.T) {
tcases := []struct {
v1, v2 Value
out Value
err error
}{{
//All Nulls
v1: NULL,
v2: NULL,
out: NULL,
}, {
// First value null.
v1: NewInt32(1),
v2: NULL,
out: NULL,
}, {
// Second value null.
v1: NULL,
v2: NewInt32(1),
out: NULL,
}, {
// case with negative value
v1: NewInt64(-1),
v2: NewInt64(-2),
out: NewInt64(2),
}, {
// testing for int64 overflow with min negative value
v1: NewInt64(math.MinInt64),
v2: NewInt64(1),
out: NewInt64(math.MinInt64),
}, {
// testing for error in types
v1: TestValue(Int64, "1.2"),
v2: NewInt64(2),
err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "strconv.ParseInt: parsing \"1.2\": invalid syntax"),
}, {
// testing for error in types
v1: NewInt64(2),
v2: TestValue(Int64, "1.2"),
err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "strconv.ParseInt: parsing \"1.2\": invalid syntax"),
}, {
// testing for uint*int
v1: NewUint64(4),
v2: NewInt64(5),
out: NewUint64(20),
}, {
// testing for uint*uint
v1: NewUint64(1),
v2: NewUint64(2),
out: NewUint64(2),
}, {
// testing for float64*int64
v1: TestValue(Float64, "1.2"),
v2: NewInt64(-2),
out: NewFloat64(-2.4),
}, {
// testing for float64*uint64
v1: TestValue(Float64, "1.2"),
v2: NewUint64(2),
out: NewFloat64(2.4),
}, {
// testing for overflow of int64
v1: NewInt64(math.MaxInt64),
v2: NewInt64(2),
err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "BIGINT value is out of range in 9223372036854775807 * 2"),
}, {
// testing for underflow of uint64*max.uint64
v1: NewInt64(2),
v2: NewUint64(math.MaxUint64),
err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "BIGINT UNSIGNED value is out of range in 18446744073709551615 * 2"),
}, {
v1: NewUint64(math.MaxUint64),
v2: NewUint64(1),
out: NewUint64(math.MaxUint64),
}, {
//Checking whether maxInt value can be passed as uint value
v1: NewUint64(math.MaxInt64),
v2: NewInt64(3),
err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "BIGINT UNSIGNED value is out of range in 9223372036854775807 * 3"),
}}

for _, tcase := range tcases {

got, err := Multiply(tcase.v1, tcase.v2)

if !vterrors.Equals(err, tcase.err) {
t.Errorf("Multiply(%v, %v) error: %v, want %v", printValue(tcase.v1), printValue(tcase.v2), vterrors.Print(err), vterrors.Print(tcase.err))
}
if tcase.err != nil {
continue
}

if !reflect.DeepEqual(got, tcase.out) {
t.Errorf("Multiply(%v, %v): %v, want %v", printValue(tcase.v1), printValue(tcase.v2), printValue(got), printValue(tcase.out))
}
}

}

func TestSubtract(t *testing.T) {
tcases := []struct {
v1, v2 Value
Expand Down