github.com/dolthub/go-mysql-server@v0.18.0/sql/range_cut.go (about)

     1  // Copyright 2021 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
    16  
    17  import (
    18  	"fmt"
    19  )
    20  
    21  // RangeCut represents a position on the line of all possible values.
    22  type RangeCut interface {
    23  	// Compare returns an integer stating the relative position of the calling RangeCut to the given RangeCut.
    24  	Compare(RangeCut, Type) (int, error)
    25  	// String returns the RangeCut as a string for display purposes.
    26  	String() string
    27  	// TypeAsLowerBound returns the bound type if the calling RangeCut is the lower bound of a range.
    28  	TypeAsLowerBound() RangeBoundType
    29  	// TypeAsUpperBound returns the bound type if the calling RangeCut is the upper bound of a range.
    30  	TypeAsUpperBound() RangeBoundType
    31  }
    32  
    33  // RangeBoundType is the bound of the RangeCut.
    34  type RangeBoundType int
    35  
    36  const (
    37  	// Open bounds represent exclusion.
    38  	Open RangeBoundType = iota
    39  	// Closed bounds represent inclusion.
    40  	Closed
    41  )
    42  
    43  // Inclusive returns whether the bound represents inclusion.
    44  func (bt RangeBoundType) Inclusive() bool {
    45  	return bt == Closed
    46  }
    47  
    48  // GetRangeCutKey returns the inner value from the given RangeCut.
    49  func GetRangeCutKey(c RangeCut) interface{} {
    50  	switch c := c.(type) {
    51  	case Below:
    52  		return c.Key
    53  	case Above:
    54  		return c.Key
    55  	default:
    56  		panic(fmt.Errorf("need to check the RangeCut type before calling GetRangeCutKey, used on `%T`", c))
    57  	}
    58  }
    59  
    60  func RangeCutIsBinding(c RangeCut) bool {
    61  	switch c.(type) {
    62  	case Below, Above:
    63  		return true
    64  	case AboveAll, AboveNull, BelowNull:
    65  		return false
    66  	default:
    67  		panic(fmt.Errorf("unknown range cut %v", c))
    68  	}
    69  }
    70  
    71  // GetRangeCutMax returns the RangeCut with the highest value.
    72  func GetRangeCutMax(typ Type, cuts ...RangeCut) (RangeCut, error) {
    73  	i := 0
    74  	var maxCut RangeCut
    75  	for ; i < len(cuts); i++ {
    76  		if cuts[i] != nil {
    77  			maxCut = cuts[i]
    78  			i++
    79  			break
    80  		}
    81  	}
    82  	for ; i < len(cuts); i++ {
    83  		if cuts[i] == nil {
    84  			continue
    85  		}
    86  		comp, err := maxCut.Compare(cuts[i], typ)
    87  		if err != nil {
    88  			return maxCut, err
    89  		}
    90  		if comp == -1 {
    91  			maxCut = cuts[i]
    92  		}
    93  	}
    94  	return maxCut, nil
    95  }
    96  
    97  // GetRangeCutMin returns the RangeCut with the lowest value.
    98  func GetRangeCutMin(typ Type, cuts ...RangeCut) (RangeCut, error) {
    99  	i := 0
   100  	var minCut RangeCut
   101  	for ; i < len(cuts); i++ {
   102  		if cuts[i] != nil {
   103  			minCut = cuts[i]
   104  			i++
   105  			break
   106  		}
   107  	}
   108  	for ; i < len(cuts); i++ {
   109  		if cuts[i] == nil {
   110  			continue
   111  		}
   112  		comp, err := minCut.Compare(cuts[i], typ)
   113  		if err != nil {
   114  			return minCut, err
   115  		}
   116  		if comp == 1 {
   117  			minCut = cuts[i]
   118  		}
   119  	}
   120  	return minCut, nil
   121  }
   122  
   123  // Above represents the position immediately above the contained key.
   124  type Above struct {
   125  	Key interface{}
   126  }
   127  
   128  var _ RangeCut = Above{}
   129  
   130  // Compare implements RangeCut.
   131  func (a Above) Compare(c RangeCut, typ Type) (int, error) {
   132  	switch c := c.(type) {
   133  	case AboveAll:
   134  		return -1, nil
   135  	case AboveNull:
   136  		return 1, nil
   137  	case Above:
   138  		return typ.Compare(a.Key, c.Key)
   139  	case Below:
   140  		cmp, err := typ.Compare(a.Key, c.Key)
   141  		if err != nil {
   142  			return 0, err
   143  		}
   144  		if cmp == -1 {
   145  			return -1, nil
   146  		}
   147  		return 1, nil
   148  	case BelowNull:
   149  		return 1, nil
   150  	default:
   151  		panic(fmt.Errorf("unrecognized RangeCut type '%T'", c))
   152  	}
   153  }
   154  
   155  // String implements RangeCut.
   156  func (a Above) String() string {
   157  	return fmt.Sprintf("Above[%v]", a.Key)
   158  }
   159  
   160  // TypeAsLowerBound implements RangeCut.
   161  func (Above) TypeAsLowerBound() RangeBoundType {
   162  	return Open
   163  }
   164  
   165  // TypeAsUpperBound implements RangeCut.
   166  func (Above) TypeAsUpperBound() RangeBoundType {
   167  	return Closed
   168  }
   169  
   170  // AboveAll represents the position beyond the maximum possible value.
   171  type AboveAll struct{}
   172  
   173  var _ RangeCut = AboveAll{}
   174  
   175  // Compare implements RangeCut.
   176  func (AboveAll) Compare(c RangeCut, typ Type) (int, error) {
   177  	if _, ok := c.(AboveAll); ok {
   178  		return 0, nil
   179  	}
   180  	return 1, nil
   181  }
   182  
   183  // String implements RangeCut.
   184  func (AboveAll) String() string {
   185  	return "AboveAll"
   186  }
   187  
   188  // TypeAsLowerBound implements RangeCut.
   189  func (AboveAll) TypeAsLowerBound() RangeBoundType {
   190  	return Open
   191  }
   192  
   193  // TypeAsUpperBound implements RangeCut.
   194  func (AboveAll) TypeAsUpperBound() RangeBoundType {
   195  	return Open
   196  }
   197  
   198  // Below represents the position immediately below the contained key.
   199  type Below struct {
   200  	Key interface{}
   201  }
   202  
   203  var _ RangeCut = Below{}
   204  
   205  // Compare implements RangeCut.
   206  func (b Below) Compare(c RangeCut, typ Type) (int, error) {
   207  	switch c := c.(type) {
   208  	case AboveAll:
   209  		return -1, nil
   210  	case AboveNull:
   211  		return 1, nil
   212  	case Below:
   213  		return typ.Compare(b.Key, c.Key)
   214  	case Above:
   215  		cmp, err := typ.Compare(c.Key, b.Key)
   216  		if err != nil {
   217  			return 0, err
   218  		}
   219  		if cmp == -1 {
   220  			return 1, nil
   221  		}
   222  		return -1, nil
   223  	case BelowNull:
   224  		return 1, nil
   225  	default:
   226  		panic(fmt.Errorf("unrecognized RangeCut type '%T'", c))
   227  	}
   228  }
   229  
   230  // String implements RangeCut.
   231  func (b Below) String() string {
   232  	return fmt.Sprintf("Below[%v]", b.Key)
   233  }
   234  
   235  // TypeAsLowerBound implements RangeCut.
   236  func (Below) TypeAsLowerBound() RangeBoundType {
   237  	return Closed
   238  }
   239  
   240  // TypeAsUpperBound implements RangeCut.
   241  func (Below) TypeAsUpperBound() RangeBoundType {
   242  	return Open
   243  }
   244  
   245  // AboveNull represents the position just above NULL, lower than every possible value in the domain.
   246  type AboveNull struct{}
   247  
   248  var _ RangeCut = AboveNull{}
   249  
   250  // Compare implements RangeCut.
   251  func (AboveNull) Compare(c RangeCut, typ Type) (int, error) {
   252  	if _, ok := c.(AboveNull); ok {
   253  		return 0, nil
   254  	}
   255  	if _, ok := c.(BelowNull); ok {
   256  		return 1, nil
   257  	}
   258  	return -1, nil
   259  }
   260  
   261  // String implements RangeCut.
   262  func (AboveNull) String() string {
   263  	return "AboveNull"
   264  }
   265  
   266  // TypeAsLowerBound implements RangeCut.
   267  func (AboveNull) TypeAsLowerBound() RangeBoundType {
   268  	return Open
   269  }
   270  
   271  // TypeAsUpperBound implements RangeCut.
   272  func (AboveNull) TypeAsUpperBound() RangeBoundType {
   273  	return Closed
   274  }
   275  
   276  // BelowNull represents the position below NULL, which sorts before |AboveNull|
   277  // and every non-NULL value in the domain.
   278  type BelowNull struct{}
   279  
   280  var _ RangeCut = BelowNull{}
   281  
   282  // Compare implements RangeCut.
   283  func (BelowNull) Compare(c RangeCut, typ Type) (int, error) {
   284  	// BelowNull overlaps with itself
   285  	if _, ok := c.(BelowNull); ok {
   286  		return 0, nil
   287  	}
   288  	return -1, nil
   289  }
   290  
   291  // String implements RangeCut.
   292  func (BelowNull) String() string {
   293  	return "BelowNull"
   294  }
   295  
   296  // TypeAsLowerBound implements RangeCut.
   297  func (BelowNull) TypeAsLowerBound() RangeBoundType {
   298  	return Closed
   299  }
   300  
   301  // TypeAsUpperBound implements RangeCut.
   302  func (BelowNull) TypeAsUpperBound() RangeBoundType {
   303  	return Open
   304  }