Example #1
0
func (*testResultFieldSuite) TestMain(c *C) {
	col := column.Col{
		ColumnInfo: model.ColumnInfo{
			FieldType: *types.NewFieldType(mysql.TypeLong),
			Name:      model.NewCIStr("c1"),
		},
	}
	col.Flag |= mysql.UnsignedFlag

	r := &field.ResultField{
		Col:          col,
		Name:         "c1",
		OrgTableName: "t1",
	}

	c.Assert(r.String(), Equals, "c1")
	r.TableName = "a"
	c.Assert(r.String(), Equals, "a.c1")
	r.DBName = "test"
	c.Assert(r.String(), Equals, "test.a.c1")

	cr := r.Clone()
	c.Assert(r.String(), Equals, cr.String())

	col1 := column.Col{
		ColumnInfo: model.ColumnInfo{
			FieldType: *types.NewFieldType(mysql.TypeLong),
			Name:      model.NewCIStr("c2"),
		},
	}
	col1.Flag |= mysql.UnsignedFlag

	r1 := &field.ResultField{
		Col:          col1,
		Name:         "c2",
		TableName:    "a",
		OrgTableName: "t1",
		DBName:       "test",
	}

	rs := []*field.ResultField{r, r1}
	ns := field.RFQNames(rs)
	c.Assert(ns, HasLen, 2)
	c.Assert(ns[0], Equals, "\"c1\"")
	c.Assert(ns[1], Equals, "\"c2\"")

	col2 := column.Col{
		ColumnInfo: model.ColumnInfo{
			FieldType: *types.NewFieldType(mysql.TypeVarchar),
			Name:      model.NewCIStr("c3"),
		},
	}
	col2.Flag |= mysql.UnsignedFlag
	col3 := column.Col{
		ColumnInfo: model.ColumnInfo{
			FieldType: *types.NewFieldType(mysql.TypeBlob),
			Name:      model.NewCIStr("c4"),
		},
	}
	col3.Flag |= mysql.UnsignedFlag

	cols := []*column.Col{&col, &col1, &col2, &col3}
	rs = field.ColsToResultFields(cols, "t")
	c.Assert(rs, HasLen, 4)
	c.Assert(rs[2].Tp, Equals, mysql.TypeVarString)
	c.Assert(rs[3].Tp, Equals, mysql.TypeBlob)

	// For CheckAmbiguousField
	err := field.CheckAmbiguousField("c1", rs, field.OrgFieldNameFlag)
	c.Assert(err, IsNil)

	col4 := column.Col{
		ColumnInfo: model.ColumnInfo{
			FieldType: *types.NewFieldType(mysql.TypeVarchar),
			Name:      model.NewCIStr("c2"),
		},
	}
	r2 := &field.ResultField{
		Col:          col4,
		Name:         "c22",
		TableName:    "b",
		OrgTableName: "t2",
		DBName:       "test",
	}
	rs = []*field.ResultField{r, r1, r2}
	// r1 and r2 are ambiguous: same column name but different table names
	err = field.CheckAmbiguousField("c2", rs, field.OrgFieldNameFlag)
	c.Assert(err, NotNil)
	// r1 and r2 with different alias name
	err = field.CheckAmbiguousField("c2", rs, field.FieldNameFlag)
	c.Assert(err, IsNil)

	// For CloneFieldByName
	_, err = field.CloneFieldByName("cx", rs, field.OrgFieldNameFlag)
	c.Assert(err, NotNil)
	_, err = field.CloneFieldByName("c2", rs, field.OrgFieldNameFlag)
	c.Assert(err, IsNil)

	// For check all fields name
	names := []string{"cx"}
	err = field.CheckAllFieldNames(names, rs, field.OrgFieldNameFlag)
	c.Assert(err, NotNil)
	names = []string{"c1"}
	err = field.CheckAllFieldNames(names, rs, field.OrgFieldNameFlag)
	c.Assert(err, IsNil)

	// For ContainAllFieldNames
	names = []string{"cx", "c2"}
	b := field.ContainAllFieldNames(names, rs, field.OrgFieldNameFlag)
	c.Assert(b, IsFalse)
	names = []string{"c2", "c1"}
	b = field.ContainAllFieldNames(names, rs, field.OrgFieldNameFlag)
	c.Assert(b, IsTrue)

	// For GetFieldIndex
	f1 := &field.Field{
		Expr:   &expression.Ident{CIStr: model.NewCIStr("c1")},
		AsName: "a",
	}
	f2 := &field.Field{
		Expr:   &expression.Ident{CIStr: model.NewCIStr("c2")},
		AsName: "a",
	}
	fs := []*field.Field{f1, f2}
	idxs := field.GetFieldIndex("c1", fs, field.OrgFieldNameFlag)
	c.Assert(idxs, HasLen, 1)

	idxs = field.GetFieldIndex("a", fs, field.FieldNameFlag)
	c.Assert(idxs, HasLen, 2)

}
Example #2
0
// 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.(expressions.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] = &expressions.Position{N: position}
		} else {
			names := expressions.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 expressions.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]; expressions.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
}
Example #3
0
// Plan gets GroupByDefaultPlan.
func (r *GroupByRset) Plan(ctx context.Context) (plan.Plan, error) {
	fields := r.SelectList.Fields

	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])
			}

			// use Position expression for the associated field.
			r.By[i] = &expression.Position{N: position}
		} else {
			index, err := r.SelectList.CheckReferAmbiguous(e)
			if err != nil {
				return nil, errors.Errorf("Column '%s' in group statement is ambiguous", e)
			} else if _, ok := aggFields[index]; ok {
				return nil, errors.Errorf("Can't group on '%s'", e)
			}

			// TODO: check more ambiguous case
			// 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 ambiguous

			// TODO: use visitor to check aggregate function
			names := expression.MentionedColumns(e)
			for _, name := range names {
				indices := field.GetFieldIndex(name, fields[0:r.SelectList.HiddenFieldOffset], field.DefaultFieldFlag)
				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
}