github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/soliton/ranger/ranger.go (about) 1 // Copyright 2020 WHTCORPS INC, 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 ranger 15 16 import ( 17 "bytes" 18 "math" 19 "sort" 20 "unicode/utf8" 21 22 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 23 "github.com/whtcorpsinc/BerolinaSQL/ast" 24 "github.com/whtcorpsinc/BerolinaSQL/charset" 25 "github.com/whtcorpsinc/errors" 26 "github.com/whtcorpsinc/milevadb/ekv" 27 "github.com/whtcorpsinc/milevadb/memex" 28 "github.com/whtcorpsinc/milevadb/soliton/codec" 29 "github.com/whtcorpsinc/milevadb/stochastikctx" 30 "github.com/whtcorpsinc/milevadb/stochastikctx/stmtctx" 31 "github.com/whtcorpsinc/milevadb/types" 32 ) 33 34 func validInterval(sc *stmtctx.StatementContext, low, high point) (bool, error) { 35 l, err := codec.EncodeKey(sc, nil, low.value) 36 if err != nil { 37 return false, errors.Trace(err) 38 } 39 if low.excl { 40 l = ekv.Key(l).PrefixNext() 41 } 42 r, err := codec.EncodeKey(sc, nil, high.value) 43 if err != nil { 44 return false, errors.Trace(err) 45 } 46 if !high.excl { 47 r = ekv.Key(r).PrefixNext() 48 } 49 return bytes.Compare(l, r) < 0, nil 50 } 51 52 // points2Ranges build index ranges from range points. 53 // Only one defCausumn is built there. If there're multiple defCausumns, use appendPoints2Ranges. 54 func points2Ranges(sc *stmtctx.StatementContext, rangePoints []point, tp *types.FieldType) ([]*Range, error) { 55 ranges := make([]*Range, 0, len(rangePoints)/2) 56 for i := 0; i < len(rangePoints); i += 2 { 57 startPoint, err := convertPoint(sc, rangePoints[i], tp) 58 if err != nil { 59 return nil, errors.Trace(err) 60 } 61 endPoint, err := convertPoint(sc, rangePoints[i+1], tp) 62 if err != nil { 63 return nil, errors.Trace(err) 64 } 65 less, err := validInterval(sc, startPoint, endPoint) 66 if err != nil { 67 return nil, errors.Trace(err) 68 } 69 if !less { 70 continue 71 } 72 // If defCausumn has not null flag, [null, null] should be removed. 73 if allegrosql.HasNotNullFlag(tp.Flag) && endPoint.value.HoTT() == types.HoTTNull { 74 continue 75 } 76 77 ran := &Range{ 78 LowVal: []types.Causet{startPoint.value}, 79 LowExclude: startPoint.excl, 80 HighVal: []types.Causet{endPoint.value}, 81 HighExclude: endPoint.excl, 82 } 83 ranges = append(ranges, ran) 84 } 85 return ranges, nil 86 } 87 88 func convertPoint(sc *stmtctx.StatementContext, point point, tp *types.FieldType) (point, error) { 89 switch point.value.HoTT() { 90 case types.HoTTMaxValue, types.HoTTMinNotNull: 91 return point, nil 92 } 93 casted, err := point.value.ConvertTo(sc, tp) 94 if err != nil { 95 return point, errors.Trace(err) 96 } 97 valCmpCasted, err := point.value.CompareCauset(sc, &casted) 98 if err != nil { 99 return point, errors.Trace(err) 100 } 101 point.value = casted 102 if valCmpCasted == 0 { 103 return point, nil 104 } 105 if point.start { 106 if point.excl { 107 if valCmpCasted < 0 { 108 // e.g. "a > 1.9" convert to "a >= 2". 109 point.excl = false 110 } 111 } else { 112 if valCmpCasted > 0 { 113 // e.g. "a >= 1.1 convert to "a > 1" 114 point.excl = true 115 } 116 } 117 } else { 118 if point.excl { 119 if valCmpCasted > 0 { 120 // e.g. "a < 1.1" convert to "a <= 1" 121 point.excl = false 122 } 123 } else { 124 if valCmpCasted < 0 { 125 // e.g. "a <= 1.9" convert to "a < 2" 126 point.excl = true 127 } 128 } 129 } 130 return point, nil 131 } 132 133 // appendPoints2Ranges appends additional defCausumn ranges for multi-defCausumn index. 134 // The additional defCausumn ranges can only be appended to point ranges. 135 // for example we have an index (a, b), if the condition is (a > 1 and b = 2) 136 // then we can not build a conjunctive ranges for this index. 137 func appendPoints2Ranges(sc *stmtctx.StatementContext, origin []*Range, rangePoints []point, 138 ft *types.FieldType) ([]*Range, error) { 139 var newIndexRanges []*Range 140 for i := 0; i < len(origin); i++ { 141 oRange := origin[i] 142 if !oRange.IsPoint(sc) { 143 newIndexRanges = append(newIndexRanges, oRange) 144 } else { 145 newRanges, err := appendPoints2IndexRange(sc, oRange, rangePoints, ft) 146 if err != nil { 147 return nil, errors.Trace(err) 148 } 149 newIndexRanges = append(newIndexRanges, newRanges...) 150 } 151 } 152 return newIndexRanges, nil 153 } 154 155 func appendPoints2IndexRange(sc *stmtctx.StatementContext, origin *Range, rangePoints []point, 156 ft *types.FieldType) ([]*Range, error) { 157 newRanges := make([]*Range, 0, len(rangePoints)/2) 158 for i := 0; i < len(rangePoints); i += 2 { 159 startPoint, err := convertPoint(sc, rangePoints[i], ft) 160 if err != nil { 161 return nil, errors.Trace(err) 162 } 163 endPoint, err := convertPoint(sc, rangePoints[i+1], ft) 164 if err != nil { 165 return nil, errors.Trace(err) 166 } 167 less, err := validInterval(sc, startPoint, endPoint) 168 if err != nil { 169 return nil, errors.Trace(err) 170 } 171 if !less { 172 continue 173 } 174 175 lowVal := make([]types.Causet, len(origin.LowVal)+1) 176 copy(lowVal, origin.LowVal) 177 lowVal[len(origin.LowVal)] = startPoint.value 178 179 highVal := make([]types.Causet, len(origin.HighVal)+1) 180 copy(highVal, origin.HighVal) 181 highVal[len(origin.HighVal)] = endPoint.value 182 183 ir := &Range{ 184 LowVal: lowVal, 185 LowExclude: startPoint.excl, 186 HighVal: highVal, 187 HighExclude: endPoint.excl, 188 } 189 newRanges = append(newRanges, ir) 190 } 191 return newRanges, nil 192 } 193 194 func appendRanges2PointRanges(pointRanges []*Range, ranges []*Range) []*Range { 195 if len(ranges) == 0 { 196 return pointRanges 197 } 198 newRanges := make([]*Range, 0, len(pointRanges)*len(ranges)) 199 for _, pointRange := range pointRanges { 200 for _, r := range ranges { 201 lowVal := append(pointRange.LowVal, r.LowVal...) 202 highVal := append(pointRange.HighVal, r.HighVal...) 203 newRange := &Range{ 204 LowVal: lowVal, 205 LowExclude: r.LowExclude, 206 HighVal: highVal, 207 HighExclude: r.HighExclude, 208 } 209 newRanges = append(newRanges, newRange) 210 } 211 } 212 return newRanges 213 } 214 215 // points2BlockRanges build ranges for causet scan from range points. 216 // It will remove the nil and convert MinNotNull and MaxValue to MinInt64 or MinUint64 and MaxInt64 or MaxUint64. 217 func points2BlockRanges(sc *stmtctx.StatementContext, rangePoints []point, tp *types.FieldType) ([]*Range, error) { 218 ranges := make([]*Range, 0, len(rangePoints)/2) 219 var minValueCauset, maxValueCauset types.Causet 220 // Currently, causet's ekv range cannot accept encoded value of MaxValueCauset. we need to convert it. 221 if allegrosql.HasUnsignedFlag(tp.Flag) { 222 minValueCauset.SetUint64(0) 223 maxValueCauset.SetUint64(math.MaxUint64) 224 } else { 225 minValueCauset.SetInt64(math.MinInt64) 226 maxValueCauset.SetInt64(math.MaxInt64) 227 } 228 for i := 0; i < len(rangePoints); i += 2 { 229 startPoint, err := convertPoint(sc, rangePoints[i], tp) 230 if err != nil { 231 return nil, errors.Trace(err) 232 } 233 if startPoint.value.HoTT() == types.HoTTNull { 234 startPoint.value = minValueCauset 235 startPoint.excl = false 236 } else if startPoint.value.HoTT() == types.HoTTMinNotNull { 237 startPoint.value = minValueCauset 238 } 239 endPoint, err := convertPoint(sc, rangePoints[i+1], tp) 240 if err != nil { 241 return nil, errors.Trace(err) 242 } 243 if endPoint.value.HoTT() == types.HoTTMaxValue { 244 endPoint.value = maxValueCauset 245 } else if endPoint.value.HoTT() == types.HoTTNull { 246 continue 247 } 248 less, err := validInterval(sc, startPoint, endPoint) 249 if err != nil { 250 return nil, errors.Trace(err) 251 } 252 if !less { 253 continue 254 } 255 ran := &Range{ 256 LowVal: []types.Causet{startPoint.value}, 257 LowExclude: startPoint.excl, 258 HighVal: []types.Causet{endPoint.value}, 259 HighExclude: endPoint.excl, 260 } 261 ranges = append(ranges, ran) 262 } 263 return ranges, nil 264 } 265 266 // buildDeferredCausetRange builds range from CNF conditions. 267 func buildDeferredCausetRange(accessConditions []memex.Expression, sc *stmtctx.StatementContext, tp *types.FieldType, blockRange bool, defCausLen int) (ranges []*Range, err error) { 268 rb := builder{sc: sc} 269 rangePoints := fullRange 270 for _, cond := range accessConditions { 271 rangePoints = rb.intersection(rangePoints, rb.build(cond)) 272 if rb.err != nil { 273 return nil, errors.Trace(rb.err) 274 } 275 } 276 newTp := newFieldType(tp) 277 if blockRange { 278 ranges, err = points2BlockRanges(sc, rangePoints, newTp) 279 } else { 280 ranges, err = points2Ranges(sc, rangePoints, newTp) 281 } 282 if err != nil { 283 return nil, errors.Trace(err) 284 } 285 if defCausLen != types.UnspecifiedLength { 286 for _, ran := range ranges { 287 if CutCausetByPrefixLen(&ran.LowVal[0], defCausLen, tp) { 288 ran.LowExclude = false 289 } 290 if CutCausetByPrefixLen(&ran.HighVal[0], defCausLen, tp) { 291 ran.HighExclude = false 292 } 293 } 294 ranges, err = UnionRanges(sc, ranges, true) 295 if err != nil { 296 return nil, err 297 } 298 } 299 return ranges, nil 300 } 301 302 // BuildBlockRange builds range of PK defCausumn for PhysicalBlockScan. 303 func BuildBlockRange(accessConditions []memex.Expression, sc *stmtctx.StatementContext, tp *types.FieldType) ([]*Range, error) { 304 return buildDeferredCausetRange(accessConditions, sc, tp, true, types.UnspecifiedLength) 305 } 306 307 // BuildDeferredCausetRange builds range from access conditions for general defCausumns. 308 func BuildDeferredCausetRange(conds []memex.Expression, sc *stmtctx.StatementContext, tp *types.FieldType, defCausLen int) ([]*Range, error) { 309 if len(conds) == 0 { 310 return []*Range{{LowVal: []types.Causet{{}}, HighVal: []types.Causet{types.MaxValueCauset()}}}, nil 311 } 312 return buildDeferredCausetRange(conds, sc, tp, false, defCausLen) 313 } 314 315 // buildCNFIndexRange builds the range for index where the top layer is CNF. 316 func (d *rangeDetacher) buildCNFIndexRange(newTp []*types.FieldType, 317 eqAndInCount int, accessCondition []memex.Expression) ([]*Range, error) { 318 sc := d.sctx.GetStochastikVars().StmtCtx 319 rb := builder{sc: sc} 320 var ( 321 ranges []*Range 322 err error 323 ) 324 for _, defCaus := range d.defcaus { 325 newTp = append(newTp, newFieldType(defCaus.RetType)) 326 } 327 for i := 0; i < eqAndInCount; i++ { 328 // Build ranges for equal or in access conditions. 329 point := rb.build(accessCondition[i]) 330 if rb.err != nil { 331 return nil, errors.Trace(rb.err) 332 } 333 if i == 0 { 334 ranges, err = points2Ranges(sc, point, newTp[i]) 335 } else { 336 ranges, err = appendPoints2Ranges(sc, ranges, point, newTp[i]) 337 } 338 if err != nil { 339 return nil, errors.Trace(err) 340 } 341 } 342 rangePoints := fullRange 343 // Build rangePoints for non-equal access conditions. 344 for i := eqAndInCount; i < len(accessCondition); i++ { 345 rangePoints = rb.intersection(rangePoints, rb.build(accessCondition[i])) 346 if rb.err != nil { 347 return nil, errors.Trace(rb.err) 348 } 349 } 350 if eqAndInCount == 0 { 351 ranges, err = points2Ranges(sc, rangePoints, newTp[0]) 352 } else if eqAndInCount < len(accessCondition) { 353 ranges, err = appendPoints2Ranges(sc, ranges, rangePoints, newTp[eqAndInCount]) 354 } 355 if err != nil { 356 return nil, errors.Trace(err) 357 } 358 359 // Take prefix index into consideration. 360 if hasPrefix(d.lengths) { 361 if fixPrefixDefCausRange(ranges, d.lengths, newTp) { 362 ranges, err = UnionRanges(sc, ranges, d.mergeConsecutive) 363 if err != nil { 364 return nil, errors.Trace(err) 365 } 366 } 367 } 368 369 return ranges, nil 370 } 371 372 type sortRange struct { 373 originalValue *Range 374 encodedStart []byte 375 encodedEnd []byte 376 } 377 378 // UnionRanges sorts `ranges`, union adjacent ones if possible. 379 // For two intervals [a, b], [c, d], we have guaranteed that a <= c. If b >= c. Then two intervals are overlapped. 380 // And this two can be merged as [a, max(b, d)]. 381 // Otherwise they aren't overlapped. 382 func UnionRanges(sc *stmtctx.StatementContext, ranges []*Range, mergeConsecutive bool) ([]*Range, error) { 383 if len(ranges) == 0 { 384 return nil, nil 385 } 386 objects := make([]*sortRange, 0, len(ranges)) 387 for _, ran := range ranges { 388 left, err := codec.EncodeKey(sc, nil, ran.LowVal...) 389 if err != nil { 390 return nil, errors.Trace(err) 391 } 392 if ran.LowExclude { 393 left = ekv.Key(left).PrefixNext() 394 } 395 right, err := codec.EncodeKey(sc, nil, ran.HighVal...) 396 if err != nil { 397 return nil, errors.Trace(err) 398 } 399 if !ran.HighExclude { 400 right = ekv.Key(right).PrefixNext() 401 } 402 objects = append(objects, &sortRange{originalValue: ran, encodedStart: left, encodedEnd: right}) 403 } 404 sort.Slice(objects, func(i, j int) bool { 405 return bytes.Compare(objects[i].encodedStart, objects[j].encodedStart) < 0 406 }) 407 ranges = ranges[:0] 408 lastRange := objects[0] 409 for i := 1; i < len(objects); i++ { 410 if (mergeConsecutive && bytes.Compare(lastRange.encodedEnd, objects[i].encodedStart) >= 0) || 411 (!mergeConsecutive && bytes.Compare(lastRange.encodedEnd, objects[i].encodedStart) > 0) { 412 if bytes.Compare(lastRange.encodedEnd, objects[i].encodedEnd) < 0 { 413 lastRange.encodedEnd = objects[i].encodedEnd 414 lastRange.originalValue.HighVal = objects[i].originalValue.HighVal 415 lastRange.originalValue.HighExclude = objects[i].originalValue.HighExclude 416 } 417 } else { 418 ranges = append(ranges, lastRange.originalValue) 419 lastRange = objects[i] 420 } 421 } 422 ranges = append(ranges, lastRange.originalValue) 423 return ranges, nil 424 } 425 426 func hasPrefix(lengths []int) bool { 427 for _, l := range lengths { 428 if l != types.UnspecifiedLength { 429 return true 430 } 431 } 432 return false 433 } 434 435 // fixPrefixDefCausRange checks whether the range of one defCausumn exceeds the length and needs to be cut. 436 // It specially handles the last defCausumn of each range point. If the last one need to be cut, it will 437 // change the exclude status of that point and return `true` to tell 438 // that we need do a range merging since that interval may have intersection. 439 // e.g. if the interval is (-inf -inf, a xxxxx), (a xxxxx, +inf +inf) and the length of the last defCausumn is 3, 440 // then we'll change it to (-inf -inf, a xxx], [a xxx, +inf +inf). You can see that this two interval intersect, 441 // so we need a merge operation. 442 // Q: only checking the last defCausumn to decide whether the endpoint's exclude status needs to be reset is enough? 443 // A: Yes, suppose that the interval is (-inf -inf, a xxxxx b) and only the second defCausumn needs to be cut. 444 // The result would be (-inf -inf, a xxx b) if the length of it is 3. Obviously we only need to care about the data 445 // whose the first two key is `a` and `xxx`. It read all data whose index value begins with `a` and `xxx` and the third 446 // value less than `b`, covering the values begin with `a` and `xxxxx` and the third value less than `b` perfectly. 447 // So in this case we don't need to reset its exclude status. The right endpoint case can be proved in the same way. 448 func fixPrefixDefCausRange(ranges []*Range, lengths []int, tp []*types.FieldType) bool { 449 var hasCut bool 450 for _, ran := range ranges { 451 lowTail := len(ran.LowVal) - 1 452 for i := 0; i < lowTail; i++ { 453 CutCausetByPrefixLen(&ran.LowVal[i], lengths[i], tp[i]) 454 } 455 lowCut := CutCausetByPrefixLen(&ran.LowVal[lowTail], lengths[lowTail], tp[lowTail]) 456 if lowCut { 457 ran.LowExclude = false 458 } 459 highTail := len(ran.HighVal) - 1 460 for i := 0; i < highTail; i++ { 461 CutCausetByPrefixLen(&ran.HighVal[i], lengths[i], tp[i]) 462 } 463 highCut := CutCausetByPrefixLen(&ran.HighVal[highTail], lengths[highTail], tp[highTail]) 464 if highCut { 465 ran.HighExclude = false 466 } 467 hasCut = lowCut || highCut 468 } 469 return hasCut 470 } 471 472 // CutCausetByPrefixLen cuts the causet according to the prefix length. 473 // If it's UTF8 encoded, we will cut it by characters rather than bytes. 474 func CutCausetByPrefixLen(v *types.Causet, length int, tp *types.FieldType) bool { 475 if v.HoTT() == types.HoTTString || v.HoTT() == types.HoTTBytes { 476 defCausCharset := tp.Charset 477 defCausValue := v.GetBytes() 478 isUTF8Charset := defCausCharset == charset.CharsetUTF8 || defCausCharset == charset.CharsetUTF8MB4 479 if isUTF8Charset { 480 if length != types.UnspecifiedLength && utf8.RuneCount(defCausValue) > length { 481 rs := bytes.Runes(defCausValue) 482 truncateStr := string(rs[:length]) 483 // truncate value and limit its length 484 v.SetString(truncateStr, tp.DefCauslate) 485 return true 486 } 487 } else if length != types.UnspecifiedLength && len(defCausValue) > length { 488 // truncate value and limit its length 489 v.SetBytes(defCausValue[:length]) 490 if v.HoTT() == types.HoTTString { 491 v.SetString(v.GetString(), tp.DefCauslate) 492 } 493 return true 494 } 495 } 496 return false 497 } 498 499 // We cannot use the FieldType of defCausumn directly. e.g. the defCausumn a is int32 and we have a > 1111111111111111111. 500 // Obviously the constant is bigger than MaxInt32, so we will get overflow error if we use the FieldType of defCausumn a. 501 func newFieldType(tp *types.FieldType) *types.FieldType { 502 switch tp.Tp { 503 // To avoid overflow error. 504 case allegrosql.TypeTiny, allegrosql.TypeShort, allegrosql.TypeInt24, allegrosql.TypeLong, allegrosql.TypeLonglong: 505 newTp := types.NewFieldType(allegrosql.TypeLonglong) 506 newTp.Flag = tp.Flag 507 newTp.Charset = tp.Charset 508 return newTp 509 // To avoid data truncate error. 510 case allegrosql.TypeFloat, allegrosql.TypeDouble, allegrosql.TypeBlob, allegrosql.TypeTinyBlob, allegrosql.TypeMediumBlob, allegrosql.TypeLongBlob, 511 allegrosql.TypeString, allegrosql.TypeVarchar, allegrosql.TypeVarString: 512 newTp := types.NewFieldTypeWithDefCauslation(tp.Tp, tp.DefCauslate, types.UnspecifiedLength) 513 newTp.Charset = tp.Charset 514 return newTp 515 default: 516 return tp 517 } 518 } 519 520 // points2EqOrInCond constructs a 'EQUAL' or 'IN' scalar function based on the 521 // 'points'. The target defCausumn is extracted from the 'expr'. 522 // NOTE: 523 // 1. 'expr' must be either 'EQUAL' or 'IN' function. 524 // 2. 'points' should not be empty. 525 func points2EqOrInCond(ctx stochastikctx.Context, points []point, expr memex.Expression) memex.Expression { 526 // len(points) cannot be 0 here, since we impose early termination in ExtractEqAndInCondition 527 sf, _ := expr.(*memex.ScalarFunction) 528 // Constant and DeferredCauset args should have same RetType, simply get from first arg 529 retType := sf.GetArgs()[0].GetType() 530 args := make([]memex.Expression, 0, len(points)/2) 531 if sf.FuncName.L == ast.EQ { 532 if c, ok := sf.GetArgs()[0].(*memex.DeferredCauset); ok { 533 args = append(args, c) 534 } else if c, ok := sf.GetArgs()[1].(*memex.DeferredCauset); ok { 535 args = append(args, c) 536 } 537 } else { 538 args = append(args, sf.GetArgs()[0]) 539 } 540 for i := 0; i < len(points); i = i + 2 { 541 value := &memex.Constant{ 542 Value: points[i].value, 543 RetType: retType, 544 } 545 args = append(args, value) 546 } 547 funcName := ast.EQ 548 if len(args) > 2 { 549 funcName = ast.In 550 } 551 return memex.NewFunctionInternal(ctx, funcName, sf.GetType(), args...) 552 } 553 554 // DetachCondAndBuildRangeForPartition will detach the index filters from causet filters. 555 // The returned values are encapsulated into a struct DetachRangeResult, see its comments for explanation. 556 func DetachCondAndBuildRangeForPartition(sctx stochastikctx.Context, conditions []memex.Expression, defcaus []*memex.DeferredCauset, 557 lengths []int) (*DetachRangeResult, error) { 558 d := &rangeDetacher{ 559 sctx: sctx, 560 allConds: conditions, 561 defcaus: defcaus, 562 lengths: lengths, 563 mergeConsecutive: false, 564 } 565 return d.detachCondAndBuildRangeForDefCauss() 566 }