Beispiel #1
0
func builtinAvg(args []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) {
	// avg use decimal for integer and decimal type, use float for others
	// see https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html
	type avg struct {
		sum           interface{}
		n             uint64
		decimalResult bool
	}

	if _, ok := ctx[ExprEvalArgAggEmpty]; ok {
		return
	}

	fn := ctx[ExprEvalFn]
	distinct := getDistinct(ctx, fn)

	if _, ok := ctx[ExprAggDone]; ok {
		distinct.clear()

		data, ok := ctx[fn].(avg)
		if !ok {
			return
		}

		switch x := data.sum.(type) {
		case nil:
			return nil, nil
		case float64:
			return float64(x) / float64(data.n), nil
		case mysql.Decimal:
			return x.Div(mysql.NewDecimalFromUint(data.n, 0)), nil
		}
		panic("should not happend")
	}

	data, _ := ctx[fn].(avg)
	y := args[0]
	if types.IsNil(y) {
		return
	}

	ok, err := distinct.isDistinct(args...)
	if err != nil || !ok {
		// if err or not distinct, return
		return nil, err
	}

	if types.IsNil(data.sum) {
		data.n = 0
	}

	data.sum, err = calculateSum(data.sum, y)
	if err != nil {
		return nil, errors.Errorf("eval AVG aggregate err: %v", err)
	}

	data.n++
	ctx[fn] = data
	return
}
Beispiel #2
0
// operator: >=, >, <=, <, !=, <>, = <=>, etc.
// see https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html
func (o *BinaryOperation) evalComparisonOp(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) {
	a, b, err := o.get2(ctx, args)
	if err != nil {
		return nil, err
	}

	if types.IsNil(a) || types.IsNil(b) {
		// for <=>, if a and b are both nil, return true.
		// if a or b is nil, return false.
		if o.Op == opcode.NullEQ {
			return types.IsNil(a) && types.IsNil(b), nil
		}

		return nil, nil
	}

	n, err := types.Compare(a, b)
	if err != nil {
		return nil, o.traceErr(err)
	}

	r, err := getCompResult(o.Op, n)
	if err != nil {
		return nil, o.errorf(err.Error())
	}

	return r, nil
}
Beispiel #3
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
}
Beispiel #4
0
func (e *Evaluator) handleOrOr(o *ast.BinaryOperationExpr) bool {
	leftVal := o.L.GetValue()
	righVal := o.R.GetValue()
	if !types.IsNil(leftVal) {
		x, err := types.ToBool(leftVal)
		if err != nil {
			e.err = errors.Trace(err)
			return false
		} else if x == 1 {
			// true || any other types is true.
			o.SetValue(x)
			return true
		}
	}
	if !types.IsNil(righVal) {
		y, err := types.ToBool(righVal)
		if err != nil {
			e.err = errors.Trace(err)
			return false
		} else if y == 1 {
			o.SetValue(y)
			return true
		}
	}
	if types.IsNil(leftVal) || types.IsNil(righVal) {
		o.SetValue(nil)
		return true
	}
	o.SetValue(int64(0))
	return true
}
Beispiel #5
0
func (e *Evaluator) patternIn(n *ast.PatternInExpr) bool {
	lhs := n.Expr.GetValue()
	if types.IsNil(lhs) {
		n.SetValue(nil)
		return true
	}
	hasNull := false
	for _, v := range n.List {
		if types.IsNil(v.GetValue()) {
			hasNull = true
			continue
		}
		r, err := types.Compare(n.Expr.GetValue(), v.GetValue())
		if err != nil {
			e.err = errors.Trace(err)
			return false
		}
		if r == 0 {
			n.SetValue(boolToInt64(!n.Not))
			return true
		}
	}
	if hasNull {
		// if no matched but we got null in In, return null
		// e.g 1 in (null, 2, 3) returns null
		n.SetValue(nil)
		return true
	}
	n.SetValue(boolToInt64(n.Not))
	return true
}
Beispiel #6
0
func (e *Evaluator) handleComparisonOp(o *ast.BinaryOperationExpr) bool {
	a, b := types.Coerce(o.L.GetValue(), o.R.GetValue())
	if types.IsNil(a) || types.IsNil(b) {
		// for <=>, if a and b are both nil, return true.
		// if a or b is nil, return false.
		if o.Op == opcode.NullEQ {
			if types.IsNil(a) || types.IsNil(b) {
				o.SetValue(oneI64)
			} else {
				o.SetValue(zeroI64)
			}
		} else {
			o.SetValue(nil)
		}
		return true
	}

	n, err := types.Compare(a, b)
	if err != nil {
		e.err = errors.Trace(err)
		return false
	}

	r, err := getCompResult(o.Op, n)
	if err != nil {
		e.err = errors.Trace(err)
		return false
	}
	if r {
		o.SetValue(oneI64)
	} else {
		o.SetValue(zeroI64)
	}
	return true
}
Beispiel #7
0
func (e *Evaluator) handleXor(o *ast.BinaryOperationExpr) bool {
	leftVal := o.L.GetValue()
	righVal := o.R.GetValue()
	if types.IsNil(leftVal) || types.IsNil(righVal) {
		o.SetValue(nil)
		return true
	}
	x, err := types.ToBool(leftVal)
	if err != nil {
		e.err = errors.Trace(err)
		return false
	}

	y, err := types.ToBool(righVal)
	if err != nil {
		e.err = errors.Trace(err)
		return false
	}
	if x == y {
		o.SetValue(int64(0))
	} else {
		o.SetValue(int64(1))
	}
	return true
}
Beispiel #8
0
func (o *BinaryOperation) evalLogicXor(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) {
	a, err := o.L.Eval(ctx, args)
	if err != nil || types.IsNil(a) {
		return nil, o.traceErr(err)
	}

	x, err := types.ToBool(a)
	if err != nil {
		return nil, o.traceErr(err)
	}

	b, err := o.R.Eval(ctx, args)
	if err != nil || types.IsNil(b) {
		return nil, o.traceErr(err)
	}

	y, err := types.ToBool(b)
	if err != nil {
		return nil, o.traceErr(err)
	}

	if x == y {
		return int64(0), nil
	}

	return int64(1), nil
}
Beispiel #9
0
// Eval implements the Expression Eval interface.
func (p *PatternRegexp) Eval(ctx context.Context, args map[interface{}]interface{}) (v interface{}, err error) {
	var sexpr string
	var ok bool
	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, ok = expr.(string)
		if !ok {
			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, ok := pattern.(string)
		if !ok {
			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
}
Beispiel #10
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
}
Beispiel #11
0
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
}
Beispiel #12
0
// Eval implements the Expression Eval interface.
func (is *IsTruth) Eval(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) {
	if err := CheckOneColumn(ctx, is.Expr); err != nil {
		return nil, errors.Trace(err)
	}

	val, err := is.Expr.Eval(ctx, args)
	if err != nil {
		return nil, errors.Trace(err)
	}

	if types.IsNil(val) {
		// null is true/false -> false
		// null is not true/false -> true
		return is.Not, nil
	}

	b, err := types.ToBool(val)
	if err != nil {
		return nil, errors.Trace(err)
	}

	if !is.Not {
		// true/false is true/false
		return b == is.True, nil
	}

	// true/false is not true/false
	return b != is.True, nil
}
Beispiel #13
0
func builtinCount(args []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) {
	if _, ok := ctx[ExprEvalArgAggEmpty]; ok {
		return int64(0), nil
	}

	fn := ctx[ExprEvalFn]
	distinct := getDistinct(ctx, fn)

	if _, ok := ctx[ExprAggDone]; ok {
		distinct.clear()
		return ctx[fn].(int64), nil
	}

	n, _ := ctx[fn].(int64)

	if !types.IsNil(args[0]) {
		ok, err := distinct.isDistinct(args...)
		if err != nil || !ok {
			// if err or not distinct, return
			return nil, err
		}
		n++
	}

	ctx[fn] = n
	return
}
Beispiel #14
0
func (e *Evaluator) checkInList(not bool, in interface{}, list []interface{}) (interface{}, error) {
	hasNull := false
	for _, v := range list {
		if types.IsNil(v) {
			hasNull = true
			continue
		}

		r, err := types.Compare(in, v)
		if err != nil {
			return nil, errors.Trace(err)
		}

		if r == 0 {
			return !not, nil
		}
	}

	if hasNull {
		// if no matched but we got null in In, return null
		// e.g 1 in (null, 2, 3) returns null
		return nil, nil
	}

	return not, nil
}
Beispiel #15
0
func (e *Evaluator) patternIn(n *ast.PatternInExpr) bool {
	lhs := n.Expr.GetValue()
	if types.IsNil(lhs) {
		n.SetValue(nil)
		return true
	}
	if n.Sel == nil {
		values := make([]interface{}, 0, len(n.List))
		for _, ei := range n.List {
			values = append(values, ei.GetValue())
		}
		x := e.checkInList(n.Not, lhs, values)
		if e.err != nil {
			return false
		}
		n.SetValue(x)
		return true
	}
	se := n.Sel.(*ast.SubqueryExpr)
	sel := se.SubqueryExec

	res := sel.GetValue().([]interface{})
	x := e.checkInList(n.Not, lhs, res)
	if e.err != nil {
		return false
	}
	n.SetValue(x)
	return true
}
Beispiel #16
0
// See https://dev.mysql.com/doc/refman/5.7/en/control-flow-functions.html#function_nullif
func builtinNullIf(args []interface{}, m map[interface{}]interface{}) (interface{}, error) {
	// nullif(expr1, expr2)
	// returns null if expr1 = expr2 is true, otherwise returns expr1
	v1 := args[0]
	v2 := args[1]

	if types.IsNil(v1) || types.IsNil(v2) {
		return v1, nil
	}

	if n, err := types.Compare(v1, v2); err != nil || n == 0 {
		return nil, err
	}

	return v1, nil
}
Beispiel #17
0
func (n *PatternIn) checkInList(in interface{}, list []interface{}) (interface{}, error) {
	hasNull := false
	for _, v := range list {
		if types.IsNil(v) {
			hasNull = true
			continue
		}

		r, err := types.Compare(in, v)
		if err != nil {
			return nil, err
		}

		if r == 0 {
			return !n.Not, nil
		}
	}

	if hasNull {
		// if no matched but we got null in In, return null
		// e.g 1 in (null, 2, 3) returns null
		return nil, nil
	}

	return n.Not, nil
}
Beispiel #18
0
// 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
}
Beispiel #19
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 types.IsNil(fs) {
		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 types.IsNil(fs) {
		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
}
Beispiel #20
0
// See: http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_coalesce
func builtinCoalesce(args []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) {
	for _, v := range args {
		if !types.IsNil(v) {
			return v, nil
		}
	}
	return nil, nil
}
Beispiel #21
0
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
}
Beispiel #22
0
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_minute
func builtinMinute(args []interface{}, ctx map[interface{}]interface{}) (interface{}, error) {
	v, err := convertToDuration(args[0], mysql.MaxFsp)
	if err != nil || types.IsNil(v) {
		return v, err
	}

	// No need to check type here.
	d := v.(mysql.Duration)
	return int64(d.Minute()), nil
}
Beispiel #23
0
func builtinGroupConcat(args []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) {
	// TODO: the real group_concat is very complex, here we just support the simplest one.
	if _, ok := ctx[ExprEvalArgAggEmpty]; ok {
		return nil, nil
	}

	fn := ctx[ExprEvalFn]
	distinct := getDistinct(ctx, fn)
	if _, ok := ctx[ExprAggDone]; ok {
		distinct.clear()
		if v, _ := ctx[fn]; !types.IsNil(v) {
			return v.(string), nil
		}
		return nil, nil
	}

	var buf bytes.Buffer
	if v := ctx[fn]; !types.IsNil(v) {
		s := v.(string)
		// now use comma separator
		buf.WriteString(s)
		buf.WriteString(",")
	}

	ok, err := distinct.isDistinct(args...)
	if err != nil || !ok {
		// if err or not distinct, return
		return nil, err
	}

	for i := 0; i < len(args); i++ {
		if types.IsNil(args[i]) {
			// if any is nil, we will not concat
			return
		}

		buf.WriteString(fmt.Sprintf("%v", args[i]))
	}

	// TODO: if total length is greater than global var group_concat_max_len, truncate it.
	ctx[fn] = buf.String()
	return
}
Beispiel #24
0
func (o *BinaryOperation) evalOrOr(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) {
	a, err := o.L.Eval(ctx, args)
	if err != nil {
		return nil, o.traceErr(err)
	}

	var (
		x int64
		y int64
	)

	if !types.IsNil(a) {
		x, err = types.ToBool(a)
		if err != nil {
			return nil, o.traceErr(err)
		} else if x == 1 {
			// true || any other types is true
			return x, nil
		}
	}

	b, err := o.R.Eval(ctx, args)
	if err != nil {
		return nil, o.traceErr(err)
	}

	if !types.IsNil(b) {
		y, err = types.ToBool(b)
		if err != nil {
			return nil, o.traceErr(err)
		} else if y == 1 {
			return y, nil
		}
	}

	// here x and y are all not true
	// if a or b is nil
	if types.IsNil(a) || types.IsNil(b) {
		return nil, nil
	}

	return int64(0), nil
}
Beispiel #25
0
// 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
}
Beispiel #26
0
func (e *Evaluator) isNull(v *ast.IsNullExpr) bool {
	var boolVal bool
	if types.IsNil(v.Expr.GetValue()) {
		boolVal = true
	}
	if v.Not {
		boolVal = !boolVal
	}
	v.SetValue(boolToInt64(boolVal))
	return true
}
Beispiel #27
0
// Eval implements the Expression Eval interface.
func (is *IsNull) Eval(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) {
	if err := CheckOneColumn(ctx, is.Expr); err != nil {
		return nil, errors.Trace(err)
	}

	val, err := is.Expr.Eval(ctx, args)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return types.IsNil(val) != is.Not, nil
}
Beispiel #28
0
// See https://dev.mysql.com/doc/refman/5.7/en/control-flow-functions.html#function_ifnull
func builtinIfNull(args []interface{}, m map[interface{}]interface{}) (interface{}, error) {
	// ifnull(expr1, expr2)
	// if expr1 is not null, return expr1, otherwise, return expr2
	v1 := args[0]
	v2 := args[1]

	if !types.IsNil(v1) {
		return v1, nil
	}

	return v2, nil
}
Beispiel #29
0
func (o *BinaryOperation) evalAndAnd(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) {
	a, err := o.L.Eval(ctx, args)
	if err != nil {
		return nil, o.traceErr(err)
	}

	if !types.IsNil(a) {
		var x int64
		x, err = types.ToBool(a)
		if err != nil {
			return nil, o.traceErr(err)
		} else if x == 0 {
			// false && any other types is false
			return x, nil
		}
	}

	b, err := o.R.Eval(ctx, args)
	if err != nil {
		return nil, o.traceErr(err)
	}

	if !types.IsNil(b) {
		var y int64
		y, err = types.ToBool(b)
		if err != nil {
			return nil, o.traceErr(err)
		} else if y == 0 {
			return y, nil
		}
	}

	// here x and y are all not false
	// if a or b is nil
	if types.IsNil(a) || types.IsNil(b) {
		return nil, nil
	}

	return int64(1), nil
}
Beispiel #30
0
func (e *Evaluator) handleBitOp(o *ast.BinaryOperationExpr) bool {
	a, b := types.Coerce(o.L.GetValue(), o.R.GetValue())

	if types.IsNil(a) || types.IsNil(b) {
		o.SetValue(nil)
		return true
	}

	x, err := types.ToInt64(a)
	if err != nil {
		e.err = errors.Trace(err)
		return false
	}

	y, err := types.ToInt64(b)
	if err != nil {
		e.err = errors.Trace(err)
		return false
	}

	// use a int64 for bit operator, return uint64
	switch o.Op {
	case opcode.And:
		o.SetValue(uint64(x & y))
	case opcode.Or:
		o.SetValue(uint64(x | y))
	case opcode.Xor:
		o.SetValue(uint64(x ^ y))
	case opcode.RightShift:
		o.SetValue(uint64(x) >> uint64(y))
	case opcode.LeftShift:
		o.SetValue(uint64(x) << uint64(y))
	default:
		e.err = ErrInvalidOperation.Gen("invalid op %v in bit operation", o.Op)
		return false
	}
	return true
}