mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-07 09:05:55 +00:00
fix oversized rangeEQ
This commit is contained in:
parent
b9b0dd293f
commit
e6b4cc2f32
2 changed files with 43 additions and 20 deletions
29
fragment.go
29
fragment.go
|
|
@ -1330,19 +1330,20 @@ func (f *fragment) rangeEQ(tx Tx, bitDepth uint, predicate int64) (*Row, error)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// Filter to only positive/negative numbers.
|
||||
upredicate := absInt64(predicate)
|
||||
if uint(bits.Len64(upredicate)) > bitDepth {
|
||||
// Predicate is out of range.
|
||||
return NewRow(), nil
|
||||
}
|
||||
|
||||
// Filter to only positive/negative numbers.
|
||||
r, err := f.row(tx, bsiSignBit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if predicate < 0 {
|
||||
r, err := f.row(tx, bsiSignBit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b = b.Intersect(r) // only negatives
|
||||
} else {
|
||||
r, err := f.row(tx, bsiSignBit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b = b.Difference(r) // only positives
|
||||
}
|
||||
|
||||
|
|
@ -1428,18 +1429,10 @@ func (f *fragment) rangeLT(tx Tx, bitDepth uint, predicate int64, allowEquality
|
|||
}
|
||||
}
|
||||
|
||||
// msb gives the 1-indexed position (counting from lsb) of the most
|
||||
// significant bit. E.G. for 1 it would return 1, for 2 2, for 3 2,
|
||||
// for 4 3, for 8 4, etc.
|
||||
func msb(x uint64) uint {
|
||||
lz := bits.LeadingZeros64(x)
|
||||
return 64 - uint(lz)
|
||||
}
|
||||
|
||||
// rangeLTUnsigned returns all bits LT/LTE the predicate without considering the sign bit.
|
||||
func (f *fragment) rangeLTUnsigned(tx Tx, filter *Row, bitDepth uint, predicate uint64, allowEquality bool) (*Row, error) {
|
||||
switch {
|
||||
case msb(predicate) > bitDepth:
|
||||
case uint(bits.Len64(predicate)) > bitDepth:
|
||||
fallthrough
|
||||
case predicate == (1<<bitDepth)-1 && allowEquality:
|
||||
// This query matches all possible values.
|
||||
|
|
|
|||
|
|
@ -710,6 +710,34 @@ func TestFragment_Range(t *testing.T) {
|
|||
}
|
||||
})
|
||||
|
||||
t.Run("EQOversizeRegression", func(t *testing.T) {
|
||||
f, idx := mustOpenFragment("i", "f", viewStandard, 0, "")
|
||||
_ = idx
|
||||
defer f.Clean(t)
|
||||
|
||||
// Obtain transaction.
|
||||
tx := &RoaringTx{fragment: f}
|
||||
|
||||
// Set values.
|
||||
if _, err := f.setValue(tx, 1000, 1, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if _, err := f.setValue(tx, 2000, 1, 1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Query for equality.
|
||||
if b, err := f.rangeOp(tx, pql.EQ, 1, 3); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(b.Columns(), []uint64{}) {
|
||||
t.Fatalf("unexpected columns: %+v", b.Columns())
|
||||
}
|
||||
if b, err := f.rangeOp(tx, pql.EQ, 1, 4); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(b.Columns(), []uint64{}) {
|
||||
t.Fatalf("unexpected columns: %+v", b.Columns())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("NEQ", func(t *testing.T) {
|
||||
f, idx := mustOpenFragment("i", "f", viewStandard, 0, "")
|
||||
_ = idx
|
||||
|
|
@ -909,7 +937,8 @@ func TestFragment_Range(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("GTOversizeRegression", func(t *testing.T) {
|
||||
f := mustOpenFragment("i", "f", viewStandard, 0, "")
|
||||
f, idx := mustOpenFragment("i", "f", viewStandard, 0, "")
|
||||
_ = idx
|
||||
defer f.Clean(t)
|
||||
|
||||
// Obtain transaction.
|
||||
|
|
@ -982,7 +1011,8 @@ func TestFragment_Range(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("BetweenCommonBitsRegression", func(t *testing.T) {
|
||||
f := mustOpenFragment("i", "f", viewStandard, 0, "")
|
||||
f, idx := mustOpenFragment("i", "f", viewStandard, 0, "")
|
||||
_ = idx
|
||||
defer f.Clean(t)
|
||||
|
||||
// Obtain transaction.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue