diff --git a/ddl/ddl.go b/ddl/ddl.go index ee99e8e597ef2..2980fe8c93483 100644 --- a/ddl/ddl.go +++ b/ddl/ddl.go @@ -203,10 +203,8 @@ var ( ErrCoalesceOnlyOnHashPartition = terror.ClassDDL.New(codeCoalesceOnlyOnHashPartition, mysql.MySQLErrName[mysql.ErrCoalesceOnlyOnHashPartition]) // ErrViewWrongList returns create view must include all columns in the select clause ErrViewWrongList = terror.ClassDDL.New(codeViewWrongList, mysql.MySQLErrName[mysql.ErrViewWrongList]) - // ErrTableIsNotView returns for table is not view. - ErrTableIsNotView = terror.ClassDDL.New(codeErrWrongObject, "'%s.%s' is not VIEW") - // ErrTableIsNotBaseTable returns for table is not base table. - ErrTableIsNotBaseTable = terror.ClassDDL.New(codeErrWrongObject, "'%s.%s' is not BASE TABLE") + // ErrWrongObject returns for wrong object. + ErrWrongObject = terror.ClassDDL.New(codeErrWrongObject, mysql.MySQLErrName[mysql.ErrWrongObject]) ) // DDL is responsible for updating schema in data store and maintaining in-memory InfoSchema cache. diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index 910b0b2036aa7..88af5175cc290 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -1179,7 +1179,7 @@ func (d *ddl) CreateView(ctx sessionctx.Context, s *ast.CreateViewStmt) (err err var oldViewTblID int64 if oldView != nil { if !oldView.Meta().IsView() { - return ErrTableIsNotView.GenWithStackByArgs(ident.Schema, ident.Name) + return ErrWrongObject.GenWithStackByArgs(ident.Schema, ident.Name, "VIEW") } oldViewTblID = oldView.Meta().ID } @@ -1442,7 +1442,7 @@ func (d *ddl) AlterTable(ctx sessionctx.Context, ident ast.Ident, specs []*ast.A is := d.infoHandle.Get() if is.TableIsView(ident.Schema, ident.Name) { - return ErrTableIsNotBaseTable.GenWithStackByArgs(ident.Schema, ident.Name) + return ErrWrongObject.GenWithStackByArgs(ident.Schema, ident.Name, "BASE TABLE") } for _, spec := range validSpecs { @@ -2406,7 +2406,7 @@ func (d *ddl) DropView(ctx sessionctx.Context, ti ast.Ident) (err error) { } if !tb.Meta().IsView() { - return ErrTableIsNotView.GenWithStackByArgs(ti.Schema, ti.Name) + return ErrWrongObject.GenWithStackByArgs(ti.Schema, ti.Name, "VIEW") } job := &model.Job{ diff --git a/executor/ddl_test.go b/executor/ddl_test.go index 2a7849595483e..d3d2f49800259 100644 --- a/executor/ddl_test.go +++ b/executor/ddl_test.go @@ -185,7 +185,7 @@ func (s *testSuite3) TestCreateView(c *C) { tk.MustExec("create or replace view v1 (c,d) as select a,b from t1 ") tk.MustExec("create table if not exists t1 (a int ,b int)") _, err = tk.Exec("create or replace view t1 as select * from t1") - c.Assert(err.Error(), Equals, ddl.ErrTableIsNotView.GenWithStackByArgs("test", "t1").Error()) + c.Assert(err.Error(), Equals, ddl.ErrWrongObject.GenWithStackByArgs("test", "t1", "VIEW").Error()) } func (s *testSuite3) TestCreateDropDatabase(c *C) { @@ -264,7 +264,7 @@ func (s *testSuite3) TestAlterTableAddColumn(c *C) { tk.MustQuery("select c3 from alter_test").Check(testkit.Rows("CURRENT_TIMESTAMP")) tk.MustExec("create or replace view alter_view as select c1,c2 from alter_test") _, err = tk.Exec("alter table alter_view add column c4 varchar(50)") - c.Assert(err.Error(), Equals, ddl.ErrTableIsNotBaseTable.GenWithStackByArgs("test", "alter_view").Error()) + c.Assert(err.Error(), Equals, ddl.ErrWrongObject.GenWithStackByArgs("test", "alter_view", "BASE TABLE").Error()) tk.MustExec("drop view alter_view") } @@ -312,7 +312,7 @@ func (s *testSuite3) TestAlterTableModifyColumn(c *C) { c.Assert(createSQL, Equals, expected) tk.MustExec("create or replace view alter_view as select c1,c2 from mc") _, err = tk.Exec("alter table alter_view modify column c2 text") - c.Assert(err.Error(), Equals, ddl.ErrTableIsNotBaseTable.GenWithStackByArgs("test", "alter_view").Error()) + c.Assert(err.Error(), Equals, ddl.ErrWrongObject.GenWithStackByArgs("test", "alter_view", "BASE TABLE").Error()) tk.MustExec("drop view alter_view") } diff --git a/executor/errors.go b/executor/errors.go index 30662d0cc2368..9b5caa85ac18b 100644 --- a/executor/errors.go +++ b/executor/errors.go @@ -48,6 +48,7 @@ var ( ErrDBaccessDenied = terror.ClassExecutor.New(mysql.ErrDBaccessDenied, mysql.MySQLErrName[mysql.ErrDBaccessDenied]) ErrTableaccessDenied = terror.ClassExecutor.New(mysql.ErrTableaccessDenied, mysql.MySQLErrName[mysql.ErrTableaccessDenied]) ErrBadDB = terror.ClassExecutor.New(mysql.ErrBadDB, mysql.MySQLErrName[mysql.ErrBadDB]) + ErrWrongObject = terror.ClassExecutor.New(mysql.ErrWrongObject, mysql.MySQLErrName[mysql.ErrWrongObject]) ) func init() { @@ -63,6 +64,7 @@ func init() { mysql.ErrDBaccessDenied: mysql.ErrDBaccessDenied, mysql.ErrTableaccessDenied: mysql.ErrTableaccessDenied, mysql.ErrBadDB: mysql.ErrBadDB, + mysql.ErrWrongObject: mysql.ErrWrongObject, } terror.ErrClassToMySQLCodes[terror.ClassExecutor] = tableMySQLErrCodes } diff --git a/executor/show.go b/executor/show.go index 014d17171f1b1..9c7c5955bc5bd 100644 --- a/executor/show.go +++ b/executor/show.go @@ -107,6 +107,8 @@ func (e *ShowExec) fetchAll() error { return e.fetchShowColumns() case ast.ShowCreateTable: return e.fetchShowCreateTable() + case ast.ShowCreateView: + return e.fetchShowCreateView() case ast.ShowCreateDatabase: return e.fetchShowCreateDatabase() case ast.ShowDatabases: @@ -764,6 +766,27 @@ func (e *ShowExec) fetchShowCreateTable() error { return nil } +func (e *ShowExec) fetchShowCreateView() error { + db, ok := e.is.SchemaByName(e.DBName) + if !ok { + return infoschema.ErrDatabaseNotExists.GenWithStackByArgs(e.DBName.O) + } + + tb, err := e.getTable() + if err != nil { + return errors.Trace(err) + } + + if !tb.Meta().IsView() { + return ErrWrongObject.GenWithStackByArgs(db.Name.O, tb.Meta().Name.O, "VIEW") + } + + var buf bytes.Buffer + e.fetchShowCreateTable4View(tb.Meta(), &buf) + e.appendRow([]interface{}{tb.Meta().Name.O, buf.String(), tb.Meta().Charset, tb.Meta().Collate}) + return nil +} + func (e *ShowExec) fetchShowCreateTable4View(tb *model.TableInfo, buf *bytes.Buffer) { sqlMode := e.ctx.GetSessionVars().SQLMode diff --git a/executor/show_test.go b/executor/show_test.go index 8aa83b2593353..1a8bdbe641b7f 100644 --- a/executor/show_test.go +++ b/executor/show_test.go @@ -309,6 +309,7 @@ func (s *testSuite2) TestShowCreateTable(c *C) { tk.MustExec("drop view if exists v1") tk.MustExec("create or replace definer=`root`@`127.0.0.1` view v1 as select * from t1") tk.MustQuery("show create table v1").Check(testutil.RowsWithSep("|", "v1|CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`127.0.0.1` SQL SECURITY DEFINER VIEW `v1` (`a`, `b`) AS select * from t1 ")) + tk.MustQuery("show create view v1").Check(testutil.RowsWithSep("|", "v1|CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`127.0.0.1` SQL SECURITY DEFINER VIEW `v1` (`a`, `b`) AS select * from t1 ")) tk.MustExec("drop view v1") tk.MustExec("drop table t1") diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index a204c1f6ede43..750fe14117160 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -969,6 +969,9 @@ func (b *PlanBuilder) buildShow(show *ast.ShowStmt) (Plan, error) { if table, err := b.is.TableByName(show.Table.Schema, show.Table.Name); err == nil { isView = table.Meta().IsView() } + case ast.ShowCreateView: + err := ErrSpecificAccessDenied.GenWithStackByArgs("SHOW VIEW") + b.visitInfo = appendVisitInfo(b.visitInfo, mysql.ShowViewPriv, "", "", "", err) } p.SetSchema(buildShowSchema(show, isView)) } @@ -1744,6 +1747,8 @@ func buildShowSchema(s *ast.ShowStmt, isView bool) (schema *expression.Schema) { } else { names = []string{"View", "Create View", "character_set_client", "collation_connection"} } + case ast.ShowCreateView: + names = []string{"View", "Create View", "character_set_client", "collation_connection"} case ast.ShowCreateDatabase: names = []string{"Database", "Create Database"} case ast.ShowGrants: