示例#1
0
// ResolveSelectList gets fields and result fields from selectFields and srcFields,
// including field validity check and wildcard field processing.
func ResolveSelectList(selectFields []*field.Field, srcFields []*field.ResultField) (*SelectList, error) {
	selectList := &SelectList{
		Fields:       make([]*field.Field, 0, len(selectFields)),
		ResultFields: make([]*field.ResultField, 0, len(selectFields)),
		AggFields:    make(map[int]struct{}),
		FromFields:   srcFields,
	}

	wildcardNum := 0
	for _, v := range selectFields {
		// Check metioned field.
		names := expression.MentionedColumns(v.Expr)
		if len(names) == 0 {
			selectList.AddField(v, nil)
			continue
		}

		// Check wildcard field.
		name := names[0]
		table, ok, err := field.CheckWildcardField(name)
		if err != nil {
			return nil, err
		}
		if ok {
			// Check unqualified wildcard field number,
			// like `select *, * from t`.
			if table == "" {
				wildcardNum++
				if wildcardNum > 1 {
					return nil, errors.Errorf("wildcard field exist more than once")
				}
			}

			selectList.updateFields(table, srcFields)
			continue
		}

		var result *field.ResultField
		if err = field.CheckAllFieldNames(names, srcFields, field.DefaultFieldFlag); err != nil {
			return nil, errors.Trace(err)
		}

		if _, ok := v.Expr.(*expression.Ident); ok {
			// Field is ident.
			if result, err = field.CloneFieldByName(name, srcFields, field.DefaultFieldFlag); err != nil {
				return nil, errors.Trace(err)
			}

			// Maybe alias name or only column name.
			if !expression.IsQualified(v.Name) {
				result.Name = v.Name
			}
		} else {
			// The field is not an ident, maybe binary expression,
			// like `select c1 + c2`, or `select c1 + 10`, etc.
			result = &field.ResultField{Name: v.Name}
		}

		selectList.AddField(v, result)
	}

	selectList.HiddenFieldOffset = len(selectList.Fields)
	selectList.resolveAggFields()

	if selectList.HiddenFieldOffset == 0 {
		return nil, errors.Errorf("invalid empty select fields")
	}

	return selectList, nil
}
示例#2
0
文件: groupby.go 项目: nengwang/tidb
// Plan gets GroupByDefaultPlan.
func (r *GroupByRset) Plan(ctx context.Context) (plan.Plan, error) {
	fields := r.SelectList.Fields
	resultfields := r.SelectList.ResultFields
	srcFields := r.Src.GetFields()

	r.SelectList.AggFields = GetAggFields(fields)
	aggFields := r.SelectList.AggFields

	for i, e := range r.By {
		if v, ok := e.(expression.Value); ok {
			var position int
			switch u := v.Val.(type) {
			case int64:
				position = int(u)
			case uint64:
				position = int(u)
			default:
				continue
			}

			if position < 1 || position > len(fields) {
				return nil, errors.Errorf("Unknown column '%d' in 'group statement'", position)
			}

			index := position - 1
			if _, ok := aggFields[index]; ok {
				return nil, errors.Errorf("Can't group on '%s'", fields[index].Name)
			}

			// use Position expression for the associated field.
			r.By[i] = &expression.Position{N: position}
		} else {
			names := expression.MentionedColumns(e)
			for _, name := range names {
				if field.ContainFieldName(name, srcFields, field.DefaultFieldFlag) {
					// check whether column is qualified, like `select t.c1 c1, t.c2 from t group by t.c1, t.c2`
					// no need to check ambiguous field.
					if expression.IsQualified(name) {
						continue
					}

					// check ambiguous fields, like `select c1 as c2, c2 from t group by c2`.
					if err := field.CheckAmbiguousField(name, resultfields, field.DefaultFieldFlag); err == nil {
						continue
					}
				}

				// check reference to group function name
				indices := field.GetFieldIndex(name, fields[0:r.SelectList.HiddenFieldOffset], field.CheckFieldFlag)
				if len(indices) > 1 {
					// check ambiguous fields, like `select c1 as a, c2 as a from t group by a`,
					// notice that `select c2 as c2, c2 as c2 from t group by c2;` is valid.
					if r.HasAmbiguousField(indices, fields[0:r.SelectList.HiddenFieldOffset]) {
						return nil, errors.Errorf("Column '%s' in group statement is ambiguous", name)
					}
				} else if len(indices) == 1 {
					// check reference to aggregate function, like `select c1, count(c1) as b from t group by b + 1`.
					index := indices[0]
					if _, ok := aggFields[index]; ok {
						return nil, errors.Errorf("Reference '%s' not supported (reference to group function)", name)
					}
				}
			}

			// group by should be an expression, a qualified field name or a select field position,
			// but can not contain any aggregate function.
			if e := r.By[i]; expression.ContainAggregateFunc(e) {
				return nil, errors.Errorf("group by cannot contain aggregate function %s", e.String())
			}
		}
	}

	return &plans.GroupByDefaultPlan{By: r.By, Src: r.Src,
		SelectList: r.SelectList}, nil
}