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 }