// UpdateAggFields adds aggregate function resultfield to select result field list. func (s *SelectList) UpdateAggFields(expr expression.Expression) (expression.Expression, error) { // We must add aggregate function to hidden select list // and use a position expression to fetch its value later. name := strings.ToLower(expr.String()) index := -1 for i := 0; i < s.HiddenFieldOffset; i++ { // only check origin name, e,g. "select sum(c1) as a from t order by sum(c1)" // or "select sum(c1) from t order by sum(c1)" if s.ResultFields[i].ColumnInfo.Name.L == name { index = i break } } if index == -1 { f := &field.Field{Expr: expr} s.AddField(f, nil) pos := len(s.Fields) s.AggFields[pos-1] = struct{}{} return &expression.Position{N: pos, Name: name}, nil } // select list has this field, use it directly. return &expression.Position{N: index + 1, Name: name}, nil }
// UpdateAggFields adds aggregate function resultfield to select result field list. func (s *SelectList) UpdateAggFields(expr expression.Expression, tableFields []*field.ResultField) (expression.Expression, error) { // For aggregate function, the name can be in table or select list. names := expressions.MentionedColumns(expr) for _, name := range names { if field.ContainFieldName(name, tableFields, field.DefaultFieldFlag) { continue } if field.ContainFieldName(name, s.ResultFields, field.DefaultFieldFlag) { continue } return nil, errors.Errorf("Unknown column '%s'", name) } // We must add aggregate function to hidden select list // and use a position expression to fetch its value later. exprName := expr.String() if !field.ContainFieldName(exprName, s.ResultFields, field.CheckFieldFlag) { f := &field.Field{Expr: expr, Name: exprName} resultField := &field.ResultField{Name: exprName} s.AddField(f, resultField) return &expressions.Position{N: len(s.Fields), Name: exprName}, nil } return nil, nil }
// Eval is a helper function evaluates expression v and do a panic if evaluating error. func Eval(v expression.Expression, ctx context.Context, env map[interface{}]interface{}) (y interface{}) { var err error y, err = v.Eval(ctx, env) if err != nil { panic(err) // panic ok here } return }
func (r *JoinPlan) filterNode(ctx context.Context, expr expression.Expression, node plan.Plan) (plan.Plan, bool, error) { if node == nil { return r, false, nil } e2 := expr.Clone() return node.Filter(ctx, e2) }
// CheckAmbiguous checks whether an identifier reference is ambiguous or not in select list. // e,g, "select c1 as a, c2 as a from t group by a" is ambiguous, // but "select c1 as a, c1 as a from t group by a" is not. // "select c1 as a, c2 + 1 as a from t group by a" is not ambiguous too, // If no ambiguous, -1 means expr refers none in select list, else an index for first match. // CheckAmbiguous will break the check when finding first matching which is not an indentifier, // or an index for an identifier field in the end, -1 means none found. func (s *SelectList) CheckAmbiguous(expr expression.Expression) (int, error) { if _, ok := expr.(*expression.Ident); !ok { return -1, nil } name := expr.String() if field.IsQualifiedName(name) { // name is qualified, no need to check return -1, nil } // select c1 as a, 1 as a, c2 as a from t order by a is not ambiguous. // select c1 as a, c2 as a from t order by a is ambiguous. // select 1 as a, c1 as a from t order by a is not ambiguous. // select c1 as a, sum(c1) as a from t group by a is error. // select c1 as a, 1 as a, sum(c1) as a from t group by a is not error. // so we will break the check if matching a none identifier field. lastIndex := -1 // only check origin select list, no hidden field. for i := 0; i < s.HiddenFieldOffset; i++ { if !strings.EqualFold(s.ResultFields[i].Name, name) { continue } if _, ok := s.Fields[i].Expr.(*expression.Ident); !ok { // not identfier, return directly. return i, nil } if lastIndex == -1 { // first match, continue lastIndex = i continue } // check origin name, e,g. "select c1 as c2, c2 from t group by c2" is ambiguous. if s.ResultFields[i].ColumnInfo.Name.L != s.ResultFields[lastIndex].ColumnInfo.Name.L { return -1, errors.Errorf("refer %s is ambiguous", expr) } // check table name, e.g, "select t.c1, c1 from t group by c1" is not ambiguous. if s.ResultFields[i].TableName != s.ResultFields[lastIndex].TableName { return -1, errors.Errorf("refer %s is ambiguous", expr) } // TODO: check database name if possible. } return lastIndex, nil }
// EvalBoolExpr evaluates an expression and convert its return value to bool. func EvalBoolExpr(ctx context.Context, expr expression.Expression, m map[interface{}]interface{}) (bool, error) { val, err := expr.Eval(ctx, m) if err != nil { return false, err } if val == nil { return false, nil } x, err := types.ToBool(val) if err != nil { return false, err } return x != 0, nil }
func staticExpr(e expression.Expression) (expression.Expression, error) { if e.IsStatic() { v, err := e.Eval(nil, nil) if err != nil { return nil, err } if v == nil { return Value{nil}, nil } return Value{v}, nil } return e, nil }
func (r *WhereRset) planStatic(ctx context.Context, e expression.Expression) (plan.Plan, error) { val, err := e.Eval(nil, nil) if err != nil { return nil, err } if val == nil { // like `select * from t where null`. return &plans.NullPlan{Fields: r.Src.GetFields()}, nil } n, err := types.ToBool(val) if err != nil { return nil, err } if n == 0 { // like `select * from t where 0`. return &plans.NullPlan{Fields: r.Src.GetFields()}, nil } return &plans.FilterDefaultPlan{Plan: r.Src, Expr: e}, nil }
func retrieveColumnsInExpression(expr expression.Expression, schema expression.Schema) ( expression.Expression, error) { switch v := expr.(type) { case *expression.ScalarFunction: for i, arg := range v.Args { newExpr, err := retrieveColumnsInExpression(arg, schema) if err != nil { return nil, errors.Trace(err) } v.Args[i] = newExpr } case *expression.Column: if !v.Correlated { newColumn := schema.RetrieveColumn(v) if newColumn == nil { return nil, errors.Errorf("Can't Find column %s.", expr.ToString()) } return newColumn, nil } } return expr, nil }
func (s *testVisitorSuite) TestBase(c *C) { val := expression.Value{Val: 1} visitor := expression.NewIdentEvalVisitor() var exp expression.Expression exp = &expression.Between{Expr: val, Left: val, Right: val} exp.Accept(visitor) exp = expression.NewBinaryOperation(opcode.And, val, val) exp.Accept(visitor) exp, _ = expression.NewCall("avg", []expression.Expression{val}, true) exp.Accept(visitor) rows := [][]interface{}{{1}} sq := newMockSubQuery(rows, []string{"a"}) exp = expression.NewCompareSubQuery(opcode.EQ, val, sq, true) exp.Accept(visitor) exp = &expression.Default{Name: "a"} exp.Accept(visitor) exp = expression.NewExistsSubQuery(sq) exp.Accept(visitor) when := &expression.WhenClause{Expr: val, Result: val} exp = &expression.FunctionCase{ WhenClauses: []*expression.WhenClause{when}, Value: val, ElseClause: val, } exp.Accept(visitor) exp = &expression.FunctionCast{Expr: val, Tp: types.NewFieldType(mysql.TypeLong), FunctionType: expression.ConvertFunction} exp.Accept(visitor) exp = &expression.FunctionConvert{Expr: val, Charset: "utf8"} exp.Accept(visitor) exp = &expression.FunctionSubstring{StrExpr: expression.Value{Val: "string"}, Pos: expression.Value{Val: 0}, Len: val} exp.Accept(visitor) exp = &expression.IsNull{Expr: val} exp.Accept(visitor) exp = &expression.IsTruth{Expr: val} exp.Accept(visitor) exp = &expression.ParamMarker{Expr: val} exp.Accept(visitor) exp = &expression.PatternIn{Expr: val, List: []expression.Expression{val}} exp.Accept(visitor) exp = &expression.PatternLike{Expr: val, Pattern: val} exp.Accept(visitor) exp = &expression.PatternRegexp{Expr: val, Pattern: val} exp.Accept(visitor) exp = &expression.PExpr{Expr: val} exp.Accept(visitor) exp = &expression.Position{Name: "a"} exp.Accept(visitor) exp = &expression.Row{Values: []expression.Expression{val}} exp.Accept(visitor) exp = &expression.UnaryOperation{V: val} exp.Accept(visitor) exp = &expression.Values{CIStr: model.NewCIStr("a")} exp.Accept(visitor) exp = &expression.Variable{Name: "a"} exp.Accept(visitor) }