github.com/dolthub/go-mysql-server@v0.18.0/sql/index_builder_test.go (about) 1 // Copyright 2022 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package sql_test 16 17 import ( 18 "context" 19 "fmt" 20 "testing" 21 22 "github.com/stretchr/testify/assert" 23 24 "github.com/dolthub/go-mysql-server/sql" 25 "github.com/dolthub/go-mysql-server/sql/types" 26 ) 27 28 func TestIndexBuilderRanges(t *testing.T) { 29 ctx := sql.NewContext(context.Background()) 30 31 t.Run("None=[NULL,Inf)", func(t *testing.T) { 32 builder := sql.NewIndexBuilder(testIndex{1}) 33 ranges := builder.Ranges(ctx) 34 assert.NotNil(t, ranges) 35 assert.Equal(t, sql.RangeCollection{sql.Range{sql.AllRangeColumnExpr(types.Int8)}}, ranges) 36 }) 37 38 t.Run("IsNull=[NULL,NULL]", func(t *testing.T) { 39 builder := sql.NewIndexBuilder(testIndex{1}) 40 builder = builder.IsNull(ctx, "column_0") 41 ranges := builder.Ranges(ctx) 42 assert.NotNil(t, ranges) 43 assert.Equal(t, sql.RangeCollection{sql.Range{sql.NullRangeColumnExpr(types.Int8)}}, ranges) 44 }) 45 46 t.Run("IsNull,Equals2=EmptyRange", func(t *testing.T) { 47 builder := sql.NewIndexBuilder(testIndex{1}) 48 builder = builder.IsNull(ctx, "column_0") 49 builder = builder.Equals(ctx, "column_0", 2) 50 ranges := builder.Ranges(ctx) 51 assert.NotNil(t, ranges) 52 assert.Equal(t, sql.RangeCollection{sql.Range{sql.EmptyRangeColumnExpr(types.Int8)}}, ranges) 53 }) 54 55 t.Run("NotEquals2=(NULL,2),(2,Inf)", func(t *testing.T) { 56 builder := sql.NewIndexBuilder(testIndex{1}) 57 builder = builder.NotEquals(ctx, "column_0", 2) 58 ranges := builder.Ranges(ctx) 59 assert.NotNil(t, ranges) 60 assert.Equal(t, sql.RangeCollection{sql.Range{sql.GreaterThanRangeColumnExpr(int8(2), types.Int8)}, sql.Range{sql.LessThanRangeColumnExpr(int8(2), types.Int8)}}, ranges) 61 }) 62 63 t.Run("NotEquals2,Equals2=(Inf,Inf)", func(t *testing.T) { 64 builder := sql.NewIndexBuilder(testIndex{1}) 65 builder = builder.NotEquals(ctx, "column_0", 2) 66 builder = builder.Equals(ctx, "column_0", 2) 67 ranges := builder.Ranges(ctx) 68 assert.NotNil(t, ranges) 69 assert.Equal(t, sql.RangeCollection{sql.Range{sql.EmptyRangeColumnExpr(types.Int8)}}, ranges) 70 }) 71 72 t.Run("Equals2,NotEquals2=(Inf,Inf)", func(t *testing.T) { 73 builder := sql.NewIndexBuilder(testIndex{1}) 74 builder = builder.Equals(ctx, "column_0", 2) 75 builder = builder.NotEquals(ctx, "column_0", 2) 76 ranges := builder.Ranges(ctx) 77 assert.NotNil(t, ranges) 78 assert.Equal(t, sql.RangeCollection{sql.Range{sql.EmptyRangeColumnExpr(types.Int8)}}, ranges) 79 }) 80 81 t.Run("LT4=(NULL,4)", func(t *testing.T) { 82 builder := sql.NewIndexBuilder(testIndex{1}) 83 builder = builder.LessThan(ctx, "column_0", 4) 84 ranges := builder.Ranges(ctx) 85 assert.NotNil(t, ranges) 86 assert.Equal(t, sql.RangeCollection{sql.Range{sql.LessThanRangeColumnExpr(int8(4), types.Int8)}}, ranges) 87 }) 88 89 t.Run("GT2,LT4=(2,4)", func(t *testing.T) { 90 builder := sql.NewIndexBuilder(testIndex{1}) 91 builder = builder.GreaterThan(ctx, "column_0", 2) 92 builder = builder.LessThan(ctx, "column_0", 4) 93 ranges := builder.Ranges(ctx) 94 assert.NotNil(t, ranges) 95 assert.Equal(t, sql.RangeCollection{sql.Range{sql.OpenRangeColumnExpr(int8(2), int8(4), types.Int8)}}, ranges) 96 }) 97 98 t.Run("GT2,GT6=(4,Inf)", func(t *testing.T) { 99 builder := sql.NewIndexBuilder(testIndex{1}) 100 builder = builder.GreaterThan(ctx, "column_0", 2) 101 builder = builder.GreaterThan(ctx, "column_0", 6) 102 ranges := builder.Ranges(ctx) 103 assert.NotNil(t, ranges) 104 assert.Equal(t, sql.RangeCollection{sql.Range{sql.GreaterThanRangeColumnExpr(int8(6), types.Int8)}}, ranges) 105 }) 106 107 t.Run("GT2,LT4,GT6=(Inf,Inf)", func(t *testing.T) { 108 builder := sql.NewIndexBuilder(testIndex{1}) 109 builder = builder.GreaterThan(ctx, "column_0", 2) 110 builder = builder.LessThan(ctx, "column_0", 4) 111 builder = builder.GreaterThan(ctx, "column_0", 6) 112 ranges := builder.Ranges(ctx) 113 assert.NotNil(t, ranges) 114 assert.Equal(t, sql.RangeCollection{sql.Range{sql.EmptyRangeColumnExpr(types.Int8)}}, ranges) 115 }) 116 117 t.Run("NotEqual2,NotEquals4=(2,4),(4,Inf),(NULL,2)", func(t *testing.T) { 118 builder := sql.NewIndexBuilder(testIndex{1}) 119 builder = builder.NotEquals(ctx, "column_0", 2) 120 builder = builder.NotEquals(ctx, "column_0", 4) 121 ranges := builder.Ranges(ctx) 122 assert.NotNil(t, ranges) 123 assert.Equal(t, sql.RangeCollection{sql.Range{sql.OpenRangeColumnExpr(int8(2), int8(4), types.Int8)}, sql.Range{sql.GreaterThanRangeColumnExpr(int8(4), types.Int8)}, sql.Range{sql.LessThanRangeColumnExpr(int8(2), types.Int8)}}, ranges) 124 }) 125 126 t.Run("ThreeColumnCombine", func(t *testing.T) { 127 clauses := make([]sql.RangeCollection, 3) 128 clauses[0] = sql.NewIndexBuilder(testIndex{3}).GreaterOrEqual(ctx, "column_0", 99).LessThan(ctx, "column_1", 66).Ranges(ctx) 129 clauses[1] = sql.NewIndexBuilder(testIndex{3}).GreaterOrEqual(ctx, "column_0", 1).LessOrEqual(ctx, "column_0", 47).Ranges(ctx) 130 clauses[2] = sql.NewIndexBuilder(testIndex{3}).NotEquals(ctx, "column_0", 2).LessThan(ctx, "column_1", 30).Ranges(ctx) 131 assert.Len(t, clauses[0], 1) 132 assert.Len(t, clauses[1], 1) 133 assert.Len(t, clauses[2], 2) 134 for _, perm := range [][]int{ 135 {0, 1, 2}, 136 {0, 2, 1}, 137 {1, 2, 0}, 138 {1, 0, 2}, 139 {2, 0, 1}, 140 {2, 1, 0}, 141 } { 142 var all sql.RangeCollection 143 all = append(all, clauses[perm[0]]...) 144 all = append(all, clauses[perm[1]]...) 145 all = append(all, clauses[perm[2]]...) 146 combined, err := sql.RemoveOverlappingRanges(all...) 147 assert.NoError(t, err) 148 assert.NotNil(t, combined) 149 assert.Equal(t, sql.RangeCollection{ 150 sql.Range{sql.LessThanRangeColumnExpr(int8(1), types.Int8), sql.LessThanRangeColumnExpr(int8(30), types.Int8), sql.AllRangeColumnExpr(types.Int8)}, 151 sql.Range{sql.ClosedRangeColumnExpr(int8(1), int8(47), types.Int8), sql.AllRangeColumnExpr(types.Int8), sql.AllRangeColumnExpr(types.Int8)}, 152 sql.Range{sql.OpenRangeColumnExpr(int8(47), int8(99), types.Int8), sql.LessThanRangeColumnExpr(int8(30), types.Int8), sql.AllRangeColumnExpr(types.Int8)}, 153 sql.Range{sql.GreaterOrEqualRangeColumnExpr(int8(99), types.Int8), sql.LessThanRangeColumnExpr(int8(66), types.Int8), sql.AllRangeColumnExpr(types.Int8)}, 154 }, combined) 155 } 156 }) 157 } 158 159 type testIndex struct { 160 numcols int 161 } 162 163 func (testIndex) CanSupport(...sql.Range) bool { 164 return true 165 } 166 167 func (testIndex) ID() string { 168 return "test_index" 169 } 170 171 func (testIndex) Database() string { 172 return "database" 173 } 174 175 func (testIndex) Table() string { 176 return "table" 177 } 178 179 func (i testIndex) Expressions() []string { 180 res := make([]string, i.numcols) 181 for i := range res { 182 res[i] = fmt.Sprintf("column_%d", i) 183 } 184 return res 185 } 186 187 func (testIndex) IsUnique() bool { 188 return false 189 } 190 191 func (testIndex) IsSpatial() bool { 192 return false 193 } 194 195 func (testIndex) IsFullText() bool { 196 return false 197 } 198 199 func (testIndex) Comment() string { 200 return "" 201 } 202 203 func (testIndex) IndexType() string { 204 return "FAKE" 205 } 206 207 func (testIndex) IsGenerated() bool { 208 return false 209 } 210 211 func (i testIndex) ColumnExpressionTypes() []sql.ColumnExpressionType { 212 es := i.Expressions() 213 res := make([]sql.ColumnExpressionType, len(es)) 214 for i := range es { 215 res[i] = sql.ColumnExpressionType{Expression: es[i], Type: types.Int8} 216 } 217 return res 218 } 219 220 func (testIndex) PrefixLengths() []uint16 { 221 return nil 222 } 223 224 var _ sql.Index = testIndex{}