Merge pull request #185 from travisturner/decimal-min-max-overflow

Avoid overflow on decimal min/max default values
This commit is contained in:
Travis Turner 2020-03-18 08:01:40 -05:00 • committed by GitHub
commit 419c2179b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 39 additions and 3 deletions

View file

@ -195,8 +195,19 @@ func OptFieldTypeDecimal(scale int64, minmax ...int64) FieldOption {
if len(minmax) == 2 {
min, max := minmax[0], minmax[1]
if scale != 0 {
min = int64(float64(min) * math.Pow10(int(scale)))
max = int64(float64(max) * math.Pow10(int(scale)))
// If the min/max provided are already on the boundary of int64,
// then we don't want to operate on them and cause overflow.
// There are still overflow scenarios where a user provides a
// min/max which is not on the boundary, but overflow once the
// scale is applied. This does not address those cases, but at
// least it addresses the default case (where a min/max is not
// provided).
if min != math.MinInt64 {
min = int64(float64(min) * math.Pow10(int(scale)))
}
if max != math.MaxInt64 {
max = int64(float64(max) * math.Pow10(int(scale)))
}
}
if min > max {
return errors.Errorf("decimal field min cannot be greater than max, got %d, %d", min, max)
@ -208,7 +219,7 @@ func OptFieldTypeDecimal(scale int64, minmax ...int64) FieldOption {
} else if len(minmax) == 1 {
// It's not necessary to handle the scale==0 case separately,
// but it avoids the type conversion.
if scale == 0 {
if scale == 0 || minmax[0] == math.MinInt64 {
fo.Min = minmax[0]
} else {
fo.Min = int64(float64(minmax[0]) * math.Pow10(int(scale)))

View file

@ -654,6 +654,31 @@ func TestIntField_MinMaxForShard(t *testing.T) {
}
}
func TestDecimalField_MinMaxBoundaries(t *testing.T) {
for i, test := range []struct {
min int64
max int64
scale int64
expmin int64
expmax int64
}{
{min: math.MinInt64, max: math.MaxInt64, scale: 3, expmin: math.MinInt64, expmax: math.MaxInt64},
{min: 44, max: 88, scale: 3, expmin: 44000, expmax: 88000},
{min: -44, max: 88, scale: 3, expmin: -44000, expmax: 88000},
} {
t.Run("minmax"+strconv.Itoa(i), func(t *testing.T) {
f := MustOpenField(OptFieldTypeDecimal(test.scale, test.min, test.max))
if f.Options().Min != test.expmin {
t.Fatalf("expected min: %v, but got: %v", test.expmin, f.Options().Min)
}
if f.Options().Max != test.expmax {
t.Fatalf("expected max: %v, but got: %v", test.expmax, f.Options().Max)
}
})
}
}
func TestDecimalField_MinMaxForShard(t *testing.T) {
f := MustOpenField(OptFieldTypeDecimal(3))