// 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 }
// 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 }