diff --git a/ddl/db_test.go b/ddl/db_test.go index 9f3ad3fd45788..f575210ebaf74 100644 --- a/ddl/db_test.go +++ b/ddl/db_test.go @@ -2037,6 +2037,71 @@ func (s *testDBSuite) TestCreateTableWithLike(c *C) { s.tk.MustExec("drop database ctwl_db1") } +// TestCreateTableWithLike2 tests create table with like when refer table have non-public column/index. +func (s *testDBSuite) TestCreateTableWithLike2(c *C) { + s.tk = testkit.NewTestKit(c, s.store) + s.tk.MustExec("use test_db") + s.tk.MustExec("drop table if exists t1,t2;") + defer s.tk.MustExec("drop table if exists t1,t2;") + s.tk.MustExec("create table t1 (a int, b int, c int, index idx1(c));") + + tbl1 := s.testGetTableByName(c, "test_db", "t1") + doneCh := make(chan error, 2) + hook := &ddl.TestDDLCallback{} + hook.OnJobRunBeforeExported = func(job *model.Job) { + if job.Type != model.ActionAddColumn && job.Type != model.ActionDropColumn && job.Type != model.ActionAddIndex && job.Type != model.ActionDropIndex { + return + } + if job.TableID != tbl1.Meta().ID { + return + } + if job.SchemaState == model.StateDeleteOnly { + go backgroundExec(s.store, "create table t2 like t1", doneCh) + } + } + originalHook := s.dom.DDL().(ddl.DDLForTest).GetHook() + defer s.dom.DDL().(ddl.DDLForTest).SetHook(originalHook) + s.dom.DDL().(ddl.DDLForTest).SetHook(hook) + + // create table when refer table add column + s.tk.MustExec("alter table t1 add column d int") + checkTbl2 := func() { + err := <-doneCh + c.Assert(err, IsNil) + s.tk.MustExec("alter table t2 add column e int") + t2Info := s.testGetTableByName(c, "test_db", "t2") + c.Assert(len(t2Info.Meta().Columns), Equals, 4) + c.Assert(len(t2Info.Meta().Columns), Equals, len(t2Info.Cols())) + } + checkTbl2() + + // create table when refer table drop column + s.tk.MustExec("drop table t2;") + s.tk.MustExec("alter table t1 drop column b;") + checkTbl2() + + // create table when refer table add index + s.tk.MustExec("drop table t2;") + s.tk.MustExec("alter table t1 add index idx2(a);") + checkTbl2 = func() { + err := <-doneCh + c.Assert(err, IsNil) + s.tk.MustExec("alter table t2 add column e int") + tbl2 := s.testGetTableByName(c, "test_db", "t2") + c.Assert(len(tbl2.Meta().Columns), Equals, 4) + c.Assert(len(tbl2.Meta().Columns), Equals, len(tbl2.Cols())) + c.Assert(len(tbl2.Meta().Indices), Equals, 1) + c.Assert(tbl2.Meta().Indices[0].Name.L, Equals, "idx1") + } + checkTbl2() + + // create table when refer table drop index. + s.tk.MustExec("drop table t2;") + s.tk.MustExec("alter table t1 drop index idx2;") + checkTbl2() + +} + func (s *testDBSuite) TestCreateTable(c *C) { s.tk.MustExec("use test") s.tk.MustExec("CREATE TABLE `t` (`a` double DEFAULT 1.0 DEFAULT now() DEFAULT 2.0 );") diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index 1df7de0415b61..e6f1813a80961 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -920,10 +920,7 @@ func (d *ddl) CreateTableWithLike(ctx sessionctx.Context, ident, referIdent ast. return infoschema.ErrTableExists.GenWithStackByArgs(ident) } - tblInfo := *referTbl.Meta() - tblInfo.Name = ident.Name - tblInfo.AutoIncID = 0 - tblInfo.ForeignKeys = nil + tblInfo := buildTableInfoWithLike(ident, referTbl.Meta()) tblInfo.ID, err = d.genGlobalID() if err != nil { return errors.Trace(err) @@ -941,6 +938,24 @@ func (d *ddl) CreateTableWithLike(ctx sessionctx.Context, ident, referIdent ast. return errors.Trace(err) } +func buildTableInfoWithLike(ident ast.Ident, referTblInfo *model.TableInfo) model.TableInfo { + tblInfo := *referTblInfo + // Check non-public column and adjust column offset. + newColumns := referTblInfo.Cols() + newIndices := make([]*model.IndexInfo, 0, len(tblInfo.Indices)) + for _, idx := range tblInfo.Indices { + if idx.State == model.StatePublic { + newIndices = append(newIndices, idx) + } + } + tblInfo.Columns = newColumns + tblInfo.Indices = newIndices + tblInfo.Name = ident.Name + tblInfo.AutoIncID = 0 + tblInfo.ForeignKeys = nil + return tblInfo +} + func findTableOptionCharset(options []*ast.TableOption) string { var tableCharset string for i := len(options) - 1; i >= 0; i-- {