diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index a2cb983d533ac..5cec63b7d51b2 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -1638,12 +1638,15 @@ func checkTableInfoValid(tblInfo *model.TableInfo) error { return checkInvisibleIndexOnPK(tblInfo) } -func buildTableInfoWithLike(ident ast.Ident, referTblInfo *model.TableInfo, s *ast.CreateTableStmt) (*model.TableInfo, error) { +func buildTableInfoWithLike(ctx sessionctx.Context, ident ast.Ident, referTblInfo *model.TableInfo, s *ast.CreateTableStmt) (*model.TableInfo, error) { // Check the referred table is a real table object. if referTblInfo.IsSequence() || referTblInfo.IsView() { return nil, ErrWrongObject.GenWithStackByArgs(ident.Schema, referTblInfo.Name, "BASE TABLE") } tblInfo := *referTblInfo + if err := setTemporaryType(ctx, &tblInfo, s); err != nil { + return nil, errors.Trace(err) + } // Check non-public column and adjust column offset. newColumns := referTblInfo.Cols() newIndices := make([]*model.IndexInfo, 0, len(tblInfo.Indices)) @@ -1731,22 +1734,8 @@ func buildTableInfoWithStmt(ctx sessionctx.Context, s *ast.CreateTableStmt, dbCh if err != nil { return nil, errors.Trace(err) } - switch s.TemporaryKeyword { - case ast.TemporaryGlobal: - tbInfo.TempTableType = model.TempTableGlobal - if !ctx.GetSessionVars().EnableGlobalTemporaryTable { - return nil, errors.New("global temporary table is experimental and it is switched off by tidb_enable_global_temporary_table") - } - // "create global temporary table ... on commit preserve rows" - if !s.OnCommitDelete { - return nil, errors.Trace(errUnsupportedOnCommitPreserve) - } - case ast.TemporaryLocal: - // TODO: set "tbInfo.TempTableType = model.TempTableLocal" after local temporary table is supported. - tbInfo.TempTableType = model.TempTableNone - ctx.GetSessionVars().StmtCtx.AppendWarning(errors.New("local TEMPORARY TABLE is not supported yet, TEMPORARY will be parsed but ignored")) - case ast.TemporaryNone: - tbInfo.TempTableType = model.TempTableNone + if err = setTemporaryType(ctx, tbInfo, s); err != nil { + return nil, errors.Trace(err) } if err = setTableAutoRandomBits(ctx, tbInfo, colDefs); err != nil { @@ -1808,7 +1797,7 @@ func (d *ddl) CreateTable(ctx sessionctx.Context, s *ast.CreateTableStmt) (err e // build tableInfo var tbInfo *model.TableInfo if s.ReferTable != nil { - tbInfo, err = buildTableInfoWithLike(ident, referTbl.Meta(), s) + tbInfo, err = buildTableInfoWithLike(ctx, ident, referTbl.Meta(), s) } else { tbInfo, err = buildTableInfoWithStmt(ctx, s, schema.Charset, schema.Collate) } @@ -1828,6 +1817,27 @@ func (d *ddl) CreateTable(ctx sessionctx.Context, s *ast.CreateTableStmt) (err e return d.CreateTableWithInfo(ctx, schema.Name, tbInfo, onExist, false /*tryRetainID*/) } +func setTemporaryType(ctx sessionctx.Context, tbInfo *model.TableInfo, s *ast.CreateTableStmt) error { + switch s.TemporaryKeyword { + case ast.TemporaryGlobal: + tbInfo.TempTableType = model.TempTableGlobal + if !ctx.GetSessionVars().EnableGlobalTemporaryTable { + return errors.New("global temporary table is experimental and it is switched off by tidb_enable_global_temporary_table") + } + // "create global temporary table ... on commit preserve rows" + if !s.OnCommitDelete { + return errors.Trace(errUnsupportedOnCommitPreserve) + } + case ast.TemporaryLocal: + // TODO: set "tbInfo.TempTableType = model.TempTableLocal" after local temporary table is supported. + tbInfo.TempTableType = model.TempTableNone + ctx.GetSessionVars().StmtCtx.AppendWarning(errors.New("local TEMPORARY TABLE is not supported yet, TEMPORARY will be parsed but ignored")) + default: + tbInfo.TempTableType = model.TempTableNone + } + return nil +} + func (d *ddl) CreateTableWithInfo( ctx sessionctx.Context, dbName model.CIStr, diff --git a/ddl/serial_test.go b/ddl/serial_test.go index b06139c8dd312..82ed77d82fd16 100644 --- a/ddl/serial_test.go +++ b/ddl/serial_test.go @@ -613,6 +613,39 @@ func (s *testSerialSuite) TestCreateTableWithLikeAtTemporaryMode(c *C) { c.Assert(err, IsNil) tableInfo := table.Meta() c.Assert(len(tableInfo.ForeignKeys), Equals, 0) + + // Issue 25613. + // Test from->normal, to->normal. + tk.MustExec("drop table if exists tb1, tb2") + tk.MustExec("create table tb1(id int);") + tk.MustExec("create table tb2 like tb1") + defer tk.MustExec("drop table if exists tb1, tb2") + tk.MustQuery("show create table tb2;").Check(testkit.Rows("tb2 CREATE TABLE `tb2` (\n" + + " `id` int(11) DEFAULT NULL\n" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin")) + + // Test from->normal, to->global temporary. + tk.MustExec("drop table if exists tb3, tb4") + tk.MustExec("create table tb3(id int);") + tk.MustExec("create global temporary table tb4 like tb3 on commit delete rows;") + defer tk.MustExec("drop table if exists tb3, tb4") + tk.MustQuery("show create table tb4;").Check(testkit.Rows("tb4 CREATE GLOBAL TEMPORARY TABLE `tb4` (\n" + + " `id` int(11) DEFAULT NULL\n" + + ") ENGINE=memory DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ON COMMIT DELETE ROWS")) + + // Test from->global temporary, to->normal. + tk.MustExec("drop table if exists tb5, tb6") + tk.MustExec("create global temporary table tb5(id int) on commit delete rows;") + _, err = tk.Exec("create table tb6 like tb5;") + c.Assert(err.Error(), Equals, core.ErrOptOnTemporaryTable.GenWithStackByArgs("create table like").Error()) + defer tk.MustExec("drop table if exists tb5, tb6") + + // Test from->global temporary, to->global temporary. + tk.MustExec("drop table if exists tb7, tb8") + tk.MustExec("create global temporary table tb7(id int) on commit delete rows;") + _, err = tk.Exec("create global temporary table tb8 like tb7 on commit delete rows;") + c.Assert(err.Error(), Equals, core.ErrOptOnTemporaryTable.GenWithStackByArgs("create table like").Error()) + defer tk.MustExec("drop table if exists tb7, tb8") } // TestCancelAddIndex1 tests canceling ddl job when the add index worker is not started.