github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/executor/executor_ddl.go (about) 1 // Copyright 2016 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package executor 15 16 import ( 17 "strings" 18 19 "github.com/insionng/yougam/libraries/juju/errors" 20 "github.com/insionng/yougam/libraries/pingcap/tidb/ast" 21 "github.com/insionng/yougam/libraries/pingcap/tidb/context" 22 "github.com/insionng/yougam/libraries/pingcap/tidb/infoschema" 23 "github.com/insionng/yougam/libraries/pingcap/tidb/model" 24 "github.com/insionng/yougam/libraries/pingcap/tidb/mysql" 25 "github.com/insionng/yougam/libraries/pingcap/tidb/privilege" 26 "github.com/insionng/yougam/libraries/pingcap/tidb/sessionctx" 27 "github.com/insionng/yougam/libraries/pingcap/tidb/terror" 28 ) 29 30 // DDLExec represents a DDL executor. 31 type DDLExec struct { 32 Statement ast.StmtNode 33 ctx context.Context 34 is infoschema.InfoSchema 35 done bool 36 } 37 38 // Fields implements Executor Fields interface. 39 func (e *DDLExec) Fields() []*ast.ResultField { 40 return nil 41 } 42 43 // Next implements Execution Next interface. 44 func (e *DDLExec) Next() (*Row, error) { 45 if e.done { 46 return nil, nil 47 } 48 var err error 49 switch x := e.Statement.(type) { 50 case *ast.TruncateTableStmt: 51 err = e.executeTruncateTable(x) 52 case *ast.CreateDatabaseStmt: 53 err = e.executeCreateDatabase(x) 54 case *ast.CreateTableStmt: 55 err = e.executeCreateTable(x) 56 case *ast.CreateIndexStmt: 57 err = e.executeCreateIndex(x) 58 case *ast.DropDatabaseStmt: 59 err = e.executeDropDatabase(x) 60 case *ast.DropTableStmt: 61 err = e.executeDropTable(x) 62 case *ast.DropIndexStmt: 63 err = e.executeDropIndex(x) 64 case *ast.AlterTableStmt: 65 err = e.executeAlterTable(x) 66 } 67 if err != nil { 68 return nil, errors.Trace(err) 69 } 70 e.done = true 71 return nil, nil 72 } 73 74 // Close implements Executor Close interface. 75 func (e *DDLExec) Close() error { 76 return nil 77 } 78 79 func (e *DDLExec) executeTruncateTable(s *ast.TruncateTableStmt) error { 80 table, ok := e.is.TableByID(s.Table.TableInfo.ID) 81 if !ok { 82 return errors.New("table not found, should never happen") 83 } 84 return table.Truncate(e.ctx) 85 } 86 87 func (e *DDLExec) executeCreateDatabase(s *ast.CreateDatabaseStmt) error { 88 var opt *ast.CharsetOpt 89 if len(s.Options) != 0 { 90 opt = &ast.CharsetOpt{} 91 for _, val := range s.Options { 92 switch val.Tp { 93 case ast.DatabaseOptionCharset: 94 opt.Chs = val.Value 95 case ast.DatabaseOptionCollate: 96 opt.Col = val.Value 97 } 98 } 99 } 100 err := sessionctx.GetDomain(e.ctx).DDL().CreateSchema(e.ctx, model.NewCIStr(s.Name), opt) 101 if err != nil { 102 if terror.ErrorEqual(err, infoschema.ErrDatabaseExists) && s.IfNotExists { 103 err = nil 104 } 105 } 106 return errors.Trace(err) 107 } 108 109 func (e *DDLExec) executeCreateTable(s *ast.CreateTableStmt) error { 110 ident := ast.Ident{Schema: s.Table.Schema, Name: s.Table.Name} 111 err := sessionctx.GetDomain(e.ctx).DDL().CreateTable(e.ctx, ident, s.Cols, s.Constraints, s.Options) 112 if terror.ErrorEqual(err, infoschema.ErrTableExists) { 113 if s.IfNotExists { 114 return nil 115 } 116 return infoschema.ErrTableExists.Gen("CREATE TABLE: table exists %s", ident) 117 } 118 return errors.Trace(err) 119 } 120 121 func (e *DDLExec) executeCreateIndex(s *ast.CreateIndexStmt) error { 122 ident := ast.Ident{Schema: s.Table.Schema, Name: s.Table.Name} 123 err := sessionctx.GetDomain(e.ctx).DDL().CreateIndex(e.ctx, ident, s.Unique, model.NewCIStr(s.IndexName), s.IndexColNames) 124 return errors.Trace(err) 125 } 126 127 func (e *DDLExec) executeDropDatabase(s *ast.DropDatabaseStmt) error { 128 err := sessionctx.GetDomain(e.ctx).DDL().DropSchema(e.ctx, model.NewCIStr(s.Name)) 129 if terror.ErrorEqual(err, infoschema.ErrDatabaseNotExists) { 130 if s.IfExists { 131 err = nil 132 } else { 133 err = infoschema.ErrDatabaseDropExists.Gen("Can't drop database '%s'; database doesn't exist", s.Name) 134 } 135 } 136 return errors.Trace(err) 137 } 138 139 func (e *DDLExec) executeDropTable(s *ast.DropTableStmt) error { 140 var notExistTables []string 141 for _, tn := range s.Tables { 142 fullti := ast.Ident{Schema: tn.Schema, Name: tn.Name} 143 schema, ok := e.is.SchemaByName(tn.Schema) 144 if !ok { 145 // TODO: we should return special error for table not exist, checking "not exist" is not enough, 146 // because some other errors may contain this error string too. 147 notExistTables = append(notExistTables, fullti.String()) 148 continue 149 } 150 tb, err := e.is.TableByName(tn.Schema, tn.Name) 151 if err != nil && strings.HasSuffix(err.Error(), "not exist") { 152 notExistTables = append(notExistTables, fullti.String()) 153 continue 154 } else if err != nil { 155 return errors.Trace(err) 156 } 157 // Check Privilege 158 privChecker := privilege.GetPrivilegeChecker(e.ctx) 159 hasPriv, err := privChecker.Check(e.ctx, schema, tb.Meta(), mysql.DropPriv) 160 if err != nil { 161 return errors.Trace(err) 162 } 163 if !hasPriv { 164 return errors.Errorf("You do not have the privilege to drop table %s.%s.", tn.Schema, tn.Name) 165 } 166 167 err = sessionctx.GetDomain(e.ctx).DDL().DropTable(e.ctx, fullti) 168 if infoschema.ErrDatabaseNotExists.Equal(err) || infoschema.ErrTableNotExists.Equal(err) { 169 notExistTables = append(notExistTables, fullti.String()) 170 } else if err != nil { 171 return errors.Trace(err) 172 } 173 } 174 if len(notExistTables) > 0 && !s.IfExists { 175 return infoschema.ErrTableDropExists.Gen("DROP TABLE: table %s does not exist", strings.Join(notExistTables, ",")) 176 } 177 return nil 178 } 179 180 func (e *DDLExec) executeDropIndex(s *ast.DropIndexStmt) error { 181 ti := ast.Ident{Schema: s.Table.Schema, Name: s.Table.Name} 182 err := sessionctx.GetDomain(e.ctx).DDL().DropIndex(e.ctx, ti, model.NewCIStr(s.IndexName)) 183 if (infoschema.ErrDatabaseNotExists.Equal(err) || infoschema.ErrTableNotExists.Equal(err)) && s.IfExists { 184 err = nil 185 } 186 return errors.Trace(err) 187 } 188 189 func (e *DDLExec) executeAlterTable(s *ast.AlterTableStmt) error { 190 ti := ast.Ident{Schema: s.Table.Schema, Name: s.Table.Name} 191 err := sessionctx.GetDomain(e.ctx).DDL().AlterTable(e.ctx, ti, s.Specs) 192 return errors.Trace(err) 193 } 194 195 func joinColumnName(columnName *ast.ColumnName) string { 196 var originStrs []string 197 if columnName.Schema.O != "" { 198 originStrs = append(originStrs, columnName.Schema.O) 199 } 200 if columnName.Table.O != "" { 201 originStrs = append(originStrs, columnName.Table.O) 202 } 203 originStrs = append(originStrs, columnName.Name.O) 204 return strings.Join(originStrs, ".") 205 }