diff --git a/client/orm_test.go b/client/orm_test.go index 57a70f1cc..988f6a4a4 100644 --- a/client/orm_test.go +++ b/client/orm_test.go @@ -1210,11 +1210,11 @@ func compareFieldOptions(t *testing.T, opts *FieldOptions, fieldType FieldType, if cacheSize != opts.CacheSize() { t.Fatalf("%d != %d", cacheSize, opts.CacheSize()) } - if min != opts.Min() { - t.Fatalf("%d != %d", min, opts.Min()) + if !min.EqualTo(opts.Min()) { + t.Fatalf("%v != %v", min, opts.Min()) } - if max != opts.Max() { - t.Fatalf("%d != %d", max, opts.Max()) + if !max.EqualTo(opts.Max()) { + t.Fatalf("%v != %v", max, opts.Max()) } if foreignIndex != opts.ForeignIndex() { t.Fatalf("%s != %s", foreignIndex, opts.ForeignIndex()) diff --git a/cmd/import.go b/cmd/import.go index 52f28a4aa..2f589fcf8 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -3,15 +3,45 @@ package cmd import ( "context" + "fmt" "io" + "strconv" pilosa "github.com/molecula/featurebase/v3" "github.com/molecula/featurebase/v3/ctl" + "github.com/molecula/featurebase/v3/pql" "github.com/spf13/cobra" ) var Importer *ctl.ImportCommand +// DecimalFlagValue is used to set the unexported value field in a decimal. It also +// fulfills the flag.Value interface. +type DecimalFlagValue struct { + dec *pql.Decimal +} + +func (dfv *DecimalFlagValue) String() string { + return fmt.Sprintf("%v", dfv.dec.Value()) +} + +func (dfv *DecimalFlagValue) Set(s string) error { + i, err := strconv.ParseInt(s, 10, 64) + if err != nil { + return err + } + if dfv.dec == nil { + d := pql.NewDecimal(0, 0) + dfv.dec = &d + } + dfv.dec.SetValue(i) + return nil +} + +func (dfv *DecimalFlagValue) Type() string { + return fmt.Sprintf("%T", int64(0)) +} + // newImportCommand runs the FeatureBase import subcommand for ingesting bulk data. func newImportCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command { Importer = ctl.NewImportCommand(stdin, stdout, stderr) @@ -34,6 +64,8 @@ omitted. If it is present then its format should be YYYY-MM-DDTHH:MM. }, } + fieldMin := DecimalFlagValue{dec: &Importer.FieldOptions.Min} + fieldMax := DecimalFlagValue{dec: &Importer.FieldOptions.Max} flags := importCmd.Flags() flags.StringVarP(&Importer.Host, "host", "", "localhost:10101", "host:port of FeatureBase.") flags.StringVarP(&Importer.Index, "index", "i", "", "FeatureBase index to import into.") @@ -41,8 +73,8 @@ omitted. If it is present then its format should be YYYY-MM-DDTHH:MM. flags.BoolVar(&Importer.IndexOptions.Keys, "index-keys", false, "Specify keys=true when creating an index") flags.BoolVar(&Importer.FieldOptions.Keys, "field-keys", false, "Specify keys=true when creating a field") flags.StringVar(&Importer.FieldOptions.Type, "field-type", "", "Specify the field type when creating a field. One of: set, int, decimal, time, bool, mutex") - flags.Int64Var(&Importer.FieldOptions.Min.Value, "field-min", 0, "Specify the minimum for an int field on creation") // TODO: noting that decimal field min/max are not supported here. - flags.Int64Var(&Importer.FieldOptions.Max.Value, "field-max", 0, "Specify the maximum for an int field on creation") + flags.Var(&fieldMin, "field-min", "Specify the minimum for an int field on creation") // TODO: noting that decimal field min/max are not supported here. + flags.Var(&fieldMax, "field-max", "Specify the maximum for an int field on creation") flags.StringVar(&Importer.FieldOptions.CacheType, "field-cache-type", pilosa.CacheTypeRanked, "Specify the cache type for a set field on creation. One of: none, lru, ranked") flags.Uint32Var(&Importer.FieldOptions.CacheSize, "field-cache-size", 50000, "Specify the cache size for a set field on creation") flags.Var(&Importer.FieldOptions.TimeQuantum, "field-time-quantum", "Specify the time quantum for a time field on creation. One of: D, DH, H, M, MD, MDH, Y, YM, YMD, YMDH") diff --git a/ctl/import.go b/ctl/import.go index 8d44fd98e..963aaaf52 100644 --- a/ctl/import.go +++ b/ctl/import.go @@ -102,7 +102,7 @@ func (cmd *ImportCommand) Run(ctx context.Context) error { // set the correct type for the field if cmd.FieldOptions.TimeQuantum != "" { cmd.FieldOptions.Type = pilosa.FieldTypeTime - } else if cmd.FieldOptions.Min != pql.NewDecimal(0, 0) || cmd.FieldOptions.Max != pql.NewDecimal(0, 0) { + } else if !cmd.FieldOptions.Min.EqualTo(pql.NewDecimal(0, 0)) || !cmd.FieldOptions.Max.EqualTo(pql.NewDecimal(0, 0)) { cmd.FieldOptions.Type = pilosa.FieldTypeInt } else { cmd.FieldOptions.Type = pilosa.FieldTypeSet diff --git a/encoding/proto/proto.go b/encoding/proto/proto.go index c8e1d0a04..81f15effd 100644 --- a/encoding/proto/proto.go +++ b/encoding/proto/proto.go @@ -704,8 +704,8 @@ func (s Serializer) encodeFieldOptions(o *pilosa.FieldOptions) *pb.FieldOptions Type: o.Type, CacheType: o.CacheType, CacheSize: o.CacheSize, - Min: &pb.Decimal{Value: o.Min.Value, Scale: o.Min.Scale}, - Max: &pb.Decimal{Value: o.Max.Value, Scale: o.Max.Scale}, + Min: s.encodeDecimal(&o.Min), + Max: s.encodeDecimal(&o.Max), Base: o.Base, Scale: o.Scale, BitDepth: uint64(o.BitDepth), @@ -1139,8 +1139,11 @@ func (s Serializer) decodeFieldOptions(options *pb.FieldOptions, m *pilosa.Field } func (s Serializer) decodeDecimal(d *pb.Decimal, m *pql.Decimal) { - m.Value = d.Value - m.Scale = d.Scale + // err should always be nil, unless there's a problem with the standard library + err := m.GobDecode(d.Gob) + if err != nil { + panic(err) + } } func (s Serializer) decodeNodes(a []*pb.Node, m []*topology.Node) { @@ -1743,10 +1746,9 @@ func (s Serializer) decodeDecimalStruct(pb *pb.Decimal) *pql.Decimal { if pb == nil { return nil } - return &pql.Decimal{ - Value: pb.Value, - Scale: pb.Scale, - } + d := &pql.Decimal{} + s.decodeDecimal(pb, d) + return d } func (s Serializer) encodeSignedRow(r pilosa.SignedRow) *pb.SignedRow { @@ -1962,9 +1964,9 @@ func (s Serializer) encodeDecimal(p *pql.Decimal) *pb.Decimal { if p == nil { return nil } + gob, _ := p.GobEncode() // ignore err on purpose return &pb.Decimal{ - Value: p.Value, - Scale: p.Scale, + Gob: gob, } } diff --git a/executor.go b/executor.go index 0e1b372cb..32d1b71eb 100644 --- a/executor.go +++ b/executor.go @@ -928,9 +928,8 @@ func (e *executor) executeFieldValueCallShard(ctx context.Context, qcx *Qcx, fie if field.Type() == FieldTypeInt { other.Val = value } else if field.Type() == FieldTypeDecimal { - other.DecimalVal = &pql.Decimal{ - Value: value, - Scale: field.Options().Scale} + dec := pql.NewDecimal(value, field.Options().Scale) + other.DecimalVal = &dec other.FloatVal = 0 other.Val = 0 } else if field.Type() == FieldTypeTimestamp { @@ -1076,9 +1075,8 @@ func (e *executor) executeSum(ctx context.Context, qcx *Qcx, index string, c *pq return ValCount{}, newNotFoundError(ErrFieldNotFound, fieldName) } if field.Type() == FieldTypeDecimal { - other.DecimalVal = &pql.Decimal{ - Value: other.Val, - Scale: field.Options().Scale} + dec := pql.NewDecimal(other.Val, field.Options().Scale) + other.DecimalVal = &dec other.FloatVal = 0 other.Val = 0 } @@ -1894,6 +1892,8 @@ func (e *executor) executeSumCountShard(ctx context.Context, qcx *Qcx, index str } if field.Type() == FieldTypeDecimal { out.FloatVal = float64(int64(vsum)+(int64(vcount)*bsig.Base)) / math.Pow(10, float64(bsig.Scale)) + dec := pql.NewDecimal((int64(vsum) + (int64(vcount) * bsig.Base)), bsig.Scale) + out.DecimalVal = &dec } return out, nil } @@ -3117,7 +3117,7 @@ func (e *executor) executeGroupBy(ctx context.Context, qcx *Qcx, index string, c } } for _, res := range results { - if res.DecimalAgg != 0 && aggType == "sum" { + if res.DecimalAgg != nil && aggType == "sum" { aggType = "decimalSum" break } @@ -3361,31 +3361,31 @@ func (g *GroupCounts) MarshalJSON() ([]byte, error) { // GroupCount represents a result item for a group by query. type GroupCount struct { - Group []FieldRow `json:"group"` - Count uint64 `json:"count"` - Agg int64 `json:"-"` - DecimalAgg float64 `json:"-"` + Group []FieldRow `json:"group"` + Count uint64 `json:"count"` + Agg int64 `json:"-"` + DecimalAgg *pql.Decimal `json:"-"` } type groupCountSum struct { - Group []FieldRow `json:"group"` - Count uint64 `json:"count"` - Agg int64 `json:"sum"` - DecimalAgg float64 `json:"-"` + Group []FieldRow `json:"group"` + Count uint64 `json:"count"` + Agg int64 `json:"sum"` + DecimalAgg *pql.Decimal `json:"-"` } type groupCountAggregate struct { - Group []FieldRow `json:"group"` - Count uint64 `json:"count"` - Agg int64 `json:"aggregate"` - DecimalAgg float64 `json:"-"` + Group []FieldRow `json:"group"` + Count uint64 `json:"count"` + Agg int64 `json:"aggregate"` + DecimalAgg *pql.Decimal `json:"-"` } type groupCountDecimalSum struct { - Group []FieldRow `json:"group"` - Count uint64 `json:"count"` - Agg int64 `json:"-"` - DecimalAgg float64 `json:"sum"` + Group []FieldRow `json:"group"` + Count uint64 `json:"count"` + Agg int64 `json:"-"` + DecimalAgg *pql.Decimal `json:"sum"` } var _ GroupCount = GroupCount(groupCountSum{}) @@ -3422,7 +3422,10 @@ func mergeGroupCounts(a, b []GroupCount, limit int) []GroupCount { case 0: a[i].Count += b[j].Count a[i].Agg += b[j].Agg - a[i].DecimalAgg += b[j].DecimalAgg + if a[i].DecimalAgg != nil && b[j].DecimalAgg != nil { + sum := pql.AddDecimal(*a[i].DecimalAgg, *b[j].DecimalAgg) + a[i].DecimalAgg = &sum + } ret = append(ret, a[i]) i++ j++ @@ -3972,10 +3975,12 @@ func (t ExtractedTable) ToRows(callback func(*proto.RowResponse) error) error { }, } case pql.Decimal: + rValue := r.Value() + rValuePtr := &rValue col = &proto.ColumnResponse{ ColumnVal: &proto.ColumnResponse_DecimalVal{ DecimalVal: &proto.Decimal{ - Value: r.Value, + Value: rValuePtr.Int64(), Scale: r.Scale, }, }, @@ -7772,10 +7777,12 @@ func (v ValCount) ToRows(callback func(*proto.RowResponse) error) error { {Name: "value", Datatype: "decimal"}, {Name: "count", Datatype: "int64"}, } + vValue := v.DecimalVal.Value() + vValuePtr := &vValue if err := callback(&proto.RowResponse{ Headers: ci, Columns: []*proto.ColumnResponse{ - {ColumnVal: &proto.ColumnResponse_DecimalVal{DecimalVal: &proto.Decimal{Value: v.DecimalVal.Value, Scale: v.DecimalVal.Scale}}}, + {ColumnVal: &proto.ColumnResponse_DecimalVal{DecimalVal: &proto.Decimal{Value: vValuePtr.Int64(), Scale: v.DecimalVal.Scale}}}, {ColumnVal: &proto.ColumnResponse_Int64Val{Int64Val: v.Count}}, }}); err != nil { return errors.Wrap(err, "calling callback") @@ -8244,7 +8251,7 @@ func (gbi *groupByIterator) Next(ctx context.Context) (ret GroupCount, done bool } ret.Count = uint64(result.Count) ret.Agg = result.Val - ret.DecimalAgg = result.FloatVal + ret.DecimalAgg = result.DecimalVal } } if ret.Count == 0 { diff --git a/executor_test.go b/executor_test.go index 904e935a7..974060936 100644 --- a/executor_test.go +++ b/executor_test.go @@ -2279,31 +2279,31 @@ func TestExecutor_Execute_MinMax(t *testing.T) { }{ { 2, - pql.Decimal{Value: 1, Scale: -1}, - pql.Decimal{Value: 2, Scale: -1}, - pql.Decimal{Value: 115, Scale: 1}, - pql.Decimal{Value: 1150, Scale: 2}, + pql.NewDecimal(1, -1), + pql.NewDecimal(2, -1), + pql.NewDecimal(115, 1), + pql.NewDecimal(1150, 2), }, { 2, - pql.Decimal{Value: -1, Scale: -1}, - pql.Decimal{Value: 2, Scale: -1}, - pql.Decimal{Value: 115, Scale: 1}, - pql.Decimal{Value: 1150, Scale: 2}, + pql.NewDecimal(-1, -1), + pql.NewDecimal(2, -1), + pql.NewDecimal(115, 1), + pql.NewDecimal(1150, 2), }, { 2, - pql.Decimal{Value: -1, Scale: -1}, - pql.Decimal{Value: 2, Scale: -1}, - pql.Decimal{Value: -95, Scale: 1}, - pql.Decimal{Value: -950, Scale: 2}, + pql.NewDecimal(-1, -1), + pql.NewDecimal(2, -1), + pql.NewDecimal(-95, 1), + pql.NewDecimal(-950, 2), }, { 2, - pql.Decimal{Value: -2, Scale: -1}, - pql.Decimal{Value: -1, Scale: -1}, - pql.Decimal{Value: -115, Scale: 1}, - pql.Decimal{Value: -1150, Scale: 2}, + pql.NewDecimal(-2, -1), + pql.NewDecimal(-1, -1), + pql.NewDecimal(-115, 1), + pql.NewDecimal(-1150, 2), }, } // This extra field exists to make there be shards which are present, @@ -2859,7 +2859,7 @@ func TestExecutor_Execute_Sum(t *testing.T) { t.Run("NoFilter", func(t *testing.T) { if result, err := c.GetNode(0).API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `Sum(field=dec)`}); err != nil { t.Fatal(err) - } else if !reflect.DeepEqual(result.Results[0], pilosa.ValCount{DecimalVal: &pql.Decimal{Value: 700007, Scale: 3}, Count: 3}) { + } else if !reflect.DeepEqual(result.Results[0], pilosa.ValCount{DecimalVal: pql.NewDecimal(700007, 3).Clone(), Count: 3}) { t.Fatalf("unexpected result: %s", spew.Sdump(result)) } }) @@ -2867,7 +2867,7 @@ func TestExecutor_Execute_Sum(t *testing.T) { t.Run("WithFilter", func(t *testing.T) { if result, err := c.GetNode(0).API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `Sum(Row(x=0), field=dec)`}); err != nil { t.Fatal(err) - } else if !reflect.DeepEqual(result.Results[0], pilosa.ValCount{DecimalVal: &pql.Decimal{Value: 500005, Scale: 3}, Count: 2}) { + } else if !reflect.DeepEqual(result.Results[0], pilosa.ValCount{DecimalVal: pql.NewDecimal(500005, 3).Clone(), Count: 2}) { t.Fatalf("unexpected result: %s", spew.Sdump(result)) } }) @@ -2875,7 +2875,7 @@ func TestExecutor_Execute_Sum(t *testing.T) { t.Run("NoFilter", func(t *testing.T) { if result, err := c.GetNode(0).API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `Sum(dec)`}); err != nil { t.Fatal(err) - } else if !reflect.DeepEqual(result.Results[0], pilosa.ValCount{DecimalVal: &pql.Decimal{Value: 700007, Scale: 3}, Count: 3}) { + } else if !reflect.DeepEqual(result.Results[0], pilosa.ValCount{DecimalVal: pql.NewDecimal(700007, 3).Clone(), Count: 3}) { t.Fatalf("unexpected result: %s", spew.Sdump(result)) } }) @@ -2883,7 +2883,7 @@ func TestExecutor_Execute_Sum(t *testing.T) { t.Run("WithFilter", func(t *testing.T) { if result, err := c.GetNode(0).API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `Sum(dec, Row(x=0))`}); err != nil { t.Fatal(err) - } else if !reflect.DeepEqual(result.Results[0], pilosa.ValCount{DecimalVal: &pql.Decimal{Value: 500005, Scale: 3}, Count: 2}) { + } else if !reflect.DeepEqual(result.Results[0], pilosa.ValCount{DecimalVal: pql.NewDecimal(500005, 3).Clone(), Count: 2}) { t.Fatalf("unexpected result: %s", spew.Sdump(result)) } }) @@ -4046,7 +4046,7 @@ func TestExecutor_Execute_FieldValue(t *testing.T) { } else { switch exp := test.expVal.(type) { case pql.Decimal: - if *vc.DecimalVal != exp { + if !vc.DecimalVal.EqualTo(exp) { t.Fatalf("test %d on node%d expected pql.Decimal(%s), but got: %s", i, n, exp, vc.DecimalVal) } case int64: @@ -5368,15 +5368,15 @@ func TestExecutor_GroupByStrings(t *testing.T) { { query: "GroupBy(Rows(generals), aggregate=Sum(field=dv))", expected: []pilosa.GroupCount{ - {Group: []pilosa.FieldRow{{Field: "generals", RowID: 1, RowKey: "r1"}}, Count: 5, Agg: 2775, DecimalAgg: 27.75}, - {Group: []pilosa.FieldRow{{Field: "generals", RowID: 2, RowKey: "r2"}}, Count: 5, Agg: 3220, DecimalAgg: 32.20}, + {Group: []pilosa.FieldRow{{Field: "generals", RowID: 1, RowKey: "r1"}}, Count: 5, Agg: 2775, DecimalAgg: pql.NewDecimal(2775, 2).Clone()}, + {Group: []pilosa.FieldRow{{Field: "generals", RowID: 2, RowKey: "r2"}}, Count: 5, Agg: 3220, DecimalAgg: pql.NewDecimal(3220, 2).Clone()}, }, }, { query: "GroupBy(Rows(generals), aggregate=Sum(field=ndv))", expected: []pilosa.GroupCount{ - {Group: []pilosa.FieldRow{{Field: "generals", RowID: 1, RowKey: "r1"}}, Count: 5, Agg: -2775, DecimalAgg: -277.5}, - {Group: []pilosa.FieldRow{{Field: "generals", RowID: 2, RowKey: "r2"}}, Count: 5, Agg: -3220, DecimalAgg: -322.0}, + {Group: []pilosa.FieldRow{{Field: "generals", RowID: 1, RowKey: "r1"}}, Count: 5, Agg: -2775, DecimalAgg: pql.NewDecimal(-2775, 1).Clone()}, + {Group: []pilosa.FieldRow{{Field: "generals", RowID: 2, RowKey: "r2"}}, Count: 5, Agg: -3220, DecimalAgg: pql.NewDecimal(-3220, 1).Clone()}, }, }, { @@ -5519,7 +5519,7 @@ func TestExecutor_GroupByStrings(t *testing.T) { } for i, tst := range tests { - t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + t.Run(fmt.Sprintf("%s%d", tst.query, i), func(t *testing.T) { r, err := c.GetNode(0).API.Query(context.Background(), &pilosa.QueryRequest{ Index: "istring", Query: tst.query, @@ -8673,7 +8673,7 @@ func TestToRows(t *testing.T) { if e != nil { t.Fatal("Shouldn't be err ", e) } - v.DecimalVal = &pql.Decimal{Value: 1, Scale: 1} + v.DecimalVal = pql.NewDecimal(1, 1).Clone() e = v.ToRows(func(*proto.RowResponse) error { return nil }) diff --git a/field_internal_test.go b/field_internal_test.go index e625a09b9..1d775e702 100644 --- a/field_internal_test.go +++ b/field_internal_test.go @@ -754,29 +754,29 @@ func TestDecimalField_MinMaxForShard(t *testing.T) { name: "single", columnIDs: []uint64{1}, values: []float64{10.1}, - expMax: ValCount{Val: 10100, DecimalVal: &pql.Decimal{Value: 10100, Scale: 3}, Count: 1}, - expMin: ValCount{Val: 10100, DecimalVal: &pql.Decimal{Value: 10100, Scale: 3}, Count: 1}, + expMax: ValCount{Val: 10100, DecimalVal: pql.NewDecimal(10100, 3).Clone(), Count: 1}, + expMin: ValCount{Val: 10100, DecimalVal: pql.NewDecimal(10100, 3).Clone(), Count: 1}, }, { name: "twovals", columnIDs: []uint64{1, 2}, values: []float64{10.1, 20.2}, - expMax: ValCount{Val: 20200, DecimalVal: &pql.Decimal{Value: 20200, Scale: 3}, Count: 1}, - expMin: ValCount{Val: 10100, DecimalVal: &pql.Decimal{Value: 10100, Scale: 3}, Count: 1}, + expMax: ValCount{Val: 20200, DecimalVal: pql.NewDecimal(20200, 3).Clone(), Count: 1}, + expMin: ValCount{Val: 10100, DecimalVal: pql.NewDecimal(10100, 3).Clone(), Count: 1}, }, { name: "multiplecounts", columnIDs: []uint64{1, 2, 3, 4, 5}, values: []float64{10.1, 20.2, 10.1, 10.1, 20.2}, - expMax: ValCount{Val: 20200, DecimalVal: &pql.Decimal{Value: 20200, Scale: 3}, Count: 2}, - expMin: ValCount{Val: 10100, DecimalVal: &pql.Decimal{Value: 10100, Scale: 3}, Count: 3}, + expMax: ValCount{Val: 20200, DecimalVal: pql.NewDecimal(20200, 3).Clone(), Count: 2}, + expMin: ValCount{Val: 10100, DecimalVal: pql.NewDecimal(10100, 3).Clone(), Count: 3}, }, { name: "middlevals", columnIDs: []uint64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, values: []float64{10.1, 20.2, 10.1, 10.1, 20.2, 11, 12, 11, 13, 11}, - expMax: ValCount{Val: 20200, DecimalVal: &pql.Decimal{Value: 20200, Scale: 3}, Count: 2}, - expMin: ValCount{Val: 10100, DecimalVal: &pql.Decimal{Value: 10100, Scale: 3}, Count: 3}, + expMax: ValCount{Val: 20200, DecimalVal: pql.NewDecimal(20200, 3).Clone(), Count: 2}, + expMin: ValCount{Val: 10100, DecimalVal: pql.NewDecimal(10100, 3).Clone(), Count: 3}, }, } { t.Run(test.name+strconv.Itoa(i), func(t *testing.T) { diff --git a/field_test.go b/field_test.go index 635ab7e7c..1c602416a 100644 --- a/field_test.go +++ b/field_test.go @@ -279,10 +279,23 @@ func TestField_ClearValue(t *testing.T) { func TestFieldInfoMarshal(t *testing.T) { f := &pilosa.FieldInfo{Name: "timestamp", CreatedAt: 1649270079233541000, - Options: pilosa.FieldOptions{Base: 0, BitDepth: 0x0, Min: pql.Decimal{Value: -4294967296, - Scale: 0}, Max: pql.Decimal{Value: 4294967296, Scale: 0}, Scale: 0, Keys: false, - NoStandardView: false, CacheType: "", Type: "timestamp", TimeUnit: "s", - TimeQuantum: "", ForeignIndex: "", TTL: 0}, Cardinality: (*uint64)(nil)} + Options: pilosa.FieldOptions{ + Base: 0, + BitDepth: 0x0, + Min: pql.NewDecimal(-4294967296, 0), + Max: pql.NewDecimal(4294967296, 0), + Scale: 0, + Keys: false, + NoStandardView: false, + CacheType: "", + Type: "timestamp", + TimeUnit: "s", + TimeQuantum: "", + ForeignIndex: "", + TTL: 0, + }, + Cardinality: (*uint64)(nil), + } a, err := json.Marshal(f) if err != nil { t.Fatalf("unexpected error marshalling index info, %v", err) diff --git a/index.go b/index.go index 1c4bb268a..21c85b7fd 100644 --- a/index.go +++ b/index.go @@ -4,6 +4,7 @@ package pilosa import ( "context" "fmt" + "math/big" "os" "path/filepath" "sort" @@ -651,12 +652,15 @@ func (i *Index) CreateFieldIfNotExistsWithOptions(name string, opt *FieldOptions if opt != nil && (opt.Type == FieldTypeInt || opt.Type == FieldTypeTimestamp) { min, max := pql.MinMax(0) // ensure the provided bounds are valid - if opt.Max.Value == 0 { + zero := big.NewInt(0) + maxv := opt.Max.Value() + if maxv.Cmp(zero) == 0 { opt.Max = max } else if max.LessThan(opt.Max) { opt.Max = max } - if opt.Min.Value == 0 { + minv := opt.Min.Value() + if minv.Cmp(zero) == 0 { opt.Min = min } else if min.GreaterThan(opt.Min) { opt.Min = min @@ -665,14 +669,18 @@ func (i *Index) CreateFieldIfNotExistsWithOptions(name string, opt *FieldOptions // added for backward compatablity with old schemas if opt != nil && opt.Type == FieldTypeDecimal { min, max := pql.MinMax(opt.Scale) + zero := big.NewInt(0) + // ensure the provided bounds are valid - if opt.Max.Value == 0 { + maxv := opt.Max.Value() + if maxv.Cmp(zero) == 0 { opt.Max = max } else if max.LessThan(opt.Max) { opt.Max = max } - if opt.Min.Value == 0 { + minv := opt.Min.Value() + if minv.Cmp(zero) == 0 { opt.Min = min } else if min.GreaterThan(opt.Min) { opt.Min = min diff --git a/index_test.go b/index_test.go index a979cb487..cf4955a67 100644 --- a/index_test.go +++ b/index_test.go @@ -203,7 +203,7 @@ func TestIndex_CreateField(t *testing.T) { t.Run("DecimalField", func(t *testing.T) { index := test.MustOpenIndex(t) - _, err := index.CreateField("f", pilosa.OptFieldTypeDecimal(1, pql.Decimal{Value: -1}, pql.Decimal{Value: 1}), pilosa.OptFieldKeys()) + _, err := index.CreateField("f", pilosa.OptFieldTypeDecimal(1, pql.NewDecimal(-1, 0), pql.NewDecimal(1, 0)), pilosa.OptFieldKeys()) if errors.Cause(err) != pilosa.ErrDecimalFieldWithKeys { t.Fatal("decimal field cannot be created with keys=true") } diff --git a/pb/public.pb.go b/pb/public.pb.go index 818b26892..f4bab252a 100644 --- a/pb/public.pb.go +++ b/pb/public.pb.go @@ -1243,8 +1243,7 @@ func (m *ValCount) GetTimestampVal() string { } type Decimal struct { - Value int64 `protobuf:"varint,1,opt,name=Value,proto3" json:"Value,omitempty"` - Scale int64 `protobuf:"varint,2,opt,name=Scale,proto3" json:"Scale,omitempty"` + Gob []byte `protobuf:"bytes,1,opt,name=Gob,proto3" json:"Gob,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1283,18 +1282,11 @@ func (m *Decimal) XXX_DiscardUnknown() { var xxx_messageInfo_Decimal proto.InternalMessageInfo -func (m *Decimal) GetValue() int64 { +func (m *Decimal) GetGob() []byte { if m != nil { - return m.Value + return m.Gob } - return 0 -} - -func (m *Decimal) GetScale() int64 { - if m != nil { - return m.Scale - } - return 0 + return nil } type DistinctTimestamp struct { @@ -2657,113 +2649,113 @@ func init() { func init() { proto.RegisterFile("public.proto", fileDescriptor_413a91106d7bcce8) } var fileDescriptor_413a91106d7bcce8 = []byte{ - // 1694 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0x5b, 0x6f, 0x23, 0x49, - 0x15, 0x4e, 0x5f, 0x7c, 0x3b, 0x76, 0x9c, 0xa4, 0x36, 0xbb, 0xf4, 0x0e, 0x59, 0xe3, 0x6d, 0xa1, - 0xc5, 0x4b, 0x50, 0x56, 0x18, 0x18, 0xa1, 0x91, 0x60, 0x14, 0xc7, 0x19, 0x62, 0xcd, 0x24, 0x33, - 0x94, 0x43, 0xe0, 0x61, 0x5e, 0x3a, 0x76, 0xe1, 0x69, 0xd1, 0x76, 0x9b, 0xee, 0xf6, 0x38, 0xf9, - 0x01, 0x08, 0x7e, 0x02, 0x6f, 0xfc, 0x1a, 0x04, 0x6f, 0xf0, 0xc8, 0x23, 0x1a, 0xde, 0xf8, 0x15, - 0xe8, 0x9c, 0xaa, 0xea, 0x9b, 0x9d, 0xd1, 0x68, 0xc4, 0x5b, 0x9f, 0x4b, 0x9d, 0xaa, 0xf3, 0x9d, - 0xab, 0x0d, 0xad, 0xe5, 0xea, 0x36, 0xf0, 0x27, 0x27, 0xcb, 0x28, 0x4c, 0x42, 0x66, 0x2e, 0x6f, - 0xdd, 0x7b, 0xb0, 0x78, 0xb8, 0x66, 0x0e, 0xd4, 0xce, 0xc2, 0x60, 0x35, 0x5f, 0xc4, 0x8e, 0xd1, - 0xb5, 0x7a, 0x36, 0xd7, 0x24, 0x63, 0x60, 0x3f, 0x17, 0xf7, 0xb1, 0x63, 0x75, 0xad, 0x5e, 0x83, - 0xd3, 0x37, 0x6a, 0xf3, 0xd0, 0x8b, 0xfc, 0xc5, 0xcc, 0xb1, 0xbb, 0x46, 0xaf, 0xc5, 0x35, 0xc9, - 0x0e, 0xa1, 0x32, 0x5a, 0x4c, 0xc5, 0x9d, 0x53, 0xe9, 0x1a, 0xbd, 0x06, 0x97, 0x04, 0x72, 0x9f, - 0xf9, 0x22, 0x98, 0x3a, 0x55, 0xc9, 0x25, 0xc2, 0xed, 0x41, 0x83, 0x87, 0xeb, 0x4b, 0x2f, 0x89, - 0xfc, 0x3b, 0xf6, 0x6d, 0xb0, 0x79, 0xb8, 0x96, 0xb7, 0x37, 0xfb, 0xb5, 0x93, 0xe5, 0xed, 0x09, - 0x0f, 0xd7, 0x9c, 0x98, 0xee, 0x29, 0x34, 0xc6, 0xfe, 0x6c, 0x21, 0xa6, 0xf8, 0xd4, 0xcf, 0xc1, - 0x7a, 0x15, 0xa2, 0xa2, 0x91, 0x57, 0x44, 0x1e, 0x8a, 0xae, 0xc4, 0xcc, 0x31, 0x4b, 0xa2, 0x2b, - 0x31, 0x73, 0x7f, 0x0a, 0x6d, 0x1e, 0xae, 0x47, 0x53, 0xb1, 0x48, 0xfc, 0xdf, 0xfa, 0x22, 0x22, - 0xc7, 0xd2, 0x1b, 0x6d, 0x79, 0x51, 0xea, 0xac, 0x99, 0x39, 0xeb, 0x3e, 0x82, 0xea, 0x68, 0xf8, - 0xc2, 0x8f, 0x13, 0xb6, 0x0f, 0xd6, 0x68, 0xa8, 0x0f, 0xe0, 0xa7, 0x7b, 0x06, 0x07, 0xe7, 0x77, - 0x49, 0xe4, 0x4d, 0x12, 0x31, 0x1d, 0x0d, 0x25, 0x64, 0xac, 0x0d, 0xe6, 0x68, 0x48, 0xef, 0xb3, - 0xb9, 0x39, 0x1a, 0xb2, 0x0e, 0xd8, 0x37, 0x5e, 0x20, 0x8d, 0x36, 0xfb, 0x80, 0xcf, 0x92, 0x06, - 0x39, 0xf1, 0xdd, 0xd7, 0x05, 0x23, 0x0a, 0x8f, 0xcf, 0xa0, 0x4a, 0x28, 0xc9, 0xeb, 0x1a, 0x5c, - 0x51, 0xec, 0x9b, 0x2c, 0x50, 0xd2, 0xde, 0xa7, 0x68, 0x6f, 0xe3, 0x11, 0x69, 0xfc, 0xdc, 0x2f, - 0xa0, 0xf6, 0x5c, 0xdc, 0xd3, 0xfb, 0xb5, 0x77, 0x46, 0xce, 0xbb, 0x7f, 0x18, 0xf0, 0x49, 0x7a, - 0xfa, 0xda, 0xbb, 0x0d, 0xc4, 0x8d, 0x17, 0xac, 0x04, 0xeb, 0x68, 0x5f, 0x8d, 0xe2, 0x9b, 0x2f, - 0x76, 0xc8, 0x73, 0xf6, 0x65, 0x8a, 0x14, 0x2a, 0x34, 0x51, 0x41, 0x5d, 0x73, 0xb1, 0xa3, 0xb2, - 0xe4, 0x08, 0xea, 0x83, 0xf1, 0x88, 0xcc, 0x39, 0x56, 0xd7, 0xe8, 0x59, 0x17, 0x3b, 0x3c, 0xe5, - 0xb0, 0x47, 0x50, 0xbb, 0x5c, 0x25, 0xe2, 0x6e, 0x34, 0xa4, 0x1c, 0xb2, 0x2f, 0x76, 0xb8, 0x66, - 0xe0, 0x49, 0xfa, 0x7c, 0x2e, 0xee, 0x65, 0x22, 0xe1, 0x49, 0xcd, 0x61, 0x87, 0x60, 0x0f, 0xc2, - 0x30, 0xa0, 0x64, 0xaa, 0xe3, 0x6d, 0x48, 0x0d, 0x6a, 0x50, 0x21, 0xc3, 0xee, 0x1d, 0x1c, 0x16, - 0x1d, 0x52, 0x61, 0x61, 0x60, 0xa1, 0x3d, 0x43, 0xd9, 0x43, 0x82, 0xed, 0x53, 0xa8, 0x4c, 0x75, - 0x3f, 0x06, 0xeb, 0x1b, 0xa8, 0x92, 0x19, 0x99, 0xf0, 0xcd, 0xfe, 0xb7, 0x0a, 0xf0, 0x66, 0x00, - 0x71, 0xa5, 0x36, 0x68, 0x10, 0xbe, 0x2f, 0xa3, 0xd1, 0xd0, 0xfd, 0x59, 0x19, 0x4a, 0x8a, 0x19, - 0xc2, 0x7e, 0xe5, 0xcd, 0x85, 0xbc, 0x99, 0xd3, 0x37, 0xf2, 0xae, 0xef, 0x97, 0x82, 0xae, 0x6e, - 0x70, 0xfa, 0x76, 0x57, 0xd0, 0x2e, 0x1e, 0xc7, 0xc7, 0xe4, 0x92, 0x60, 0xeb, 0x63, 0x48, 0x9e, - 0x66, 0x47, 0xbf, 0x9c, 0x1d, 0xce, 0xe6, 0x89, 0x72, 0x82, 0xfc, 0x1c, 0xec, 0x57, 0x9e, 0x1f, - 0x6d, 0xa4, 0xed, 0xbe, 0xc4, 0xcb, 0xa2, 0x17, 0x5a, 0x12, 0xf8, 0xca, 0x59, 0xb8, 0x5a, 0x24, - 0x12, 0x30, 0x2e, 0x09, 0xf7, 0x29, 0x34, 0xf0, 0xbc, 0xf4, 0xf5, 0x48, 0x1a, 0x53, 0x79, 0x53, - 0xc7, 0xdb, 0x91, 0xe6, 0xf2, 0x8a, 0xb4, 0x0f, 0x98, 0xf9, 0x3e, 0x30, 0x00, 0x40, 0x69, 0x2c, - 0x2d, 0x74, 0xa0, 0x42, 0x94, 0x72, 0x39, 0x33, 0x21, 0xd9, 0x0f, 0xd8, 0xf8, 0x02, 0xfb, 0x4e, - 0xf2, 0xf8, 0xc7, 0x28, 0x96, 0x19, 0x87, 0x2f, 0xb0, 0xb8, 0xca, 0x89, 0x10, 0xea, 0x12, 0xa8, - 0x70, 0x9d, 0x19, 0x30, 0x72, 0x06, 0x90, 0x8b, 0xfd, 0x61, 0xa8, 0x7d, 0x23, 0x02, 0xab, 0x90, - 0x87, 0xeb, 0x0c, 0x06, 0x45, 0xb1, 0xef, 0xe8, 0x5b, 0x6c, 0xf2, 0xb3, 0x41, 0xf5, 0x81, 0xf7, - 0xeb, 0x0b, 0x7f, 0x03, 0xf0, 0x8b, 0x28, 0x5c, 0x2d, 0x09, 0x22, 0xe6, 0x42, 0x85, 0x28, 0xe5, - 0x53, 0x0b, 0xd5, 0xf5, 0x7b, 0xb8, 0x14, 0x6d, 0x07, 0x17, 0x83, 0x70, 0x3a, 0x9b, 0xc9, 0xf2, - 0xe1, 0xf8, 0xe9, 0xfe, 0xc5, 0x80, 0xfa, 0x8d, 0x17, 0xa4, 0xe2, 0x1b, 0x2f, 0x50, 0xbe, 0xe2, - 0x67, 0xd1, 0x8c, 0xa5, 0xcd, 0x3c, 0x82, 0xfa, 0xb3, 0x20, 0xf4, 0x12, 0x54, 0x46, 0x5b, 0x06, - 0x4f, 0x69, 0x76, 0x0c, 0x30, 0x14, 0x13, 0x7f, 0xee, 0x05, 0x28, 0xb5, 0xb3, 0x7a, 0x56, 0x5c, - 0x9e, 0x13, 0x33, 0x17, 0x5a, 0xd7, 0xfe, 0x5c, 0xc4, 0x89, 0x37, 0x5f, 0xa2, 0xba, 0x6c, 0xf3, - 0x05, 0x9e, 0xfb, 0x13, 0xa8, 0xa9, 0x13, 0xdb, 0xa3, 0x81, 0xdc, 0xf1, 0xc4, 0x0b, 0x84, 0x7e, - 0x23, 0x11, 0xee, 0x53, 0x38, 0x18, 0xfa, 0x71, 0xe2, 0x2f, 0x26, 0x49, 0x6a, 0x0e, 0x03, 0xa0, - 0xca, 0x51, 0xb5, 0x41, 0x49, 0xa5, 0x35, 0x65, 0x66, 0x35, 0xe5, 0xfe, 0xd5, 0x80, 0xd6, 0x2f, - 0x57, 0x22, 0xba, 0xe7, 0xe2, 0xf7, 0x2b, 0x11, 0x27, 0x78, 0x0f, 0xd1, 0x3a, 0xd2, 0x44, 0xa0, - 0xc9, 0xf1, 0x1b, 0x2f, 0x9a, 0xca, 0x12, 0xb1, 0xb9, 0xa2, 0x28, 0xd6, 0x62, 0x1e, 0x26, 0x82, - 0x9c, 0xaa, 0x73, 0x45, 0xb1, 0x63, 0x68, 0x9d, 0xcf, 0x6f, 0xc5, 0x74, 0x2a, 0xa6, 0x43, 0x2f, - 0xf1, 0x9c, 0x7a, 0x71, 0x42, 0x15, 0x84, 0xec, 0xbb, 0xb0, 0xfb, 0x2a, 0x12, 0xd7, 0x91, 0xb7, - 0x88, 0x03, 0x2f, 0x11, 0x53, 0xa7, 0x41, 0xb6, 0x8a, 0x4c, 0x76, 0x04, 0x8d, 0x4b, 0xef, 0xee, - 0x52, 0xcc, 0xc3, 0xe8, 0xde, 0x01, 0x02, 0x21, 0x63, 0xb8, 0x2f, 0x60, 0x57, 0xb9, 0x11, 0x2f, - 0xc3, 0x45, 0x2c, 0x30, 0xca, 0xe7, 0x51, 0xa4, 0xbc, 0xc0, 0x4f, 0xf6, 0x35, 0xd4, 0xb8, 0x88, - 0x57, 0x41, 0xa2, 0xeb, 0x7c, 0x0f, 0x9f, 0xa3, 0x4f, 0xad, 0x82, 0x84, 0x6b, 0xb9, 0xfb, 0xdf, - 0x0a, 0x34, 0x73, 0x82, 0xb4, 0xf3, 0x60, 0xf7, 0xdc, 0x95, 0x9d, 0x07, 0xe7, 0x26, 0x0f, 0xd7, - 0x1b, 0x23, 0x15, 0xab, 0xa5, 0x05, 0xc6, 0x95, 0x4a, 0x49, 0xe3, 0x2a, 0x2b, 0x4e, 0x6b, 0x7b, - 0x71, 0xe2, 0x1a, 0xf1, 0xc6, 0x5b, 0xcc, 0xc4, 0x94, 0x12, 0xa9, 0xce, 0x35, 0xc9, 0x7a, 0x59, - 0xd6, 0x12, 0xbe, 0xaa, 0x0a, 0x34, 0x8f, 0x67, 0x39, 0x2d, 0x6b, 0x0e, 0x87, 0x4f, 0x4d, 0xc6, - 0x47, 0x52, 0xec, 0x31, 0xb4, 0x5f, 0x06, 0xd3, 0xac, 0xaa, 0x62, 0x15, 0x89, 0x36, 0xda, 0xc9, - 0xd8, 0xbc, 0xa4, 0xc5, 0x9e, 0x94, 0x27, 0x3f, 0xc5, 0xa4, 0xd9, 0x67, 0xca, 0xcf, 0x9c, 0x84, - 0x97, 0x77, 0x84, 0xe3, 0xdc, 0xe2, 0x41, 0x81, 0x6a, 0xf6, 0x77, 0xf1, 0x58, 0xca, 0xe4, 0xb9, - 0xc5, 0xe4, 0x24, 0xdf, 0xc7, 0x9c, 0x26, 0x69, 0xb7, 0x35, 0x42, 0x92, 0xcb, 0xf3, 0x9d, 0xee, - 0x38, 0xd7, 0x38, 0x9d, 0x56, 0x66, 0x3c, 0x65, 0xf2, 0x5c, 0x63, 0x3d, 0xdb, 0xb2, 0x24, 0x38, - 0xbb, 0x74, 0xa8, 0xbc, 0x01, 0x48, 0x21, 0xdf, 0xb2, 0x54, 0x3c, 0x29, 0x4f, 0x18, 0xa7, 0x9d, - 0x41, 0x51, 0x94, 0xf0, 0xf2, 0x2c, 0x3a, 0xce, 0x6d, 0x6b, 0xce, 0x5e, 0xf6, 0xda, 0x94, 0xc9, - 0x73, 0xdb, 0xdc, 0x0f, 0xa1, 0x99, 0x0f, 0xd4, 0x3e, 0xa9, 0xef, 0x15, 0x03, 0x15, 0xf3, 0xbc, - 0x0e, 0x3a, 0xb8, 0x51, 0xfe, 0xce, 0x41, 0xe6, 0xe0, 0x86, 0x90, 0x6f, 0xea, 0xbb, 0x7f, 0x33, - 0x61, 0x77, 0x34, 0x5f, 0x86, 0x51, 0x92, 0xeb, 0x01, 0x72, 0x21, 0x35, 0xb6, 0x2e, 0xa4, 0x66, - 0x69, 0x06, 0x50, 0x2f, 0xa0, 0x16, 0x69, 0x73, 0x49, 0xe4, 0xf2, 0xd1, 0x2e, 0xe4, 0xe3, 0x11, - 0x34, 0xe4, 0x08, 0x45, 0x51, 0x85, 0x44, 0x19, 0x43, 0xae, 0xc8, 0x6b, 0x5a, 0x91, 0x6a, 0xd4, - 0xb9, 0x34, 0xc9, 0x3a, 0x00, 0x52, 0x8d, 0x84, 0x75, 0x12, 0xe6, 0x38, 0x28, 0x4f, 0x1d, 0x8a, - 0x9d, 0x6a, 0xd7, 0xea, 0x59, 0x3c, 0xc7, 0x61, 0x5f, 0x41, 0x9b, 0x9c, 0x38, 0x8b, 0x04, 0x36, - 0x93, 0xd3, 0x84, 0xf2, 0xd9, 0xe2, 0x25, 0x2e, 0xea, 0x91, 0x5b, 0x99, 0x9e, 0xec, 0x34, 0x25, - 0x2e, 0x4d, 0x8c, 0x40, 0x78, 0x11, 0x65, 0x6c, 0x9d, 0x4b, 0xc2, 0xfd, 0x97, 0x09, 0x4c, 0x22, - 0x29, 0xd7, 0x9d, 0xff, 0x1b, 0x9c, 0xef, 0x87, 0xad, 0x08, 0x4e, 0x6d, 0x03, 0x9c, 0x6c, 0x1e, - 0x48, 0x60, 0xf4, 0x3c, 0xe8, 0x42, 0x53, 0x0f, 0x34, 0x14, 0x22, 0xaa, 0x06, 0xcf, 0xb3, 0x70, - 0x72, 0x8d, 0x13, 0xfc, 0x8d, 0xa2, 0x54, 0x1a, 0x64, 0xbb, 0xc0, 0xdb, 0x02, 0x2d, 0x7c, 0x20, - 0xb4, 0xcd, 0xf7, 0x43, 0xdb, 0xca, 0x43, 0xfb, 0x47, 0x03, 0x5a, 0xa7, 0x49, 0x38, 0xf7, 0x27, - 0x5c, 0x4c, 0xc2, 0x68, 0xfa, 0x30, 0xa8, 0x12, 0x3e, 0x33, 0x0f, 0x5f, 0x0f, 0xac, 0xd1, 0xdb, - 0x48, 0xf5, 0xdf, 0xcf, 0x68, 0xef, 0xd8, 0x88, 0x12, 0x47, 0x15, 0xf6, 0x25, 0x98, 0xa3, 0x88, - 0x72, 0xb6, 0xd9, 0x3f, 0xc8, 0x14, 0xb5, 0x8e, 0x39, 0x8a, 0xdc, 0x1f, 0xc0, 0xa1, 0x7c, 0x88, - 0x16, 0xa9, 0x81, 0x73, 0x08, 0x95, 0xf3, 0x28, 0x0a, 0xf5, 0xc8, 0x91, 0x04, 0x2e, 0xd6, 0xe9, - 0x0c, 0xc3, 0x60, 0x7c, 0x4c, 0x4e, 0x6c, 0xfb, 0x35, 0xd9, 0x85, 0xe6, 0x55, 0x98, 0xfc, 0x3a, - 0xf2, 0x13, 0x6a, 0x49, 0x72, 0x70, 0xe4, 0x59, 0xee, 0xd7, 0xf0, 0x69, 0xe9, 0xe6, 0x6c, 0x32, - 0x62, 0x1a, 0x59, 0xd9, 0x2f, 0xb2, 0x31, 0x7c, 0x92, 0xaa, 0x8e, 0x86, 0x1f, 0xf5, 0xc6, 0x4d, - 0xa3, 0xdf, 0xcf, 0x79, 0x4e, 0x46, 0xd5, 0xf5, 0x5b, 0xbc, 0x71, 0x07, 0xe0, 0x28, 0x34, 0xe5, - 0x4f, 0x62, 0xf5, 0x82, 0x1b, 0x5f, 0xac, 0x1f, 0xfa, 0x25, 0x40, 0x6b, 0x85, 0x49, 0x3f, 0xa4, - 0xe9, 0xdb, 0xfd, 0x93, 0x09, 0x87, 0xdb, 0x8c, 0x64, 0x09, 0x65, 0xe4, 0x12, 0x8a, 0xf5, 0xa1, - 0xf2, 0xd6, 0x17, 0x6b, 0xbd, 0x0b, 0x1c, 0xe5, 0x82, 0xbd, 0xf1, 0x06, 0x2e, 0x55, 0xb1, 0x90, - 0x4e, 0x27, 0x89, 0x1f, 0x2e, 0xf4, 0x66, 0x2b, 0x29, 0xbc, 0x61, 0x10, 0x84, 0x93, 0xdf, 0xc9, - 0x1f, 0x65, 0x5c, 0x12, 0x5b, 0x0a, 0xa3, 0xf2, 0x81, 0x85, 0x51, 0xdd, 0x5a, 0x18, 0x3d, 0xd8, - 0xfb, 0xd5, 0x72, 0xea, 0x25, 0xe2, 0xfc, 0xce, 0x8f, 0x13, 0xb1, 0x98, 0x08, 0xa7, 0x46, 0x1e, - 0x95, 0xd9, 0xee, 0x1f, 0x0c, 0xd8, 0x55, 0x5e, 0x48, 0xd1, 0x03, 0xfb, 0x3b, 0x03, 0x1b, 0xdd, - 0xd3, 0x0b, 0x21, 0xc1, 0x9d, 0xa2, 0x65, 0x11, 0xb6, 0x0a, 0xad, 0x7d, 0xb0, 0xc6, 0x22, 0x51, - 0x7f, 0x5c, 0xe0, 0x27, 0xb6, 0x06, 0x12, 0xc9, 0x72, 0x8c, 0xd5, 0xfe, 0x57, 0xe0, 0xb9, 0xaf, - 0xe1, 0xf3, 0x02, 0xa4, 0x54, 0x8d, 0x3a, 0x2c, 0xd9, 0xea, 0x68, 0x14, 0x56, 0xc7, 0xef, 0x41, - 0xe5, 0x26, 0x17, 0x98, 0x03, 0x39, 0x2f, 0x73, 0xce, 0x70, 0x29, 0x77, 0xc7, 0x85, 0x79, 0x89, - 0x3d, 0xf2, 0x74, 0x36, 0x8b, 0xc4, 0xcc, 0x4b, 0x74, 0xb2, 0x64, 0x0c, 0xf6, 0x15, 0x54, 0x49, - 0x59, 0x9b, 0x2d, 0x2f, 0x40, 0x4a, 0x3a, 0xd8, 0xff, 0xfb, 0xbb, 0x8e, 0xf1, 0xcf, 0x77, 0x1d, - 0xe3, 0xdf, 0xef, 0x3a, 0xc6, 0x9f, 0xff, 0xd3, 0xd9, 0xb9, 0xad, 0xd2, 0xff, 0x3e, 0x3f, 0xfa, - 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x48, 0x84, 0x6e, 0xe4, 0x07, 0x12, 0x00, 0x00, + // 1692 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0x4b, 0x6f, 0x1b, 0xd7, + 0x15, 0xd6, 0x3c, 0xf8, 0x3a, 0xa4, 0x28, 0xe9, 0x5a, 0x76, 0xc7, 0xb6, 0xcc, 0xd2, 0x83, 0xc2, + 0xa5, 0xab, 0x42, 0x46, 0xd9, 0xc2, 0x28, 0x0c, 0xb4, 0x86, 0x28, 0xca, 0x16, 0x61, 0x4b, 0x76, + 0xaf, 0x54, 0xb5, 0x0b, 0x6f, 0x46, 0xe4, 0x2d, 0x3d, 0xe8, 0x90, 0xc3, 0xcc, 0x0c, 0x4d, 0xe9, + 0x07, 0x04, 0xc9, 0x4f, 0xc8, 0x2e, 0xbf, 0x26, 0x48, 0x76, 0xc9, 0x32, 0xcb, 0xc0, 0xd9, 0xe5, + 0x57, 0x04, 0xe7, 0xdc, 0x3b, 0x4f, 0x52, 0x86, 0x61, 0x64, 0x37, 0xe7, 0x71, 0xcf, 0xbd, 0xe7, + 0x3b, 0x4f, 0x12, 0x1a, 0xb3, 0xf9, 0x85, 0xe7, 0x0e, 0xf7, 0x66, 0x81, 0x1f, 0xf9, 0x4c, 0x9f, + 0x5d, 0xd8, 0x57, 0x60, 0x70, 0x7f, 0xc1, 0x2c, 0xa8, 0x1c, 0xf8, 0xde, 0x7c, 0x32, 0x0d, 0x2d, + 0xad, 0x6d, 0x74, 0x4c, 0x1e, 0x93, 0x8c, 0x81, 0xf9, 0x42, 0x5c, 0x85, 0x96, 0xd1, 0x36, 0x3a, + 0x35, 0x4e, 0xdf, 0xa8, 0xcd, 0x7d, 0x27, 0x70, 0xa7, 0x63, 0xcb, 0x6c, 0x6b, 0x9d, 0x06, 0x8f, + 0x49, 0xb6, 0x0d, 0xa5, 0xc1, 0x74, 0x24, 0x2e, 0xad, 0x52, 0x5b, 0xeb, 0xd4, 0xb8, 0x24, 0x90, + 0xfb, 0xcc, 0x15, 0xde, 0xc8, 0x2a, 0x4b, 0x2e, 0x11, 0x76, 0x07, 0x6a, 0xdc, 0x5f, 0x1c, 0x3b, + 0x51, 0xe0, 0x5e, 0xb2, 0xbb, 0x60, 0x72, 0x7f, 0x21, 0x6f, 0xaf, 0x77, 0x2b, 0x7b, 0xb3, 0x8b, + 0x3d, 0xee, 0x2f, 0x38, 0x31, 0xed, 0x7d, 0xa8, 0x9d, 0xba, 0xe3, 0xa9, 0x18, 0xe1, 0x53, 0x6f, + 0x83, 0xf1, 0xda, 0x47, 0x45, 0x2d, 0xab, 0x88, 0x3c, 0x14, 0x9d, 0x88, 0xb1, 0xa5, 0x17, 0x44, + 0x27, 0x62, 0x6c, 0xff, 0x1d, 0x9a, 0xdc, 0x5f, 0x0c, 0x46, 0x62, 0x1a, 0xb9, 0xff, 0x73, 0x45, + 0x40, 0x8e, 0x25, 0x37, 0x9a, 0xf2, 0xa2, 0xc4, 0x59, 0x3d, 0x75, 0xd6, 0xbe, 0x03, 0xe5, 0x41, + 0xff, 0xa5, 0x1b, 0x46, 0x6c, 0x13, 0x8c, 0x41, 0x3f, 0x3e, 0x80, 0x9f, 0xf6, 0x01, 0x6c, 0x1d, + 0x5e, 0x46, 0x81, 0x33, 0x8c, 0xc4, 0x68, 0xd0, 0x97, 0x90, 0xb1, 0x26, 0xe8, 0x83, 0x3e, 0xbd, + 0xcf, 0xe4, 0xfa, 0xa0, 0xcf, 0x5a, 0x60, 0x9e, 0x3b, 0x9e, 0x34, 0x5a, 0xef, 0x02, 0x3e, 0x4b, + 0x1a, 0xe4, 0xc4, 0xb7, 0xdf, 0xe4, 0x8c, 0x28, 0x3c, 0x6e, 0x41, 0x99, 0x50, 0x92, 0xd7, 0xd5, + 0xb8, 0xa2, 0xd8, 0xa3, 0x34, 0x50, 0xd2, 0xde, 0x4d, 0xb4, 0xb7, 0xf4, 0x88, 0x24, 0x7e, 0xf6, + 0x3d, 0xa8, 0xbc, 0x10, 0x57, 0xf4, 0xfe, 0xd8, 0x3b, 0x2d, 0xe3, 0xdd, 0xf7, 0x1a, 0xdc, 0x48, + 0x4e, 0x9f, 0x39, 0x17, 0x9e, 0x38, 0x77, 0xbc, 0xb9, 0x60, 0xad, 0xd8, 0x57, 0x2d, 0xff, 0xe6, + 0xa3, 0x35, 0xf2, 0x9c, 0xdd, 0x4f, 0x90, 0x42, 0x85, 0x3a, 0x2a, 0xa8, 0x6b, 0x8e, 0xd6, 0x54, + 0x96, 0xec, 0x40, 0xb5, 0x77, 0x3a, 0x20, 0x73, 0x96, 0xd1, 0xd6, 0x3a, 0xc6, 0xd1, 0x1a, 0x4f, + 0x38, 0xec, 0x0e, 0x54, 0x8e, 0xe7, 0x91, 0xb8, 0x1c, 0xf4, 0x29, 0x87, 0xcc, 0xa3, 0x35, 0x1e, + 0x33, 0xf0, 0x24, 0x7d, 0xbe, 0x10, 0x57, 0x32, 0x91, 0xf0, 0x64, 0xcc, 0x61, 0xdb, 0x60, 0xf6, + 0x7c, 0xdf, 0xa3, 0x64, 0xaa, 0xe2, 0x6d, 0x48, 0xf5, 0x2a, 0x50, 0x22, 0xc3, 0xf6, 0x25, 0x6c, + 0xe7, 0x1d, 0x52, 0x61, 0x61, 0x60, 0xa0, 0x3d, 0x4d, 0xd9, 0x43, 0x82, 0x6d, 0x52, 0xa8, 0x74, + 0x75, 0x3f, 0x06, 0xeb, 0x11, 0x94, 0xc9, 0x8c, 0x4c, 0xf8, 0x7a, 0xf7, 0x77, 0x39, 0x78, 0x53, + 0x80, 0xb8, 0x52, 0xeb, 0xd5, 0x08, 0xdf, 0x57, 0xc1, 0xa0, 0x6f, 0xff, 0xa3, 0x08, 0x25, 0xc5, + 0x0c, 0x61, 0x3f, 0x71, 0x26, 0x42, 0xde, 0xcc, 0xe9, 0x1b, 0x79, 0x67, 0x57, 0x33, 0x41, 0x57, + 0xd7, 0x38, 0x7d, 0xdb, 0x73, 0x68, 0xe6, 0x8f, 0xe3, 0x63, 0x32, 0x49, 0xb0, 0xf2, 0x31, 0x24, + 0x4f, 0xb2, 0xa3, 0x5b, 0xcc, 0x0e, 0x6b, 0xf9, 0x44, 0x31, 0x41, 0xfe, 0x09, 0xe6, 0x6b, 0xc7, + 0x0d, 0x96, 0xd2, 0x76, 0x53, 0xe2, 0x65, 0xd0, 0x0b, 0x0d, 0x09, 0x7c, 0xe9, 0xc0, 0x9f, 0x4f, + 0x23, 0x09, 0x18, 0x97, 0x84, 0xfd, 0x14, 0x6a, 0x78, 0x5e, 0xfa, 0xba, 0x23, 0x8d, 0xa9, 0xbc, + 0xa9, 0xe2, 0xed, 0x48, 0x73, 0x79, 0x45, 0xd2, 0x07, 0xf4, 0x6c, 0x1f, 0xe8, 0x01, 0xa0, 0x34, + 0x94, 0x16, 0x5a, 0x50, 0x22, 0x4a, 0xb9, 0x9c, 0x9a, 0x90, 0xec, 0x6b, 0x6c, 0xdc, 0xc3, 0xbe, + 0x13, 0x3d, 0xfe, 0x1b, 0x8a, 0x65, 0xc6, 0xe1, 0x0b, 0x0c, 0xae, 0x72, 0xc2, 0x87, 0xaa, 0x04, + 0xca, 0x5f, 0xa4, 0x06, 0xb4, 0x8c, 0x01, 0xe4, 0x62, 0x7f, 0xe8, 0xc7, 0xbe, 0x11, 0x81, 0x55, + 0xc8, 0xfd, 0x45, 0x0a, 0x83, 0xa2, 0xd8, 0xef, 0xe3, 0x5b, 0x4c, 0xf2, 0xb3, 0x46, 0xf5, 0x81, + 0xf7, 0xc7, 0x17, 0xfe, 0x17, 0xe0, 0x79, 0xe0, 0xcf, 0x67, 0x04, 0x11, 0xb3, 0xa1, 0x44, 0x94, + 0xf2, 0xa9, 0x81, 0xea, 0xf1, 0x7b, 0xb8, 0x14, 0xad, 0x06, 0x17, 0x83, 0xb0, 0x3f, 0x1e, 0xcb, + 0xf2, 0xe1, 0xf8, 0x69, 0x7f, 0xad, 0x41, 0xf5, 0xdc, 0xf1, 0x12, 0xf1, 0xb9, 0xe3, 0x29, 0x5f, + 0xf1, 0x33, 0x6f, 0xc6, 0x88, 0xcd, 0xdc, 0x81, 0xea, 0x33, 0xcf, 0x77, 0x22, 0x54, 0x46, 0x5b, + 0x1a, 0x4f, 0x68, 0xb6, 0x0b, 0xd0, 0x17, 0x43, 0x77, 0xe2, 0x78, 0x28, 0x35, 0xd3, 0x7a, 0x56, + 0x5c, 0x9e, 0x11, 0x33, 0x1b, 0x1a, 0x67, 0xee, 0x44, 0x84, 0x91, 0x33, 0x99, 0xa1, 0xba, 0x6c, + 0xf3, 0x39, 0x9e, 0x7d, 0x17, 0x2a, 0xea, 0x04, 0xbe, 0xef, 0xb9, 0x7f, 0x41, 0xef, 0x6b, 0x70, + 0xfc, 0xb4, 0x9f, 0xc2, 0x56, 0xdf, 0x0d, 0x23, 0x77, 0x3a, 0x8c, 0x92, 0x43, 0x08, 0xb3, 0x2a, + 0x3a, 0xd5, 0xec, 0x24, 0x95, 0x54, 0x8e, 0x9e, 0x56, 0x8e, 0xfd, 0x8d, 0x06, 0x8d, 0x7f, 0xcd, + 0x45, 0x70, 0xc5, 0xc5, 0x67, 0x73, 0x11, 0x46, 0xe8, 0x31, 0xd1, 0x71, 0x3c, 0x89, 0x40, 0x93, + 0xa7, 0x6f, 0x9d, 0x60, 0x24, 0x0b, 0xc1, 0xe4, 0x8a, 0xa2, 0x88, 0x8a, 0x89, 0x1f, 0x09, 0x7a, + 0x7a, 0x95, 0x2b, 0x8a, 0xed, 0x42, 0xe3, 0x70, 0x72, 0x21, 0x46, 0x23, 0x31, 0xea, 0x3b, 0x91, + 0x63, 0x55, 0xf3, 0x73, 0x28, 0x27, 0x64, 0x7f, 0x80, 0xf5, 0xd7, 0x81, 0x38, 0x0b, 0x9c, 0x69, + 0xe8, 0x39, 0x91, 0x18, 0x59, 0x35, 0xb2, 0x95, 0x67, 0xb2, 0x1d, 0xa8, 0x1d, 0x3b, 0x97, 0xc7, + 0x62, 0xe2, 0x07, 0x57, 0x16, 0x50, 0x38, 0x52, 0x86, 0xfd, 0x12, 0xd6, 0x95, 0x1b, 0xe1, 0xcc, + 0x9f, 0x86, 0x02, 0xb1, 0x3a, 0x0c, 0x02, 0xe5, 0x05, 0x7e, 0xb2, 0x87, 0x50, 0xe1, 0x22, 0x9c, + 0x7b, 0x51, 0x5c, 0xcd, 0x1b, 0xf8, 0x9c, 0xf8, 0xd4, 0xdc, 0x8b, 0x78, 0x2c, 0xb7, 0x7f, 0x29, + 0x41, 0x3d, 0x23, 0x48, 0xfa, 0x0b, 0xf6, 0xc8, 0x75, 0xd9, 0x5f, 0x70, 0x3a, 0x72, 0x7f, 0xb1, + 0x34, 0x38, 0xb1, 0x26, 0x1a, 0xa0, 0x9d, 0xa8, 0xc4, 0xd3, 0x4e, 0xd2, 0x12, 0x34, 0x56, 0x97, + 0x20, 0x2e, 0x0b, 0x6f, 0x9d, 0xe9, 0x58, 0x8c, 0x28, 0x5d, 0xaa, 0x3c, 0x26, 0x59, 0x27, 0xcd, + 0x4d, 0xc2, 0x57, 0xe5, 0x7a, 0xcc, 0xe3, 0x69, 0xe6, 0xca, 0xca, 0xc2, 0x11, 0x53, 0x91, 0xf1, + 0x91, 0x14, 0x7b, 0x0c, 0xcd, 0x57, 0xde, 0x28, 0xad, 0x9d, 0x50, 0x45, 0xa2, 0x89, 0x76, 0x52, + 0x36, 0x2f, 0x68, 0xb1, 0x27, 0xc5, 0xf9, 0x4e, 0x31, 0xa9, 0x77, 0x99, 0xf2, 0x33, 0x23, 0xe1, + 0xc5, 0x4d, 0x60, 0x37, 0xb3, 0x5e, 0x50, 0xa0, 0xea, 0xdd, 0x75, 0x3c, 0x96, 0x30, 0x79, 0x66, + 0xfd, 0xd8, 0xcb, 0x76, 0x2b, 0xab, 0x4e, 0xda, 0xcd, 0x18, 0x21, 0xc9, 0xe5, 0xd9, 0x7e, 0xb6, + 0x9b, 0x69, 0x8f, 0x56, 0x23, 0x35, 0x9e, 0x30, 0x79, 0xa6, 0x7d, 0x1e, 0xac, 0x58, 0x05, 0xac, + 0x75, 0x3a, 0x54, 0x9c, 0xf3, 0x52, 0xc8, 0x57, 0xac, 0x0e, 0x4f, 0x8a, 0x73, 0xc4, 0x6a, 0xa6, + 0x50, 0xe4, 0x25, 0xbc, 0x38, 0x71, 0x76, 0x33, 0x3b, 0x99, 0xb5, 0x91, 0xbe, 0x36, 0x61, 0xf2, + 0xcc, 0xce, 0xf6, 0x17, 0xa8, 0x67, 0x03, 0xb5, 0x49, 0xea, 0x1b, 0xf9, 0x40, 0x85, 0x3c, 0xab, + 0x83, 0x0e, 0x2e, 0x95, 0xbf, 0xb5, 0x95, 0x3a, 0xb8, 0x24, 0xe4, 0xcb, 0xfa, 0xf6, 0xb7, 0x3a, + 0xac, 0x0f, 0x26, 0x33, 0x3f, 0x88, 0x32, 0x3d, 0x40, 0xae, 0x9d, 0xda, 0xca, 0xb5, 0x53, 0x2f, + 0x74, 0x7a, 0xea, 0x05, 0xd4, 0x08, 0x4d, 0x2e, 0x89, 0x4c, 0x3e, 0x9a, 0xb9, 0x7c, 0xdc, 0x81, + 0x9a, 0x1c, 0x94, 0x28, 0x2a, 0x91, 0x28, 0x65, 0xc8, 0x45, 0x78, 0x41, 0x8b, 0x50, 0x85, 0x3a, + 0x57, 0x4c, 0xb2, 0x16, 0x80, 0x54, 0x23, 0x61, 0x95, 0x84, 0x19, 0x0e, 0xca, 0x13, 0x87, 0x42, + 0xab, 0xdc, 0x36, 0x3a, 0x06, 0xcf, 0x70, 0xd8, 0x03, 0x68, 0x92, 0x13, 0x07, 0x81, 0xc0, 0x66, + 0xb2, 0x1f, 0x51, 0x3e, 0x1b, 0xbc, 0xc0, 0x45, 0x3d, 0x72, 0x2b, 0xd5, 0x93, 0x9d, 0xa6, 0xc0, + 0xa5, 0xb9, 0xe0, 0x09, 0x27, 0xa0, 0x8c, 0xad, 0x72, 0x49, 0xd8, 0x3f, 0xea, 0xc0, 0x24, 0x92, + 0x72, 0xa9, 0xf9, 0xcd, 0xe0, 0xfc, 0x30, 0x6c, 0x79, 0x70, 0x2a, 0x4b, 0xe0, 0xa4, 0xf3, 0x40, + 0x02, 0x13, 0xcf, 0x83, 0x36, 0xd4, 0xe3, 0xb1, 0x85, 0x42, 0x44, 0x55, 0xe3, 0x59, 0x16, 0xce, + 0xa7, 0xd3, 0x08, 0x7f, 0x89, 0x28, 0x95, 0x1a, 0xd9, 0xce, 0xf1, 0x56, 0x40, 0x0b, 0x1f, 0x09, + 0x6d, 0xfd, 0xc3, 0xd0, 0x36, 0xb2, 0xd0, 0x7e, 0xa1, 0x41, 0x63, 0x3f, 0xf2, 0x27, 0xee, 0x90, + 0x8b, 0xa1, 0x1f, 0x8c, 0xae, 0x07, 0x55, 0xc2, 0xa7, 0x67, 0xe1, 0xeb, 0x80, 0x31, 0x78, 0x17, + 0xa8, 0xfe, 0x7b, 0x8b, 0xb6, 0x8b, 0xa5, 0x28, 0x71, 0x54, 0x61, 0xf7, 0x41, 0x1f, 0x04, 0x94, + 0xb3, 0xf5, 0xee, 0x56, 0xaa, 0x18, 0xeb, 0xe8, 0x83, 0xc0, 0xfe, 0x33, 0x6c, 0xcb, 0x87, 0xc4, + 0x22, 0x35, 0x70, 0xb6, 0xa1, 0x74, 0x18, 0x04, 0x7e, 0x3c, 0x72, 0x24, 0x81, 0xeb, 0x73, 0x32, + 0xc3, 0x30, 0x18, 0x9f, 0x92, 0x13, 0xab, 0x7e, 0x33, 0xb6, 0xa1, 0x7e, 0xe2, 0x47, 0xff, 0x09, + 0xdc, 0x88, 0x5a, 0x92, 0x1c, 0x1c, 0x59, 0x96, 0xfd, 0x10, 0x6e, 0x16, 0x6e, 0x4e, 0x27, 0x23, + 0xa6, 0x91, 0x91, 0xfe, 0xee, 0x3a, 0x85, 0x1b, 0x89, 0xea, 0xa0, 0xff, 0x49, 0x6f, 0x5c, 0x36, + 0xfa, 0xa7, 0x8c, 0xe7, 0x64, 0x54, 0x5d, 0xbf, 0xc2, 0x1b, 0xbb, 0x07, 0x96, 0x42, 0x53, 0xfe, + 0xf0, 0x55, 0x2f, 0x38, 0x77, 0xc5, 0xe2, 0xba, 0x7d, 0x9f, 0xd6, 0x0a, 0x9d, 0x36, 0x21, 0xfa, + 0xb6, 0xbf, 0xd4, 0x61, 0x7b, 0x95, 0x91, 0x34, 0xa1, 0xb4, 0x4c, 0x42, 0xb1, 0x2e, 0x94, 0xde, + 0xb9, 0x62, 0x11, 0xef, 0x02, 0x3b, 0x99, 0x60, 0x2f, 0xbd, 0x81, 0x4b, 0x55, 0x2c, 0xa4, 0xfd, + 0x61, 0xe4, 0xfa, 0xd3, 0x78, 0x7f, 0x95, 0x14, 0xde, 0xd0, 0xf3, 0xfc, 0xe1, 0xff, 0xe5, 0x4f, + 0x2f, 0x2e, 0x89, 0x15, 0x85, 0x51, 0xfa, 0xc8, 0xc2, 0x28, 0xaf, 0x2c, 0x8c, 0x0e, 0x6c, 0xfc, + 0x7b, 0x36, 0x72, 0x22, 0x71, 0x78, 0xe9, 0x86, 0x91, 0x98, 0x0e, 0x85, 0x55, 0x21, 0x8f, 0x8a, + 0x6c, 0xfb, 0x73, 0x0d, 0xd6, 0x95, 0x17, 0x52, 0x74, 0xcd, 0x96, 0xce, 0xc0, 0x44, 0xf7, 0xe2, + 0x85, 0x90, 0xe0, 0x4e, 0xd0, 0x32, 0x08, 0x5b, 0x85, 0xd6, 0x26, 0x18, 0xa7, 0x22, 0x52, 0x7f, + 0x4f, 0xe0, 0x27, 0xb6, 0x06, 0x12, 0xc9, 0x72, 0x0c, 0xd5, 0xfe, 0x97, 0xe3, 0xd9, 0x6f, 0xe0, + 0x76, 0x0e, 0x52, 0xaa, 0xc6, 0x38, 0x2c, 0xe9, 0xea, 0xa8, 0xe5, 0x56, 0xc7, 0x3f, 0x42, 0xe9, + 0x3c, 0x13, 0x98, 0x2d, 0x39, 0x2f, 0x33, 0xce, 0x70, 0x29, 0xb7, 0x4f, 0x73, 0xf3, 0x12, 0x7b, + 0xe4, 0xfe, 0x78, 0x1c, 0x88, 0xb1, 0x13, 0xc5, 0xc9, 0x92, 0x32, 0xd8, 0x03, 0x28, 0x93, 0x72, + 0x6c, 0xb6, 0xb8, 0x00, 0x29, 0x69, 0x6f, 0xf3, 0xbb, 0xf7, 0x2d, 0xed, 0x87, 0xf7, 0x2d, 0xed, + 0xa7, 0xf7, 0x2d, 0xed, 0xab, 0x9f, 0x5b, 0x6b, 0x17, 0x65, 0xfa, 0x77, 0xe7, 0xaf, 0xbf, 0x06, + 0x00, 0x00, 0xff, 0xff, 0x51, 0x2f, 0x5d, 0x6f, 0xed, 0x11, 0x00, 0x00, } func (m *Row) Marshal() (dAtA []byte, err error) { @@ -3834,15 +3826,12 @@ func (m *Decimal) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } - if m.Scale != 0 { - i = encodeVarintPublic(dAtA, i, uint64(m.Scale)) + if len(m.Gob) > 0 { + i -= len(m.Gob) + copy(dAtA[i:], m.Gob) + i = encodeVarintPublic(dAtA, i, uint64(len(m.Gob))) i-- - dAtA[i] = 0x10 - } - if m.Value != 0 { - i = encodeVarintPublic(dAtA, i, uint64(m.Value)) - i-- - dAtA[i] = 0x8 + dAtA[i] = 0xa } return len(dAtA) - i, nil } @@ -5635,11 +5624,9 @@ func (m *Decimal) Size() (n int) { } var l int _ = l - if m.Value != 0 { - n += 1 + sovPublic(uint64(m.Value)) - } - if m.Scale != 0 { - n += 1 + sovPublic(uint64(m.Scale)) + l = len(m.Gob) + if l > 0 { + n += 1 + l + sovPublic(uint64(l)) } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) @@ -8774,10 +8761,10 @@ func (m *Decimal) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Gob", wireType) } - m.Value = 0 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowPublic @@ -8787,30 +8774,26 @@ func (m *Decimal) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Value |= int64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Scale", wireType) + if byteLen < 0 { + return ErrInvalidLengthPublic } - m.Scale = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPublic - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Scale |= int64(b&0x7F) << shift - if b < 0x80 { - break - } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthPublic } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Gob = append(m.Gob[:0], dAtA[iNdEx:postIndex]...) + if m.Gob == nil { + m.Gob = []byte{} + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipPublic(dAtA[iNdEx:]) diff --git a/pb/public.proto b/pb/public.proto index d5dbf06c6..d22f12e74 100644 --- a/pb/public.proto +++ b/pb/public.proto @@ -113,8 +113,7 @@ message ValCount { } message Decimal { - int64 Value = 1; - int64 Scale = 2; + bytes Gob = 1; } message DistinctTimestamp { diff --git a/pql/ast_test.go b/pql/ast_test.go index 2311053f7..375d93405 100644 --- a/pql/ast_test.go +++ b/pql/ast_test.go @@ -40,7 +40,7 @@ func TestCondition_StringWithSubj(t *testing.T) { }{ {pql.BETWEEN, []interface{}{int64(4), int64(8)}, "4<=subj<=8"}, {pql.BETWEEN, []interface{}{uint64(5), uint64(9)}, "5<=subj<=9"}, - {pql.BETWEEN, []interface{}{pql.Decimal{Value: -401, Scale: 2}, pql.Decimal{Value: 802, Scale: 1}}, "-4.01<=subj<=80.2"}, + {pql.BETWEEN, []interface{}{pql.NewDecimal(-401, 2), pql.NewDecimal(802, 1)}, "-4.01<=subj<=80.2"}, {pql.EQ, nil, "subj==null"}, {pql.NEQ, nil, "subj!=null"}, } { diff --git a/pql/decimal.go b/pql/decimal.go index 19837d893..6dda17f22 100644 --- a/pql/decimal.go +++ b/pql/decimal.go @@ -2,8 +2,9 @@ package pql import ( - "fmt" + "encoding/binary" "math" + "math/big" "strconv" "strings" @@ -51,22 +52,74 @@ func Pow10(p int64) int64 { // Precision is currently not considered; precision, for // our purposes is implied to be the complete, known value. type Decimal struct { - Value int64 + value big.Int Scale int64 } +func (d *Decimal) Value() big.Int { + val := big.NewInt(0) + val.Set(&d.value) + return *val +} + +func (d *Decimal) SetValue(v int64) { + val := big.NewInt(v) + d.value = *val +} + func (d Decimal) Clone() (r *Decimal) { + val := big.NewInt(0) + val.Set(&d.value) r = &Decimal{ - Value: d.Value, + value: *val, Scale: d.Scale, } return } +func (d *Decimal) GobEncode() ([]byte, error) { + if d == nil { + return nil, nil + } + valBuf, err := d.value.GobEncode() + if err != nil { + return nil, err + } + valSz := len(valBuf) + + // make a buffer the size of our Decimal, plus our 8 byte Scale, + // plus 1 byte for sign of scale + buf := make([]byte, valSz+8) + copy(buf[:valSz], valBuf) + + binary.LittleEndian.PutUint64(buf[valSz:valSz+8], uint64(d.Scale)) + + return buf, nil +} + +func (d *Decimal) GobDecode(buf []byte) error { + if len(buf) == 0 { + // they sent a nil or default value + *d = Decimal{} + return nil + } + + valPart := len(buf) - 8 + value := big.NewInt(0) + if err := value.GobDecode(buf[:valPart]); err != nil { + return err + } + d.value = *value + + d.Scale = int64(binary.LittleEndian.Uint64(buf[valPart : valPart+8])) + return nil +} + // NewDecimal returns a Decimal based on the provided arguments. func NewDecimal(value, scale int64) Decimal { + v := big.NewInt(value) return Decimal{ - Value: value, + value: *v, Scale: scale, } } @@ -79,6 +132,20 @@ func MinMax(scale int64) (Decimal, Decimal) { return min, max } +// AddDecimal adds a and b together and returns a new Decimal with the computed sum. +// +// If the Scale of a and b don't match, the returned Decimal will have the +// smallest Scale needed to precisely represent the sum. +func AddDecimal(a, b Decimal) Decimal { + ac, bc := sameScalify(a, b) + apv, bpv := &ac.value, &bc.value + apv.Add(apv, bpv) + return Decimal{ + value: *apv, + Scale: ac.Scale, + } +} + // LessThan returns true if d < d2. func (d Decimal) LessThan(d2 Decimal) bool { return d.lessThan(d2, false) @@ -99,84 +166,56 @@ func (d Decimal) GreaterThanOrEqualTo(d2 Decimal) bool { return d.greaterThan(d2, true) } -// EqualTo returns true if d == d2. -func (d Decimal) EqualTo(d2 Decimal) bool { - if d.Scale == d2.Scale { - return d.Value == d2.Value +func (d *Decimal) withLargerScale(scale int64) *Decimal { + dc := d.Clone() + val := &dc.value + ten := big.NewInt(10) + for dc.Scale < scale { + val = val.Mul(val, ten) + dc.Scale++ } - quotientD := quotient(d) - quotientD2 := quotient(d2) - if quotientD != quotientD2 { - return false + return dc +} + +func sameScalify(d, d2 Decimal) (*Decimal, *Decimal) { + dc := d.Clone() + d2c := d2.Clone() + + if dc.Scale < d2c.Scale { + dc = dc.withLargerScale(d2c.Scale) + } else { + d2c = d2c.withLargerScale(dc.Scale) } - remainderD, remainderD2 := remainder(d), remainder(d2) - if d.Scale < d2.Scale { - scaleDiff := d2.Scale - d.Scale - return (remainderD * pow10[scaleDiff]) == remainderD2 + + return dc, d2c +} + +func (d Decimal) cmp(d2 Decimal) int { + if d.Scale == d2.Scale { + return (&d.value).Cmp(&d2.value) } - scaleDiff := d.Scale - d2.Scale - return remainderD == (remainderD2 * pow10[scaleDiff]) + dc, d2c := sameScalify(d, d2) + return (&dc.value).Cmp(&d2c.value) +} + +// EqualTo returns true if d == d2. +func (d Decimal) EqualTo(d2 Decimal) bool { + return d.cmp(d2) == 0 } func (d Decimal) lessThan(d2 Decimal, eq bool) bool { - if d.Scale == d2.Scale { - if eq { - return d.Value <= d2.Value - } - return d.Value < d2.Value + if eq { + return d.cmp(d2) <= 0 } - - quotientD, quotientD2 := quotient(d), quotient(d2) - if quotientD < quotientD2 { - return true - } else if quotientD == quotientD2 { - remainderD, remainderD2 := remainder(d), remainder(d2) - if d.Scale < d2.Scale { - scaleDiff := d2.Scale - d.Scale - if eq { - return (remainderD * pow10[scaleDiff]) <= remainderD2 - } - return (remainderD * pow10[scaleDiff]) < remainderD2 - } - scaleDiff := d.Scale - d2.Scale - if eq { - return remainderD <= (remainderD2 * pow10[scaleDiff]) - } - return remainderD < (remainderD2 * pow10[scaleDiff]) - } - - return false + return d.cmp(d2) < 0 } func (d Decimal) greaterThan(d2 Decimal, eq bool) bool { - if d.Scale == d2.Scale { - if eq { - return d.Value >= d2.Value - } - return d.Value > d2.Value + if eq { + return d.cmp(d2) >= 0 } - - quotientD, quotientD2 := quotient(d), quotient(d2) - if quotientD > quotientD2 { - return true - } else if quotientD == quotientD2 { - remainderD, remainderD2 := remainder(d), remainder(d2) - if d.Scale < d2.Scale { - scaleDiff := d2.Scale - d.Scale - if eq { - return (remainderD * pow10[scaleDiff]) >= remainderD2 - } - return (remainderD * pow10[scaleDiff]) > remainderD2 - } - scaleDiff := d.Scale - d2.Scale - if eq { - return remainderD >= (remainderD2 * pow10[scaleDiff]) - } - return remainderD > (remainderD2 * pow10[scaleDiff]) - } - - return false + return d.cmp(d2) > 0 } // SupportedByScale returns true if d can be represented @@ -205,16 +244,17 @@ func (d Decimal) IsValid() bool { } // ToInt64 returns d as an int64 adjusted to the -// provided scale. +// provided scale. If d.value cannot be represented +// as an int64, results are undefined. func (d Decimal) ToInt64(scale int64) int64 { var ret int64 scaleDiff := scale - d.Scale if scaleDiff == 0 { - ret = d.Value + ret = d.value.Int64() } else if scaleDiff < 0 { - ret = d.Value / Pow10(-1*scaleDiff) + ret = d.value.Int64() / Pow10(-1*scaleDiff) } else { - ret = d.Value * Pow10(scaleDiff) + ret = d.value.Int64() * Pow10(scaleDiff) } return ret } @@ -222,12 +262,14 @@ func (d Decimal) ToInt64(scale int64) int64 { // Float64 returns d as a float64. // TODO: this could potentially lose precision; we should audit // its use and protect against unexpected results. +// If d.value cannot be represented as an int64, +// results are undefined. func (d Decimal) Float64() float64 { var ret float64 if d.Scale == 0 { - ret = float64(d.Value) + ret = float64(d.value.Int64()) } else { - ret = float64(d.Value) / math.Pow10(int(d.Scale)) + ret = float64(d.value.Int64()) / math.Pow10(int(d.Scale)) } return ret } @@ -237,7 +279,10 @@ func (d Decimal) String() string { var s string var neg bool - sval := fmt.Sprintf("%d", d.Value) + sval := d.value.String() + if len(sval) == 0 { + return "" + } // Strip the negative sign off for now, and // re-apply it at the end. @@ -388,7 +433,6 @@ func ParseDecimal(s string) (Decimal, error) { } else { return Decimal{}, errors.Errorf("value out of range: %s", mantissa) } - // We have to use ParseUint here (as opposed to ParseInt) because // math.MinInt64 is a valid value, but its absolute value is not. // So this allows us to handle that one value without overflow, and @@ -407,8 +451,9 @@ func ParseDecimal(s string) (Decimal, error) { value *= -1 } + bigVal := big.NewInt(value) return Decimal{ - Value: value, + value: *bigVal, Scale: scale, }, nil } @@ -455,24 +500,6 @@ func reducePrecision(sign bool, mantissa []byte, scale int64) ([]byte, int64, bo return reducePrecision(sign, mantissa[:len(mantissa)-1], scale-1) } -func quotient(d Decimal) int64 { - if d.Scale == 0 { - return d.Value - } else if d.Scale > 0 && d.Scale < 19 { - return d.Value / pow10[d.Scale] - } else if d.Scale < 0 && d.Scale > -19 { - return d.Value * pow10[-1*d.Scale] - } - return 0 -} - -func remainder(d Decimal) int64 { - if d.Scale >= 0 && d.Scale < 19 { - return d.Value % pow10[d.Scale] - } - return 0 -} - // UnmarshalJSON is a custom unmarshaller for the Decimal // type. The intention is to avoid the use of float64 // anywhere, so this unmarhaller parses the decimal out @@ -482,7 +509,7 @@ func (d *Decimal) UnmarshalJSON(data []byte) error { if err != nil { return errors.Wrapf(err, "parsing decimal: %s", string(data)) } - d.Value = o.Value + d.value = o.value d.Scale = o.Scale return nil @@ -505,7 +532,7 @@ func (d *Decimal) UnmarshalYAML(unmarshal func(interface{}) error) error { if err != nil { return errors.Wrapf(err, "parsing decimal: %s", data) } - d.Value = o.Value + d.value = o.value d.Scale = o.Scale return nil diff --git a/pql/decimal_internal_test.go b/pql/decimal_internal_test.go new file mode 100644 index 000000000..5b3b10ea2 --- /dev/null +++ b/pql/decimal_internal_test.go @@ -0,0 +1,133 @@ +package pql + +import ( + "fmt" + "math" + "math/big" + "reflect" + "testing" +) + +type testAddDecimalCase struct { + a Decimal + b Decimal + exp Decimal +} + +func TestAddDecimal(t *testing.T) { + toDecimal := func(a interface{}) Decimal { + switch ac := a.(type) { + case string: + return mustParse(t, ac) + case Decimal: + return ac + default: + t.Fatalf("cannot support type %T", ac) + } + return Decimal{} + } + + newTestAddDecimalCase := func(a, b, exp interface{}) testAddDecimalCase { + return testAddDecimalCase{ + a: toDecimal(a), + b: toDecimal(b), + exp: toDecimal(exp), + } + } + + tests := []testAddDecimalCase{ + newTestAddDecimalCase("40.37", "40.37", "80.74"), + newTestAddDecimalCase("18.5", "9.25", "27.75"), + newTestAddDecimalCase("18.50", "9.25", "27.75"), + newTestAddDecimalCase("-18.50", "-9.25", "-27.75"), + newTestAddDecimalCase("-40.37", "40.37", NewDecimal(0, 0)), + newTestAddDecimalCase("-50.38", "-50.38", "-100.76"), + newTestAddDecimalCase("-40.381", "-40.38", "-80.761"), + newTestAddDecimalCase("-40.3700000000000000000001", "-50.38", "-90.7500000000000000000001"), + newTestAddDecimalCase("10.37000000000000001", "-10", "0.37000000000000001"), + // this is a weird one. because we reduce precision when we parse strings, we + // expect the value to be smaller than it really should be if you did + // the math yourself. + // + // there's not really a good way around this unless we use math/big.Int to represent + // our Value/Scale. + // + // but if we did this, to quote seebs: "i suspect that + // our performance would tank so badly by the time we were doing >63-bit + // numbers that there's no real-world benefit to us." + newTestAddDecimalCase("10.370000000000000001", "-10", "0.37"), + newTestAddDecimalCase("-9223372036854775807", "-9223372036854775807", "-18446744073709551614"), + newTestAddDecimalCase("9223372036854775807", "9223372036854775807", "18446744073709551614"), + newTestAddDecimalCase(NewDecimal(0, 0), NewDecimal(1, 4), NewDecimal(1, 4)), + } + + for i, test := range tests { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + t.Logf("first %#v %#v", test.a, test.b) + if got := AddDecimal(test.a, test.b); !got.EqualTo(test.exp) { + t.Logf("LOG: %#v + %#v, expected %#v, got %#v", test.a, test.b, test.exp, got) + t.Errorf("%v + %v, expected %v, got %v", test.a, test.b, test.exp, got) + } + + t.Logf("second %v %v", test.a, test.b) + if got := AddDecimal(test.b, test.a); !got.EqualTo(test.exp) { + t.Logf("LOG: %#v + %#v, expected %#v, got %#v", test.a, test.b, test.exp, got) + t.Errorf("%v + %v, expected %v, got %v", test.b, test.a, test.exp, got) + } + }) + } +} + +func mustParse(t *testing.T, num string) Decimal { + t.Helper() + d, err := ParseDecimal(num) + if err != nil { + v := big.NewInt(0) + if _, ok := v.SetString(num, 10); !ok { + t.Fatalf("unexpected error parsing %s to Decimal: %v", num, err) + } + d.value = *v + } + return d +} + +func TestGobEncodeDecode(t *testing.T) { + for i := int64(-10); i < 10; i++ { + for j := int64(-10); j < 10; j++ { + decimal := &Decimal{value: *(big.NewInt(i)), Scale: j} + t.Run(fmt.Sprintf("v%ds%d", i, j), func(t *testing.T) { + encoded, err := decimal.GobEncode() + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + decoded := &Decimal{} + err = decoded.GobDecode(encoded) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !reflect.DeepEqual(decimal, decoded) { + t.Errorf("%v != %v", decimal, encoded) + } + }) + } + } + + i := int64(math.MaxInt64) + j := int64(math.MinInt64) + decimal := &Decimal{value: *(big.NewInt(i)), Scale: j} + t.Run(fmt.Sprintf("v%ds%d", i, j), func(t *testing.T) { + encoded, err := decimal.GobEncode() + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + decoded := &Decimal{} + err = decoded.GobDecode(encoded) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !reflect.DeepEqual(decimal, decoded) { + t.Errorf("%v != %v", decimal, encoded) + } + }) + +} diff --git a/pql/decimal_test.go b/pql/decimal_test.go index ea24685ff..dd45fceb2 100644 --- a/pql/decimal_test.go +++ b/pql/decimal_test.go @@ -18,48 +18,48 @@ func TestDecimal(t *testing.T) { exp pql.Decimal expErr string }{ - {"0", pql.Decimal{0, 0}, ""}, - {"-0", pql.Decimal{0, 0}, ""}, - {"0.0", pql.Decimal{0, 0}, ""}, - {"0.", pql.Decimal{0, 0}, ""}, - {"-0.00", pql.Decimal{0, 0}, ""}, - {"123.4567", pql.Decimal{1234567, 4}, ""}, - {"123.456700", pql.Decimal{1234567, 4}, ""}, - {"00123.4567", pql.Decimal{1234567, 4}, ""}, - {"+123.4567", pql.Decimal{1234567, 4}, ""}, - {"-123.4567", pql.Decimal{-1234567, 4}, ""}, - {"-00123.4567", pql.Decimal{-1234567, 4}, ""}, - {"-12.25", pql.Decimal{-1225, 2}, ""}, + {"0", pql.NewDecimal(0, 0), ""}, + {"-0", pql.NewDecimal(0, 0), ""}, + {"0.0", pql.NewDecimal(0, 0), ""}, + {"0.", pql.NewDecimal(0, 0), ""}, + {"-0.00", pql.NewDecimal(0, 0), ""}, + {"123.4567", pql.NewDecimal(1234567, 4), ""}, + {"123.456700", pql.NewDecimal(1234567, 4), ""}, + {"00123.4567", pql.NewDecimal(1234567, 4), ""}, + {"+123.4567", pql.NewDecimal(1234567, 4), ""}, + {"-123.4567", pql.NewDecimal(-1234567, 4), ""}, + {"-00123.4567", pql.NewDecimal(-1234567, 4), ""}, + {"-12.25", pql.NewDecimal(-1225, 2), ""}, - {"123", pql.Decimal{123, 0}, ""}, - {"-12300", pql.Decimal{-123, -2}, ""}, - {"+012300", pql.Decimal{123, -2}, ""}, - {"12300", pql.Decimal{123, -2}, ""}, - {"12300.", pql.Decimal{123, -2}, ""}, - {"12300.0", pql.Decimal{123, -2}, ""}, - {"123.0", pql.Decimal{123, 0}, ""}, + {"123", pql.NewDecimal(123, 0), ""}, + {"-12300", pql.NewDecimal(-123, -2), ""}, + {"+012300", pql.NewDecimal(123, -2), ""}, + {"12300", pql.NewDecimal(123, -2), ""}, + {"12300.", pql.NewDecimal(123, -2), ""}, + {"12300.0", pql.NewDecimal(123, -2), ""}, + {"123.0", pql.NewDecimal(123, 0), ""}, - {".123", pql.Decimal{123, 3}, ""}, - {"0.123", pql.Decimal{123, 3}, ""}, - {"0.001230", pql.Decimal{123, 5}, ""}, - {"-0.001230", pql.Decimal{-123, 5}, ""}, + {".123", pql.NewDecimal(123, 3), ""}, + {"0.123", pql.NewDecimal(123, 3), ""}, + {"0.001230", pql.NewDecimal(123, 5), ""}, + {"-0.001230", pql.NewDecimal(-123, 5), ""}, // int64 edges. - {".000009223372036854775807", pql.Decimal{9223372036854775807, 24}, ""}, - {"-.000009223372036854775808", pql.Decimal{-9223372036854775808, 24}, ""}, - {"92233720368547.75807", pql.Decimal{9223372036854775807, 5}, ""}, - {"-92233720368547.75807", pql.Decimal{-9223372036854775807, 5}, ""}, - {"9223372036854775807000", pql.Decimal{9223372036854775807, -3}, ""}, - {"-9223372036854775807000", pql.Decimal{-9223372036854775807, -3}, ""}, + {".000009223372036854775807", pql.NewDecimal(9223372036854775807, 24), ""}, + {"-.000009223372036854775808", pql.NewDecimal(-9223372036854775808, 24), ""}, + {"92233720368547.75807", pql.NewDecimal(9223372036854775807, 5), ""}, + {"-92233720368547.75807", pql.NewDecimal(-9223372036854775807, 5), ""}, + {"9223372036854775807000", pql.NewDecimal(9223372036854775807, -3), ""}, + {"-9223372036854775807000", pql.NewDecimal(-9223372036854775807, -3), ""}, // precision adjustment - {"2.666666666666666667", pql.Decimal{2666666666666666667, 18}, ""}, - {"2.6666666666666666667", pql.Decimal{2666666666666666666, 18}, ""}, - {"2.6666666666666666666667", pql.Decimal{2666666666666666666, 18}, ""}, - {"-9.223372036854775808", pql.Decimal{-9223372036854775808, 18}, ""}, - {"-9.223372036854775809", pql.Decimal{-922337203685477580, 17}, ""}, - {"9.223372036854775807", pql.Decimal{9223372036854775807, 18}, ""}, - {"9.223372036854775808", pql.Decimal{922337203685477580, 17}, ""}, + {"2.666666666666666667", pql.NewDecimal(2666666666666666667, 18), ""}, + {"2.6666666666666666667", pql.NewDecimal(2666666666666666666, 18), ""}, + {"2.6666666666666666666667", pql.NewDecimal(2666666666666666666, 18), ""}, + {"-9.223372036854775808", pql.NewDecimal(-9223372036854775808, 18), ""}, + {"-9.223372036854775809", pql.NewDecimal(-922337203685477580, 17), ""}, + {"9.223372036854775807", pql.NewDecimal(9223372036854775807, 18), ""}, + {"9.223372036854775808", pql.NewDecimal(922337203685477580, 17), ""}, // Error cases. {"", pql.Decimal{}, "decimal string is empty"}, @@ -87,7 +87,7 @@ func TestDecimal(t *testing.T) { } } else if err != nil { t.Fatalf("test %d parsing string `%s`: %s", i, test.s, err) - } else if dec != test.exp { + } else if !dec.EqualTo(test.exp) { t.Fatalf("test %d parsing string `%s`: expected: %v, but got: %v", i, test.s, test.exp, dec) } } @@ -99,22 +99,22 @@ func TestDecimal(t *testing.T) { scale int64 exp int64 }{ - {pql.Decimal{0, 0}, 0, 0}, // 0 : 0 - {pql.Decimal{0, 0}, 1, 0}, // 0 : 0.0 - {pql.Decimal{0, 0}, -1, 0}, // 0 : 0 + {pql.NewDecimal(0, 0), 0, 0}, // 0 : 0 + {pql.NewDecimal(0, 0), 1, 0}, // 0 : 0.0 + {pql.NewDecimal(0, 0), -1, 0}, // 0 : 0 - {pql.Decimal{1234567, 4}, 5, 12345670}, // 123.4567 : 123.45670 - {pql.Decimal{1234567, 4}, 4, 1234567}, // 123.4567 : 123.4567 - {pql.Decimal{1234567, 4}, 3, 123456}, // 123.4567 : 123.456 + {pql.NewDecimal(1234567, 4), 5, 12345670}, // 123.4567 : 123.45670 + {pql.NewDecimal(1234567, 4), 4, 1234567}, // 123.4567 : 123.4567 + {pql.NewDecimal(1234567, 4), 3, 123456}, // 123.4567 : 123.456 - {pql.Decimal{-1234567, 4}, 5, -12345670}, // -123.4567 : -123.45670 - {pql.Decimal{-1234567, 4}, 4, -1234567}, // -123.4567 : -123.4567 - {pql.Decimal{-1234567, 4}, 3, -123456}, // -123.4567 : -123.456 + {pql.NewDecimal(-1234567, 4), 5, -12345670}, // -123.4567 : -123.45670 + {pql.NewDecimal(-1234567, 4), 4, -1234567}, // -123.4567 : -123.4567 + {pql.NewDecimal(-1234567, 4), 3, -123456}, // -123.4567 : -123.456 - {pql.Decimal{123, -2}, 5, 1230000000}, // 12300 : 12300.00000 - {pql.Decimal{123, -2}, -1, 1230}, // 12300 : 1230 - {pql.Decimal{123, 1}, -1, 1}, // 12.3 : 1 - {pql.Decimal{123, 1}, -2, 0}, // 12.3 : 0 + {pql.NewDecimal(123, -2), 5, 1230000000}, // 12300 : 12300.00000 + {pql.NewDecimal(123, -2), -1, 1230}, // 12300 : 1230 + {pql.NewDecimal(123, 1), -1, 1}, // 12.3 : 1 + {pql.NewDecimal(123, 1), -2, 0}, // 12.3 : 0 } for i, test := range tests { v := test.dec.ToInt64(test.scale) diff --git a/pql/parser_test.go b/pql/parser_test.go index b829d6079..ebadbbeff 100644 --- a/pql/parser_test.go +++ b/pql/parser_test.go @@ -94,10 +94,10 @@ func TestParser_Parse(t *testing.T) { &pql.Call{ Name: "Row", Args: map[string]interface{}{ - "key": pql.Decimal{1225, 2}, - "foo": pql.Decimal{13167, 3}, - "bar": pql.Decimal{2, 0}, - "baz": pql.Decimal{9, 1}, + "key": pql.NewDecimal(1225, 2), + "foo": pql.NewDecimal(13167, 3), + "bar": pql.NewDecimal(2, 0), + "baz": pql.NewDecimal(9, 1), }, }, ) { @@ -114,7 +114,7 @@ func TestParser_Parse(t *testing.T) { &pql.Call{ Name: "Row", Args: map[string]interface{}{ - "key": pql.Decimal{-1225, 2}, + "key": pql.NewDecimal(-1225, 2), "foo": int64(-13), }, }, @@ -170,7 +170,7 @@ func TestParser_Parse(t *testing.T) { Name: "Row", Args: map[string]interface{}{ "key": "foo", - "x": &pql.Condition{Op: pql.EQ, Value: pql.Decimal{1225, 2}}, + "x": &pql.Condition{Op: pql.EQ, Value: pql.NewDecimal(1225, 2)}, "y": &pql.Condition{Op: pql.GTE, Value: int64(100)}, "z": &pql.Condition{Op: pql.BETWEEN, Value: []interface{}{int64(4), int64(8)}}, "m": &pql.Condition{Op: pql.NEQ, Value: nil}, diff --git a/server/grpc.go b/server/grpc.go index 90233317d..4c100bb80 100644 --- a/server/grpc.go +++ b/server/grpc.go @@ -1053,8 +1053,9 @@ func (h *GRPCHandler) Inspect(req *pb.InspectRequest, stream pb.Pilosa_InspectSe if len(resp.Results) > 0 { valCount, ok := resp.Results[0].(pilosa.ValCount) if ok && valCount.Count == 1 { + valVal := valCount.DecimalVal.Value() rowResp.Columns = append(rowResp.Columns, - &pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_DecimalVal{DecimalVal: &pb.Decimal{Value: valCount.DecimalVal.Value, Scale: valCount.DecimalVal.Scale}}}) + &pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_DecimalVal{DecimalVal: &pb.Decimal{Value: (&valVal).Int64(), Scale: valCount.DecimalVal.Scale}}}) colAdded++ } else { rowResp.Columns = append(rowResp.Columns, @@ -1380,8 +1381,9 @@ func (h *GRPCHandler) Inspect(req *pb.InspectRequest, stream pb.Pilosa_InspectSe if len(resp.Results) > 0 { valCount, ok := resp.Results[0].(pilosa.ValCount) if ok && valCount.Count == 1 { + valVal := valCount.DecimalVal.Value() rowResp.Columns = append(rowResp.Columns, - &pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_DecimalVal{DecimalVal: &pb.Decimal{Value: valCount.DecimalVal.Value, Scale: valCount.DecimalVal.Scale}}}) + &pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_DecimalVal{DecimalVal: &pb.Decimal{Value: (&valVal).Int64(), Scale: valCount.DecimalVal.Scale}}}) colAdded++ } else { rowResp.Columns = append(rowResp.Columns, diff --git a/server/handler_test.go b/server/handler_test.go index 1f8225bba..72d10ae04 100644 --- a/server/handler_test.go +++ b/server/handler_test.go @@ -263,7 +263,7 @@ func TestHandler_Endpoints(t *testing.T) { } } - f, err = i2.CreateFieldIfNotExists("f2", pilosa.OptFieldTypeDecimal(1, pql.Decimal{Value: -10}, pql.Decimal{Value: 10})) + f, err = i2.CreateFieldIfNotExists("f2", pilosa.OptFieldTypeDecimal(1, pql.NewDecimal(-10, 0), pql.NewDecimal(10, 0))) if err != nil { t.Fatal(err) } @@ -744,10 +744,10 @@ func TestHandler_Endpoints(t *testing.T) { } if field != nil { // happy linter if !reflect.DeepEqual(pql.NewDecimal(math.MinInt64, 0), field.Options.Min) { - t.Fatalf("field min %d != %d", int64(math.MinInt64), field.Options.Min) + t.Fatalf("field min %v != %v", int64(math.MinInt64), field.Options.Min) } if !reflect.DeepEqual(pql.NewDecimal(math.MaxInt64, 0), field.Options.Max) { - t.Fatalf("field max %d != %d", int64(math.MaxInt64), field.Options.Max) + t.Fatalf("field max %v != %v", int64(math.MaxInt64), field.Options.Max) } } }) @@ -775,10 +775,10 @@ func TestHandler_Endpoints(t *testing.T) { } if field != nil { // happy linter if !reflect.DeepEqual(pql.NewDecimal(math.MinInt64, 0), field.Options.Min) { - t.Fatalf("field min %d != %d", int64(math.MinInt64), field.Options.Min) + t.Fatalf("field min %v != %v", int64(math.MinInt64), field.Options.Min) } if !reflect.DeepEqual(pql.NewDecimal(1, -1), field.Options.Max) { - t.Fatalf("field max %d != %d", 10, field.Options.Max) + t.Fatalf("field max %v != %v", 10, field.Options.Max) } } }) @@ -806,10 +806,10 @@ func TestHandler_Endpoints(t *testing.T) { } if field != nil { // happy linter if !reflect.DeepEqual(pql.NewDecimal(-1, -1), field.Options.Min) { - t.Fatalf("field min %d != %d", 10, field.Options.Min) + t.Fatalf("field min %v != %v", 10, field.Options.Min) } if !reflect.DeepEqual(pql.NewDecimal(math.MaxInt64, 0), field.Options.Max) { - t.Fatalf("field max %d != %d", int64(math.MaxInt64), field.Options.Max) + t.Fatalf("field max %v != %v", int64(math.MaxInt64), field.Options.Max) } } }) @@ -847,10 +847,10 @@ func TestHandler_Endpoints(t *testing.T) { } if field != nil { // happy linter if !reflect.DeepEqual(pql.NewDecimal(math.MinInt64, 0), field.Options.Min) { - t.Fatalf("field min %d != %d", int64(math.MinInt64), field.Options.Min) + t.Fatalf("field min %v != %v", int64(math.MinInt64), field.Options.Min) } if !reflect.DeepEqual(pql.NewDecimal(math.MaxInt64, 0), field.Options.Max) { - t.Fatalf("field max %d != %d", int64(math.MaxInt64), field.Options.Max) + t.Fatalf("field max %v != %v", int64(math.MaxInt64), field.Options.Max) } } }) @@ -879,10 +879,10 @@ func TestHandler_Endpoints(t *testing.T) { } if field != nil { // happy linter if !reflect.DeepEqual(pql.NewDecimal(math.MinInt64, 1), field.Options.Min) { - t.Fatalf("field min %d != %d", pql.NewDecimal(math.MinInt64, 1), field.Options.Min) + t.Fatalf("field min %v != %v", pql.NewDecimal(math.MinInt64, 1), field.Options.Min) } if !reflect.DeepEqual(pql.NewDecimal(105, 1), field.Options.Max) { - t.Fatalf("field max %s != %d", pql.NewDecimal(105, 1), field.Options.Max) + t.Fatalf("field max %v != %v", pql.NewDecimal(105, 1), field.Options.Max) } } }) @@ -910,10 +910,10 @@ func TestHandler_Endpoints(t *testing.T) { } if field != nil { // happy linter if !reflect.DeepEqual(pql.NewDecimal(math.MinInt64, 2), field.Options.Min) { - t.Fatalf("field min %d != %d", pql.NewDecimal(math.MinInt64, 1), field.Options.Min) + t.Fatalf("field min %v != %v", pql.NewDecimal(math.MinInt64, 1), field.Options.Min) } if !reflect.DeepEqual(pql.NewDecimal(math.MaxInt64, 2), field.Options.Max) { - t.Fatalf("field min %d != %d", pql.NewDecimal(math.MaxInt64, 2), field.Options.Max) + t.Fatalf("field min %v != %v", pql.NewDecimal(math.MaxInt64, 2), field.Options.Max) } } }) diff --git a/server/pg.go b/server/pg.go index 87b1f8fa8..d529b6254 100644 --- a/server/pg.go +++ b/server/pg.go @@ -467,10 +467,10 @@ func pgWriteRowser(w pg.QueryResultWriter, result pb.ToRowser) error { case *pb.ColumnResponse_BoolVal: v = strconv.FormatBool(col.BoolVal) case *pb.ColumnResponse_DecimalVal: - v = pql.Decimal{ - Value: col.DecimalVal.Value, - Scale: col.DecimalVal.Scale, - }.String() + v = pql.NewDecimal( + col.DecimalVal.Value, + col.DecimalVal.Scale, + ).String() case *pb.ColumnResponse_Float64Val: v = strconv.FormatFloat(col.Float64Val, 'g', -1, 64) case *pb.ColumnResponse_Int64Val: diff --git a/server/server_test.go b/server/server_test.go index 0c5970381..8ef2290da 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -197,8 +197,8 @@ func TestMain_MinMaxFloat(t *testing.T) { } // Query row. - exp0 := pilosa.ValCount{DecimalVal: &pql.Decimal{Value: 4440, Scale: 3}, Count: 1} - exp1 := pilosa.ValCount{DecimalVal: &pql.Decimal{Value: 1320, Scale: 3}, Count: 1} + exp0 := pilosa.ValCount{DecimalVal: pql.NewDecimal(4440, 3).Clone(), Count: 1} + exp1 := pilosa.ValCount{DecimalVal: pql.NewDecimal(1320, 3).Clone(), Count: 1} if res, err := m.QueryProtobuf("i", `Max(field=dec) Min(field=dec)`); err != nil { t.Fatal(err) } else if !reflect.DeepEqual(res.Results[0], exp0) || !reflect.DeepEqual(res.Results[1], exp1) {