planner: fix error when window function is used in view definition (#25930)

This commit is contained in:
guo-shaoge
2021-08-16 17:22:00 +08:00
committed by GitHub
parent 583d2d39e5
commit d128bc1099
2 changed files with 47 additions and 16 deletions

View File

@ -4111,6 +4111,18 @@ func (s *testIntegrationSerialSuite) TestIssue26214(c *C) {
c.Assert(core.ErrUnknownColumn.Equal(err), IsTrue)
}
func (s *testIntegrationSuite) TestCreateViewWithWindowFunc(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t6;")
tk.MustExec("CREATE TABLE t6(t TIME, ts TIMESTAMP);")
tk.MustExec("INSERT INTO t6 VALUES ('12:30', '2016-07-05 08:30:42');")
tk.MustExec("drop view if exists v;")
tk.MustExec("CREATE definer='root'@'localhost' VIEW v AS SELECT COUNT(*) OVER w0, COUNT(*) OVER w from t6 WINDOW w0 AS (), w AS (w0 ORDER BY t);")
rows := tk.MustQuery("select * from v;")
rows.Check(testkit.Rows("1 1"))
}
func (s *testIntegrationSerialSuite) TestLimitPushDown(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test")

View File

@ -1133,6 +1133,9 @@ func (b *PlanBuilder) buildProjectionField(ctx context.Context, p LogicalPlan, f
if isCol {
return col, name, nil
}
if expr == nil {
return nil, name, nil
}
newCol := &expression.Column{
UniqueID: b.ctx.GetSessionVars().AllocPlanColumnID(),
RetType: expr.GetType(),
@ -3175,15 +3178,37 @@ func unfoldWildStar(field *ast.SelectField, outputName types.NameSlice, column [
return resultList
}
func (b *PlanBuilder) addAliasName(selectFields []*ast.SelectField, p LogicalPlan) (resultList []*ast.SelectField, err error) {
if len(selectFields) != len(p.OutputNames()) {
return nil, errors.Errorf("lengths of selectFields and OutputNames are not equal(%d, %d)",
len(selectFields), len(p.OutputNames()))
func (b *PlanBuilder) addAliasName(ctx context.Context, selectFields []*ast.SelectField, p LogicalPlan) (resultList []*ast.SelectField, err error) {
projOutNames := make([]*types.FieldName, 0, len(selectFields))
for _, field := range selectFields {
colNameField, isColumnNameExpr := field.Expr.(*ast.ColumnNameExpr)
if isColumnNameExpr {
colName := colNameField.Name.Name
if field.AsName.L != "" {
colName = field.AsName
}
projOutNames = append(projOutNames, &types.FieldName{
TblName: colNameField.Name.Table,
OrigTblName: colNameField.Name.Table,
ColName: colName,
OrigColName: colNameField.Name.Name,
DBName: colNameField.Name.Schema,
})
} else {
// create view v as select name_const('col', 100);
// The column in v should be 'col', so we call `buildProjectionField` to handle this.
_, name, err := b.buildProjectionField(ctx, p, field, nil)
if err != nil {
return nil, err
}
projOutNames = append(projOutNames, name)
}
}
for i, field := range selectFields {
newField := *field
if newField.AsName.L == "" {
newField.AsName = p.OutputNames()[i].ColName
newField.AsName = projOutNames[i].ColName
}
resultList = append(resultList, &newField)
}
@ -3475,6 +3500,11 @@ func (b *PlanBuilder) buildSelect(ctx context.Context, sel *ast.SelectStmt) (p L
return nil, err
}
if b.capFlag&canExpandAST != 0 {
// To be compabitle with MySQL, we add alias name for each select field when creating view.
sel.Fields.Fields, err = b.addAliasName(ctx, sel.Fields.Fields, p)
if err != nil {
return nil, err
}
originalFields = sel.Fields.Fields
}
@ -3585,17 +3615,6 @@ func (b *PlanBuilder) buildSelect(ctx context.Context, sel *ast.SelectStmt) (p L
return nil, err
}
if b.capFlag&canExpandAST != 0 {
// To be compabitle with MySQL, we add alias name for each select field when creating view.
// This function assumes one to one mapping between sel.Fields.Fields and p.OutputNames().
// So we do this step right after Projection is built.
sel.Fields.Fields, err = b.addAliasName(sel.Fields.Fields, p)
if err != nil {
return nil, err
}
originalFields = sel.Fields.Fields
}
if sel.Having != nil {
b.curClause = havingClause
p, err = b.buildSelection(ctx, p, sel.Having.Expr, havingMap)