github.com/dolthub/go-mysql-server@v0.18.0/sql/range_column_expr.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 "sort" 20 "strings" 21 ) 22 23 // RangeType returns what a RangeColumnExpr represents, such as a GreaterThan on some column, or a column set between 24 // two bounds. 25 type RangeType int 26 27 const ( 28 RangeType_Invalid RangeType = iota // This range is invalid, which should not be possible. Please create a GitHub issue if this is ever returned. 29 RangeType_Empty // This range represents the empty set of values. 30 RangeType_All // This range represents every possible value. 31 RangeType_GreaterThan // This range is equivalent to checking for all values greater than the lowerbound. 32 RangeType_GreaterOrEqual // This range is equivalent to checking for all values greater than or equal to the lowerbound. 33 RangeType_LessThanOrNull // This range is equivalent to checking for all values less than the upperbound. 34 RangeType_LessOrEqualOrNull // This range is equivalent to checking for all values less than or equal to the upperbound. 35 RangeType_ClosedClosed // This range covers a finite set of values with the lower and upperbounds inclusive. 36 RangeType_OpenOpen // This range covers a finite set of values with the lower and upperbounds exclusive. 37 RangeType_OpenClosed // This range covers a finite set of values with the lowerbound exclusive and upperbound inclusive. 38 RangeType_ClosedOpen // This range covers a finite set of values with the lowerbound inclusive and upperbound exclusive. 39 RangeType_EqualNull // A range matching only NULL. 40 ) 41 42 // RangeColumnExpr represents the contiguous set of values on a specific column. 43 type RangeColumnExpr struct { 44 LowerBound RangeCut 45 UpperBound RangeCut 46 Typ Type 47 } 48 49 // OpenRangeColumnExpr returns a RangeColumnExpr representing {l < x < u}. 50 func OpenRangeColumnExpr(lower, upper interface{}, typ Type) RangeColumnExpr { 51 if lower == nil || upper == nil { 52 return EmptyRangeColumnExpr(typ) 53 } 54 return RangeColumnExpr{ 55 Above{Key: lower}, 56 Below{Key: upper}, 57 typ, 58 } 59 } 60 61 // ClosedRangeColumnExpr returns a RangeColumnExpr representing {l <= x <= u}. 62 func ClosedRangeColumnExpr(lower, upper interface{}, typ Type) RangeColumnExpr { 63 if lower == nil || upper == nil { 64 return EmptyRangeColumnExpr(typ) 65 } 66 return RangeColumnExpr{ 67 Below{Key: lower}, 68 Above{Key: upper}, 69 typ, 70 } 71 } 72 73 // CustomRangeColumnExpr returns a RangeColumnExpr defined by the bounds given. 74 func CustomRangeColumnExpr(lower, upper interface{}, lowerBound, upperBound RangeBoundType, typ Type) RangeColumnExpr { 75 if lower == nil || upper == nil { 76 return EmptyRangeColumnExpr(typ) 77 } 78 var lCut RangeCut 79 var uCut RangeCut 80 if lowerBound == Open { 81 lCut = Above{Key: lower} 82 } else { 83 lCut = Below{Key: lower} 84 } 85 if upperBound == Open { 86 uCut = Below{Key: upper} 87 } else { 88 uCut = Above{Key: upper} 89 } 90 return RangeColumnExpr{ 91 lCut, 92 uCut, 93 typ, 94 } 95 } 96 97 // LessThanRangeColumnExpr returns a RangeColumnExpr representing {x < u}. 98 func LessThanRangeColumnExpr(upper interface{}, typ Type) RangeColumnExpr { 99 if upper == nil { 100 return EmptyRangeColumnExpr(typ) 101 } 102 return RangeColumnExpr{ 103 AboveNull{}, 104 Below{Key: upper}, 105 typ, 106 } 107 } 108 109 // LessOrEqualRangeColumnExpr returns a RangeColumnExpr representing {x <= u}. 110 func LessOrEqualRangeColumnExpr(upper interface{}, typ Type) RangeColumnExpr { 111 if upper == nil { 112 return EmptyRangeColumnExpr(typ) 113 } 114 return RangeColumnExpr{ 115 AboveNull{}, 116 Above{Key: upper}, 117 typ, 118 } 119 } 120 121 // GreaterThanRangeColumnExpr returns a RangeColumnExpr representing {x > l}. 122 func GreaterThanRangeColumnExpr(lower interface{}, typ Type) RangeColumnExpr { 123 if lower == nil { 124 return EmptyRangeColumnExpr(typ) 125 } 126 return RangeColumnExpr{ 127 Above{Key: lower}, 128 AboveAll{}, 129 typ, 130 } 131 } 132 133 // GreaterOrEqualRangeColumnExpr returns a RangeColumnExpr representing {x >= l}. 134 func GreaterOrEqualRangeColumnExpr(lower interface{}, typ Type) RangeColumnExpr { 135 if lower == nil { 136 return EmptyRangeColumnExpr(typ) 137 } 138 return RangeColumnExpr{ 139 Below{Key: lower}, 140 AboveAll{}, 141 typ, 142 } 143 } 144 145 // AllRangeColumnExpr returns a RangeColumnExpr representing all values. 146 func AllRangeColumnExpr(typ Type) RangeColumnExpr { 147 return RangeColumnExpr{ 148 BelowNull{}, 149 AboveAll{}, 150 typ, 151 } 152 } 153 154 // EmptyRangeColumnExpr returns the empty RangeColumnExpr for the given type. 155 func EmptyRangeColumnExpr(typ Type) RangeColumnExpr { 156 return RangeColumnExpr{ 157 AboveAll{}, 158 AboveAll{}, 159 typ, 160 } 161 } 162 163 // NullRangeColumnExpr returns the null RangeColumnExpr for the given type. 164 func NullRangeColumnExpr(typ Type) RangeColumnExpr { 165 return RangeColumnExpr{ 166 LowerBound: BelowNull{}, 167 UpperBound: AboveNull{}, 168 Typ: typ, 169 } 170 } 171 172 // NotNullRangeColumnExpr returns the not null RangeColumnExpr for the given type. 173 func NotNullRangeColumnExpr(typ Type) RangeColumnExpr { 174 return RangeColumnExpr{ 175 AboveNull{}, 176 AboveAll{}, 177 typ, 178 } 179 } 180 181 // Equals checks for equality with the given RangeColumnExpr. 182 func (r RangeColumnExpr) Equals(other RangeColumnExpr) (bool, error) { 183 cmpLower, err := r.LowerBound.Compare(other.LowerBound, r.Typ) 184 if err != nil { 185 return false, err 186 } 187 cmpUpper, err := r.UpperBound.Compare(other.UpperBound, r.Typ) 188 if err != nil { 189 return false, err 190 } 191 return cmpLower == 0 && cmpUpper == 0, nil 192 } 193 194 // HasLowerBound returns whether this RangeColumnExpr has a value for the lower bound. 195 func (r RangeColumnExpr) HasLowerBound() bool { 196 return RangeCutIsBinding(r.LowerBound) 197 } 198 199 // HasUpperBound returns whether this RangeColumnExpr has a value for the upper bound. 200 func (r RangeColumnExpr) HasUpperBound() bool { 201 return RangeCutIsBinding(r.UpperBound) 202 } 203 204 // IsEmpty returns whether this RangeColumnExpr is empty. 205 func (r RangeColumnExpr) IsEmpty() (bool, error) { 206 cmp, err := r.LowerBound.Compare(r.UpperBound, r.Typ) 207 return cmp >= 0, err 208 } 209 210 // IsConnected evaluates whether the given RangeColumnExpr overlaps or is adjacent to the calling RangeColumnExpr. 211 func (r RangeColumnExpr) IsConnected(other RangeColumnExpr) (bool, error) { 212 if r.Typ.String() != other.Typ.String() { 213 return false, nil 214 } 215 comp, err := r.LowerBound.Compare(other.UpperBound, r.Typ) 216 if err != nil { 217 return false, err 218 } 219 if comp > 0 { 220 return false, nil 221 } 222 comp, err = other.LowerBound.Compare(r.UpperBound, r.Typ) 223 if err != nil { 224 return false, err 225 } 226 return comp <= 0, nil 227 } 228 229 // Overlaps evaluates whether the given RangeColumnExpr overlaps the calling RangeColumnExpr. If they do, returns the 230 // overlapping region as a RangeColumnExpr. 231 func (r RangeColumnExpr) Overlaps(other RangeColumnExpr) (RangeColumnExpr, bool, error) { 232 if r.Typ.String() != other.Typ.String() { 233 return EmptyRangeColumnExpr(r.Typ), false, nil 234 } 235 comp, err := r.LowerBound.Compare(other.UpperBound, r.Typ) 236 if err != nil || comp >= 0 { 237 return EmptyRangeColumnExpr(r.Typ), false, err 238 } 239 comp, err = other.LowerBound.Compare(r.UpperBound, r.Typ) 240 if err != nil || comp >= 0 { 241 return EmptyRangeColumnExpr(r.Typ), false, err 242 } 243 lowerbound, err := GetRangeCutMax(r.Typ, r.LowerBound, other.LowerBound) 244 if err != nil { 245 return EmptyRangeColumnExpr(r.Typ), false, err 246 } 247 upperbound, err := GetRangeCutMin(r.Typ, r.UpperBound, other.UpperBound) 248 if err != nil { 249 return EmptyRangeColumnExpr(r.Typ), false, err 250 } 251 return RangeColumnExpr{ 252 LowerBound: lowerbound, 253 UpperBound: upperbound, 254 Typ: r.Typ, 255 }, true, nil 256 } 257 258 // Subtract removes the given RangeColumnExpr from the calling RangeColumnExpr. In the event that the given 259 // RangeColumnExpr is a strict subset of the calling RangeColumnExpr, two RangeColumnExprs will be returned. If the 260 // given RangeColumnExpr does not overlap the calling RangeColumnExpr, then the calling RangeColumnExpr is returned. 261 // If the calling RangeColumnExpr is a strict subset (or equivalent) of the given RangeColumnExpr, then an empty slice 262 // is returned. In all other cases, a slice with a single RangeColumnExpr will be returned. 263 func (r RangeColumnExpr) Subtract(other RangeColumnExpr) ([]RangeColumnExpr, error) { 264 _, overlaps, err := r.Overlaps(other) 265 if err != nil { 266 return nil, err 267 } 268 if !overlaps { 269 return []RangeColumnExpr{r}, nil 270 } 271 lComp, err := r.LowerBound.Compare(other.LowerBound, r.Typ) 272 if err != nil { 273 return nil, err 274 } 275 uComp, err := r.UpperBound.Compare(other.UpperBound, r.Typ) 276 if err != nil { 277 return nil, err 278 } 279 // Each bound, when compared to the other, has 3 possible states: less (-1), equal (0), or greater (1). 280 // As there are two bounds (upper and lower), that gives us 9 total combinations. 281 // To make use of a switch statement (avoiding 9 if-else statements), we can convert the states to an integer. 282 // Adding 1 to each bound moves the lowest value to 0 and highest to 2, so we can use it as a trit (ternary "bit"). 283 switch (3 * (lComp + 1)) + (uComp + 1) { 284 case 0: // lComp == -1 && uComp == -1 285 return []RangeColumnExpr{{r.LowerBound, other.LowerBound, r.Typ}}, nil 286 case 1: // lComp == -1 && uComp == 0 287 return []RangeColumnExpr{{r.LowerBound, other.LowerBound, r.Typ}}, nil 288 case 2: // lComp == -1 && uComp == 1 289 return []RangeColumnExpr{ 290 {r.LowerBound, other.LowerBound, r.Typ}, 291 {other.UpperBound, r.UpperBound, r.Typ}, 292 }, nil 293 case 3: // lComp == 0 && uComp == -1 294 return nil, nil 295 case 4: // lComp == 0 && uComp == 0 296 return nil, nil 297 case 5: // lComp == 0 && uComp == 1 298 return []RangeColumnExpr{{other.UpperBound, r.UpperBound, r.Typ}}, nil 299 case 6: // lComp == 1 && uComp == -1 300 return nil, nil 301 case 7: // lComp == 1 && uComp == 0 302 return nil, nil 303 case 8: // lComp == 1 && uComp == 1 304 return []RangeColumnExpr{{other.UpperBound, r.UpperBound, r.Typ}}, nil 305 default: // should never be hit 306 panic(fmt.Errorf("unknown RangeColumnExpr subtraction case: %d", (3*(lComp+1))+(uComp+1))) 307 } 308 } 309 310 // IsSubsetOf evaluates whether the calling RangeColumnExpr is fully encompassed by the given RangeColumnExpr. 311 func (r RangeColumnExpr) IsSubsetOf(other RangeColumnExpr) (bool, error) { 312 if r.Typ.String() != other.Typ.String() { 313 return false, nil 314 } 315 comp, err := r.LowerBound.Compare(other.LowerBound, r.Typ) 316 if err != nil || comp == -1 { 317 return false, err 318 } 319 comp, err = r.UpperBound.Compare(other.UpperBound, r.Typ) 320 if err != nil || comp == 1 { 321 return false, err 322 } 323 return true, nil 324 } 325 326 // IsSupersetOf evaluates whether the calling RangeColumnExpr fully encompasses the given RangeColumnExpr. 327 func (r RangeColumnExpr) IsSupersetOf(other RangeColumnExpr) (bool, error) { 328 return other.IsSubsetOf(r) 329 } 330 331 // String returns this RangeColumnExpr as a string for display purposes. 332 func (r RangeColumnExpr) String() string { 333 return fmt.Sprintf("(%s, %s)", r.LowerBound.String(), r.UpperBound.String()) 334 } 335 336 // DebugString returns this RangeColumnExpr as a string for debugging purposes. 337 func (r RangeColumnExpr) DebugString() string { 338 var lowerB interface{} = "-∞" 339 if RangeCutIsBinding(r.LowerBound) { 340 lowerB = GetRangeCutKey(r.LowerBound) 341 } 342 var upperB interface{} = "∞" 343 if RangeCutIsBinding(r.UpperBound) { 344 upperB = GetRangeCutKey(r.UpperBound) 345 } 346 switch v := lowerB.(type) { 347 case []byte: 348 lowerB = string(v) 349 } 350 switch v := upperB.(type) { 351 case []byte: 352 upperB = string(v) 353 } 354 355 sb := strings.Builder{} 356 switch r.LowerBound.(type) { 357 case Above: 358 lowerB := GetRangeCutKey(r.LowerBound) 359 sb.WriteString("(" + fmt.Sprint(lowerB)) 360 case Below: 361 lowerB := GetRangeCutKey(r.LowerBound) 362 sb.WriteString("[" + fmt.Sprint(lowerB)) 363 case AboveAll: 364 sb.WriteString("(∞") 365 case AboveNull: 366 sb.WriteString("(NULL") 367 case BelowNull: 368 sb.WriteString("[NULL") 369 } 370 sb.WriteString(", ") 371 switch r.UpperBound.(type) { 372 case Above: 373 upperB := GetRangeCutKey(r.UpperBound) 374 sb.WriteString(fmt.Sprint(upperB) + "]") 375 case Below: 376 upperB := GetRangeCutKey(r.UpperBound) 377 sb.WriteString(fmt.Sprint(upperB) + ")") 378 case AboveAll: 379 sb.WriteString("∞)") 380 case AboveNull: 381 sb.WriteString("NULL]") 382 case BelowNull: 383 sb.WriteString("NULL)") 384 } 385 return sb.String() 386 } 387 388 // TryIntersect attempts to intersect the given RangeColumnExpr with the calling RangeColumnExpr. Returns true if the 389 // intersection result is not the empty RangeColumnExpr, however a valid RangeColumnExpr is always returned if the error 390 // is nil. 391 func (r RangeColumnExpr) TryIntersect(other RangeColumnExpr) (RangeColumnExpr, bool, error) { 392 _, l, err := OrderedCuts(r.LowerBound, other.LowerBound, r.Typ) 393 if err != nil { 394 return RangeColumnExpr{}, false, err 395 } 396 u, _, err := OrderedCuts(r.UpperBound, other.UpperBound, r.Typ) 397 if err != nil { 398 return RangeColumnExpr{}, false, err 399 } 400 comp, err := l.Compare(u, r.Typ) 401 if err != nil { 402 return RangeColumnExpr{}, false, err 403 } 404 if comp < 0 { 405 return RangeColumnExpr{l, u, r.Typ}, true, nil 406 } 407 return EmptyRangeColumnExpr(r.Typ), false, nil 408 } 409 410 // TryUnion attempts to combine the given RangeColumnExpr with the calling RangeColumnExpr. Returns true if the union 411 // was a success. 412 func (r RangeColumnExpr) TryUnion(other RangeColumnExpr) (RangeColumnExpr, bool, error) { 413 if isEmpty, err := other.IsEmpty(); err != nil { 414 return RangeColumnExpr{}, false, err 415 } else if isEmpty { 416 return r, true, nil 417 } 418 if isEmpty, err := r.IsEmpty(); err != nil { 419 return RangeColumnExpr{}, false, err 420 } else if isEmpty { 421 return other, true, nil 422 } 423 connected, err := r.IsConnected(other) 424 if err != nil { 425 return RangeColumnExpr{}, false, err 426 } 427 if !connected { 428 return RangeColumnExpr{}, false, nil 429 } 430 l, _, err := OrderedCuts(r.LowerBound, other.LowerBound, r.Typ) 431 if err != nil { 432 return RangeColumnExpr{}, false, err 433 } 434 _, u, err := OrderedCuts(r.UpperBound, other.UpperBound, r.Typ) 435 if err != nil { 436 return RangeColumnExpr{}, false, err 437 } 438 return RangeColumnExpr{l, u, r.Typ}, true, nil 439 } 440 441 // Type returns this RangeColumnExpr's RangeType. 442 func (r RangeColumnExpr) Type() RangeType { 443 switch r.LowerBound.(type) { 444 case Above: 445 switch r.UpperBound.(type) { 446 case Above: 447 return RangeType_OpenClosed 448 case AboveAll: 449 return RangeType_GreaterThan 450 case Below: 451 return RangeType_OpenOpen 452 } 453 case AboveAll: 454 switch r.UpperBound.(type) { 455 case AboveAll: 456 return RangeType_Empty 457 } 458 case Below: 459 switch r.UpperBound.(type) { 460 case Above: 461 return RangeType_ClosedClosed 462 case AboveAll: 463 return RangeType_GreaterOrEqual 464 case Below: 465 return RangeType_ClosedOpen 466 } 467 case AboveNull: 468 switch r.UpperBound.(type) { 469 case Above: 470 return RangeType_OpenClosed 471 case AboveAll: 472 // TODO: NotNull? 473 return RangeType_GreaterThan 474 case Below: 475 return RangeType_OpenOpen 476 case AboveNull: 477 return RangeType_Empty 478 } 479 case BelowNull: 480 switch r.UpperBound.(type) { 481 case Above: 482 return RangeType_LessOrEqualOrNull 483 case AboveAll: 484 return RangeType_All 485 case Below: 486 return RangeType_LessThanOrNull 487 case AboveNull: 488 return RangeType_EqualNull 489 case BelowNull: 490 return RangeType_Empty 491 } 492 } 493 return RangeType_Invalid 494 } 495 496 // RepresentsEquals returns whether this RangeColumnExpr represents an "equals". An "equals" is a special kind of 497 // RangeType_ClosedClosed that iterates over a single value (or the specific prefix of some value). 498 func (r RangeColumnExpr) RepresentsEquals() (bool, error) { 499 if r.Type() == RangeType_ClosedClosed { 500 cmp, err := r.Typ.Compare(GetRangeCutKey(r.LowerBound), GetRangeCutKey(r.UpperBound)) 501 if err != nil { 502 return false, err 503 } 504 return cmp == 0, nil 505 } 506 return false, nil 507 } 508 509 // OrderedCuts returns the given Cuts in order from lowest-touched values to highest-touched values. 510 func OrderedCuts(l, r RangeCut, typ Type) (RangeCut, RangeCut, error) { 511 comp, err := l.Compare(r, typ) 512 if err != nil { 513 return nil, nil, err 514 } 515 if comp <= 0 { 516 return l, r, nil 517 } 518 return r, l, nil 519 } 520 521 // rangeColumnExprSlice is a sortable slice of RangeColumnExprs. 522 type rangeColumnExprSlice struct { 523 ranges []RangeColumnExpr 524 err error 525 } 526 527 func (r *rangeColumnExprSlice) Len() int { return len(r.ranges) } 528 func (r *rangeColumnExprSlice) Swap(i, j int) { r.ranges[i], r.ranges[j] = r.ranges[j], r.ranges[i] } 529 func (r *rangeColumnExprSlice) Less(i, j int) bool { 530 lc, err := r.ranges[i].LowerBound.Compare(r.ranges[j].LowerBound, r.ranges[i].Typ) 531 if err != nil { 532 r.err = err 533 return false 534 } 535 if lc < 0 { 536 return true 537 } else if lc > 0 { 538 return false 539 } 540 uc, err := r.ranges[i].UpperBound.Compare(r.ranges[j].UpperBound, r.ranges[i].Typ) 541 if err != nil { 542 r.err = err 543 return false 544 } 545 return uc < 0 546 } 547 548 // SimplifyRangeColumn combines all RangeColumnExprs that are connected and returns a new slice. 549 func SimplifyRangeColumn(rces ...RangeColumnExpr) ([]RangeColumnExpr, error) { 550 if len(rces) == 0 { 551 return rces, nil 552 } 553 typ := rces[0].Typ 554 for i := 1; i < len(rces); i++ { 555 if typ.Type() != rces[i].Typ.Type() { 556 return nil, fmt.Errorf("may only simplify ranges that share the same type") 557 } 558 } 559 sorted := make([]RangeColumnExpr, len(rces)) 560 copy(sorted, rces) 561 rSlice := &rangeColumnExprSlice{ranges: sorted} 562 sort.Sort(rSlice) 563 if rSlice.err != nil { 564 return nil, rSlice.err 565 } 566 var res []RangeColumnExpr 567 cur := EmptyRangeColumnExpr(rces[0].Typ) 568 for _, r := range sorted { 569 merged, ok, err := cur.TryUnion(r) 570 if err != nil { 571 return nil, err 572 } 573 if ok { 574 cur = merged 575 } else if curIsEmpty, err := cur.IsEmpty(); err != nil { 576 return nil, err 577 } else if !curIsEmpty { 578 res = append(res, cur) 579 cur = r 580 } 581 } 582 if curIsEmpty, err := cur.IsEmpty(); err != nil { 583 return nil, err 584 } else if !curIsEmpty { 585 res = append(res, cur) 586 } 587 return res, nil 588 }