github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/dbs/memristed/memex/util.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 memex 15 16 import ( 17 "math" 18 "strconv" 19 "strings" 20 "time" 21 "unicode" 22 23 "github.com/whtcorpsinc/errors" 24 "github.com/whtcorpsinc/BerolinaSQL/ast" 25 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 26 "github.com/whtcorpsinc/BerolinaSQL/opcode" 27 "github.com/whtcorpsinc/BerolinaSQL/terror" 28 "github.com/whtcorpsinc/milevadb/stochastikctx" 29 "github.com/whtcorpsinc/milevadb/types" 30 "github.com/whtcorpsinc/milevadb/types/BerolinaSQL_driver" 31 "github.com/whtcorpsinc/milevadb/soliton/chunk" 32 "github.com/whtcorpsinc/milevadb/soliton/defCauslate" 33 "github.com/whtcorpsinc/milevadb/soliton/logutil" 34 "go.uber.org/zap" 35 "golang.org/x/tools/container/intsets" 36 ) 37 38 // cowExprRef is a copy-on-write slice ref soliton using in `DeferredCausetSubstitute` 39 // to reduce unnecessary allocation for Expression arguments array 40 type cowExprRef struct { 41 ref []Expression 42 new []Expression 43 } 44 45 // Set will allocate new array if changed flag true 46 func (c *cowExprRef) Set(i int, changed bool, val Expression) { 47 if c.new != nil { 48 c.new[i] = val 49 return 50 } 51 if !changed { 52 return 53 } 54 c.new = make([]Expression, len(c.ref)) 55 copy(c.new, c.ref[:i]) 56 c.new[i] = val 57 } 58 59 // Result return the final reference 60 func (c *cowExprRef) Result() []Expression { 61 if c.new != nil { 62 return c.new 63 } 64 return c.ref 65 } 66 67 // Filter the input memexs, append the results to result. 68 func Filter(result []Expression, input []Expression, filter func(Expression) bool) []Expression { 69 for _, e := range input { 70 if filter(e) { 71 result = append(result, e) 72 } 73 } 74 return result 75 } 76 77 // FilterOutInPlace do the filtering out in place. 78 // The remained are the ones who doesn't match the filter, storing in the original slice. 79 // The filteredOut are the ones match the filter, storing in a new slice. 80 func FilterOutInPlace(input []Expression, filter func(Expression) bool) (remained, filteredOut []Expression) { 81 for i := len(input) - 1; i >= 0; i-- { 82 if filter(input[i]) { 83 filteredOut = append(filteredOut, input[i]) 84 input = append(input[:i], input[i+1:]...) 85 } 86 } 87 return input, filteredOut 88 } 89 90 // ExtractDependentDeferredCausets extracts all dependent defCausumns from a virtual defCausumn. 91 func ExtractDependentDeferredCausets(expr Expression) []*DeferredCauset { 92 // Pre-allocate a slice to reduce allocation, 8 doesn't have special meaning. 93 result := make([]*DeferredCauset, 0, 8) 94 return extractDependentDeferredCausets(result, expr) 95 } 96 97 func extractDependentDeferredCausets(result []*DeferredCauset, expr Expression) []*DeferredCauset { 98 switch v := expr.(type) { 99 case *DeferredCauset: 100 result = append(result, v) 101 if v.VirtualExpr != nil { 102 result = extractDependentDeferredCausets(result, v.VirtualExpr) 103 } 104 case *ScalarFunction: 105 for _, arg := range v.GetArgs() { 106 result = extractDependentDeferredCausets(result, arg) 107 } 108 } 109 return result 110 } 111 112 // ExtractDeferredCausets extracts all defCausumns from an memex. 113 func ExtractDeferredCausets(expr Expression) []*DeferredCauset { 114 // Pre-allocate a slice to reduce allocation, 8 doesn't have special meaning. 115 result := make([]*DeferredCauset, 0, 8) 116 return extractDeferredCausets(result, expr, nil) 117 } 118 119 // ExtractCorDeferredCausets extracts correlated defCausumn from given memex. 120 func ExtractCorDeferredCausets(expr Expression) (defcaus []*CorrelatedDeferredCauset) { 121 switch v := expr.(type) { 122 case *CorrelatedDeferredCauset: 123 return []*CorrelatedDeferredCauset{v} 124 case *ScalarFunction: 125 for _, arg := range v.GetArgs() { 126 defcaus = append(defcaus, ExtractCorDeferredCausets(arg)...) 127 } 128 } 129 return 130 } 131 132 // ExtractDeferredCausetsFromExpressions is a more efficient version of ExtractDeferredCausets for batch operation. 133 // filter can be nil, or a function to filter the result defCausumn. 134 // It's often observed that the pattern of the caller like this: 135 // 136 // defcaus := ExtractDeferredCausets(...) 137 // for _, defCaus := range defcaus { 138 // if xxx(defCaus) {...} 139 // } 140 // 141 // Provide an additional filter argument, this can be done in one step. 142 // To avoid allocation for defcaus that not need. 143 func ExtractDeferredCausetsFromExpressions(result []*DeferredCauset, exprs []Expression, filter func(*DeferredCauset) bool) []*DeferredCauset { 144 for _, expr := range exprs { 145 result = extractDeferredCausets(result, expr, filter) 146 } 147 return result 148 } 149 150 func extractDeferredCausets(result []*DeferredCauset, expr Expression, filter func(*DeferredCauset) bool) []*DeferredCauset { 151 switch v := expr.(type) { 152 case *DeferredCauset: 153 if filter == nil || filter(v) { 154 result = append(result, v) 155 } 156 case *ScalarFunction: 157 for _, arg := range v.GetArgs() { 158 result = extractDeferredCausets(result, arg, filter) 159 } 160 } 161 return result 162 } 163 164 // ExtractDeferredCausetSet extracts the different values of `UniqueId` for defCausumns in memexs. 165 func ExtractDeferredCausetSet(exprs []Expression) *intsets.Sparse { 166 set := &intsets.Sparse{} 167 for _, expr := range exprs { 168 extractDeferredCausetSet(expr, set) 169 } 170 return set 171 } 172 173 func extractDeferredCausetSet(expr Expression, set *intsets.Sparse) { 174 switch v := expr.(type) { 175 case *DeferredCauset: 176 set.Insert(int(v.UniqueID)) 177 case *ScalarFunction: 178 for _, arg := range v.GetArgs() { 179 extractDeferredCausetSet(arg, set) 180 } 181 } 182 } 183 184 func setExprDeferredCausetInOperand(expr Expression) Expression { 185 switch v := expr.(type) { 186 case *DeferredCauset: 187 defCaus := v.Clone().(*DeferredCauset) 188 defCaus.InOperand = true 189 return defCaus 190 case *ScalarFunction: 191 args := v.GetArgs() 192 for i, arg := range args { 193 args[i] = setExprDeferredCausetInOperand(arg) 194 } 195 } 196 return expr 197 } 198 199 // DeferredCausetSubstitute substitutes the defCausumns in filter to memexs in select fields. 200 // e.g. select * from (select b as a from t) k where a < 10 => select * from (select b as a from t where b < 10) k. 201 func DeferredCausetSubstitute(expr Expression, schemaReplicant *Schema, newExprs []Expression) Expression { 202 _, resExpr := DeferredCausetSubstituteImpl(expr, schemaReplicant, newExprs) 203 return resExpr 204 } 205 206 // DeferredCausetSubstituteImpl tries to substitute defCausumn expr using newExprs, 207 // the newFunctionInternal is only called if its child is substituted 208 func DeferredCausetSubstituteImpl(expr Expression, schemaReplicant *Schema, newExprs []Expression) (bool, Expression) { 209 switch v := expr.(type) { 210 case *DeferredCauset: 211 id := schemaReplicant.DeferredCausetIndex(v) 212 if id == -1 { 213 return false, v 214 } 215 newExpr := newExprs[id] 216 if v.InOperand { 217 newExpr = setExprDeferredCausetInOperand(newExpr) 218 } 219 newExpr.SetCoercibility(v.Coercibility()) 220 return true, newExpr 221 case *ScalarFunction: 222 if v.FuncName.L == ast.Cast { 223 newFunc := v.Clone().(*ScalarFunction) 224 _, newFunc.GetArgs()[0] = DeferredCausetSubstituteImpl(newFunc.GetArgs()[0], schemaReplicant, newExprs) 225 return true, newFunc 226 } 227 // cowExprRef is a copy-on-write soliton, args array allocation happens only 228 // when expr in args is changed 229 refExprArr := cowExprRef{v.GetArgs(), nil} 230 substituted := false 231 _, defCausl := DeriveDefCauslationFromExprs(v.GetCtx(), v.GetArgs()...) 232 for idx, arg := range v.GetArgs() { 233 changed, newFuncExpr := DeferredCausetSubstituteImpl(arg, schemaReplicant, newExprs) 234 if defCauslate.NewDefCauslationEnabled() { 235 // Make sure the defCauslation used by the ScalarFunction isn't changed and its result defCauslation is not weaker than the defCauslation used by the ScalarFunction. 236 if changed { 237 changed = false 238 tmpArgs := make([]Expression, 0, len(v.GetArgs())) 239 _ = append(append(append(tmpArgs, refExprArr.Result()[0:idx]...), refExprArr.Result()[idx+1:]...), newFuncExpr) 240 _, newDefCausl := DeriveDefCauslationFromExprs(v.GetCtx(), append(v.GetArgs(), newFuncExpr)...) 241 if defCausl == newDefCausl { 242 changed = checkDefCauslationStrictness(defCausl, newFuncExpr.GetType().DefCauslate) 243 } 244 } 245 } 246 refExprArr.Set(idx, changed, newFuncExpr) 247 if changed { 248 substituted = true 249 } 250 } 251 if substituted { 252 return true, NewFunctionInternal(v.GetCtx(), v.FuncName.L, v.RetType, refExprArr.Result()...) 253 } 254 } 255 return false, expr 256 } 257 258 // checkDefCauslationStrictness check defCauslation strictness-ship between `defCausl` and `newFuncDefCausl` 259 // return true iff `newFuncDefCausl` is not weaker than `defCausl` 260 func checkDefCauslationStrictness(defCausl, newFuncDefCausl string) bool { 261 defCauslGroupID, ok1 := DefCauslationStrictnessGroup[defCausl] 262 newFuncDefCauslGroupID, ok2 := DefCauslationStrictnessGroup[newFuncDefCausl] 263 264 if ok1 && ok2 { 265 if defCauslGroupID == newFuncDefCauslGroupID { 266 return true 267 } 268 269 for _, id := range DefCauslationStrictness[defCauslGroupID] { 270 if newFuncDefCauslGroupID == id { 271 return true 272 } 273 } 274 } 275 276 return false 277 } 278 279 // getValidPrefix gets a prefix of string which can parsed to a number with base. the minimum base is 2 and the maximum is 36. 280 func getValidPrefix(s string, base int64) string { 281 var ( 282 validLen int 283 upper rune 284 ) 285 switch { 286 case base >= 2 && base <= 9: 287 upper = rune('0' + base) 288 case base <= 36: 289 upper = rune('A' + base - 10) 290 default: 291 return "" 292 } 293 Loop: 294 for i := 0; i < len(s); i++ { 295 c := rune(s[i]) 296 switch { 297 case unicode.IsDigit(c) || unicode.IsLower(c) || unicode.IsUpper(c): 298 c = unicode.ToUpper(c) 299 if c < upper { 300 validLen = i + 1 301 } else { 302 break Loop 303 } 304 case c == '+' || c == '-': 305 if i != 0 { 306 break Loop 307 } 308 default: 309 break Loop 310 } 311 } 312 if validLen > 1 && s[0] == '+' { 313 return s[1:validLen] 314 } 315 return s[:validLen] 316 } 317 318 // SubstituteCorDefCaus2Constant will substitute correlated defCausumn to constant value which it contains. 319 // If the args of one scalar function are all constant, we will substitute it to constant. 320 func SubstituteCorDefCaus2Constant(expr Expression) (Expression, error) { 321 switch x := expr.(type) { 322 case *ScalarFunction: 323 allConstant := true 324 newArgs := make([]Expression, 0, len(x.GetArgs())) 325 for _, arg := range x.GetArgs() { 326 newArg, err := SubstituteCorDefCaus2Constant(arg) 327 if err != nil { 328 return nil, err 329 } 330 _, ok := newArg.(*Constant) 331 newArgs = append(newArgs, newArg) 332 allConstant = allConstant && ok 333 } 334 if allConstant { 335 val, err := x.Eval(chunk.Event{}) 336 if err != nil { 337 return nil, err 338 } 339 return &Constant{Value: val, RetType: x.GetType()}, nil 340 } 341 var newSf Expression 342 if x.FuncName.L == ast.Cast { 343 newSf = BuildCastFunction(x.GetCtx(), newArgs[0], x.RetType) 344 } else { 345 newSf = NewFunctionInternal(x.GetCtx(), x.FuncName.L, x.GetType(), newArgs...) 346 } 347 return newSf, nil 348 case *CorrelatedDeferredCauset: 349 return &Constant{Value: *x.Data, RetType: x.GetType()}, nil 350 case *Constant: 351 if x.DeferredExpr != nil { 352 newExpr := FoldConstant(x) 353 return &Constant{Value: newExpr.(*Constant).Value, RetType: x.GetType()}, nil 354 } 355 } 356 return expr, nil 357 } 358 359 // timeZone2Duration converts timezone whose format should satisfy the regular condition 360 // `(^(+|-)(0?[0-9]|1[0-2]):[0-5]?\d$)|(^+13:00$)` to time.Duration. 361 func timeZone2Duration(tz string) time.Duration { 362 sign := 1 363 if strings.HasPrefix(tz, "-") { 364 sign = -1 365 } 366 367 i := strings.Index(tz, ":") 368 h, err := strconv.Atoi(tz[1:i]) 369 terror.Log(err) 370 m, err := strconv.Atoi(tz[i+1:]) 371 terror.Log(err) 372 return time.Duration(sign) * (time.Duration(h)*time.Hour + time.Duration(m)*time.Minute) 373 } 374 375 var logicalOps = map[string]struct{}{ 376 ast.LT: {}, 377 ast.GE: {}, 378 ast.GT: {}, 379 ast.LE: {}, 380 ast.EQ: {}, 381 ast.NE: {}, 382 ast.UnaryNot: {}, 383 ast.LogicAnd: {}, 384 ast.LogicOr: {}, 385 ast.LogicXor: {}, 386 ast.In: {}, 387 ast.IsNull: {}, 388 ast.IsTruthWithoutNull: {}, 389 ast.IsFalsity: {}, 390 ast.Like: {}, 391 } 392 393 var oppositeOp = map[string]string{ 394 ast.LT: ast.GE, 395 ast.GE: ast.LT, 396 ast.GT: ast.LE, 397 ast.LE: ast.GT, 398 ast.EQ: ast.NE, 399 ast.NE: ast.EQ, 400 ast.LogicOr: ast.LogicAnd, 401 ast.LogicAnd: ast.LogicOr, 402 } 403 404 // a op b is equal to b symmetricOp a 405 var symmetricOp = map[opcode.Op]opcode.Op{ 406 opcode.LT: opcode.GT, 407 opcode.GE: opcode.LE, 408 opcode.GT: opcode.LT, 409 opcode.LE: opcode.GE, 410 opcode.EQ: opcode.EQ, 411 opcode.NE: opcode.NE, 412 opcode.NullEQ: opcode.NullEQ, 413 } 414 415 func pushNotAcrossArgs(ctx stochastikctx.Context, exprs []Expression, not bool) ([]Expression, bool) { 416 newExprs := make([]Expression, 0, len(exprs)) 417 flag := false 418 for _, expr := range exprs { 419 newExpr, changed := pushNotAcrossExpr(ctx, expr, not) 420 flag = changed || flag 421 newExprs = append(newExprs, newExpr) 422 } 423 return newExprs, flag 424 } 425 426 // pushNotAcrossExpr try to eliminate the NOT expr in memex tree. 427 // Input `not` indicates whether there's a `NOT` be pushed down. 428 // Output `changed` indicates whether the output memex differs from the 429 // input `expr` because of the pushed-down-not. 430 func pushNotAcrossExpr(ctx stochastikctx.Context, expr Expression, not bool) (_ Expression, changed bool) { 431 if f, ok := expr.(*ScalarFunction); ok { 432 switch f.FuncName.L { 433 case ast.UnaryNot: 434 child, err := wrapWithIsTrue(ctx, true, f.GetArgs()[0], true) 435 if err != nil { 436 return expr, false 437 } 438 var childExpr Expression 439 childExpr, changed = pushNotAcrossExpr(f.GetCtx(), child, !not) 440 if !changed && !not { 441 return expr, false 442 } 443 return childExpr, true 444 case ast.LT, ast.GE, ast.GT, ast.LE, ast.EQ, ast.NE: 445 if not { 446 return NewFunctionInternal(f.GetCtx(), oppositeOp[f.FuncName.L], f.GetType(), f.GetArgs()...), true 447 } 448 newArgs, changed := pushNotAcrossArgs(f.GetCtx(), f.GetArgs(), false) 449 if !changed { 450 return f, false 451 } 452 return NewFunctionInternal(f.GetCtx(), f.FuncName.L, f.GetType(), newArgs...), true 453 case ast.LogicAnd, ast.LogicOr: 454 var ( 455 newArgs []Expression 456 changed bool 457 ) 458 funcName := f.FuncName.L 459 if not { 460 newArgs, _ = pushNotAcrossArgs(f.GetCtx(), f.GetArgs(), true) 461 funcName = oppositeOp[f.FuncName.L] 462 changed = true 463 } else { 464 newArgs, changed = pushNotAcrossArgs(f.GetCtx(), f.GetArgs(), false) 465 } 466 if !changed { 467 return f, false 468 } 469 return NewFunctionInternal(f.GetCtx(), funcName, f.GetType(), newArgs...), true 470 } 471 } 472 if not { 473 expr = NewFunctionInternal(ctx, ast.UnaryNot, types.NewFieldType(allegrosql.TypeTiny), expr) 474 } 475 return expr, not 476 } 477 478 // PushDownNot pushes the `not` function down to the memex's arguments. 479 func PushDownNot(ctx stochastikctx.Context, expr Expression) Expression { 480 newExpr, _ := pushNotAcrossExpr(ctx, expr, false) 481 return newExpr 482 } 483 484 // Contains tests if `exprs` contains `e`. 485 func Contains(exprs []Expression, e Expression) bool { 486 for _, expr := range exprs { 487 if e == expr { 488 return true 489 } 490 } 491 return false 492 } 493 494 // ExtractFiltersFromDNFs checks whether the cond is DNF. If so, it will get the extracted part and the remained part. 495 // The original DNF will be replaced by the remained part or just be deleted if remained part is nil. 496 // And the extracted part will be appended to the end of the orignal slice. 497 func ExtractFiltersFromDNFs(ctx stochastikctx.Context, conditions []Expression) []Expression { 498 var allExtracted []Expression 499 for i := len(conditions) - 1; i >= 0; i-- { 500 if sf, ok := conditions[i].(*ScalarFunction); ok && sf.FuncName.L == ast.LogicOr { 501 extracted, remained := extractFiltersFromDNF(ctx, sf) 502 allExtracted = append(allExtracted, extracted...) 503 if remained == nil { 504 conditions = append(conditions[:i], conditions[i+1:]...) 505 } else { 506 conditions[i] = remained 507 } 508 } 509 } 510 return append(conditions, allExtracted...) 511 } 512 513 // extractFiltersFromDNF extracts the same condition that occurs in every DNF item and remove them from dnf leaves. 514 func extractFiltersFromDNF(ctx stochastikctx.Context, dnfFunc *ScalarFunction) ([]Expression, Expression) { 515 dnfItems := FlattenDNFConditions(dnfFunc) 516 sc := ctx.GetStochastikVars().StmtCtx 517 codeMap := make(map[string]int) 518 hashcode2Expr := make(map[string]Expression) 519 for i, dnfItem := range dnfItems { 520 innerMap := make(map[string]struct{}) 521 cnfItems := SplitCNFItems(dnfItem) 522 for _, cnfItem := range cnfItems { 523 code := cnfItem.HashCode(sc) 524 if i == 0 { 525 codeMap[string(code)] = 1 526 hashcode2Expr[string(code)] = cnfItem 527 } else if _, ok := codeMap[string(code)]; ok { 528 // We need this check because there may be the case like `select * from t, t1 where (t.a=t1.a and t.a=t1.a) or (something). 529 // We should make sure that the two `t.a=t1.a` contributes only once. 530 // TODO: do this out of this function. 531 if _, ok = innerMap[string(code)]; !ok { 532 codeMap[string(code)]++ 533 innerMap[string(code)] = struct{}{} 534 } 535 } 536 } 537 } 538 // We should make sure that this item occurs in every DNF item. 539 for hashcode, cnt := range codeMap { 540 if cnt < len(dnfItems) { 541 delete(hashcode2Expr, hashcode) 542 } 543 } 544 if len(hashcode2Expr) == 0 { 545 return nil, dnfFunc 546 } 547 newDNFItems := make([]Expression, 0, len(dnfItems)) 548 onlyNeedExtracted := false 549 for _, dnfItem := range dnfItems { 550 cnfItems := SplitCNFItems(dnfItem) 551 newCNFItems := make([]Expression, 0, len(cnfItems)) 552 for _, cnfItem := range cnfItems { 553 code := cnfItem.HashCode(sc) 554 _, ok := hashcode2Expr[string(code)] 555 if !ok { 556 newCNFItems = append(newCNFItems, cnfItem) 557 } 558 } 559 // If the extracted part is just one leaf of the DNF memex. Then the value of the total DNF memex is 560 // always the same with the value of the extracted part. 561 if len(newCNFItems) == 0 { 562 onlyNeedExtracted = true 563 break 564 } 565 newDNFItems = append(newDNFItems, ComposeCNFCondition(ctx, newCNFItems...)) 566 } 567 extractedExpr := make([]Expression, 0, len(hashcode2Expr)) 568 for _, expr := range hashcode2Expr { 569 extractedExpr = append(extractedExpr, expr) 570 } 571 if onlyNeedExtracted { 572 return extractedExpr, nil 573 } 574 return extractedExpr, ComposeDNFCondition(ctx, newDNFItems...) 575 } 576 577 // DeriveRelaxedFiltersFromDNF given a DNF memex, derive a relaxed DNF memex which only contains defCausumns 578 // in specified schemaReplicant; the derived memex is a superset of original memex, i.e, any tuple satisfying 579 // the original memex must satisfy the derived memex. Return nil when the derived memex is universal set. 580 // A running example is: for schemaReplicant of t1, `(t1.a=1 and t2.a=1) or (t1.a=2 and t2.a=2)` would be derived as 581 // `t1.a=1 or t1.a=2`, while `t1.a=1 or t2.a=1` would get nil. 582 func DeriveRelaxedFiltersFromDNF(expr Expression, schemaReplicant *Schema) Expression { 583 sf, ok := expr.(*ScalarFunction) 584 if !ok || sf.FuncName.L != ast.LogicOr { 585 return nil 586 } 587 ctx := sf.GetCtx() 588 dnfItems := FlattenDNFConditions(sf) 589 newDNFItems := make([]Expression, 0, len(dnfItems)) 590 for _, dnfItem := range dnfItems { 591 cnfItems := SplitCNFItems(dnfItem) 592 newCNFItems := make([]Expression, 0, len(cnfItems)) 593 for _, cnfItem := range cnfItems { 594 if itemSF, ok := cnfItem.(*ScalarFunction); ok && itemSF.FuncName.L == ast.LogicOr { 595 relaxedCNFItem := DeriveRelaxedFiltersFromDNF(cnfItem, schemaReplicant) 596 if relaxedCNFItem != nil { 597 newCNFItems = append(newCNFItems, relaxedCNFItem) 598 } 599 // If relaxed memex for embedded DNF is universal set, just drop this CNF item 600 continue 601 } 602 // This cnfItem must be simple memex now 603 // If it cannot be fully covered by schemaReplicant, just drop this CNF item 604 if ExprFromSchema(cnfItem, schemaReplicant) { 605 newCNFItems = append(newCNFItems, cnfItem) 606 } 607 } 608 // If this DNF item involves no defCausumn of specified schemaReplicant, the relaxed memex must be universal set 609 if len(newCNFItems) == 0 { 610 return nil 611 } 612 newDNFItems = append(newDNFItems, ComposeCNFCondition(ctx, newCNFItems...)) 613 } 614 return ComposeDNFCondition(ctx, newDNFItems...) 615 } 616 617 // GetEventLen gets the length if the func is event, returns 1 if not event. 618 func GetEventLen(e Expression) int { 619 if f, ok := e.(*ScalarFunction); ok && f.FuncName.L == ast.EventFunc { 620 return len(f.GetArgs()) 621 } 622 return 1 623 } 624 625 // CheckArgsNotMultiDeferredCausetEvent checks the args are not multi-defCausumn event. 626 func CheckArgsNotMultiDeferredCausetEvent(args ...Expression) error { 627 for _, arg := range args { 628 if GetEventLen(arg) != 1 { 629 return ErrOperandDeferredCausets.GenWithStackByArgs(1) 630 } 631 } 632 return nil 633 } 634 635 // GetFuncArg gets the argument of the function at idx. 636 func GetFuncArg(e Expression, idx int) Expression { 637 if f, ok := e.(*ScalarFunction); ok { 638 return f.GetArgs()[idx] 639 } 640 return nil 641 } 642 643 // PopEventFirstArg pops the first element and returns the rest of event. 644 // e.g. After this function (1, 2, 3) becomes (2, 3). 645 func PopEventFirstArg(ctx stochastikctx.Context, e Expression) (ret Expression, err error) { 646 if f, ok := e.(*ScalarFunction); ok && f.FuncName.L == ast.EventFunc { 647 args := f.GetArgs() 648 if len(args) == 2 { 649 return args[1], nil 650 } 651 ret, err = NewFunction(ctx, ast.EventFunc, f.GetType(), args[1:]...) 652 return ret, err 653 } 654 return 655 } 656 657 // exprStack is a stack of memexs. 658 type exprStack struct { 659 stack []Expression 660 } 661 662 // pop pops an memex from the stack. 663 func (s *exprStack) pop() Expression { 664 if s.len() == 0 { 665 return nil 666 } 667 lastIdx := s.len() - 1 668 expr := s.stack[lastIdx] 669 s.stack = s.stack[:lastIdx] 670 return expr 671 } 672 673 // popN pops n memexs from the stack. 674 // If n greater than stack length or n is negative, it pops all the memexs. 675 func (s *exprStack) popN(n int) []Expression { 676 if n > s.len() || n < 0 { 677 n = s.len() 678 } 679 idx := s.len() - n 680 exprs := s.stack[idx:] 681 s.stack = s.stack[:idx] 682 return exprs 683 } 684 685 // push pushes one memex to the stack. 686 func (s *exprStack) push(expr Expression) { 687 s.stack = append(s.stack, expr) 688 } 689 690 // len returns the length of th stack. 691 func (s *exprStack) len() int { 692 return len(s.stack) 693 } 694 695 // CausetToConstant generates a Constant memex from a Causet. 696 func CausetToConstant(d types.Causet, tp byte) *Constant { 697 return &Constant{Value: d, RetType: types.NewFieldType(tp)} 698 } 699 700 // ParamMarkerExpression generate a getparam function memex. 701 func ParamMarkerExpression(ctx stochastikctx.Context, v *driver.ParamMarkerExpr) (Expression, error) { 702 useCache := ctx.GetStochastikVars().StmtCtx.UseCache 703 isPointInterDirc := ctx.GetStochastikVars().StmtCtx.PointInterDirc 704 tp := types.NewFieldType(allegrosql.TypeUnspecified) 705 types.DefaultParamTypeForValue(v.GetValue(), tp) 706 value := &Constant{Value: v.Causet, RetType: tp} 707 if useCache || isPointInterDirc { 708 value.ParamMarker = &ParamMarker{ 709 order: v.Order, 710 ctx: ctx, 711 } 712 } 713 return value, nil 714 } 715 716 // DisableParseJSONFlag4Expr disables ParseToJSONFlag for `expr` except DeferredCauset. 717 // We should not *PARSE* a string as JSON under some scenarios. ParseToJSONFlag 718 // is 0 for JSON defCausumn yet(as well as JSON correlated defCausumn), so we can skip 719 // it. Moreover, DeferredCauset.RetType refers to the schemareplicant, if we modify it, data 720 // race may happen if another goroutine read from the schemareplicant at the same 721 // time. 722 func DisableParseJSONFlag4Expr(expr Expression) { 723 if _, isDeferredCauset := expr.(*DeferredCauset); isDeferredCauset { 724 return 725 } 726 if _, isCorDefCaus := expr.(*CorrelatedDeferredCauset); isCorDefCaus { 727 return 728 } 729 expr.GetType().Flag &= ^allegrosql.ParseToJSONFlag 730 } 731 732 // ConstructPositionExpr constructs PositionExpr with the given ParamMarkerExpr. 733 func ConstructPositionExpr(p *driver.ParamMarkerExpr) *ast.PositionExpr { 734 return &ast.PositionExpr{P: p} 735 } 736 737 // PosFromPositionExpr generates a position value from PositionExpr. 738 func PosFromPositionExpr(ctx stochastikctx.Context, v *ast.PositionExpr) (int, bool, error) { 739 if v.P == nil { 740 return v.N, false, nil 741 } 742 value, err := ParamMarkerExpression(ctx, v.P.(*driver.ParamMarkerExpr)) 743 if err != nil { 744 return 0, true, err 745 } 746 pos, isNull, err := GetIntFromConstant(ctx, value) 747 if err != nil || isNull { 748 return 0, true, err 749 } 750 return pos, false, nil 751 } 752 753 // GetStringFromConstant gets a string value from the Constant memex. 754 func GetStringFromConstant(ctx stochastikctx.Context, value Expression) (string, bool, error) { 755 con, ok := value.(*Constant) 756 if !ok { 757 err := errors.Errorf("Not a Constant memex %+v", value) 758 return "", true, err 759 } 760 str, isNull, err := con.EvalString(ctx, chunk.Event{}) 761 if err != nil || isNull { 762 return "", true, err 763 } 764 return str, false, nil 765 } 766 767 // GetIntFromConstant gets an interger value from the Constant memex. 768 func GetIntFromConstant(ctx stochastikctx.Context, value Expression) (int, bool, error) { 769 str, isNull, err := GetStringFromConstant(ctx, value) 770 if err != nil || isNull { 771 return 0, true, err 772 } 773 intNum, err := strconv.Atoi(str) 774 if err != nil { 775 return 0, true, nil 776 } 777 return intNum, false, nil 778 } 779 780 // BuildNotNullExpr wraps up `not(isnull())` for given memex. 781 func BuildNotNullExpr(ctx stochastikctx.Context, expr Expression) Expression { 782 isNull := NewFunctionInternal(ctx, ast.IsNull, types.NewFieldType(allegrosql.TypeTiny), expr) 783 notNull := NewFunctionInternal(ctx, ast.UnaryNot, types.NewFieldType(allegrosql.TypeTiny), isNull) 784 return notNull 785 } 786 787 // IsRuntimeConstExpr checks if a expr can be treated as a constant in **interlock**. 788 func IsRuntimeConstExpr(expr Expression) bool { 789 switch x := expr.(type) { 790 case *ScalarFunction: 791 if _, ok := unFoldableFunctions[x.FuncName.L]; ok { 792 return false 793 } 794 for _, arg := range x.GetArgs() { 795 if !IsRuntimeConstExpr(arg) { 796 return false 797 } 798 } 799 return true 800 case *DeferredCauset: 801 return false 802 case *Constant, *CorrelatedDeferredCauset: 803 return true 804 } 805 return false 806 } 807 808 // IsMublockEffectsExpr checks if expr contains function which is mublock or has side effects. 809 func IsMublockEffectsExpr(expr Expression) bool { 810 switch x := expr.(type) { 811 case *ScalarFunction: 812 if _, ok := mublockEffectsFunctions[x.FuncName.L]; ok { 813 return true 814 } 815 for _, arg := range x.GetArgs() { 816 if IsMublockEffectsExpr(arg) { 817 return true 818 } 819 } 820 case *DeferredCauset: 821 case *Constant: 822 if x.DeferredExpr != nil { 823 return IsMublockEffectsExpr(x.DeferredExpr) 824 } 825 } 826 return false 827 } 828 829 // RemoveDupExprs removes identical exprs. Not that if expr contains functions which 830 // are mublock or have side effects, we cannot remove it even if it has duplicates; 831 // if the plan is going to be cached, we cannot remove memexs containing `?` neither. 832 func RemoveDupExprs(ctx stochastikctx.Context, exprs []Expression) []Expression { 833 res := make([]Expression, 0, len(exprs)) 834 exists := make(map[string]struct{}, len(exprs)) 835 sc := ctx.GetStochastikVars().StmtCtx 836 for _, expr := range exprs { 837 if ContainMublockConst(ctx, []Expression{expr}) { 838 res = append(res, expr) 839 continue 840 } 841 key := string(expr.HashCode(sc)) 842 if _, ok := exists[key]; !ok || IsMublockEffectsExpr(expr) { 843 res = append(res, expr) 844 exists[key] = struct{}{} 845 } 846 } 847 return res 848 } 849 850 // GetUint64FromConstant gets a uint64 from constant memex. 851 func GetUint64FromConstant(expr Expression) (uint64, bool, bool) { 852 con, ok := expr.(*Constant) 853 if !ok { 854 logutil.BgLogger().Warn("not a constant memex", zap.String("memex", expr.ExplainInfo())) 855 return 0, false, false 856 } 857 dt := con.Value 858 if con.ParamMarker != nil { 859 dt = con.ParamMarker.GetUserVar() 860 } else if con.DeferredExpr != nil { 861 var err error 862 dt, err = con.DeferredExpr.Eval(chunk.Event{}) 863 if err != nil { 864 logutil.BgLogger().Warn("eval deferred expr failed", zap.Error(err)) 865 return 0, false, false 866 } 867 } 868 switch dt.HoTT() { 869 case types.HoTTNull: 870 return 0, true, true 871 case types.HoTTInt64: 872 val := dt.GetInt64() 873 if val < 0 { 874 return 0, false, false 875 } 876 return uint64(val), false, true 877 case types.HoTTUint64: 878 return dt.GetUint64(), false, true 879 } 880 return 0, false, false 881 } 882 883 // ContainVirtualDeferredCauset checks if the memexs contain a virtual defCausumn 884 func ContainVirtualDeferredCauset(exprs []Expression) bool { 885 for _, expr := range exprs { 886 switch v := expr.(type) { 887 case *DeferredCauset: 888 if v.VirtualExpr != nil { 889 return true 890 } 891 case *ScalarFunction: 892 if ContainVirtualDeferredCauset(v.GetArgs()) { 893 return true 894 } 895 } 896 } 897 return false 898 } 899 900 // ContainMublockConst checks if the memexs contain a lazy constant. 901 func ContainMublockConst(ctx stochastikctx.Context, exprs []Expression) bool { 902 // Treat all constants immublock if plan cache is not enabled for this query. 903 if !ctx.GetStochastikVars().StmtCtx.UseCache { 904 return false 905 } 906 for _, expr := range exprs { 907 switch v := expr.(type) { 908 case *Constant: 909 if v.ParamMarker != nil || v.DeferredExpr != nil { 910 return true 911 } 912 case *ScalarFunction: 913 if ContainMublockConst(ctx, v.GetArgs()) { 914 return true 915 } 916 } 917 } 918 return false 919 } 920 921 const ( 922 _ = iota 923 kib = 1 << (10 * iota) 924 mib = 1 << (10 * iota) 925 gib = 1 << (10 * iota) 926 tib = 1 << (10 * iota) 927 pib = 1 << (10 * iota) 928 eib = 1 << (10 * iota) 929 ) 930 931 const ( 932 nano = 1 933 micro = 1000 * nano 934 milli = 1000 * micro 935 sec = 1000 * milli 936 min = 60 * sec 937 hour = 60 * min 938 dayTime = 24 * hour 939 ) 940 941 // GetFormatBytes convert byte count to value with units. 942 func GetFormatBytes(bytes float64) string { 943 var divisor float64 944 var unit string 945 946 bytesAbs := math.Abs(bytes) 947 if bytesAbs >= eib { 948 divisor = eib 949 unit = "EiB" 950 } else if bytesAbs >= pib { 951 divisor = pib 952 unit = "PiB" 953 } else if bytesAbs >= tib { 954 divisor = tib 955 unit = "TiB" 956 } else if bytesAbs >= gib { 957 divisor = gib 958 unit = "GiB" 959 } else if bytesAbs >= mib { 960 divisor = mib 961 unit = "MiB" 962 } else if bytesAbs >= kib { 963 divisor = kib 964 unit = "KiB" 965 } else { 966 divisor = 1 967 unit = "bytes" 968 } 969 970 if divisor == 1 { 971 return strconv.FormatFloat(bytes, 'f', 0, 64) + " " + unit 972 } 973 value := float64(bytes) / divisor 974 if math.Abs(value) >= 100000.0 { 975 return strconv.FormatFloat(value, 'e', 2, 64) + " " + unit 976 } 977 return strconv.FormatFloat(value, 'f', 2, 64) + " " + unit 978 } 979 980 // GetFormatNanoTime convert time in nanoseconds to value with units. 981 func GetFormatNanoTime(time float64) string { 982 var divisor float64 983 var unit string 984 985 timeAbs := math.Abs(time) 986 if timeAbs >= dayTime { 987 divisor = dayTime 988 unit = "d" 989 } else if timeAbs >= hour { 990 divisor = hour 991 unit = "h" 992 } else if timeAbs >= min { 993 divisor = min 994 unit = "min" 995 } else if timeAbs >= sec { 996 divisor = sec 997 unit = "s" 998 } else if timeAbs >= milli { 999 divisor = milli 1000 unit = "ms" 1001 } else if timeAbs >= micro { 1002 divisor = micro 1003 unit = "us" 1004 } else { 1005 divisor = 1 1006 unit = "ns" 1007 } 1008 1009 if divisor == 1 { 1010 return strconv.FormatFloat(time, 'f', 0, 64) + " " + unit 1011 } 1012 value := float64(time) / divisor 1013 if math.Abs(value) >= 100000.0 { 1014 return strconv.FormatFloat(value, 'e', 2, 64) + " " + unit 1015 } 1016 return strconv.FormatFloat(value, 'f', 2, 64) + " " + unit 1017 }