@@ -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.
831880func (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
0 commit comments