Skip to content

Commit 44a44da

Browse files
authored
Merge pull request pingcap#3 from zimulala/zimuxia/rename-db-4.0
2 parents 9c7f792 + 11e2b23 commit 44a44da

File tree

12 files changed

+166
-12
lines changed

12 files changed

+166
-12
lines changed

ddl/db_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2652,6 +2652,28 @@ func (s *testDBSuite3) TestTruncateTable(c *C) {
26522652

26532653
}
26542654

2655+
func (s *testDBSuite3) TestRenameDatabase(c *C) {
2656+
s.tk = testkit.NewTestKitWithInit(c, s.store)
2657+
s.tk.MustExec("create database db charset utf8 collate utf8_general_ci;")
2658+
s.tk.MustExec("use db")
2659+
s.tk.MustExec("create table t(c1 int, c2 int)")
2660+
ctx := s.tk.Se.(sessionctx.Context)
2661+
is := domain.GetDomain(ctx).InfoSchema()
2662+
dbInfo, ok := is.SchemaByName(model.NewCIStr("db"))
2663+
c.Assert(ok, IsTrue)
2664+
oldDatabaseID := dbInfo.ID
2665+
s.tk.MustExec("rename database db to newDB")
2666+
is = domain.GetDomain(ctx).InfoSchema()
2667+
newDBInfo, ok := is.SchemaByName(model.NewCIStr("newDB"))
2668+
c.Assert(ok, IsTrue)
2669+
c.Assert(oldDatabaseID, Equals, newDBInfo.ID)
2670+
2671+
// for failure cases
2672+
s.tk.MustGetErrCode("rename database db_not_exit to db", errno.ErrBadDB)
2673+
s.tk.MustGetErrCode("rename database newDB to test", errno.ErrDBCreateExists)
2674+
s.tk.MustGetErrCode("rename database newDB to dbxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", errno.ErrTooLongIdent)
2675+
}
2676+
26552677
func (s *testDBSuite4) TestRenameTable(c *C) {
26562678
isAlterTable := false
26572679
s.testRenameTable(c, "rename table %s to %s", isAlterTable)

ddl/ddl.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ type DDL interface {
9393
CreateSchema(ctx sessionctx.Context, name model.CIStr, charsetInfo *ast.CharsetOpt) error
9494
AlterSchema(ctx sessionctx.Context, stmt *ast.AlterDatabaseStmt) error
9595
DropSchema(ctx sessionctx.Context, schema model.CIStr) error
96+
RenameSchema(ctx sessionctx.Context, oldDB, newDB model.CIStr) error
9697
CreateTable(ctx sessionctx.Context, stmt *ast.CreateTableStmt) error
9798
CreateView(ctx sessionctx.Context, stmt *ast.CreateViewStmt) error
9899
DropTable(ctx sessionctx.Context, tableIdent ast.Ident) (err error)

ddl/ddl_api.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,33 @@ func (d *ddl) AlterSchema(ctx sessionctx.Context, stmt *ast.AlterDatabaseStmt) (
175175
return errors.Trace(err)
176176
}
177177

178+
func (d *ddl) RenameSchema(ctx sessionctx.Context, oldDB, newDB model.CIStr) error {
179+
is := d.GetInfoSchemaWithInterceptor(ctx)
180+
oldSchema, ok := is.SchemaByName(oldDB)
181+
if !ok {
182+
return errors.Trace(infoschema.ErrDatabaseNotExists)
183+
}
184+
_, ok = is.SchemaByName(newDB)
185+
if ok {
186+
return errors.Trace(infoschema.ErrDatabaseExists)
187+
}
188+
if err := checkTooLongSchema(newDB); err != nil {
189+
return errors.Trace(err)
190+
}
191+
192+
job := &model.Job{
193+
SchemaID: oldSchema.ID,
194+
SchemaName: oldSchema.Name.L,
195+
Type: model.ActionRenameDatabase,
196+
BinlogInfo: &model.HistoryInfo{},
197+
Args: []interface{}{newDB},
198+
}
199+
200+
err := d.doDDLJob(ctx, job)
201+
err = d.callHookOnChanged(err)
202+
return errors.Trace(err)
203+
}
204+
178205
func (d *ddl) DropSchema(ctx sessionctx.Context, schema model.CIStr) (err error) {
179206
is := d.GetInfoSchemaWithInterceptor(ctx)
180207
old, ok := is.SchemaByName(schema)

ddl/ddl_worker.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,8 @@ func (w *worker) runDDLJob(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64,
629629
ver, err = onRebaseAutoRandomType(d.store, t, job)
630630
case model.ActionRenameTable:
631631
ver, err = onRenameTable(d, t, job)
632+
case model.ActionRenameDatabase:
633+
ver, err = onRenameSchema(t, job)
632634
case model.ActionShardRowID:
633635
ver, err = w.onShardRowID(d, t, job)
634636
case model.ActionModifyTableComment:

ddl/ddl_worker_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,8 @@ func buildCancelJobTests(firstID int64) []testCancelJob {
450450
{act: model.ActionAddPrimaryKey, jobIDs: []int64{firstID + 35}, cancelRetErrs: []error{admin.ErrCancelFinishedDDLJob.GenWithStackByArgs(firstID + 35)}, cancelState: model.StatePublic},
451451
{act: model.ActionDropPrimaryKey, jobIDs: []int64{firstID + 36}, cancelRetErrs: noErrs, cancelState: model.StateWriteOnly},
452452
{act: model.ActionDropPrimaryKey, jobIDs: []int64{firstID + 37}, cancelRetErrs: []error{admin.ErrCannotCancelDDLJob.GenWithStackByArgs(firstID + 37)}, cancelState: model.StateDeleteOnly},
453+
454+
{act: model.ActionRenameDatabase, jobIDs: []int64{firstID + 38}, cancelRetErrs: noErrs, cancelState: model.StateNone},
453455
}
454456

455457
return tests
@@ -851,6 +853,12 @@ func (s *testDDLSuite) TestCancelJob(c *C) {
851853
testDropIndex(c, ctx, d, dbInfo, tblInfo, idxOrigName)
852854
c.Check(errors.ErrorStack(checkErr), Equals, "")
853855
s.checkDropIdx(c, d, dbInfo.ID, tblInfo.ID, idxOrigName, true)
856+
857+
// for rename database
858+
updateTest(&tests[33])
859+
doDDLJobErrWithSchemaState(ctx, d, c, dbInfo1.ID, 0, model.ActionRenameDatabase, []interface{}{"newDB"}, &cancelState)
860+
c.Check(checkErr, IsNil)
861+
testCheckSchemaState(c, d, dbInfo, model.StatePublic)
854862
}
855863

856864
func (s *testDDLSuite) TestIgnorableSpec(c *C) {

ddl/schema.go

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func onCreateSchema(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ error
3232
dbInfo.ID = schemaID
3333
dbInfo.State = model.StateNone
3434

35-
err := checkSchemaNotExists(d, t, schemaID, dbInfo)
35+
err := checkSchemaNotExists(d, t, schemaID, dbInfo.Name)
3636
if err != nil {
3737
if infoschema.ErrDatabaseExists.Equal(err) {
3838
// The database already exists, can't create it, we should cancel this job now.
@@ -63,10 +63,10 @@ func onCreateSchema(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ error
6363
}
6464
}
6565

66-
func checkSchemaNotExists(d *ddlCtx, t *meta.Meta, schemaID int64, dbInfo *model.DBInfo) error {
66+
func checkSchemaNotExists(d *ddlCtx, t *meta.Meta, schemaID int64, dbName model.CIStr) error {
6767
// d.infoHandle maybe nil in some test.
6868
if d.infoHandle == nil {
69-
return checkSchemaNotExistsFromStore(t, schemaID, dbInfo)
69+
return checkSchemaNotExistsFromStore(t, schemaID, dbName)
7070
}
7171
// Try to use memory schema info to check first.
7272
currVer, err := t.GetSchemaVersion()
@@ -75,35 +75,34 @@ func checkSchemaNotExists(d *ddlCtx, t *meta.Meta, schemaID int64, dbInfo *model
7575
}
7676
is := d.infoHandle.Get()
7777
if is.SchemaMetaVersion() == currVer {
78-
return checkSchemaNotExistsFromInfoSchema(is, schemaID, dbInfo)
78+
return checkSchemaNotExistsFromInfoSchema(is, schemaID, dbName)
7979
}
80-
return checkSchemaNotExistsFromStore(t, schemaID, dbInfo)
80+
return checkSchemaNotExistsFromStore(t, schemaID, dbName)
8181
}
8282

83-
func checkSchemaNotExistsFromInfoSchema(is infoschema.InfoSchema, schemaID int64, dbInfo *model.DBInfo) error {
83+
func checkSchemaNotExistsFromInfoSchema(is infoschema.InfoSchema, schemaID int64, dbName model.CIStr) error {
8484
// Check database exists by name.
85-
if is.SchemaExists(dbInfo.Name) {
86-
return infoschema.ErrDatabaseExists.GenWithStackByArgs(dbInfo.Name)
85+
if is.SchemaExists(dbName) {
86+
return infoschema.ErrDatabaseExists.GenWithStackByArgs(dbName)
8787
}
8888
// Check database exists by ID.
8989
if _, ok := is.SchemaByID(schemaID); ok {
90-
return infoschema.ErrDatabaseExists.GenWithStackByArgs(dbInfo.Name)
90+
return infoschema.ErrDatabaseExists.GenWithStackByArgs(dbName)
9191
}
9292
return nil
9393
}
9494

95-
func checkSchemaNotExistsFromStore(t *meta.Meta, schemaID int64, dbInfo *model.DBInfo) error {
95+
func checkSchemaNotExistsFromStore(t *meta.Meta, schemaID int64, dbName model.CIStr) error {
9696
dbs, err := t.ListDatabases()
9797
if err != nil {
9898
return errors.Trace(err)
9999
}
100100

101101
for _, db := range dbs {
102-
if db.Name.L == dbInfo.Name.L {
102+
if db.Name.L == dbName.L {
103103
if db.ID != schemaID {
104104
return infoschema.ErrDatabaseExists.GenWithStackByArgs(db.Name)
105105
}
106-
dbInfo = db
107106
}
108107
}
109108
return nil
@@ -140,6 +139,34 @@ func onModifySchemaCharsetAndCollate(t *meta.Meta, job *model.Job) (ver int64, _
140139
return ver, nil
141140
}
142141

142+
func onRenameSchema(t *meta.Meta, job *model.Job) (ver int64, _ error) {
143+
var newDBName model.CIStr
144+
if err := job.DecodeArgs(&newDBName); err != nil {
145+
job.State = model.JobStateCancelled
146+
return ver, errors.Trace(err)
147+
}
148+
149+
dbInfo, err := t.GetDatabase(job.SchemaID)
150+
if err != nil {
151+
job.State = model.JobStateCancelled
152+
return ver, errors.Trace(err)
153+
}
154+
if err = checkSchemaNotExistsFromStore(t, job.SchemaID, newDBName); err != nil {
155+
job.State = model.JobStateCancelled
156+
return ver, errors.Trace(err)
157+
}
158+
159+
dbInfo.Name = newDBName
160+
if err = t.UpdateDatabase(dbInfo); err != nil {
161+
return ver, errors.Trace(err)
162+
}
163+
if ver, err = updateSchemaVersion(t, job); err != nil {
164+
return ver, errors.Trace(err)
165+
}
166+
job.FinishDBJob(model.JobStateDone, model.StatePublic, ver, dbInfo)
167+
return ver, nil
168+
}
169+
143170
func onDropSchema(t *meta.Meta, job *model.Job) (ver int64, _ error) {
144171
dbInfo, err := checkSchemaExistAndCancelNotExistJob(t, job)
145172
if err != nil {

executor/ddl.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ func (e *DDLExec) Next(ctx context.Context, req *chunk.Chunk) (err error) {
108108
err = e.executeFlashbackTable(x)
109109
case *ast.RenameTableStmt:
110110
err = e.executeRenameTable(x)
111+
case *ast.RenameDatabaseStmt:
112+
err = e.executeRenameDatabase(x)
111113
case *ast.TruncateTableStmt:
112114
err = e.executeTruncateTable(x)
113115
case *ast.LockTablesStmt:
@@ -152,6 +154,19 @@ func (e *DDLExec) executeTruncateTable(s *ast.TruncateTableStmt) error {
152154
return err
153155
}
154156

157+
func (e *DDLExec) executeRenameDatabase(s *ast.RenameDatabaseStmt) error {
158+
oldDB := model.NewCIStr(s.OldDB)
159+
newDB := model.NewCIStr(s.NewDB)
160+
161+
// Protect important system table from been dropped by a mistake.
162+
// I can hardly find a case that a user really need to do this.
163+
if oldDB.L == "mysql" {
164+
return errors.New("Rename 'mysql' database is forbidden")
165+
}
166+
167+
return domain.GetDomain(e.ctx).DDL().RenameSchema(e.ctx, oldDB, newDB)
168+
}
169+
155170
func (e *DDLExec) executeRenameTable(s *ast.RenameTableStmt) error {
156171
if len(s.TableToTables) != 1 {
157172
// Now we only allow one schema changing at the same time.

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,5 @@ require (
7474
)
7575

7676
go 1.13
77+
78+
replace github.com/pingcap/parser => github.com/bb7133/parser v0.0.0-20200429032743-4494e5f18a8d

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
1515
github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
1616
github.com/appleboy/gin-jwt/v2 v2.6.3/go.mod h1:MfPYA4ogzvOcVkRwAxT7quHOtQmVKDpTwxyUrC2DNw0=
1717
github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw=
18+
github.com/bb7133/parser v0.0.0-20200429032743-4494e5f18a8d h1:cSjNiwPNKJfxrRP+2w6hG9mnWW9eWFYFrCcifRm1D6g=
19+
github.com/bb7133/parser v0.0.0-20200429032743-4494e5f18a8d/go.mod h1:9v0Edh8IbgjGYW2ArJr19E+bvL8zKahsFp+ixWeId+4=
1820
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
1921
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
2022
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -388,6 +390,8 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5
388390
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
389391
github.com/yookoala/realpath v1.0.0/go.mod h1:gJJMA9wuX7AcqLy1+ffPatSCySA1FQ2S8Ya9AIoYBpE=
390392
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
393+
github.com/zimulala/parser v0.0.0-20200428092446-11e0c7903208 h1:+UobXq2Tc+lu10/7YZOFdSXThYlxLc3RkH7jShkmZig=
394+
github.com/zimulala/parser v0.0.0-20200428092446-11e0c7903208/go.mod h1:9v0Edh8IbgjGYW2ArJr19E+bvL8zKahsFp+ixWeId+4=
391395
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
392396
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
393397
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=

infoschema/builder.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ func (b *Builder) ApplyDiff(m *meta.Meta, diff *model.SchemaDiff) ([]int64, erro
4848
} else if diff.Type == model.ActionModifySchemaCharsetAndCollate {
4949
return nil, b.applyModifySchemaCharsetAndCollate(m, diff)
5050
}
51+
if diff.Type == model.ActionRenameDatabase {
52+
return nil, b.applyRenameSchema(m, diff)
53+
}
5154
roDBInfo, ok := b.is.SchemaByID(diff.SchemaID)
5255
if !ok {
5356
return nil, ErrDatabaseNotExists.GenWithStackByArgs(
@@ -188,6 +191,24 @@ func (b *Builder) applyModifySchemaCharsetAndCollate(m *meta.Meta, diff *model.S
188191
return nil
189192
}
190193

194+
func (b *Builder) applyRenameSchema(m *meta.Meta, diff *model.SchemaDiff) error {
195+
di, err := m.GetDatabase(diff.SchemaID)
196+
if err != nil {
197+
return errors.Trace(err)
198+
}
199+
oldDB, ok := b.is.SchemaByID(diff.SchemaID)
200+
if di == nil || ok {
201+
// This should never happen.
202+
return ErrDatabaseNotExists.GenWithStackByArgs(
203+
fmt.Sprintf("(Schema ID %d)", diff.SchemaID),
204+
)
205+
}
206+
207+
newDbInfo := b.copySchemaTables(oldDB.Name.O)
208+
newDbInfo.Name = di.Name
209+
return nil
210+
}
211+
191212
func (b *Builder) applyDropSchema(schemaID int64) []int64 {
192213
di, ok := b.is.SchemaByID(schemaID)
193214
if !ok {

0 commit comments

Comments
 (0)