예제 #1
0
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
}
예제 #2
0
파일: regexp.go 프로젝트: lovedboy/tidb
// 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
}
예제 #3
0
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
}
예제 #4
0
// 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
}
예제 #5
0
파일: evaluator.go 프로젝트: mrtoms/tidb
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
}
예제 #6
0
파일: date_arith.go 프로젝트: yzl11/vessel
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
}
예제 #7
0
파일: substring.go 프로젝트: lovedboy/tidb
// 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
}
예제 #8
0
파일: session.go 프로젝트: losas/tidb
// 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
}
예제 #9
0
파일: trim.go 프로젝트: lovedboy/tidb
// 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
}
예제 #10
0
파일: refiner.go 프로젝트: c4pt0r/tidb
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
}
예제 #11
0
// 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
}
예제 #12
0
파일: evaluator.go 프로젝트: mrtoms/tidb
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
}
예제 #13
0
파일: range.go 프로젝트: anywhy/tidb
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
}
예제 #14
0
파일: evaluator.go 프로젝트: mrtoms/tidb
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
}
예제 #15
0
파일: substring.go 프로젝트: lovedboy/tidb
// 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
}
예제 #16
0
// 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
	}
}
예제 #17
0
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
	}
}
예제 #18
0
파일: string.go 프로젝트: lovedboy/tidb
// 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
}
예제 #19
0
// 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
}
예제 #20
0
파일: date_arith.go 프로젝트: hanjinze/tidb
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
}
예제 #21
0
파일: like.go 프로젝트: lovedboy/tidb
// 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
}
예제 #22
0
파일: evaluator.go 프로젝트: mrtoms/tidb
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
}
예제 #23
0
파일: tables.go 프로젝트: lovedboy/tidb
// 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
}
예제 #24
0
파일: show.go 프로젝트: astaxie/tidb
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
}
예제 #25
0
파일: string.go 프로젝트: lovedboy/tidb
// 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
}
예제 #26
0
파일: show.go 프로젝트: kellerli/tidb
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
}
예제 #27
0
파일: session.go 프로젝트: kkpapa/tidb
// 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
}
예제 #28
0
파일: like.go 프로젝트: js-for-kids/tidb
// 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
}
예제 #29
0
파일: session.go 프로젝트: hanjinze/tidb
// 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
}
예제 #30
0
파일: stringer.go 프로젝트: 70767096/tidb
// 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
}