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{}