func (e *Evaluator) patternLike(p *ast.PatternLikeExpr) bool { expr := p.Expr.GetValue() if types.IsNil(expr) { p.SetValue(nil) return true } sexpr, err := types.ToString(expr) if err != nil { e.err = errors.Trace(err) return false } // We need to compile pattern if it has not been compiled or it is not static. var needCompile = len(p.PatChars) == 0 || !ast.IsConstant(p.Pattern) if needCompile { pattern := p.Pattern.GetValue() if types.IsNil(pattern) { p.SetValue(nil) return true } spattern, err := types.ToString(pattern) if err != nil { e.err = errors.Trace(err) return false } p.PatChars, p.PatTypes = compilePattern(spattern, p.Escape) } match := doMatch(sexpr, p.PatChars, p.PatTypes) if p.Not { match = !match } p.SetValue(boolToInt64(match)) return true }
// Eval implements the Expression Eval interface. func (p *PatternRegexp) Eval(ctx context.Context, args map[interface{}]interface{}) (v interface{}, err error) { var sexpr string switch { case p.Sexpr != nil: sexpr = *p.Sexpr default: expr, err := p.Expr.Eval(ctx, args) if err != nil { return nil, err } if types.IsNil(expr) { return nil, nil } sexpr, err = types.ToString(expr) if err != nil { return nil, errors.Errorf("non-string Expression in LIKE: %v (Value of type %T)", expr, expr) } if p.Expr.IsStatic() { p.Sexpr = new(string) *p.Sexpr = sexpr } } re := p.Re if re == nil { pattern, err := p.Pattern.Eval(ctx, args) if err != nil { return nil, err } if types.IsNil(pattern) { return nil, nil } spattern, err := types.ToString(pattern) if err != nil { return nil, errors.Errorf("non-string pattern in LIKE: %v (Value of type %T)", pattern, pattern) } if re, err = regexp.Compile(spattern); err != nil { return nil, err } if p.Pattern.IsStatic() { p.Re = re } } match := re.MatchString(sexpr) if p.Not { return !match, nil } return match, nil }
func (e *Evaluator) patternRegexp(p *ast.PatternRegexpExpr) bool { var sexpr string if p.Sexpr != nil { sexpr = *p.Sexpr } else { expr := p.Expr.GetValue() if types.IsNil(expr) { p.SetValue(nil) return true } var err error sexpr, err = types.ToString(expr) if err != nil { e.err = errors.Errorf("non-string Expression in LIKE: %v (Value of type %T)", expr, expr) return false } if ast.IsConstant(p.Expr) { p.Sexpr = new(string) *p.Sexpr = sexpr } } re := p.Re if re == nil { pattern := p.Pattern.GetValue() if types.IsNil(pattern) { p.SetValue(nil) return true } spattern, err := types.ToString(pattern) if err != nil { e.err = errors.Errorf("non-string pattern in LIKE: %v (Value of type %T)", pattern, pattern) return false } if re, err = regexp.Compile(spattern); err != nil { e.err = errors.Trace(err) return false } if ast.IsConstant(p.Pattern) { p.Re = re } } match := re.MatchString(sexpr) if p.Not { match = !match } p.SetValue(boolToInt64(match)) return true }
// Eval implements the Expression Eval interface. func (da *DateAdd) Eval(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) { dv, err := da.Date.Eval(ctx, args) if dv == nil || err != nil { return nil, errors.Trace(err) } sv, err := types.ToString(dv) if err != nil { return nil, errors.Trace(err) } f := types.NewFieldType(mysql.TypeDatetime) f.Decimal = mysql.MaxFsp dv, err = types.Convert(sv, f) if dv == nil || err != nil { return nil, errors.Trace(err) } t, ok := dv.(mysql.Time) if !ok { return nil, errors.Errorf("need time type, but got %T", dv) } iv, err := da.Interval.Eval(ctx, args) if iv == nil || err != nil { return nil, errors.Trace(err) } format, err := types.ToString(iv) if err != nil { return nil, errors.Trace(err) } years, months, days, durations, err := mysql.ExtractTimeValue(da.Unit, strings.TrimSpace(format)) if err != nil { return nil, errors.Trace(err) } t.Time = t.Time.Add(durations) t.Time = t.Time.AddDate(int(years), int(months), int(days)) // "2011-11-11 10:10:20.000000" outputs "2011-11-11 10:10:20". if t.Time.Nanosecond() == 0 { t.Fsp = 0 } return t, nil }
func (e *Evaluator) funcTrim(v *ast.FuncTrimExpr) bool { // eval str fs := v.Str.GetValue() if types.IsNil(fs) { v.SetValue(nil) return true } str, err := types.ToString(fs) if err != nil { e.err = errors.Trace(err) return false } remstr := "" // eval remstr if v.RemStr != nil { fs = v.RemStr.GetValue() if types.IsNil(fs) { v.SetValue(nil) return true } remstr, err = types.ToString(fs) if err != nil { e.err = errors.Trace(err) return false } } // Do trim var result string if v.Direction == ast.TrimLeading { if len(remstr) > 0 { result = trimLeft(str, remstr) } else { result = strings.TrimLeft(str, spaceChars) } } else if v.Direction == ast.TrimTrailing { if len(remstr) > 0 { result = trimRight(str, remstr) } else { result = strings.TrimRight(str, spaceChars) } } else if len(remstr) > 0 { x := trimLeft(str, remstr) result = trimRight(x, remstr) } else { result = strings.Trim(str, spaceChars) } v.SetValue(result) return true }
func (da *DateArith) evalArgs(ctx context.Context, args map[interface{}]interface{}) ( *evalArgsResult, error) { ret := &evalArgsResult{time: mysql.ZeroTimestamp} dVal, err := da.Date.Eval(ctx, args) if dVal == nil || err != nil { return ret, errors.Trace(err) } dValStr, err := types.ToString(dVal) if err != nil { return ret, errors.Trace(err) } f := types.NewFieldType(mysql.TypeDatetime) f.Decimal = mysql.MaxFsp dVal, err = types.Convert(dValStr, f) if dVal == nil || err != nil { return ret, errors.Trace(err) } var ok bool ret.time, ok = dVal.(mysql.Time) if !ok { return ret, errors.Errorf("need time type, but got %T", dVal) } iVal, err := da.Interval.Eval(ctx, args) if iVal == nil || err != nil { ret.time = mysql.ZeroTimestamp return ret, errors.Trace(err) } // handle adddate(expr,days) or subdate(expr,days) form if da.Form == DateArithDaysForm { if iVal, err = da.evalDaysForm(iVal); err != nil { return ret, errors.Trace(err) } } iValStr, err := types.ToString(iVal) if err != nil { return ret, errors.Trace(err) } ret.year, ret.month, ret.day, ret.duration, err = mysql.ExtractTimeValue(da.Unit, strings.TrimSpace(iValStr)) if err != nil { return ret, errors.Trace(err) } return ret, nil }
// Eval implements the Expression Eval interface. func (f *FunctionSubstringIndex) Eval(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) { fs, err := f.StrExpr.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } str, err := types.ToString(fs) if err != nil { return nil, errors.Errorf("Substring_Index invalid args, need string but get %T", fs) } t, err := f.Delim.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } delim, err := types.ToString(t) if err != nil { return nil, errors.Errorf("Substring_Index invalid delim, need string but get %T", t) } t, err = f.Count.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } c, err := types.ToInt64(t) if err != nil { return nil, errors.Trace(err) } count := int(c) strs := strings.Split(str, delim) var ( start = 0 end = len(strs) ) if count > 0 { // If count is positive, everything to the left of the final delimiter (counting from the left) is returned. if count < end { end = count } } else { // If count is negative, everything to the right of the final delimiter (counting from the right) is returned. count = -count if count < end { start = end - count } } substrs := strs[start:end] return strings.Join(substrs, delim), nil }
// getExecRet executes restricted sql and the result is one column. // It returns a string value. func (s *session) getExecRet(ctx context.Context, sql string) (string, error) { cleanTxn := s.txn == nil rs, err := s.ExecRestrictedSQL(ctx, sql) if err != nil { return "", errors.Trace(err) } defer rs.Close() row, err := rs.Next() if err != nil { return "", errors.Trace(err) } if row == nil { return "", terror.ExecResultIsEmpty } value, err := types.ToString(row.Data[0]) if err != nil { return "", errors.Trace(err) } if cleanTxn { // This function has some side effect. Run select may create new txn. // We should make environment unchanged. s.txn = nil } return value, nil }
// Eval implements the Expression Eval interface. func (f *FunctionTrim) Eval(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) { // eval str fs, err := f.Str.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } if types.IsNil(fs) { return nil, nil } str, err := types.ToString(fs) if err != nil { return nil, errors.Trace(err) } remstr := "" // eval remstr if f.RemStr != nil { fs, err = f.RemStr.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } if types.IsNil(fs) { return nil, nil } remstr, err = types.ToString(fs) if err != nil { return nil, errors.Trace(err) } } // Do trim if f.Direction == TrimLeading { if len(remstr) > 0 { return trimLeft(str, remstr), nil } return strings.TrimLeft(str, spaceChars), nil } else if f.Direction == TrimTrailing { if len(remstr) > 0 { return trimRight(str, remstr), nil } return strings.TrimRight(str, spaceChars), nil } if len(remstr) > 0 { x := trimLeft(str, remstr) x = trimRight(x, remstr) return x, nil } return strings.Trim(str, spaceChars), nil }
func (c *conditionChecker) check(condition ast.ExprNode) bool { switch x := condition.(type) { case *ast.BinaryOperationExpr: return c.checkBinaryOperation(x) case *ast.BetweenExpr: if ast.IsPreEvaluable(x.Left) && ast.IsPreEvaluable(x.Right) && c.checkColumnExpr(x.Expr) { return true } case *ast.ColumnNameExpr: return c.checkColumnExpr(x) case *ast.IsNullExpr: if c.checkColumnExpr(x.Expr) { return true } case *ast.IsTruthExpr: if c.checkColumnExpr(x.Expr) { return true } case *ast.ParenthesesExpr: return c.check(x.Expr) case *ast.PatternInExpr: if x.Sel != nil || x.Not { return false } if !c.checkColumnExpr(x.Expr) { return false } for _, val := range x.List { if !ast.IsPreEvaluable(val) { return false } } return true case *ast.PatternLikeExpr: if x.Not { return false } if !c.checkColumnExpr(x.Expr) { return false } if !ast.IsPreEvaluable(x.Pattern) { return false } patternVal := x.Pattern.GetValue() if patternVal == nil { return false } patternStr, err := types.ToString(patternVal) if err != nil { return false } if len(patternStr) == 0 { return true } firstChar := patternStr[0] return firstChar != '%' && firstChar != '_' } return false }
// Eval implements the Expression Eval interface. func (f *FunctionLocate) Eval(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) { // eval str fs, err := f.Str.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } if fs == nil { return nil, nil } str, err := types.ToString(fs) if err != nil { return nil, errors.Trace(err) } // eval substr fs, err = f.SubStr.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } if fs == nil { return nil, nil } substr, err := types.ToString(fs) if err != nil { return nil, errors.Trace(err) } // eval pos pos := 0 if f.Pos != nil { t, err := f.Pos.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } p, err := types.ToInt64(t) if err != nil { return nil, errors.Trace(err) } pos = int(p) } // eval locate if pos < 0 || pos > len(str) { return 0, errors.Errorf("Locate invalid pos args: %d", pos) } str = str[pos:] i := strings.Index(str, substr) return i + 1 + pos, nil }
func (e *Evaluator) funcLocate(v *ast.FuncLocateExpr) bool { // eval str fs := v.Str.GetValue() if types.IsNil(fs) { v.SetValue(nil) return true } str, err := types.ToString(fs) if err != nil { e.err = errors.Trace(err) return false } // eval substr fs = v.SubStr.GetValue() if types.IsNil(fs) { v.SetValue(nil) return true } substr, err := types.ToString(fs) if err != nil { e.err = errors.Trace(err) return false } // eval pos pos := 0 if v.Pos != nil { t := v.Pos.GetValue() p, err := types.ToInt64(t) if err != nil { e.err = errors.Trace(err) return false } pos = int(p) } // eval locate if pos < 0 || pos > len(str) { e.err = ErrInvalidOperation.Gen("Locate invalid pos args: %d", pos) return false } str = str[pos:] i := strings.Index(str, substr) v.SetValue(i + 1 + pos) return true }
func (r *rangeBuilder) buildFromPatternLike(x *ast.PatternLikeExpr) []rangePoint { if x.Not { // Pattern not like is not supported. r.err = ErrUnsupportedType.Gen("NOT LIKE is not supported.") return fullRange } pattern, err := types.ToString(x.Pattern.GetValue()) if err != nil { r.err = errors.Trace(err) return fullRange } lowValue := make([]byte, 0, len(pattern)) // unscape the pattern var exclude bool for i := 0; i < len(pattern); i++ { if pattern[i] == x.Escape { i++ if i < len(pattern) { lowValue = append(lowValue, pattern[i]) } else { lowValue = append(lowValue, x.Escape) } continue } if pattern[i] == '%' { break } else if pattern[i] == '_' { exclude = true break } lowValue = append(lowValue, pattern[i]) } if len(lowValue) == 0 { return []rangePoint{{value: types.MinNotNullDatum(), start: true}, {value: types.MaxValueDatum()}} } startPoint := rangePoint{start: true, excl: exclude} startPoint.value.SetBytesAsString(lowValue) highValue := make([]byte, len(lowValue)) copy(highValue, lowValue) endPoint := rangePoint{excl: true} for i := len(highValue) - 1; i >= 0; i-- { highValue[i]++ if highValue[i] != 0 { endPoint.value.SetBytesAsString(highValue) break } if i == 0 { endPoint.value = types.MaxValueDatum() break } } ranges := make([]rangePoint, 2) ranges[0] = startPoint ranges[1] = endPoint return ranges }
func (e *Evaluator) funcSubstringIndex(v *ast.FuncSubstringIndexExpr) bool { fs := v.StrExpr.GetValue() str, err := types.ToString(fs) if err != nil { e.err = ErrInvalidOperation.Gen("Substring_Index invalid args, need string but get %T", fs) return false } t := v.Delim.GetValue() delim, err := types.ToString(t) if err != nil { e.err = ErrInvalidOperation.Gen("Substring_Index invalid delim, need string but get %T", t) return false } t = v.Count.GetValue() c, err := types.ToInt64(t) if err != nil { e.err = errors.Trace(err) return false } count := int(c) strs := strings.Split(str, delim) var ( start = 0 end = len(strs) ) if count > 0 { // If count is positive, everything to the left of the final delimiter (counting from the left) is returned. if count < end { end = count } } else { // If count is negative, everything to the right of the final delimiter (counting from the right) is returned. count = -count if count < end { start = end - count } } substrs := strs[start:end] v.SetValue(strings.Join(substrs, delim)) return true }
// Eval implements the Expression Eval interface. func (f *FunctionSubstring) Eval(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) { fs, err := f.StrExpr.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } str, err := types.ToString(fs) if err != nil { return nil, errors.Errorf("Substring invalid args, need string but get %T", fs) } t, err := f.Pos.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } p, ok := t.(int64) if !ok { return nil, errors.Errorf("Substring invalid pos args, need int but get %T", t) } pos := int(p) length := -1 if f.Len != nil { t, err := f.Len.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } p, ok := t.(int64) if !ok { return nil, errors.Errorf("Substring invalid len args, need int but get %T", t) } length = int(p) } // The forms without a len argument return a substring from string str starting at position pos. // The forms with a len argument return a substring len characters long from string str, starting at position pos. // The forms that use FROM are standard SQL syntax. It is also possible to use a negative value for pos. // In this case, the beginning of the substring is pos characters from the end of the string, rather than the beginning. // A negative value may be used for pos in any of the forms of this function. if pos < 0 { pos = len(str) + pos } else { pos-- } if pos > len(str) || pos <= 0 { pos = len(str) } end := len(str) if length != -1 { end = pos + length } if end > len(str) { end = len(str) } return str[pos:end], nil }
// See: https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_upper func builtinUpper(args []interface{}, ctx map[interface{}]interface{}) (interface{}, error) { switch x := args[0].(type) { case nil: return nil, nil default: s, err := types.ToString(x) if err != nil { return nil, errors.Trace(err) } return strings.ToUpper(s), nil } }
func builtinLength(args []interface{}, _ map[interface{}]interface{}) (v interface{}, err error) { switch x := args[0].(type) { case nil: return nil, nil default: s, err := types.ToString(x) if err != nil { return nil, errors.Trace(err) } return int64(len(s)), nil } }
// See: https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_replace func builtinReplace(args []interface{}, ctx map[interface{}]interface{}) (interface{}, error) { for _, arg := range args { if types.IsNil(arg) { return nil, nil } } str, err := types.ToString(args[0]) if err != nil { return nil, errors.Trace(err) } oldStr, err := types.ToString(args[1]) if err != nil { return nil, errors.Trace(err) } newStr, err := types.ToString(args[2]) if err != nil { return nil, errors.Trace(err) } return strings.Replace(str, oldStr, newStr, -1), nil }
// See: https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_concat func builtinConcat(args []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { var s []byte for _, a := range args { if a == nil { return nil, nil } ss, err := types.ToString(a) if err != nil { return nil, errors.Trace(err) } s = append(s, []byte(ss)...) } return string(s), nil }
func (da *DateArith) evalArgs(ctx context.Context, args map[interface{}]interface{}) ( mysql.Time, int64, int64, int64, time.Duration, error) { dVal, err := da.Date.Eval(ctx, args) if dVal == nil || err != nil { return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err) } dValStr, err := types.ToString(dVal) if err != nil { return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err) } f := types.NewFieldType(mysql.TypeDatetime) f.Decimal = mysql.MaxFsp dVal, err = types.Convert(dValStr, f) if dVal == nil || err != nil { return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err) } t, ok := dVal.(mysql.Time) if !ok { return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Errorf("need time type, but got %T", dVal) } iVal, err := da.Interval.Eval(ctx, args) if iVal == nil || err != nil { return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err) } iValStr, err := types.ToString(iVal) if err != nil { return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err) } years, months, days, durations, err := mysql.ExtractTimeValue(da.Unit, strings.TrimSpace(iValStr)) if err != nil { return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err) } return t, years, months, days, durations, nil }
// Eval implements the Expression Eval interface. func (p *PatternLike) Eval(ctx context.Context, args map[interface{}]interface{}) (v interface{}, err error) { expr, err := p.Expr.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } if types.IsNil(expr) { return nil, nil } sexpr, err := types.ToString(expr) if err != nil { return nil, errors.Trace(err) } // We need to compile pattern if it has not been compiled or it is not static. var needCompile = len(p.patChars) == 0 || !p.Pattern.IsStatic() if needCompile { pattern, err := p.Pattern.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } if types.IsNil(pattern) { return nil, nil } spattern, err := types.ToString(pattern) if err != nil { return nil, errors.Trace(err) } p.patChars, p.patTypes = compilePattern(spattern, p.Escape) } match := doMatch(sexpr, p.patChars, p.patTypes) if p.Not { return !match, nil } return match, nil }
func (e *Evaluator) funcSubstring(v *ast.FuncSubstringExpr) bool { str, err := types.ToString(v.StrExpr.GetValue()) if err != nil { e.err = ErrInvalidOperation.Gen("Substring invalid args, need string but get %T", v.StrExpr.GetValue()) return false } t := v.Pos.GetValue() p, ok := t.(int64) if !ok { e.err = ErrInvalidOperation.Gen("Substring invalid pos args, need int but get %T", t) return false } pos := int(p) length := -1 if v.Len != nil { t = v.Len.GetValue() p, ok = t.(int64) if !ok { e.err = ErrInvalidOperation.Gen("Substring invalid pos args, need int but get %T", t) return false } length = int(p) } // The forms without a len argument return a substring from string str starting at position pos. // The forms with a len argument return a substring len characters long from string str, starting at position pos. // The forms that use FROM are standard SQL syntax. It is also possible to use a negative value for pos. // In this case, the beginning of the substring is pos characters from the end of the string, rather than the beginning. // A negative value may be used for pos in any of the forms of this function. if pos < 0 { pos = len(str) + pos } else { pos-- } if pos > len(str) || pos <= 0 { pos = len(str) } end := len(str) if length != -1 { end = pos + length } if end > len(str) { end = len(str) } v.SetValue(str[pos:end]) return true }
// Generate index content string representation. func (t *Table) genIndexKeyStr(colVals []interface{}) (string, error) { // Pass pre-composed error to txn. strVals := make([]string, 0, len(colVals)) for _, cv := range colVals { cvs := "NULL" var err error if cv != nil { cvs, err = types.ToString(cv) if err != nil { return "", errors.Trace(err) } } strVals = append(strVals, cvs) } return strings.Join(strVals, "-"), nil }
func (e *ShowExec) fetchShowStatus() error { statusVars, err := variable.GetStatusVars() if err != nil { return errors.Trace(err) } for status, v := range statusVars { if e.GlobalScope && v.Scope == variable.ScopeSession { continue } value, err := types.ToString(v.Value) if err != nil { return errors.Trace(err) } row := &Row{Data: types.MakeDatums(status, value)} e.rows = append(e.rows, row) } return nil }
// See: https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_left func builtinLeft(args []interface{}, _ map[interface{}]interface{}) (v interface{}, err error) { str, err := types.ToString(args[0]) if err != nil { return nil, errors.Errorf("BuiltinLeft invalid args, need string but get %T", args[0]) } // TODO: deal with other types length, ok := args[1].(int64) if !ok { return nil, errors.Errorf("BuiltinLeft invalid args, need int but get %T", args[1]) } l := int(length) if l < 0 { l = 0 } else if l > len(str) { l = len(str) } return str[:l], nil }
func (s *ShowPlan) fetchShowStatus(ctx context.Context) error { m := map[interface{}]interface{}{} statusVars, err := variable.GetStatusVars() if err != nil { return errors.Trace(err) } for status, v := range statusVars { if s.Pattern != nil { s.Pattern.Expr = expression.Value{Val: status} } else if s.Where != nil { m[expression.ExprEvalIdentFunc] = func(name string) (interface{}, error) { if strings.EqualFold(name, "Variable_name") { return status, nil } return nil, errors.Errorf("unknown field %s", name) } } match, err := s.evalCondition(ctx, m) if err != nil { return errors.Trace(err) } if !match { continue } if s.GlobalScope && v.Scope == variable.ScopeSession { continue } value, err := types.ToString(v.Value) if err != nil { return errors.Trace(err) } row := &plan.Row{Data: []interface{}{status, value}} s.rows = append(s.rows, row) } return nil }
// getExecRet executes restricted sql and the result is one column. // It returns a string value. func (s *session) getExecRet(ctx context.Context, sql string) (string, error) { rs, err := s.ExecRestrictedSQL(ctx, sql) if err != nil { return "", errors.Trace(err) } defer rs.Close() row, err := rs.Next() if err != nil { return "", errors.Trace(err) } if row == nil { return "", terror.ExecResultIsEmpty } value, err := types.ToString(row.Data[0]) if err != nil { return "", errors.Trace(err) } return value, nil }
// Eval implements the Expression Eval interface. func (p *PatternLike) Eval(ctx context.Context, args map[interface{}]interface{}) (v interface{}, err error) { expr, err := p.Expr.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } if types.IsNil(expr) { return nil, nil } sexpr, err := types.ToString(expr) if err != nil { return nil, errors.Trace(err) } // We need to compile pattern if it has not been compiled or it is not static. var needCompile = len(p.patChars) == 0 || !p.Pattern.IsStatic() if needCompile { pattern, err := p.Pattern.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } if types.IsNil(pattern) { return nil, nil } var spattern string switch v := pattern.(type) { case string: spattern = v case []byte: spattern = string(v) default: return nil, errors.Errorf("Pattern should be string or []byte in LIKE: %v (Value of type %T)", pattern, pattern) } p.patChars, p.patTypes = compilePattern(spattern, p.Escape) } match := doMatch(sexpr, p.patChars, p.patTypes) if p.Not { return !match, nil } return match, nil }
// GetGlobalSysVar implements RestrictedSQLExecutor.GetGlobalSysVar interface. func (s *session) GetGlobalSysVar(ctx context.Context, name string) (string, error) { sql := fmt.Sprintf(`SELECT VARIABLE_VALUE FROM %s.%s WHERE VARIABLE_NAME="%s";`, mysql.SystemDB, mysql.GlobalVariablesTable, name) rs, err := s.ExecRestrictedSQL(ctx, sql) if err != nil { return "", errors.Trace(err) } defer rs.Close() row, err := rs.Next() if err != nil { return "", errors.Trace(err) } if row == nil { return "", fmt.Errorf("Unknown sys var: %s", name) } value, err := types.ToString(row.Data[0]) if err != nil { return "", errors.Trace(err) } return value, nil }
// Leave implements Visitor Leave interface. func (c *stringer) Leave(in Node) (out Node, ok bool) { switch x := in.(type) { case *BinaryOperationExpr: left := c.strMap[x.L] right := c.strMap[x.R] c.strMap[x] = left + " " + x.Op.String() + " " + right case *ValueExpr: str, _ := types.ToString(x.Data) c.strMap[x] = str case *ParenthesesExpr: c.strMap[x] = "(" + c.strMap[x.Expr] + ")" case *ColumnNameExpr: c.strMap[x] = x.Name.Table.O + "." + x.Name.Name.O case *BetweenExpr: c.strMap[x] = c.strMap[x.Expr] + " BETWWEN " + c.strMap[x.Left] + " AND " + c.strMap[x.Right] default: c.strMap[in] = fmt.Sprintf("%T", in) } return in, true }