Skip to content

Commit

Permalink
address comment
Browse files Browse the repository at this point in the history
  • Loading branch information
francis0407 committed Oct 27, 2020
1 parent 4ac8522 commit 571921b
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 18 deletions.
2 changes: 1 addition & 1 deletion executor/ddl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ func (s *testSuite6) TestCreateView(c *C) {
tk.MustExec("create definer='root'@'localhost' view v_nested as select * from test_v_nested")
tk.MustExec("create definer='root'@'localhost' view v_nested2 as select * from v_nested")
_, err = tk.Exec("create or replace definer='root'@'localhost' view v_nested as select * from v_nested2")
c.Assert(terror.ErrorEqual(err, plannercore.ErrViewRecursive), IsTrue)
c.Assert(terror.ErrorEqual(err, plannercore.ErrNoSuchTable), IsTrue)
tk.MustExec("drop table test_v_nested")
tk.MustExec("drop view v_nested, v_nested2")
}
Expand Down
1 change: 1 addition & 0 deletions planner/core/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var (
ErrWrongUsage = terror.ClassOptimizer.New(mysql.ErrWrongUsage, mysql.MySQLErrName[mysql.ErrWrongUsage])
ErrUnknown = terror.ClassOptimizer.New(mysql.ErrUnknown, mysql.MySQLErrName[mysql.ErrUnknown])
ErrUnknownTable = terror.ClassOptimizer.New(mysql.ErrUnknownTable, mysql.MySQLErrName[mysql.ErrUnknownTable])
ErrNoSuchTable = terror.ClassOptimizer.New(mysql.ErrNoSuchTable, mysql.MySQLErrName[mysql.ErrNoSuchTable])
ErrViewRecursive = terror.ClassOptimizer.New(mysql.ErrViewRecursive, mysql.MySQLErrName[mysql.ErrViewRecursive])
ErrWrongArguments = terror.ClassOptimizer.New(mysql.ErrWrongArguments, mysql.MySQLErrName[mysql.ErrWrongArguments])
ErrWrongNumberOfColumnsInSelect = terror.ClassOptimizer.New(mysql.ErrWrongNumberOfColumnsInSelect, mysql.MySQLErrName[mysql.ErrWrongNumberOfColumnsInSelect])
Expand Down
28 changes: 20 additions & 8 deletions planner/core/logical_plan_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3234,21 +3234,32 @@ func (b *PlanBuilder) buildMemTable(_ context.Context, dbName model.CIStr, table
return p, nil
}

// BuildDataSourceFromView is used to build LogicalPlan from view
func (b *PlanBuilder) BuildDataSourceFromView(ctx context.Context, dbName model.CIStr, tableInfo *model.TableInfo) (LogicalPlan, error) {
viewFullName := dbName.L + "." + tableInfo.Name.L
// checkRecursiveView checks whether this view is recursively defined.
func (b *PlanBuilder) checkRecursiveView(dbName model.CIStr, tableName model.CIStr) (func(), error) {
viewFullName := dbName.L + "." + tableName.L
if b.buildingViewStack == nil {
b.buildingViewStack = set.NewStringSet()
}
// If this view has already been on the building stack, it means
// this view contains a recursive definition.
if b.buildingViewStack.Exist(viewFullName) {
return nil, ErrViewRecursive.GenWithStackByArgs(dbName.O, tableInfo.Name.O)
return nil, ErrViewRecursive.GenWithStackByArgs(dbName.O, tableName.O)
}
// If the view is being renamed, we return the mysql compatible error message.
if b.capFlag & renameView != 0 && viewFullName == b.renamingViewName {
return nil, ErrNoSuchTable.GenWithStackByArgs(dbName.O, tableName.O)
}
b.buildingViewStack.Insert(viewFullName)
defer func() {
delete(b.buildingViewStack, viewFullName)
}()
return func() {delete(b.buildingViewStack, viewFullName)}, nil
}

// BuildDataSourceFromView is used to build LogicalPlan from view
func (b *PlanBuilder) BuildDataSourceFromView(ctx context.Context, dbName model.CIStr, tableInfo *model.TableInfo) (LogicalPlan, error) {
deferFunc, err := b.checkRecursiveView(dbName, tableInfo.Name)
if err != nil {
return nil, err
}
defer deferFunc()

charset, collation := b.ctx.GetSessionVars().GetCharsetInfo()
viewParser := parser.New()
Expand All @@ -3261,7 +3272,8 @@ func (b *PlanBuilder) BuildDataSourceFromView(ctx context.Context, dbName model.
b.visitInfo = make([]visitInfo, 0)
selectLogicalPlan, err := b.Build(ctx, selectNode)
if err != nil {
if terror.ErrorNotEqual(err, ErrViewRecursive) {
if terror.ErrorNotEqual(err, ErrViewRecursive) &&
terror.ErrorNotEqual(err, ErrNoSuchTable) {
err = ErrViewInvalid.GenWithStackByArgs(dbName.O, tableInfo.Name.O)
}
return nil, err
Expand Down
17 changes: 8 additions & 9 deletions planner/core/planbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,9 @@ const (
// canExpandAST indicates whether the origin AST can be expanded during plan
// building. ONLY used for `CreateViewStmt` now.
canExpandAST
// renameView indicates a view is being renamed, so we cannot use the origin
// definition of that view.
renameView
)

// PlanBuilder builds Plan from an ast.Node.
Expand Down Expand Up @@ -445,6 +448,8 @@ type PlanBuilder struct {
partitionedTable []table.PartitionedTable
// buildingViewStack is used to check whether there is a recursive view.
buildingViewStack set.StringSet
// renamingViewName is the name of the view which is being renamed.
renamingViewName string

// evalDefaultExpr needs this information to find the corresponding column.
// It stores the OutputNames before buildProjection.
Expand Down Expand Up @@ -3028,17 +3033,11 @@ func (b *PlanBuilder) buildDDL(ctx context.Context, node ast.DDLNode) (Plan, err
v.ReferTable.Name.L, "", authErr)
}
case *ast.CreateViewStmt:
b.capFlag |= canExpandAST
b.capFlag |= canExpandAST | renameView
b.renamingViewName = v.ViewName.Schema.L + "." + v.ViewName.Name.L
defer func() {
b.capFlag &= ^canExpandAST
}()
viewFullName := v.ViewName.Schema.L + "." + v.ViewName.Name.L
b.buildingViewStack = set.NewStringSet()
// We push this view onto the building stack. So it can check
// the recursive definition of this view when building the select statement.
b.buildingViewStack.Insert(viewFullName)
defer func() {
delete(b.buildingViewStack, viewFullName)
b.capFlag &= ^renameView
}()
plan, err := b.Build(ctx, v.Select)
if err != nil {
Expand Down

0 comments on commit 571921b

Please sign in to comment.