Example #1
0
func (v *havingVisitor) checkIdentInSelectList(i *expression.Ident) (*expression.Ident, bool, error) {
	index, err := checkIdentAmbiguous(i, v.selectList, HavingClause)
	if err != nil {
		return i, false, errors.Trace(err)
	}

	if index >= 0 {
		// identifier references a select field. use it directly.
		// e,g. select c1 as c2 from t having c2, here c2 references c1.
		i.ReferScope = expression.IdentReferSelectList
		i.ReferIndex = index
		return i, true, nil
	}

	lastIndex := -1
	var lastFieldName string
	// we may meet this select c1 as c2 from t having c1, so we must check origin field name too.
	for index := 0; index < v.selectList.HiddenFieldOffset; index++ {
		e := castIdent(v.selectList.Fields[index].Expr)
		if e == nil {
			// not identifier
			continue
		}

		if !field.CheckFieldsEqual(e.L, i.L) {
			// not same, continue
			continue
		}

		if field.IsQualifiedName(i.L) {
			// qualified name, no need check
			i.ReferScope = expression.IdentReferSelectList
			i.ReferIndex = index
			return i, true, nil
		}

		if lastIndex == -1 {
			lastIndex = index
			lastFieldName = e.L
			continue
		}

		// we may meet select t1.c as a, t2.c as b from t1, t2 having c, must check ambiguous here
		if !field.CheckFieldsEqual(lastFieldName, e.L) {
			return i, false, errors.Errorf("Column '%s' in having clause is ambiguous", i)
		}

		i.ReferScope = expression.IdentReferSelectList
		i.ReferIndex = index
		return i, true, nil
	}

	if lastIndex != -1 {
		i.ReferScope = expression.IdentReferSelectList
		i.ReferIndex = lastIndex
		return i, true, nil
	}

	return i, false, nil
}
Example #2
0
func (v *havingVisitor) checkIdentInGroupBy(i *expression.Ident) (*expression.Ident, bool, error) {
	for _, by := range v.groupBy {
		e := castIdent(by)
		if e == nil {
			// group by must be a identifier too
			continue
		}

		if !field.CheckFieldsEqual(e.L, i.L) {
			// not same, continue
			continue
		}

		// if group by references select list or having is qualified identifier,
		// no other check.
		if e.ReferScope == expression.IdentReferSelectList || field.IsQualifiedName(i.L) {
			i.ReferScope = e.ReferScope
			i.ReferIndex = e.ReferIndex
			return i, true, nil
		}

		// having is unqualified name, e.g, select * from t1, t2 group by t1.c having c.
		// both t1 and t2 have column c, we must check ambiguous here.
		idx := field.GetResultFieldIndex(i.L, v.selectList.FromFields)
		if len(idx) > 1 {
			return i, false, errors.Errorf("Column '%s' in having clause is ambiguous", i)
		}

		i.ReferScope = e.ReferScope
		i.ReferIndex = e.ReferIndex
		return i, true, nil
	}

	return i, false, nil
}
Example #3
0
// 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
}