*: Support the statement of "create table ... like" (#2707)

This commit is contained in:
Lynn
2017-02-22 23:57:04 +08:00
committed by Ewan Chou
parent f7c95f3f42
commit 61868f44dc
9 changed files with 130 additions and 3 deletions

View File

@ -100,6 +100,7 @@ type DDL interface {
DropSchema(ctx context.Context, schema model.CIStr) error
CreateTable(ctx context.Context, ident ast.Ident, cols []*ast.ColumnDef,
constrs []*ast.Constraint, options []*ast.TableOption) error
CreateTableWithLike(ctx context.Context, ident, referIdent ast.Ident) error
DropTable(ctx context.Context, tableIdent ast.Ident) (err error)
CreateIndex(ctx context.Context, tableIdent ast.Ident, unique bool, indexName model.CIStr,
columnNames []*ast.IndexColName) error

View File

@ -571,6 +571,45 @@ func (d *ddl) buildTableInfo(tableName model.CIStr, cols []*table.Column, constr
return
}
func (d *ddl) CreateTableWithLike(ctx context.Context, ident, referIdent ast.Ident) error {
is := d.GetInformationSchema()
_, ok := is.SchemaByName(referIdent.Schema)
if !ok {
return infoschema.ErrTableNotExists.GenByArgs(referIdent.Schema, referIdent.Name)
}
referTbl, err := is.TableByName(referIdent.Schema, referIdent.Name)
if err != nil {
return infoschema.ErrTableNotExists.GenByArgs(referIdent.Schema, referIdent.Name)
}
schema, ok := is.SchemaByName(ident.Schema)
if !ok {
return infoschema.ErrDatabaseNotExists.GenByArgs(ident.Schema)
}
if is.TableExists(ident.Schema, ident.Name) {
return infoschema.ErrTableExists.GenByArgs(ident)
}
tblInfo := *referTbl.Meta()
tblInfo.Name = ident.Name
tblInfo.AutoIncID = 0
tblInfo.ForeignKeys = nil
tblInfo.ID, err = d.genGlobalID()
if err != nil {
return errors.Trace(err)
}
job := &model.Job{
SchemaID: schema.ID,
TableID: tblInfo.ID,
Type: model.ActionCreateTable,
BinlogInfo: &model.HistoryInfo{},
Args: []interface{}{tblInfo},
}
err = d.doDDLJob(ctx, job)
err = d.callHookOnChanged(err)
return errors.Trace(err)
}
func (d *ddl) CreateTable(ctx context.Context, ident ast.Ident, colDefs []*ast.ColumnDef,
constraints []*ast.Constraint, options []*ast.TableOption) (err error) {
is := d.GetInformationSchema()

View File

@ -894,6 +894,55 @@ func (s *testDBSuite) TestUpdateMultipleTable(c *C) {
tk.MustQuery("select * from t1").Check(testkit.Rows("8 1 9", "8 2 9"))
}
func (s *testDBSuite) TestCreateTableWithLike(c *C) {
defer testleak.AfterTest(c)
store, err := tidb.NewStore("memory://create_table_like")
c.Assert(err, IsNil)
s.tk = testkit.NewTestKit(c, store)
_, err = tidb.BootstrapSession(store)
c.Assert(err, IsNil)
// for the same database
s.tk.MustExec("use test")
s.tk.MustExec("create table tt(id int primary key)")
s.tk.MustExec("create table t (c1 int not null auto_increment, c2 int, constraint cc foreign key (c2) references tt(id), primary key(c1)) auto_increment = 10")
s.tk.MustExec("insert into t set c2=1")
s.tk.MustExec("create table t1 like test.t")
s.tk.MustExec("insert into t1 set c2=11")
s.tk.MustQuery("select * from t").Check(testkit.Rows("10 1"))
s.tk.MustQuery("select * from t1").Check(testkit.Rows("1 11"))
ctx := s.tk.Se.(context.Context)
is := sessionctx.GetDomain(ctx).InfoSchema()
tbl, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("t1"))
c.Assert(err, IsNil)
tblInfo := tbl.Meta()
c.Assert(tblInfo.ForeignKeys, IsNil)
c.Assert(tblInfo.PKIsHandle, Equals, true)
col := tblInfo.Columns[0]
hasNotNull := tmysql.HasNotNullFlag(col.Flag)
c.Assert(hasNotNull, IsTrue)
// for different databases
s.tk.MustExec("create database test1")
s.tk.MustExec("use test1")
s.tk.MustExec("create table t1 like test.t")
s.tk.MustExec("insert into t1 set c2=11")
s.tk.MustQuery("select * from t1").Check(testkit.Rows("1 11"))
is = sessionctx.GetDomain(ctx).InfoSchema()
tbl, err = is.TableByName(model.NewCIStr("test1"), model.NewCIStr("t1"))
c.Assert(err, IsNil)
c.Assert(tbl.Meta().ForeignKeys, IsNil)
// for failure cases
failSQL := fmt.Sprintf("create table t1 like test_not_exist.t")
s.testErrorCode(c, failSQL, tmysql.ErrNoSuchTable)
failSQL = fmt.Sprintf("create table t1 like test.t_not_exist")
s.testErrorCode(c, failSQL, tmysql.ErrNoSuchTable)
failSQL = fmt.Sprintf("create table test_not_exis.t1 like test.t")
s.testErrorCode(c, failSQL, tmysql.ErrBadDB)
failSQL = fmt.Sprintf("create table t1 like test.t")
s.testErrorCode(c, failSQL, tmysql.ErrTableExists)
}
func (s *testDBSuite) TestTruncateTable(c *C) {
defer testleak.AfterTest(c)
store, err := tidb.NewStore("memory://truncate_table")