github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/soliton/ranger/checker.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 "github.com/whtcorpsinc/BerolinaSQL/ast" 18 "github.com/whtcorpsinc/milevadb/memex" 19 "github.com/whtcorpsinc/milevadb/types" 20 "github.com/whtcorpsinc/milevadb/soliton/defCauslate" 21 ) 22 23 // conditionChecker checks if this condition can be pushed to index causet. 24 type conditionChecker struct { 25 defCausUniqueID int64 26 shouldReserve bool // check if a access condition should be reserved in filter conditions. 27 length int 28 } 29 30 func (c *conditionChecker) check(condition memex.Expression) bool { 31 switch x := condition.(type) { 32 case *memex.ScalarFunction: 33 return c.checkScalarFunction(x) 34 case *memex.DeferredCauset: 35 if x.RetType.EvalType() == types.ETString { 36 return false 37 } 38 return c.checkDeferredCauset(x) 39 case *memex.Constant: 40 return true 41 } 42 return false 43 } 44 45 func (c *conditionChecker) checkScalarFunction(scalar *memex.ScalarFunction) bool { 46 _, defCauslation := scalar.CharsetAndDefCauslation(scalar.GetCtx()) 47 switch scalar.FuncName.L { 48 case ast.LogicOr, ast.LogicAnd: 49 return c.check(scalar.GetArgs()[0]) && c.check(scalar.GetArgs()[1]) 50 case ast.EQ, ast.NE, ast.GE, ast.GT, ast.LE, ast.LT, ast.NullEQ: 51 if _, ok := scalar.GetArgs()[0].(*memex.Constant); ok { 52 if c.checkDeferredCauset(scalar.GetArgs()[1]) { 53 // Checks whether the scalar function is calculated use the defCauslation compatible with the defCausumn. 54 if scalar.GetArgs()[1].GetType().EvalType() == types.ETString && !defCauslate.CompatibleDefCauslate(scalar.GetArgs()[1].GetType().DefCauslate, defCauslation) { 55 return false 56 } 57 return scalar.FuncName.L != ast.NE || c.length == types.UnspecifiedLength 58 } 59 } 60 if _, ok := scalar.GetArgs()[1].(*memex.Constant); ok { 61 if c.checkDeferredCauset(scalar.GetArgs()[0]) { 62 // Checks whether the scalar function is calculated use the defCauslation compatible with the defCausumn. 63 if scalar.GetArgs()[0].GetType().EvalType() == types.ETString && !defCauslate.CompatibleDefCauslate(scalar.GetArgs()[0].GetType().DefCauslate, defCauslation) { 64 return false 65 } 66 return scalar.FuncName.L != ast.NE || c.length == types.UnspecifiedLength 67 } 68 } 69 case ast.IsNull: 70 return c.checkDeferredCauset(scalar.GetArgs()[0]) 71 case ast.IsTruthWithoutNull, ast.IsFalsity, ast.IsTruthWithNull: 72 if s, ok := scalar.GetArgs()[0].(*memex.DeferredCauset); ok { 73 if s.RetType.EvalType() == types.ETString { 74 return false 75 } 76 } 77 return c.checkDeferredCauset(scalar.GetArgs()[0]) 78 case ast.UnaryNot: 79 // TODO: support "not like" convert to access conditions. 80 if s, ok := scalar.GetArgs()[0].(*memex.ScalarFunction); ok { 81 if s.FuncName.L == ast.Like { 82 return false 83 } 84 } else { 85 // "not defCausumn" or "not constant" can't lead to a range. 86 return false 87 } 88 return c.check(scalar.GetArgs()[0]) 89 case ast.In: 90 if !c.checkDeferredCauset(scalar.GetArgs()[0]) { 91 return false 92 } 93 if scalar.GetArgs()[1].GetType().EvalType() == types.ETString && !defCauslate.CompatibleDefCauslate(scalar.GetArgs()[0].GetType().DefCauslate, defCauslation) { 94 return false 95 } 96 for _, v := range scalar.GetArgs()[1:] { 97 if _, ok := v.(*memex.Constant); !ok { 98 return false 99 } 100 } 101 return true 102 case ast.Like: 103 return c.checkLikeFunc(scalar) 104 case ast.GetParam: 105 return true 106 } 107 return false 108 } 109 110 func (c *conditionChecker) checkLikeFunc(scalar *memex.ScalarFunction) bool { 111 _, defCauslation := scalar.CharsetAndDefCauslation(scalar.GetCtx()) 112 if !defCauslate.CompatibleDefCauslate(scalar.GetArgs()[0].GetType().DefCauslate, defCauslation) { 113 return false 114 } 115 if !c.checkDeferredCauset(scalar.GetArgs()[0]) { 116 return false 117 } 118 pattern, ok := scalar.GetArgs()[1].(*memex.Constant) 119 if !ok { 120 return false 121 122 } 123 if pattern.Value.IsNull() { 124 return false 125 } 126 patternStr, err := pattern.Value.ToString() 127 if err != nil { 128 return false 129 } 130 if len(patternStr) == 0 { 131 return true 132 } 133 escape := byte(scalar.GetArgs()[2].(*memex.Constant).Value.GetInt64()) 134 for i := 0; i < len(patternStr); i++ { 135 if patternStr[i] == escape { 136 i++ 137 if i < len(patternStr)-1 { 138 continue 139 } 140 break 141 } 142 if i == 0 && (patternStr[i] == '%' || patternStr[i] == '_') { 143 return false 144 } 145 if patternStr[i] == '%' { 146 if i != len(patternStr)-1 { 147 c.shouldReserve = true 148 } 149 break 150 } 151 if patternStr[i] == '_' { 152 c.shouldReserve = true 153 break 154 } 155 } 156 return true 157 } 158 159 func (c *conditionChecker) checkDeferredCauset(expr memex.Expression) bool { 160 defCaus, ok := expr.(*memex.DeferredCauset) 161 if !ok { 162 return false 163 } 164 return c.defCausUniqueID == defCaus.UniqueID 165 }