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  }