diff --git a/executor.go b/executor.go index 413be36b4..eee4fa0ee 100644 --- a/executor.go +++ b/executor.go @@ -176,8 +176,6 @@ func (e *Executor) validateCallArgs(c *pql.Call) error { func (e *Executor) executeSum(ctx context.Context, index string, c *pql.Call, slices []uint64, opt *ExecOptions) (ValCount, error) { if frame := c.Args["frame"]; frame == "" { return ValCount{}, errors.New("Sum(): frame required") - } else if field := c.Args["field"]; field == "" { - return ValCount{}, errors.New("Sum(): field required") } if len(c.Children) > 1 { @@ -211,8 +209,6 @@ func (e *Executor) executeSum(ctx context.Context, index string, c *pql.Call, sl func (e *Executor) executeMin(ctx context.Context, index string, c *pql.Call, slices []uint64, opt *ExecOptions) (ValCount, error) { if frame := c.Args["frame"]; frame == "" { return ValCount{}, errors.New("Min(): frame required") - } else if field := c.Args["field"]; field == "" { - return ValCount{}, errors.New("Min(): field required") } if len(c.Children) > 1 { @@ -246,8 +242,6 @@ func (e *Executor) executeMin(ctx context.Context, index string, c *pql.Call, sl func (e *Executor) executeMax(ctx context.Context, index string, c *pql.Call, slices []uint64, opt *ExecOptions) (ValCount, error) { if frame := c.Args["frame"]; frame == "" { return ValCount{}, errors.New("Max(): frame required") - } else if field := c.Args["field"]; field == "" { - return ValCount{}, errors.New("Max(): field required") } if len(c.Children) > 1 { @@ -362,7 +356,7 @@ func (e *Executor) executeBitmapCallSlice(ctx context.Context, index string, c * } } -// executeSumCountSlice calculates the sum and count for fields on a slice. +// executeSumCountSlice calculates the sum and count for bsiGroups on a slice. func (e *Executor) executeSumCountSlice(ctx context.Context, index string, c *pql.Call, slice uint64) (ValCount, error) { var filter *Row if len(c.Children) == 1 { @@ -374,34 +368,33 @@ func (e *Executor) executeSumCountSlice(ctx context.Context, index string, c *pq } frameName, _ := c.Args["frame"].(string) - fieldName, _ := c.Args["field"].(string) frame := e.Holder.Frame(index, frameName) if frame == nil { return ValCount{}, nil } - field := frame.bsiGroup(fieldName) - if field == nil { + bsig := frame.bsiGroup(frameName) + if bsig == nil { return ValCount{}, nil } - fragment := e.Holder.Fragment(index, frameName, viewBSIGroupPrefix+fieldName, slice) + fragment := e.Holder.Fragment(index, frameName, viewBSIGroupPrefix+frameName, slice) if fragment == nil { return ValCount{}, nil } - vsum, vcount, err := fragment.Sum(filter, field.BitDepth()) + vsum, vcount, err := fragment.Sum(filter, bsig.BitDepth()) if err != nil { return ValCount{}, errors.Wrap(err, "computing sum") } return ValCount{ - Val: int64(vsum) + (int64(vcount) * field.Min), + Val: int64(vsum) + (int64(vcount) * bsig.Min), Count: int64(vcount), }, nil } -// executeMinSlice calculates the min for fields on a slice. +// executeMinSlice calculates the min for bsiGroups on a slice. func (e *Executor) executeMinSlice(ctx context.Context, index string, c *pql.Call, slice uint64) (ValCount, error) { var filter *Row if len(c.Children) == 1 { @@ -413,34 +406,33 @@ func (e *Executor) executeMinSlice(ctx context.Context, index string, c *pql.Cal } frameName, _ := c.Args["frame"].(string) - fieldName, _ := c.Args["field"].(string) frame := e.Holder.Frame(index, frameName) if frame == nil { return ValCount{}, nil } - field := frame.bsiGroup(fieldName) - if field == nil { + bsig := frame.bsiGroup(frameName) + if bsig == nil { return ValCount{}, nil } - fragment := e.Holder.Fragment(index, frameName, viewBSIGroupPrefix+fieldName, slice) + fragment := e.Holder.Fragment(index, frameName, viewBSIGroupPrefix+frameName, slice) if fragment == nil { return ValCount{}, nil } - fmin, fcount, err := fragment.Min(filter, field.BitDepth()) + fmin, fcount, err := fragment.Min(filter, bsig.BitDepth()) if err != nil { return ValCount{}, err } return ValCount{ - Val: int64(fmin) + field.Min, + Val: int64(fmin) + bsig.Min, Count: int64(fcount), }, nil } -// executeMaxSlice calculates the max for fields on a slice. +// executeMaxSlice calculates the max for bsiGroups on a slice. func (e *Executor) executeMaxSlice(ctx context.Context, index string, c *pql.Call, slice uint64) (ValCount, error) { var filter *Row if len(c.Children) == 1 { @@ -452,29 +444,28 @@ func (e *Executor) executeMaxSlice(ctx context.Context, index string, c *pql.Cal } frameName, _ := c.Args["frame"].(string) - fieldName, _ := c.Args["field"].(string) frame := e.Holder.Frame(index, frameName) if frame == nil { return ValCount{}, nil } - field := frame.bsiGroup(fieldName) - if field == nil { + bsig := frame.bsiGroup(frameName) + if bsig == nil { return ValCount{}, nil } - fragment := e.Holder.Fragment(index, frameName, viewBSIGroupPrefix+fieldName, slice) + fragment := e.Holder.Fragment(index, frameName, viewBSIGroupPrefix+frameName, slice) if fragment == nil { return ValCount{}, nil } - fmax, fcount, err := fragment.Max(filter, field.BitDepth()) + fmax, fcount, err := fragment.Max(filter, bsig.BitDepth()) if err != nil { return ValCount{}, err } return ValCount{ - Val: int64(fmax) + field.Min, + Val: int64(fmax) + bsig.Min, Count: int64(fcount), }, nil } @@ -685,7 +676,7 @@ func (e *Executor) executeIntersectSlice(ctx context.Context, index string, c *p // executeRangeSlice executes a range() call for a local slice. func (e *Executor) executeRangeSlice(ctx context.Context, index string, c *pql.Call, slice uint64) (*Row, error) { - // Handle field ranges differently. + // Handle bsiGroup ranges differently. if c.HasConditionArg() { return e.executeBSIGroupRangeSlice(ctx, index, c, slice) } @@ -756,38 +747,29 @@ func (e *Executor) executeRangeSlice(ctx context.Context, index string, c *pql.C return row, nil } -// executeBSIGroupRangeSlice executes a range(field) call for a local slice. +// executeBSIGroupRangeSlice executes a range(bsiGroup) call for a local slice. func (e *Executor) executeBSIGroupRangeSlice(ctx context.Context, index string, c *pql.Call, slice uint64) (*Row, error) { - // Parse frame, use default if unset. - frame, _ := c.Args["frame"].(string) - if frame == "" { - frame = DefaultFrame - } - f := e.Holder.Frame(index, frame) - if f == nil { - return nil, ErrFrameNotFound - } - - // Remove frame field. - args := pql.CopyArgs(c.Args) - delete(args, "frame") - - // Only one conditional field should remain. - if len(args) == 0 { + // Only one conditional should be present. + if len(c.Args) == 0 { return nil, errors.New("Range(): condition required") - } else if len(args) > 1 { + } else if len(c.Args) > 1 { return nil, errors.New("Range(): too many arguments") } - // Extract condition field. - var fieldName string + // Extract conditional. + var frameName string var cond *pql.Condition - for k, v := range args { + for k, v := range c.Args { vv, ok := v.(*pql.Condition) if !ok { return nil, fmt.Errorf("Range(): %q: expected condition argument, got %v", k, v) } - fieldName, cond = k, vv + frameName, cond = k, vv + } + + f := e.Holder.Frame(index, frameName) + if f == nil { + return nil, ErrFrameNotFound } // EQ null (not implemented: flip frag.NotNull with max ColumnID) @@ -799,19 +781,19 @@ func (e *Executor) executeBSIGroupRangeSlice(ctx context.Context, index string, // Handle `!= null`. if cond.Op == pql.NEQ && cond.Value == nil { - // Find field. - field := f.bsiGroup(fieldName) - if field == nil { + // Find bsiGroup. + bsig := f.bsiGroup(frameName) + if bsig == nil { return nil, ErrBSIGroupNotFound } // Retrieve fragment. - frag := e.Holder.Fragment(index, frame, viewBSIGroupPrefix+fieldName, slice) + frag := e.Holder.Fragment(index, frameName, viewBSIGroupPrefix+frameName, slice) if frag == nil { return NewRow(), nil } - return frag.NotNull(field.BitDepth()) + return frag.NotNull(bsig.BitDepth()) } else if cond.Op == pql.BETWEEN { @@ -826,33 +808,33 @@ func (e *Executor) executeBSIGroupRangeSlice(ctx context.Context, index string, } // The reason we don't just call: - // return f.RangeBetween(fieldName, predicates[0], predicates[1]) + // return f.RangeBetween(frameName, predicates[0], predicates[1]) // here is because we need the call to be slice-specific. - // Find field. - field := f.bsiGroup(fieldName) - if field == nil { + // Find bsiGroup. + bsig := f.bsiGroup(frameName) + if bsig == nil { return nil, ErrBSIGroupNotFound } - baseValueMin, baseValueMax, outOfRange := field.baseValueBetween(predicates[0], predicates[1]) + baseValueMin, baseValueMax, outOfRange := bsig.baseValueBetween(predicates[0], predicates[1]) if outOfRange { return NewRow(), nil } // Retrieve fragment. - frag := e.Holder.Fragment(index, frame, viewBSIGroupPrefix+fieldName, slice) + frag := e.Holder.Fragment(index, frameName, viewBSIGroupPrefix+frameName, slice) if frag == nil { return NewRow(), nil } // If the query is asking for the entire valid range, just return - // the not-null bitmap for the field. - if predicates[0] <= field.Min && predicates[1] >= field.Max { - return frag.NotNull(field.BitDepth()) + // the not-null bitmap for the bsiGroup. + if predicates[0] <= bsig.Min && predicates[1] >= bsig.Max { + return frag.NotNull(bsig.BitDepth()) } - return frag.RangeBetween(field.BitDepth(), baseValueMin, baseValueMax) + return frag.RangeBetween(bsig.BitDepth(), baseValueMin, baseValueMax) } else { @@ -862,36 +844,36 @@ func (e *Executor) executeBSIGroupRangeSlice(ctx context.Context, index string, return nil, errors.New("Range(): conditions only support integer values") } - // Find field. - field := f.bsiGroup(fieldName) - if field == nil { + // Find bsiGroup. + bsig := f.bsiGroup(frameName) + if bsig == nil { return nil, ErrBSIGroupNotFound } - baseValue, outOfRange := field.baseValue(cond.Op, value) + baseValue, outOfRange := bsig.baseValue(cond.Op, value) if outOfRange && cond.Op != pql.NEQ { return NewRow(), nil } // Retrieve fragment. - frag := e.Holder.Fragment(index, frame, viewBSIGroupPrefix+fieldName, slice) + frag := e.Holder.Fragment(index, frameName, viewBSIGroupPrefix+frameName, slice) if frag == nil { return NewRow(), nil } - // LT[E] and GT[E] should return all not-null if selected range fully encompasses valid field range. - if (cond.Op == pql.LT && value > field.Max) || (cond.Op == pql.LTE && value >= field.Max) || - (cond.Op == pql.GT && value < field.Min) || (cond.Op == pql.GTE && value <= field.Min) { - return frag.NotNull(field.BitDepth()) + // LT[E] and GT[E] should return all not-null if selected range fully encompasses valid bsiGroup range. + if (cond.Op == pql.LT && value > bsig.Max) || (cond.Op == pql.LTE && value >= bsig.Max) || + (cond.Op == pql.GT && value < bsig.Min) || (cond.Op == pql.GTE && value <= bsig.Min) { + return frag.NotNull(bsig.BitDepth()) } // outOfRange for NEQ should return all not-null. if outOfRange && cond.Op == pql.NEQ { - return frag.NotNull(field.BitDepth()) + return frag.NotNull(bsig.BitDepth()) } - f.Stats.Count("range:field", 1, 1.0) - return frag.RangeOp(cond.Op, field.BitDepth(), baseValue) + f.Stats.Count("range:bsigroup", 1, 1.0) + return frag.RangeOp(cond.Op, bsig.BitDepth(), baseValue) } } diff --git a/executor_test.go b/executor_test.go index d06a5027c..f042d3f8f 100644 --- a/executor_test.go +++ b/executor_test.go @@ -834,7 +834,7 @@ func TestExecutor_Execute_Range(t *testing.T) { } t.Run("EQ", func(t *testing.T) { - if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=foo, foo == 20)`), nil, nil); err != nil { + if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(foo == 20)`), nil, nil); err != nil { t.Fatal(err) } else if !reflect.DeepEqual([]uint64{50, (5 * SliceWidth) + 100}, result[0].(*pilosa.Row).Columns()) { t.Fatalf("unexpected result: %s", spew.Sdump(result)) @@ -843,19 +843,19 @@ func TestExecutor_Execute_Range(t *testing.T) { t.Run("NEQ", func(t *testing.T) { // NEQ null - if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=other, other != null)`), nil, nil); err != nil { + if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(other != null)`), nil, nil); err != nil { t.Fatal(err) } else if !reflect.DeepEqual([]uint64{0}, result[0].(*pilosa.Row).Columns()) { t.Fatalf("unexpected result: %s", spew.Sdump(result)) } // NEQ - if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=foo, foo != 20)`), nil, nil); err != nil { + if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(foo != 20)`), nil, nil); err != nil { t.Fatal(err) } else if !reflect.DeepEqual([]uint64{SliceWidth, SliceWidth + 1, SliceWidth + 2}, result[0].(*pilosa.Row).Columns()) { t.Fatalf("unexpected result: %s", spew.Sdump(result)) } // NEQ - - if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=other, other != -20)`), nil, nil); err != nil { + if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(other != -20)`), nil, nil); err != nil { t.Fatal(err) } else if !reflect.DeepEqual([]uint64{0}, result[0].(*pilosa.Row).Columns()) { //t.Fatalf("unexpected result: %s", spew.Sdump(result)) @@ -864,7 +864,7 @@ func TestExecutor_Execute_Range(t *testing.T) { }) t.Run("LT", func(t *testing.T) { - if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=foo, foo < 20)`), nil, nil); err != nil { + if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(foo < 20)`), nil, nil); err != nil { t.Fatal(err) } else if !reflect.DeepEqual([]uint64{SliceWidth + 2}, result[0].(*pilosa.Row).Columns()) { t.Fatalf("unexpected result: %s", spew.Sdump(result)) @@ -872,7 +872,7 @@ func TestExecutor_Execute_Range(t *testing.T) { }) t.Run("LTE", func(t *testing.T) { - if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=foo, foo <= 20)`), nil, nil); err != nil { + if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(foo <= 20)`), nil, nil); err != nil { t.Fatal(err) } else if !reflect.DeepEqual([]uint64{50, SliceWidth + 2, (5 * SliceWidth) + 100}, result[0].(*pilosa.Row).Columns()) { t.Fatalf("unexpected result: %s", spew.Sdump(result)) @@ -880,7 +880,7 @@ func TestExecutor_Execute_Range(t *testing.T) { }) t.Run("GT", func(t *testing.T) { - if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=foo, foo > 20)`), nil, nil); err != nil { + if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(foo > 20)`), nil, nil); err != nil { t.Fatal(err) } else if !reflect.DeepEqual([]uint64{SliceWidth, SliceWidth + 1}, result[0].(*pilosa.Row).Columns()) { t.Fatalf("unexpected result: %s", spew.Sdump(result)) @@ -888,7 +888,7 @@ func TestExecutor_Execute_Range(t *testing.T) { }) t.Run("GTE", func(t *testing.T) { - if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=foo, foo >= 20)`), nil, nil); err != nil { + if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(foo >= 20)`), nil, nil); err != nil { t.Fatal(err) } else if !reflect.DeepEqual([]uint64{50, SliceWidth, SliceWidth + 1, (5 * SliceWidth) + 100}, result[0].(*pilosa.Row).Columns()) { t.Fatalf("unexpected result: %s", spew.Sdump(result)) @@ -896,7 +896,7 @@ func TestExecutor_Execute_Range(t *testing.T) { }) t.Run("BETWEEN", func(t *testing.T) { - if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=other, other >< [1, 1000])`), nil, nil); err != nil { + if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(other >< [1, 1000])`), nil, nil); err != nil { t.Fatal(err) } else if !reflect.DeepEqual([]uint64{0}, result[0].(*pilosa.Row).Columns()) { t.Fatalf("unexpected result: %s", spew.Sdump(result)) @@ -905,7 +905,7 @@ func TestExecutor_Execute_Range(t *testing.T) { // Ensure that the NotNull code path gets run. t.Run("NotNull", func(t *testing.T) { - if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=other, other >< [0, 1000])`), nil, nil); err != nil { + if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(other >< [0, 1000])`), nil, nil); err != nil { t.Fatal(err) } else if !reflect.DeepEqual([]uint64{0}, result[0].(*pilosa.Row).Columns()) { t.Fatalf("unexpected result: %s", spew.Sdump(result)) @@ -913,7 +913,7 @@ func TestExecutor_Execute_Range(t *testing.T) { }) t.Run("BelowMin", func(t *testing.T) { - if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=foo, foo == 0)`), nil, nil); err != nil { + if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(foo == 0)`), nil, nil); err != nil { t.Fatal(err) } else if !reflect.DeepEqual([]uint64{}, result[0].(*pilosa.Row).Columns()) { t.Fatalf("unexpected result: %s", spew.Sdump(result)) @@ -921,7 +921,7 @@ func TestExecutor_Execute_Range(t *testing.T) { }) t.Run("AboveMax", func(t *testing.T) { - if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=foo, foo == 200)`), nil, nil); err != nil { + if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(foo == 200)`), nil, nil); err != nil { t.Fatal(err) } else if !reflect.DeepEqual([]uint64{}, result[0].(*pilosa.Row).Columns()) { t.Fatalf("unexpected result: %s", spew.Sdump(result)) @@ -929,7 +929,7 @@ func TestExecutor_Execute_Range(t *testing.T) { }) t.Run("LTAboveMax", func(t *testing.T) { - if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=edge, edge < 200)`), nil, nil); err != nil { + if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(edge < 200)`), nil, nil); err != nil { t.Fatal(err) } else if !reflect.DeepEqual([]uint64{0, 1}, result[0].(*pilosa.Row).Columns()) { t.Fatalf("unexpected result: %s", spew.Sdump(result[0].(*pilosa.Row).Columns())) @@ -937,7 +937,7 @@ func TestExecutor_Execute_Range(t *testing.T) { }) t.Run("GTBelowMin", func(t *testing.T) { - if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=edge, edge > -200)`), nil, nil); err != nil { + if result, err := e.Execute(context.Background(), "i", test.MustParse(`Range(edge > -200)`), nil, nil); err != nil { t.Fatal(err) } else if !reflect.DeepEqual([]uint64{0, 1}, result[0].(*pilosa.Row).Columns()) { t.Fatalf("unexpected result: %s", spew.Sdump(result[0].(*pilosa.Row).Columns())) @@ -945,13 +945,7 @@ func TestExecutor_Execute_Range(t *testing.T) { }) t.Run("ErrFrameNotFound", func(t *testing.T) { - if _, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=bad_frame, foo >= 20)`), nil, nil); err != pilosa.ErrFrameNotFound { - t.Fatal(err) - } - }) - - t.Run("ErrBSIGroupNotFound", func(t *testing.T) { - if _, err := e.Execute(context.Background(), "i", test.MustParse(`Range(frame=foo, bad_field >= 20)`), nil, nil); err != pilosa.ErrBSIGroupNotFound { + if _, err := e.Execute(context.Background(), "i", test.MustParse(`Range(bad_frame >= 20)`), nil, nil); err != pilosa.ErrFrameNotFound { t.Fatal(err) } })