Beispiel #1
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
}
Beispiel #2
0
func (v *havingVisitor) visitIdentInAggregate(i *expression.Ident) (expression.Expression, error) {
	// if we are visiting aggregate function arguments, the identifier first checks in from table,
	// then in select list, and outer query finally.

	// find this identifier in FROM.
	idx := field.GetResultFieldIndex(i.L, v.selectList.FromFields)
	if len(idx) > 0 {
		i.ReferScope = expression.IdentReferFromTable
		i.ReferIndex = idx[0]
		return i, nil
	}

	// check in select list.
	index, err := checkIdentAmbiguous(i, v.selectList, HavingClause)
	if err != nil {
		return i, errors.Trace(err)
	}

	if index >= 0 {
		// find in select list
		i.ReferScope = expression.IdentReferSelectList
		i.ReferIndex = index
		return i, nil
	}

	// TODO: check in out query
	// TODO: return unknown field error, but now just return directly.
	// Because this may reference outer query.
	return i, nil
}
Beispiel #3
0
func (v *groupByVisitor) VisitIdent(i *expression.Ident) (expression.Expression, error) {
	// Group by ambiguous rule:
	//	select c1 as a, c2 as a from t group by a is ambiguous
	//	select c1 as a, c2 as a from t group by a + 1 is ambiguous
	//	select c1 as c2, c2 from t group by c2 is ambiguous
	//	select c1 as c2, c2 from t group by c2 + 1 is not ambiguous

	var (
		index int
		err   error
	)

	if v.rootIdent == i {
		// The group by is an identifier, we must check it first.
		index, err = checkIdentAmbiguous(i, v.selectList, GroupByClause)
		if err != nil {
			return nil, errors.Trace(err)
		}
	}

	// first find this identifier in FROM.
	idx := field.GetResultFieldIndex(i.L, v.selectList.FromFields)
	if len(idx) > 0 {
		i.ReferScope = expression.IdentReferFromTable
		i.ReferIndex = idx[0]
		return i, nil
	}

	if v.rootIdent != i {
		// This identifier is the part of the group by, check ambiguous here.
		index, err = checkIdentAmbiguous(i, v.selectList, GroupByClause)
		if err != nil {
			return nil, errors.Trace(err)
		}
	}

	// try to find in select list, we have got index using checkIdent before.
	if index >= 0 {
		// group by can not reference aggregate fields
		if _, ok := v.selectList.AggFields[index]; ok {
			return nil, errors.Errorf("Reference '%s' not supported (reference to group function)", i)
		}

		// find in select list
		i.ReferScope = expression.IdentReferSelectList
		i.ReferIndex = index
		return i, nil
	}

	// TODO: check in out query
	return i, errors.Errorf("Unknown column '%s' in 'group statement'", i)
}
Beispiel #4
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
}
Beispiel #5
0
func (v *fromIdentVisitor) VisitIdent(i *expression.Ident) (expression.Expression, error) {
	idx := field.GetResultFieldIndex(i.L, v.fromFields, field.DefaultFieldFlag)
	if len(idx) == 1 {
		i.ReferScope = expression.IdentReferFromTable
		i.ReferIndex = idx[0]
		return i, nil
	} else if len(idx) > 1 {
		return nil, errors.Errorf("Column '%s' in %s is ambiguous", i, v.clause)
	}

	if v.clause == onClause {
		// on clause can't check outer query.
		return nil, errors.Errorf("Unknown column '%s' in '%s'", i, v.clause)
	}

	// TODO: check in outer query
	return i, nil
}
Beispiel #6
0
func (v *orderByVisitor) VisitIdent(i *expression.Ident) (expression.Expression, error) {
	// Order by ambiguous rule:
	//	select c1 as a, c2 as a from t order by a is ambiguous
	//	select c1 as a, c2 as a from t order by a + 1 is ambiguous
	//	select c1 as c2, c2 from t order by c2 is ambiguous
	//	select c1 as c2, c2 from t order by c2 + 1 is not ambiguous

	// Order by identifier reference check
	//	select c1 as c2 from t order by c2, c2 in order by references c1 in select field.
	//	select c1 as c2 from t order by c2 + 1, c2 in order by c2 + 1 references t.c2 in from table.
	//	select c1 as c2 from t order by sum(c2), c2 in order by sum(c2) references t.c2 in from table.
	//	select c1 as c2 from t order by sum(1) + c2, c2 in order by sum(1) + c2 references t.c2 in from table.
	//	select c1 as a from t order by a, a references c1 in select field.
	//	select c1 as a from t order by sum(a), a in order by sum(a) references c1 in select field.

	// TODO: unify VisitIdent for group by and order by visitor, they are little different.

	var (
		index int
		err   error
	)

	if v.rootIdent == i {
		// The order by is an identifier, we must check it first.
		index, err = checkIdentAmbiguous(i, v.selectList, OrderByClause)
		if err != nil {
			return nil, errors.Trace(err)
		}

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

	// find this identifier in FROM.
	idx := field.GetResultFieldIndex(i.L, v.selectList.FromFields)
	if len(idx) > 0 {
		i.ReferScope = expression.IdentReferFromTable
		i.ReferIndex = idx[0]
		return i, nil
	}

	if v.rootIdent != i {
		// This identifier is the part of the order by, check ambiguous here.
		index, err = checkIdentAmbiguous(i, v.selectList, OrderByClause)
		if err != nil {
			return nil, errors.Trace(err)
		}
	}

	// try to find in select list, we have got index using checkIdentAmbiguous before.
	if index >= 0 {
		// find in select list
		i.ReferScope = expression.IdentReferSelectList
		i.ReferIndex = index
		return i, nil
	}

	// TODO: check in out query
	return i, errors.Errorf("Unknown column '%s' in 'order clause'", i)
}