From 8a22a3ede35c535cc3fe2690c1d5664ba616e275 Mon Sep 17 00:00:00 2001 From: Travis Date: Wed, 15 Apr 2020 13:47:16 -0500 Subject: [PATCH] fix some range query problems --- executor.go | 41 ++++++++++++++++++++++++++++++++++------- field.go | 4 +++- field_internal_test.go | 1 + 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/executor.go b/executor.go index 0269ba473..f810f189c 100644 --- a/executor.go +++ b/executor.go @@ -4583,22 +4583,28 @@ func getCondIntSlice(f *Field, cond *pql.Condition) ([]int64, error) { } // getScaledInt gets the scaled integer value for v based on -// the field type. +// the field type. In the `decimalToInt64()` function, the +// returned int64 value will be adjusted to correspond to the +// range of the field. This is only necessary for pql.Decimal +// values. For example, if v is less than f.Options.Min, int64 will +// return int64(f.Options.Min)-1, or math.MinInt64 if f.Options.Min +// is already equal to math.MinInt64. func getScaledInt(f *Field, v interface{}) (int64, error) { var value int64 opt := f.Options() if opt.Type == FieldTypeDecimal { - scale := opt.Scale switch tv := v.(type) { - case int64: - value = int64(float64(tv) * math.Pow10(int(scale))) case uint64: - value = int64(float64(tv) * math.Pow10(int(scale))) + dec := pql.NewDecimal(int64(tv), 0) + value = decimalToInt64(dec, opt) + case int64: + dec := pql.NewDecimal(tv, 0) + value = decimalToInt64(dec, opt) case pql.Decimal: - value = tv.ToInt64(scale) + value = decimalToInt64(tv, opt) case float64: - value = int64(tv * math.Pow10(int(scale))) + value = int64(tv * math.Pow10(int(opt.Scale))) default: return 0, errors.Errorf("unexpected decimal value type %T, val %v", tv, tv) } @@ -4614,3 +4620,24 @@ func getScaledInt(f *Field, v interface{}) (int64, error) { } return value, nil } + +func decimalToInt64(dec pql.Decimal, opt FieldOptions) int64 { + scale := opt.Scale + if dec.GreaterThanOrEqualTo(opt.Min) && dec.LessThanOrEqualTo(opt.Max) { + return dec.ToInt64(scale) + } else if dec.LessThan(opt.Min) { + value := opt.Min.ToInt64(scale) + if value != math.MinInt64 { + value-- + } + return value + } else if dec.GreaterThan(opt.Max) { + value := opt.Max.ToInt64(scale) + if value != math.MaxInt64 { + value++ + } + return value + } + + return 0 +} diff --git a/field.go b/field.go index b36db5753..88ab0c128 100644 --- a/field.go +++ b/field.go @@ -2200,7 +2200,9 @@ func (b *bsiGroup) baseValue(op pql.Token, value int64) (baseValue int64, outOfR if op == pql.GT || op == pql.GTE { if value > max { return baseValue, true - } else if value > min { + } else if value < min { + baseValue = int64(min - b.Base) + } else { baseValue = int64(value - b.Base) } } else if op == pql.LT || op == pql.LTE { diff --git a/field_internal_test.go b/field_internal_test.go index bb51a44e1..e1f20d3d6 100644 --- a/field_internal_test.go +++ b/field_internal_test.go @@ -92,6 +92,7 @@ func TestBSIGroup_BaseValue(t *testing.T) { {b1, pql.GT, -8, -8, false}, {b1, pql.GT, 1005, 0, true}, {b1, pql.GT, 0, 0, false}, + {b1, pql.GT, -300, -255, false}, {b2, pql.GT, 5, -95, false}, {b2, pql.GT, -8, -108, false},