Skip to content

Commit d1037bb

Browse files
author
James Cor
committed
rangetree and overlap check for some in queries
1 parent 97b69d5 commit d1037bb

File tree

2 files changed

+66
-22
lines changed

2 files changed

+66
-22
lines changed

sql/analyzer/costed_index_scan.go

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
"strings"
2222
"time"
2323

24+
"github.com/shopspring/decimal"
25+
2426
"github.com/dolthub/go-mysql-server/sql"
2527
"github.com/dolthub/go-mysql-server/sql/expression"
2628
"github.com/dolthub/go-mysql-server/sql/expression/function/spatial"
@@ -826,6 +828,53 @@ type indexScanRangeBuilder struct {
826828
leftover []sql.Expression
827829
}
828830

831+
func castToInt64(v any) (int64, bool) {
832+
switch v := v.(type) {
833+
case int:
834+
return int64(v), true
835+
case int8:
836+
return int64(v), true
837+
case int16:
838+
return int64(v), true
839+
case int32:
840+
return int64(v), true
841+
case int64:
842+
return v, true
843+
case float32, float64, decimal.Decimal:
844+
// TODO: return an empty range here
845+
return 0, false
846+
default:
847+
return 0, false
848+
}
849+
}
850+
851+
func setToSignedIntRange(setVals []any, colExprTypes []sql.ColumnExpressionType) (sql.MySQLRangeCollection, bool) {
852+
if len(colExprTypes) != 1 {
853+
return nil, false
854+
}
855+
typ := colExprTypes[0].Type
856+
if !types.IsSigned(typ) {
857+
return nil, false
858+
}
859+
var ok bool
860+
keys := make([]int64, len(setVals))
861+
for i, val := range setVals {
862+
keys[i], ok = castToInt64(val)
863+
if !ok {
864+
return nil, false
865+
}
866+
}
867+
slices.Sort(keys)
868+
slices.Compact(keys)
869+
res := make(sql.MySQLRangeCollection, len(keys))
870+
for i, key := range keys {
871+
res[i] = sql.MySQLRange{
872+
sql.ClosedRangeColumnExpr(key, key, typ),
873+
}
874+
}
875+
return res, true
876+
}
877+
829878
// buildRangeCollection converts our representation of the best index scan
830879
// into the format that represents an index lookup, a list of sql.Range.
831880
func (b *indexScanRangeBuilder) buildRangeCollection(f indexFilter) (sql.MySQLRangeCollection, error) {
@@ -839,18 +888,13 @@ func (b *indexScanRangeBuilder) buildRangeCollection(f indexFilter) (sql.MySQLRa
839888
case *iScanOr:
840889
ranges, err = b.rangeBuildOr(f, inScan)
841890
case *iScanLeaf:
842-
// TODO: special case for in set. can skip overlapping ranges since it's a series of equality checks
843-
// TODO: sequential integers can be converted to a single partition, but i guess that's harder?
891+
// TODO: special case for in set. can skip building range tree and overlapping range check since it's a series of equality checks
844892
if f.Op() == sql.IndexScanOpInSet {
845-
bb := sql.NewMySQLIndexBuilder(b.idx)
846-
b.rangeBuildDefaultLeaf(bb, f, inScan)
847-
if _, err := bb.Build(b.ctx); err != nil {
848-
return nil, err
893+
cets := b.idx.ColumnExpressionTypes()
894+
if ranges, ok := setToSignedIntRange(f.setValues, cets); ok {
895+
return ranges, nil
849896
}
850-
ranges = bb.Ranges(b.ctx)
851-
return ranges, nil
852897
}
853-
854898
ranges, err = b.rangeBuildLeaf(f, inScan)
855899
default:
856900
return nil, fmt.Errorf("unknown indexFilter type: %T", f)
@@ -1441,18 +1485,14 @@ func newLeaf(ctx *sql.Context, id indexScanId, e sql.Expression, underlying stri
14411485

14421486
if op == sql.IndexScanOpInSet || op == sql.IndexScanOpNotInSet {
14431487
tup := right.(expression.Tuple)
1444-
litSet := make(map[any]struct{}, len(tup))
1445-
setVals := make([]any, 0, len(tup))
1488+
litSet := make([]any, len(tup))
14461489
var litType sql.Type
1447-
for _, lit := range tup {
1490+
for i, lit := range tup {
14481491
value, err := lit.Eval(ctx, nil)
14491492
if err != nil {
14501493
return nil, false
14511494
}
1452-
if _, ok = litSet[value]; !ok {
1453-
litSet[value] = struct{}{}
1454-
setVals = append(setVals, value)
1455-
}
1495+
litSet[i] = value
14561496
if litType == nil {
14571497
litType = lit.Type()
14581498
}
@@ -1461,7 +1501,7 @@ func newLeaf(ctx *sql.Context, id indexScanId, e sql.Expression, underlying stri
14611501
id: id,
14621502
gf: gf,
14631503
op: op,
1464-
setValues: setVals,
1504+
setValues: litSet,
14651505
litType: litType,
14661506
underlying: underlying,
14671507
}, true

sql/index_builder.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,15 +120,19 @@ func (b *MySQLIndexBuilder) Equals(ctx *Context, colExpr string, keyType Type, k
120120
for i, k := range keys {
121121
// if converting from float to int results in rounding, then it's empty range
122122
if t, ok := colTyp.(NumberType); ok && !t.IsFloat() {
123-
f, c := floor(k), ceil(k)
124-
switch k.(type) {
125-
case float32, float64:
126-
if f != c {
123+
switch k := k.(type) {
124+
case float32:
125+
if float32(int64(k)) != k {
126+
potentialRanges[i] = EmptyRangeColumnExpr(colTyp)
127+
continue
128+
}
129+
case float64:
130+
if float64(int64(k)) != k {
127131
potentialRanges[i] = EmptyRangeColumnExpr(colTyp)
128132
continue
129133
}
130134
case decimal.Decimal:
131-
if !f.(decimal.Decimal).Equals(c.(decimal.Decimal)) {
135+
if !k.Equal(decimal.NewFromInt(k.IntPart())) {
132136
potentialRanges[i] = EmptyRangeColumnExpr(colTyp)
133137
continue
134138
}

0 commit comments

Comments
 (0)