planner: fix error when window function is used in view definition (#25930)
This commit is contained in:
@ -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")
|
||||
|
||||
@ -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)
|
||||
|
||||
Reference in New Issue
Block a user