github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/optimizer/plan/range.go (about) 1 // Copyright 2015 PingCAP, 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package plan 15 16 import ( 17 "fmt" 18 "math" 19 "sort" 20 21 "github.com/insionng/yougam/libraries/juju/errors" 22 "github.com/insionng/yougam/libraries/pingcap/tidb/ast" 23 "github.com/insionng/yougam/libraries/pingcap/tidb/parser/opcode" 24 "github.com/insionng/yougam/libraries/pingcap/tidb/util/types" 25 ) 26 27 type rangePoint struct { 28 value types.Datum 29 excl bool // exclude 30 start bool 31 } 32 33 func (rp rangePoint) String() string { 34 val := rp.value.GetValue() 35 if rp.value.Kind() == types.KindMinNotNull { 36 val = "-inf" 37 } else if rp.value.Kind() == types.KindMaxValue { 38 val = "+inf" 39 } 40 if rp.start { 41 symbol := "[" 42 if rp.excl { 43 symbol = "(" 44 } 45 return fmt.Sprintf("%s%v", symbol, val) 46 } 47 symbol := "]" 48 if rp.excl { 49 symbol = ")" 50 } 51 return fmt.Sprintf("%v%s", val, symbol) 52 } 53 54 type rangePointSorter struct { 55 points []rangePoint 56 err error 57 } 58 59 func (r *rangePointSorter) Len() int { 60 return len(r.points) 61 } 62 63 func (r *rangePointSorter) Less(i, j int) bool { 64 a := r.points[i] 65 b := r.points[j] 66 cmp, err := a.value.CompareDatum(b.value) 67 if err != nil { 68 r.err = err 69 return true 70 } 71 if cmp == 0 { 72 return r.equalValueLess(a, b) 73 } 74 return cmp < 0 75 } 76 77 func (r *rangePointSorter) equalValueLess(a, b rangePoint) bool { 78 if a.start && b.start { 79 return !a.excl && b.excl 80 } else if a.start { 81 return !b.excl 82 } else if b.start { 83 return a.excl || b.excl 84 } 85 return a.excl && !b.excl 86 } 87 88 func (r *rangePointSorter) Swap(i, j int) { 89 r.points[i], r.points[j] = r.points[j], r.points[i] 90 } 91 92 type rangeBuilder struct { 93 err error 94 } 95 96 func (r *rangeBuilder) build(expr ast.ExprNode) []rangePoint { 97 switch x := expr.(type) { 98 case *ast.BinaryOperationExpr: 99 return r.buildFromBinop(x) 100 case *ast.PatternInExpr: 101 return r.buildFromIn(x) 102 case *ast.ParenthesesExpr: 103 return r.build(x.Expr) 104 case *ast.BetweenExpr: 105 return r.buildFromBetween(x) 106 case *ast.IsNullExpr: 107 return r.buildFromIsNull(x) 108 case *ast.IsTruthExpr: 109 return r.buildFromIsTruth(x) 110 case *ast.PatternLikeExpr: 111 rans := r.buildFromPatternLike(x) 112 return rans 113 case *ast.ColumnNameExpr: 114 return r.buildFromColumnName(x) 115 } 116 return fullRange 117 } 118 119 func (r *rangeBuilder) buildFromBinop(x *ast.BinaryOperationExpr) []rangePoint { 120 if x.Op == opcode.OrOr { 121 return r.union(r.build(x.L), r.build(x.R)) 122 } else if x.Op == opcode.AndAnd { 123 return r.intersection(r.build(x.L), r.build(x.R)) 124 } 125 // This has been checked that the binary operation is comparison operation, and one of 126 // the operand is column name expression. 127 var value types.Datum 128 var op opcode.Op 129 if _, ok := x.L.(*ast.ValueExpr); ok { 130 value = types.NewDatum(x.L.GetValue()) 131 switch x.Op { 132 case opcode.GE: 133 op = opcode.LE 134 case opcode.GT: 135 op = opcode.LT 136 case opcode.LT: 137 op = opcode.GT 138 case opcode.LE: 139 op = opcode.GE 140 default: 141 op = x.Op 142 } 143 } else { 144 value = types.NewDatum(x.R.GetValue()) 145 op = x.Op 146 } 147 if value.Kind() == types.KindNull { 148 return nil 149 } 150 switch op { 151 case opcode.EQ: 152 startPoint := rangePoint{value: value, start: true} 153 endPoint := rangePoint{value: value} 154 return []rangePoint{startPoint, endPoint} 155 case opcode.NE: 156 startPoint1 := rangePoint{value: types.MinNotNullDatum(), start: true} 157 endPoint1 := rangePoint{value: value, excl: true} 158 startPoint2 := rangePoint{value: value, start: true, excl: true} 159 endPoint2 := rangePoint{value: types.MaxValueDatum()} 160 return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2} 161 case opcode.LT: 162 startPoint := rangePoint{value: types.MinNotNullDatum(), start: true} 163 endPoint := rangePoint{value: value, excl: true} 164 return []rangePoint{startPoint, endPoint} 165 case opcode.LE: 166 startPoint := rangePoint{value: types.MinNotNullDatum(), start: true} 167 endPoint := rangePoint{value: value} 168 return []rangePoint{startPoint, endPoint} 169 case opcode.GT: 170 startPoint := rangePoint{value: value, start: true, excl: true} 171 endPoint := rangePoint{value: types.MaxValueDatum()} 172 return []rangePoint{startPoint, endPoint} 173 case opcode.GE: 174 startPoint := rangePoint{value: value, start: true} 175 endPoint := rangePoint{value: types.MaxValueDatum()} 176 return []rangePoint{startPoint, endPoint} 177 } 178 return nil 179 } 180 181 func (r *rangeBuilder) buildFromIn(x *ast.PatternInExpr) []rangePoint { 182 if x.Not { 183 r.err = ErrUnsupportedType.Gen("NOT IN is not supported") 184 return fullRange 185 } 186 var rangePoints []rangePoint 187 for _, v := range x.List { 188 startPoint := rangePoint{value: types.NewDatum(v.GetValue()), start: true} 189 endPoint := rangePoint{value: types.NewDatum(v.GetValue())} 190 rangePoints = append(rangePoints, startPoint, endPoint) 191 } 192 sorter := rangePointSorter{points: rangePoints} 193 sort.Sort(&sorter) 194 if sorter.err != nil { 195 r.err = sorter.err 196 } 197 // check duplicates 198 hasDuplicate := false 199 isStart := false 200 for _, v := range rangePoints { 201 if isStart == v.start { 202 hasDuplicate = true 203 break 204 } 205 isStart = v.start 206 } 207 if !hasDuplicate { 208 return rangePoints 209 } 210 // remove duplicates 211 distinctRangePoints := make([]rangePoint, 0, len(rangePoints)) 212 isStart = false 213 for i := 0; i < len(rangePoints); i++ { 214 current := rangePoints[i] 215 if isStart == current.start { 216 continue 217 } 218 distinctRangePoints = append(distinctRangePoints, current) 219 isStart = current.start 220 } 221 return distinctRangePoints 222 } 223 224 func (r *rangeBuilder) buildFromBetween(x *ast.BetweenExpr) []rangePoint { 225 if x.Not { 226 binop1 := &ast.BinaryOperationExpr{Op: opcode.LT, L: x.Expr, R: x.Left} 227 binop2 := &ast.BinaryOperationExpr{Op: opcode.GT, L: x.Expr, R: x.Right} 228 range1 := r.buildFromBinop(binop1) 229 range2 := r.buildFromBinop(binop2) 230 return r.union(range1, range2) 231 } 232 binop1 := &ast.BinaryOperationExpr{Op: opcode.GE, L: x.Expr, R: x.Left} 233 binop2 := &ast.BinaryOperationExpr{Op: opcode.LE, L: x.Expr, R: x.Right} 234 range1 := r.buildFromBinop(binop1) 235 range2 := r.buildFromBinop(binop2) 236 return r.intersection(range1, range2) 237 } 238 239 func (r *rangeBuilder) buildFromIsNull(x *ast.IsNullExpr) []rangePoint { 240 if x.Not { 241 startPoint := rangePoint{value: types.MinNotNullDatum(), start: true} 242 endPoint := rangePoint{value: types.MaxValueDatum()} 243 return []rangePoint{startPoint, endPoint} 244 } 245 startPoint := rangePoint{start: true} 246 endPoint := rangePoint{} 247 return []rangePoint{startPoint, endPoint} 248 } 249 250 func (r *rangeBuilder) buildFromIsTruth(x *ast.IsTruthExpr) []rangePoint { 251 if x.True != 0 { 252 if x.Not { 253 // NOT TRUE range is {[null null] [0, 0]} 254 startPoint1 := rangePoint{start: true} 255 endPoint1 := rangePoint{} 256 startPoint2 := rangePoint{start: true} 257 startPoint2.value.SetInt64(0) 258 endPoint2 := rangePoint{} 259 endPoint2.value.SetInt64(0) 260 return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2} 261 } 262 // TRUE range is {[-inf 0) (0 +inf]} 263 startPoint1 := rangePoint{value: types.MinNotNullDatum(), start: true} 264 endPoint1 := rangePoint{excl: true} 265 endPoint1.value.SetInt64(0) 266 startPoint2 := rangePoint{excl: true, start: true} 267 startPoint2.value.SetInt64(0) 268 endPoint2 := rangePoint{value: types.MaxValueDatum()} 269 return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2} 270 } 271 if x.Not { 272 startPoint1 := rangePoint{start: true} 273 endPoint1 := rangePoint{excl: true} 274 endPoint1.value.SetInt64(0) 275 startPoint2 := rangePoint{start: true, excl: true} 276 startPoint2.value.SetInt64(0) 277 endPoint2 := rangePoint{value: types.MaxValueDatum()} 278 return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2} 279 } 280 startPoint := rangePoint{start: true} 281 startPoint.value.SetInt64(0) 282 endPoint := rangePoint{} 283 endPoint.value.SetInt64(0) 284 return []rangePoint{startPoint, endPoint} 285 } 286 287 func (r *rangeBuilder) buildFromPatternLike(x *ast.PatternLikeExpr) []rangePoint { 288 if x.Not { 289 // Pattern not like is not supported. 290 r.err = ErrUnsupportedType.Gen("NOT LIKE is not supported.") 291 return fullRange 292 } 293 pattern, err := types.ToString(x.Pattern.GetValue()) 294 if err != nil { 295 r.err = errors.Trace(err) 296 return fullRange 297 } 298 lowValue := make([]byte, 0, len(pattern)) 299 // unscape the pattern 300 var exclude bool 301 for i := 0; i < len(pattern); i++ { 302 if pattern[i] == x.Escape { 303 i++ 304 if i < len(pattern) { 305 lowValue = append(lowValue, pattern[i]) 306 } else { 307 lowValue = append(lowValue, x.Escape) 308 } 309 continue 310 } 311 if pattern[i] == '%' { 312 break 313 } else if pattern[i] == '_' { 314 exclude = true 315 break 316 } 317 lowValue = append(lowValue, pattern[i]) 318 } 319 if len(lowValue) == 0 { 320 return []rangePoint{{value: types.MinNotNullDatum(), start: true}, {value: types.MaxValueDatum()}} 321 } 322 startPoint := rangePoint{start: true, excl: exclude} 323 startPoint.value.SetBytesAsString(lowValue) 324 highValue := make([]byte, len(lowValue)) 325 copy(highValue, lowValue) 326 endPoint := rangePoint{excl: true} 327 for i := len(highValue) - 1; i >= 0; i-- { 328 highValue[i]++ 329 if highValue[i] != 0 { 330 endPoint.value.SetBytesAsString(highValue) 331 break 332 } 333 if i == 0 { 334 endPoint.value = types.MaxValueDatum() 335 break 336 } 337 } 338 ranges := make([]rangePoint, 2) 339 ranges[0] = startPoint 340 ranges[1] = endPoint 341 return ranges 342 } 343 344 func (r *rangeBuilder) buildFromColumnName(x *ast.ColumnNameExpr) []rangePoint { 345 // column name expression is equivalent to column name is true. 346 startPoint1 := rangePoint{value: types.MinNotNullDatum(), start: true} 347 endPoint1 := rangePoint{excl: true} 348 endPoint1.value.SetInt64(0) 349 startPoint2 := rangePoint{excl: true, start: true} 350 startPoint2.value.SetInt64(0) 351 endPoint2 := rangePoint{value: types.MaxValueDatum()} 352 return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2} 353 } 354 355 func (r *rangeBuilder) intersection(a, b []rangePoint) []rangePoint { 356 return r.merge(a, b, false) 357 } 358 359 func (r *rangeBuilder) union(a, b []rangePoint) []rangePoint { 360 return r.merge(a, b, true) 361 } 362 363 func (r *rangeBuilder) merge(a, b []rangePoint, union bool) []rangePoint { 364 sorter := rangePointSorter{points: append(a, b...)} 365 sort.Sort(&sorter) 366 if sorter.err != nil { 367 r.err = sorter.err 368 return nil 369 } 370 var ( 371 merged []rangePoint 372 inRangeCount int 373 requiredInRangeCount int 374 ) 375 if union { 376 requiredInRangeCount = 1 377 } else { 378 requiredInRangeCount = 2 379 } 380 for _, val := range sorter.points { 381 if val.start { 382 inRangeCount++ 383 if inRangeCount == requiredInRangeCount { 384 // just reached the required in range count, a new range started. 385 merged = append(merged, val) 386 } 387 } else { 388 if inRangeCount == requiredInRangeCount { 389 // just about to leave the required in range count, the range is ended. 390 merged = append(merged, val) 391 } 392 inRangeCount-- 393 } 394 } 395 return merged 396 } 397 398 // buildIndexRanges build index ranges from range points. 399 // Only the first column in the index is built, extra column ranges will be appended by 400 // appendIndexRanges. 401 func (r *rangeBuilder) buildIndexRanges(rangePoints []rangePoint) []*IndexRange { 402 indexRanges := make([]*IndexRange, 0, len(rangePoints)/2) 403 for i := 0; i < len(rangePoints); i += 2 { 404 startPoint := rangePoints[i] 405 endPoint := rangePoints[i+1] 406 ir := &IndexRange{ 407 LowVal: []types.Datum{startPoint.value}, 408 LowExclude: startPoint.excl, 409 HighVal: []types.Datum{endPoint.value}, 410 HighExclude: endPoint.excl, 411 } 412 indexRanges = append(indexRanges, ir) 413 } 414 return indexRanges 415 } 416 417 // appendIndexRanges appends additional column ranges for multi-column index. 418 // The additional column ranges can only be appended to point ranges. 419 // for example we have an index (a, b), if the condition is (a > 1 and b = 2) 420 // then we can not build a conjunctive ranges for this index. 421 func (r *rangeBuilder) appendIndexRanges(origin []*IndexRange, rangePoints []rangePoint) []*IndexRange { 422 var newIndexRanges []*IndexRange 423 for i := 0; i < len(origin); i++ { 424 oRange := origin[i] 425 if !oRange.IsPoint() { 426 newIndexRanges = append(newIndexRanges, oRange) 427 } else { 428 newIndexRanges = append(newIndexRanges, r.appendIndexRange(oRange, rangePoints)...) 429 } 430 } 431 return newIndexRanges 432 } 433 434 func (r *rangeBuilder) appendIndexRange(origin *IndexRange, rangePoints []rangePoint) []*IndexRange { 435 newRanges := make([]*IndexRange, 0, len(rangePoints)/2) 436 for i := 0; i < len(rangePoints); i += 2 { 437 startPoint := rangePoints[i] 438 lowVal := make([]types.Datum, len(origin.LowVal)+1) 439 copy(lowVal, origin.LowVal) 440 lowVal[len(origin.LowVal)] = startPoint.value 441 442 endPoint := rangePoints[i+1] 443 highVal := make([]types.Datum, len(origin.HighVal)+1) 444 copy(highVal, origin.HighVal) 445 highVal[len(origin.HighVal)] = endPoint.value 446 447 ir := &IndexRange{ 448 LowVal: lowVal, 449 LowExclude: startPoint.excl, 450 HighVal: highVal, 451 HighExclude: endPoint.excl, 452 } 453 newRanges = append(newRanges, ir) 454 } 455 return newRanges 456 } 457 458 func (r *rangeBuilder) buildTableRanges(rangePoints []rangePoint) []TableRange { 459 tableRanges := make([]TableRange, 0, len(rangePoints)/2) 460 for i := 0; i < len(rangePoints); i += 2 { 461 startPoint := rangePoints[i] 462 if startPoint.value.Kind() == types.KindNull || startPoint.value.Kind() == types.KindMinNotNull { 463 startPoint.value.SetInt64(math.MinInt64) 464 } 465 startInt, err := types.ToInt64(startPoint.value.GetValue()) 466 if err != nil { 467 r.err = errors.Trace(err) 468 return tableRanges 469 } 470 startDatum := types.NewDatum(startInt) 471 cmp, err := startDatum.CompareDatum(startPoint.value) 472 if err != nil { 473 r.err = errors.Trace(err) 474 return tableRanges 475 } 476 if cmp < 0 || (cmp == 0 && startPoint.excl) { 477 startInt++ 478 } 479 endPoint := rangePoints[i+1] 480 if endPoint.value.Kind() == types.KindNull { 481 endPoint.value.SetInt64(math.MinInt64) 482 } else if endPoint.value.Kind() == types.KindMaxValue { 483 endPoint.value.SetInt64(math.MaxInt64) 484 } 485 endInt, err := types.ToInt64(endPoint.value.GetValue()) 486 if err != nil { 487 r.err = errors.Trace(err) 488 return tableRanges 489 } 490 endDatum := types.NewDatum(endInt) 491 cmp, err = endDatum.CompareDatum(endPoint.value) 492 if err != nil { 493 r.err = errors.Trace(err) 494 return tableRanges 495 } 496 if cmp > 0 || (cmp == 0 && endPoint.excl) { 497 endInt-- 498 } 499 if startInt > endInt { 500 continue 501 } 502 tableRanges = append(tableRanges, TableRange{LowVal: startInt, HighVal: endInt}) 503 } 504 return tableRanges 505 }