From 26fc621f09090e9e137a35ddd68b1db74bad13c4 Mon Sep 17 00:00:00 2001 From: Travis Date: Mon, 11 Nov 2019 16:09:41 -0600 Subject: [PATCH] Support integer predicates in Decimal field range queries. --- api_test.go | 4 +-- executor.go | 62 ++++++++++++++++++++++++++------------------- http/client_test.go | 22 +++++++++++++++- 3 files changed, 59 insertions(+), 29 deletions(-) diff --git a/api_test.go b/api_test.go index 1084535af..fafae614f 100644 --- a/api_test.go +++ b/api_test.go @@ -293,7 +293,7 @@ func TestAPI_ImportValue(t *testing.T) { t.Fatal(err) } - pql := fmt.Sprintf("Row(%s>60)", field) + pql := fmt.Sprintf("Row(%s>6)", field) // Query node0. if res, err := m0.API.Query(ctx, &pilosa.QueryRequest{Index: index, Query: pql}); err != nil { @@ -389,7 +389,7 @@ func TestAPI_ImportValue(t *testing.T) { t.Fatal(err) } - pql := fmt.Sprintf("Row(%s>60)", field) + pql := fmt.Sprintf("Row(%s>600)", field) // Query node0. if res, err := m0.API.Query(ctx, &pilosa.QueryRequest{Index: index, Query: pql}); err != nil { diff --git a/executor.go b/executor.go index c019733a4..52e09010b 100644 --- a/executor.go +++ b/executor.go @@ -1972,17 +1972,9 @@ func (e *executor) executeRowBSIGroupShard(ctx context.Context, index string, c return frag.rangeBetween(bsig.BitDepth, baseValueMin, baseValueMax) } else { - value, ok := cond.Value.(int64) - if !ok { - if floatVal, ok := cond.Value.(float64); ok { - if f.Options().Type != FieldTypeDecimal { - return nil, errors.Errorf("Float value '%f' given in query to non-decimal field", floatVal) - } - scale := f.Options().Scale - value = int64(floatVal * math.Pow10(int(scale))) - } else { - return nil, errors.New("Row(): conditions only support integer values (or floats for decimal fields)") - } + value, err := getScaledInt(f, cond.Value) + if err != nil { + return nil, errors.Wrap(err, "getting scaled integer") } // Find bsiGroup. @@ -3768,21 +3760,11 @@ func getCondIntSlice(f *Field, cond *pql.Condition) ([]int64, error) { ret := make([]int64, len(val)) for i, v := range val { - switch tv := v.(type) { - case int64: - ret[i] = tv - case uint64: - ret[i] = int64(tv) - case float64: - if f.Options().Type != FieldTypeDecimal { - return nil, errors.Errorf("got a float value '%f' in a query to an integer field", tv) - } - scale := f.Options().Scale - iv := int64(tv * math.Pow10(int(scale))) - ret[i] = iv - default: - return nil, errors.Errorf("unexpected value type %T, val %v", tv, tv) + s, err := getScaledInt(f, v) + if err != nil { + return nil, errors.Wrap(err, "getting scaled integer") } + ret[i] = s } switch cond.Op { @@ -3796,5 +3778,33 @@ func getCondIntSlice(f *Field, cond *pql.Condition) ([]int64, error) { } return ret, nil - +} + +// getScaledInt gets the scaled integer value for v based on +// the field type. +func getScaledInt(f *Field, v interface{}) (int64, error) { + var value int64 + if f.Options().Type == FieldTypeDecimal { + scale := f.Options().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))) + case float64: + value = int64(tv * math.Pow10(int(scale))) + default: + return 0, errors.Errorf("unexpected decimal value type %T, val %v", tv, tv) + } + } else { + switch tv := v.(type) { + case int64: + value = tv + case uint64: + value = int64(tv) + default: + return 0, errors.Errorf("unexpected value type %T, val %v", tv, tv) + } + } + return value, nil } diff --git a/http/client_test.go b/http/client_test.go index 4f3fb7496..bc889b10d 100644 --- a/http/client_test.go +++ b/http/client_test.go @@ -1095,7 +1095,8 @@ func TestClient_CreateDecimalField(t *testing.T) { t.Fatalf("importing float values: %v", err) } - resp, err := c.Query(context.Background(), index, &pilosa.QueryRequest{Index: index, Query: "Row(dfield>21)"}) + // Integer predicate. + resp, err := c.Query(context.Background(), index, &pilosa.QueryRequest{Index: index, Query: "Row(dfield>2)"}) if err != nil { t.Fatalf("querying: %v", err) } @@ -1103,6 +1104,25 @@ func TestClient_CreateDecimalField(t *testing.T) { t.Fatalf("unexpected results: %v", resp.Results[0].(*pilosa.Row).Columns()) } + // Float predicate. + resp, err = c.Query(context.Background(), index, &pilosa.QueryRequest{Index: index, Query: "Row(dfield>2.1)"}) + if err != nil { + t.Fatalf("querying: %v", err) + } + if !reflect.DeepEqual(resp.Results[0].(*pilosa.Row).Columns(), []uint64{2, 3}) { + t.Fatalf("unexpected results: %v", resp.Results[0].(*pilosa.Row).Columns()) + } + + // Integer predicates. + resp, err = c.Query(context.Background(), index, &pilosa.QueryRequest{Index: index, Query: "Row(1