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 (*testResultFieldSuite) TestCheckFieldEquals(c *C) {
	x := "a.b.c"
	y := "a.b.c"
	c.Assert(field.CheckFieldsEqual(x, y), IsTrue)

	x = "a.b.c"
	y = "a.B.c"
	c.Assert(field.CheckFieldsEqual(x, y), IsTrue)

	x = "b.c"
	y = "a.b.c"
	c.Assert(field.CheckFieldsEqual(x, y), IsTrue)

	x = "a..c"
	y = "a.b.c"
	c.Assert(field.CheckFieldsEqual(x, y), IsTrue)

	x = "a.a..c"
	y = "a.b.c"
	c.Assert(field.CheckFieldsEqual(x, y), IsTrue)

	x = "a.b.d"
	y = "a.b.c"
	c.Assert(field.CheckFieldsEqual(x, y), IsFalse)
	x = "a.d.c"
	y = "a.b.c"
	c.Assert(field.CheckFieldsEqual(x, y), IsFalse)
	x = "d.b.c"
	y = "a.b.c"
	c.Assert(field.CheckFieldsEqual(x, y), IsFalse)
}
Example #3
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 #4
0
// CheckAndUpdateSelectList checks having fields validity and set hidden fields to selectList.
func (r *HavingRset) CheckAndUpdateSelectList(selectList *plans.SelectList, groupBy []expression.Expression, tableFields []*field.ResultField) error {
	if err := expressions.CheckOneColumn(r.Expr); err != nil {
		return errors.Trace(err)
	}

	if expressions.ContainAggregateFunc(r.Expr) {
		expr, err := selectList.UpdateAggFields(r.Expr, tableFields)
		if err != nil {
			return errors.Errorf("%s in 'having clause'", err.Error())
		}

		r.Expr = expr
	} else {
		// having can only contain group by column and select list, e.g,
		// `select c1 from t group by c2 having c3 > 0` is invalid,
		// because c3 is not in group by and select list.
		names := expressions.MentionedColumns(r.Expr)
		for _, name := range names {
			found := false

			// check name whether in select list.
			// notice that `select c1 as c2 from t group by c1, c2, c3 having c2 > c3`,
			// will use t.c2 not t.c1 here.
			if field.ContainFieldName(name, selectList.ResultFields, field.OrgFieldNameFlag) {
				continue
			}
			if field.ContainFieldName(name, selectList.ResultFields, field.FieldNameFlag) {
				if field.ContainFieldName(name, tableFields, field.OrgFieldNameFlag) {
					selectList.CloneHiddenField(name, tableFields)
				}
				continue
			}

			// check name whether in group by.
			// group by must only have column name, e.g,
			// `select c1 from t group by c2 having c2 > 0` is valid,
			// but `select c1 from t group by c2 + 1 having c2 > 0` is invalid.
			for _, by := range groupBy {
				if !field.CheckFieldsEqual(name, by.String()) {
					continue
				}

				// if name is not in table fields, it will get an unknown field error in GroupByRset,
				// so no need to check return value.
				selectList.CloneHiddenField(name, tableFields)

				found = true
				break
			}

			if !found {
				return errors.Errorf("Unknown column '%s' in 'having clause'", name)
			}
		}
	}

	return nil
}