Example #1
0
func (s *testEvaluatorSuite) TestEvaluatedFlag(c *C) {
	l := ast.NewValueExpr(int64(1))
	r := ast.NewValueExpr(int64(2))
	b := &ast.BinaryOperationExpr{L: l, R: r, Op: opcode.Plus}
	ast.SetFlag(b)
	c.Assert(ast.IsPreEvaluable(b), Equals, true)
	d, err := Eval(s.ctx, b)
	c.Assert(ast.IsEvaluated(b), Equals, true)
	c.Assert(err, IsNil)
	c.Assert(d, testutil.DatumEquals, types.NewIntDatum(3))

	funcCall := &ast.FuncCallExpr{
		FnName: model.NewCIStr("abs"),
		Args:   []ast.ExprNode{ast.NewValueExpr(int(-1))},
	}
	b = &ast.BinaryOperationExpr{L: funcCall, R: r, Op: opcode.Plus}
	ast.ResetEvaluatedFlag(b)
	ast.SetFlag(b)
	c.Assert(ast.IsPreEvaluable(b), Equals, true)
	d, err = Eval(s.ctx, b)
	c.Assert(ast.IsEvaluated(b), Equals, false)
	c.Assert(err, IsNil)
	c.Assert(d, testutil.DatumEquals, types.NewIntDatum(3))

	rf := &ast.ResultField{Expr: ast.NewValueExpr(int64(1))}
	colExpr := &ast.ColumnNameExpr{Refer: rf}
	b = &ast.BinaryOperationExpr{L: colExpr, R: r, Op: opcode.Plus}
	ast.ResetEvaluatedFlag(b)
	ast.SetFlag(b)
	c.Assert(ast.IsPreEvaluable(b), Equals, false)
	d, err = Eval(s.ctx, b)
	c.Assert(ast.IsEvaluated(b), Equals, false)
	c.Assert(err, IsNil)
	c.Assert(d, testutil.DatumEquals, types.NewIntDatum(3))
}
Example #2
0
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
}
Example #3
0
func (b *planBuilder) buildIndexScanPlan(index *model.IndexInfo, path *joinPath) Plan {
	tn := path.table
	ip := &IndexScan{Table: tn.TableInfo, Index: index, TableName: tn}
	ip.RefAccess = len(path.eqConds) > 0
	ip.SetFields(tn.GetResultFields())
	ip.TableAsName = getTableAsName(ip.Fields())

	condMap := map[ast.ExprNode]bool{}
	for _, con := range path.conditions {
		condMap[con] = true
	}
out:
	// Build equal access conditions first.
	// Starts from the first index column, if equal condition is found, add it to access conditions,
	// proceed to the next index column. until we can't find any equal condition for the column.
	for ip.AccessEqualCount < len(index.Columns) {
		for con := range condMap {
			binop, ok := con.(*ast.BinaryOperationExpr)
			if !ok || binop.Op != opcode.EQ {
				continue
			}
			if ast.IsPreEvaluable(binop.L) {
				binop.L, binop.R = binop.R, binop.L
			}
			if !ast.IsPreEvaluable(binop.R) {
				continue
			}
			cn, ok2 := binop.L.(*ast.ColumnNameExpr)
			if !ok2 || cn.Refer.Column.Name.L != index.Columns[ip.AccessEqualCount].Name.L {
				continue
			}
			ip.AccessConditions = append(ip.AccessConditions, con)
			delete(condMap, con)
			ip.AccessEqualCount++
			continue out
		}
		break
	}

	for con := range condMap {
		if ip.AccessEqualCount < len(ip.Index.Columns) {
			// Try to add non-equal access condition for index column at AccessEqualCount.
			checker := conditionChecker{tableName: tn.TableInfo.Name, idx: index, columnOffset: ip.AccessEqualCount}
			if checker.check(con) {
				ip.AccessConditions = append(ip.AccessConditions, con)
			} else {
				ip.FilterConditions = append(ip.FilterConditions, con)
			}
		} else {
			ip.FilterConditions = append(ip.FilterConditions, con)
		}
	}
	return ip
}
Example #4
0
func (c *conditionChecker) checkBinaryOperation(b *ast.BinaryOperationExpr) bool {
	switch b.Op {
	case opcode.OrOr:
		return c.check(b.L) && c.check(b.R)
	case opcode.AndAnd:
		return c.check(b.L) && c.check(b.R)
	case opcode.EQ, opcode.NE, opcode.GE, opcode.GT, opcode.LE, opcode.LT:
		if ast.IsPreEvaluable(b.L) {
			return c.checkColumnExpr(b.R)
		} else if ast.IsPreEvaluable(b.R) {
			return c.checkColumnExpr(b.L)
		}
	}
	return false
}
Example #5
0
// Eval evaluates an expression to a datum.
func Eval(ctx context.Context, expr ast.ExprNode) (d types.Datum, err error) {
	if ast.IsEvaluated(expr) {
		return *expr.GetDatum(), nil
	}
	e := &Evaluator{ctx: ctx}
	expr.Accept(e)
	if e.err != nil {
		return d, errors.Trace(e.err)
	}
	if ast.IsPreEvaluable(expr) && (expr.GetFlag()&ast.FlagHasFunc == 0) {
		expr.SetFlag(expr.GetFlag() | ast.FlagPreEvaluated)
	}
	return *expr.GetDatum(), nil
}
Example #6
0
func (r *preEvaluator) Leave(in ast.Node) (ast.Node, bool) {
	if expr, ok := in.(ast.ExprNode); ok {
		if _, ok = expr.(*ast.ValueExpr); ok {
			return in, true
		} else if ast.IsPreEvaluable(expr) {
			val, err := evaluator.Eval(r.ctx, expr)
			if err != nil {
				r.err = err
				return in, false
			}
			if ast.IsConstant(expr) {
				// The expression is constant, rewrite the expression to value expression.
				valExpr := &ast.ValueExpr{}
				valExpr.SetText(expr.Text())
				valExpr.SetType(expr.GetType())
				valExpr.SetValue(val)
				return valExpr, true
			}
			expr.SetValue(val)
		}
	}
	return in, true
}