diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index bef6621958fba..a735720242c51 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -1686,12 +1686,12 @@ func buildTableInfoWithLike(ctx sessionctx.Context, ident ast.Ident, referTblInf // BuildTableInfoFromAST builds model.TableInfo from a SQL statement. // Note: TableID and PartitionID are left as uninitialized value. func BuildTableInfoFromAST(s *ast.CreateTableStmt) (*model.TableInfo, error) { - return BuildTableInfoWithCheck(mock.NewContext(), s, mysql.DefaultCharset, "") + return buildTableInfoWithCheck(mock.NewContext(), s, mysql.DefaultCharset, "") } -// BuildTableInfoWithCheck builds model.TableInfo from a SQL statement. +// buildTableInfoWithCheck builds model.TableInfo from a SQL statement. // Note: TableID and PartitionIDs are left as uninitialized value. -func BuildTableInfoWithCheck(ctx sessionctx.Context, s *ast.CreateTableStmt, dbCharset, dbCollate string) (*model.TableInfo, error) { +func buildTableInfoWithCheck(ctx sessionctx.Context, s *ast.CreateTableStmt, dbCharset, dbCollate string) (*model.TableInfo, error) { tbInfo, err := buildTableInfoWithStmt(ctx, s, dbCharset, dbCollate) if err != nil { return nil, err @@ -1708,6 +1708,30 @@ func BuildTableInfoWithCheck(ctx sessionctx.Context, s *ast.CreateTableStmt, dbC return tbInfo, nil } +// BuildSessionTemporaryTableInfo builds model.TableInfo from a SQL statement. +func BuildSessionTemporaryTableInfo(ctx sessionctx.Context, is infoschema.InfoSchema, s *ast.CreateTableStmt, dbCharset, dbCollate string) (*model.TableInfo, error) { + ident := ast.Ident{Schema: s.Table.Schema, Name: s.Table.Name} + //build tableInfo + var tbInfo *model.TableInfo + var referTbl table.Table + var err error + if s.ReferTable != nil { + referIdent := ast.Ident{Schema: s.ReferTable.Schema, Name: s.ReferTable.Name} + _, ok := is.SchemaByName(referIdent.Schema) + if !ok { + return nil, infoschema.ErrTableNotExists.GenWithStackByArgs(referIdent.Schema, referIdent.Name) + } + referTbl, err = is.TableByName(referIdent.Schema, referIdent.Name) + if err != nil { + return nil, infoschema.ErrTableNotExists.GenWithStackByArgs(referIdent.Schema, referIdent.Name) + } + tbInfo, err = buildTableInfoWithLike(ctx, ident, referTbl.Meta(), s) + } else { + tbInfo, err = buildTableInfoWithCheck(ctx, s, dbCharset, dbCollate) + } + return tbInfo, err +} + // buildTableInfoWithStmt builds model.TableInfo from a SQL statement without validity check func buildTableInfoWithStmt(ctx sessionctx.Context, s *ast.CreateTableStmt, dbCharset, dbCollate string) (*model.TableInfo, error) { colDefs := s.Cols @@ -5765,7 +5789,7 @@ func (d *ddl) RepairTable(ctx sessionctx.Context, table *ast.TableName, createSt } // It is necessary to specify the table.ID and partition.ID manually. - newTableInfo, err := BuildTableInfoWithCheck(ctx, createStmt, oldTableInfo.Charset, oldTableInfo.Collate) + newTableInfo, err := buildTableInfoWithCheck(ctx, createStmt, oldTableInfo.Charset, oldTableInfo.Collate) if err != nil { return errors.Trace(err) } diff --git a/ddl/serial_test.go b/ddl/serial_test.go index baef8c38df4ed..ff99d04b0afb9 100644 --- a/ddl/serial_test.go +++ b/ddl/serial_test.go @@ -646,6 +646,59 @@ func (s *testSerialSuite) TestCreateTableWithLikeAtTemporaryMode(c *C) { _, 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") + + tk.MustExec("set tidb_enable_noop_functions=true") + // Test from->normal, to->local temporary + tk.MustExec("drop table if exists tb11, tb12") + tk.MustExec("create table tb11 (i int primary key, j int)") + tk.MustExec("create temporary table tb12 like tb11") + tk.MustQuery("show create table tb12;").Check(testkit.Rows("tb12 CREATE TEMPORARY TABLE `tb12` (\n" + + " `i` int(11) NOT NULL,\n `j` int(11) DEFAULT NULL,\n PRIMARY KEY (`i`) /*T![clustered_index] CLUSTERED */\n" + + ") ENGINE=memory DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin")) + tk.MustExec("create temporary table if not exists tb12 like tb11;") + c.Assert(tk.Se.(sessionctx.Context).GetSessionVars().StmtCtx.GetWarnings()[0].Err.Error(), Equals, + infoschema.ErrTableExists.GenWithStackByArgs("tb12").Error()) + defer tk.MustExec("drop table if exists tb11, tb12") + // Test from->local temporary, to->local temporary + tk.MustExec("drop table if exists tb13, tb14") + tk.MustExec("create temporary table tb13 (i int primary key, j int)") + _, err = tk.Exec("create temporary table tb14 like tb13;") + c.Assert(err.Error(), Equals, core.ErrOptOnTemporaryTable.GenWithStackByArgs("create table like").Error()) + defer tk.MustExec("drop table if exists tb13, tb14") + // Test from->local temporary, to->normal + tk.MustExec("drop table if exists tb15, tb16") + tk.MustExec("create temporary table tb15 (i int primary key, j int)") + _, err = tk.Exec("create table tb16 like tb15;") + c.Assert(err.Error(), Equals, core.ErrOptOnTemporaryTable.GenWithStackByArgs("create table like").Error()) + defer tk.MustExec("drop table if exists tb15, tb16") + + tk.MustExec("drop table if exists table_pre_split, tmp_pre_split") + tk.MustExec("create table table_pre_split(id int) shard_row_id_bits=2 pre_split_regions=2;") + _, err = tk.Exec("create temporary table tmp_pre_split like table_pre_split") + c.Assert(err.Error(), Equals, core.ErrOptOnTemporaryTable.GenWithStackByArgs("pre split regions").Error()) + defer tk.MustExec("drop table if exists table_pre_split, tmp_pre_split") + + tk.MustExec("drop table if exists table_shard_row_id, tmp_shard_row_id") + tk.MustExec("create table table_shard_row_id(id int) shard_row_id_bits=2;") + _, err = tk.Exec("create temporary table tmp_shard_row_id like table_shard_row_id") + c.Assert(err.Error(), Equals, core.ErrOptOnTemporaryTable.GenWithStackByArgs("shard_row_id_bits").Error()) + defer tk.MustExec("drop table if exists table_shard_row_id, tmp_shard_row_id") + + tk.MustExec("drop table if exists partition_table, tmp_partition_table") + tk.MustExec("create table partition_table (a int, b int) partition by hash(a) partitions 3;") + tk.MustGetErrCode("create temporary table tmp_partition_table like partition_table", errno.ErrPartitionNoTemporary) + defer tk.MustExec("drop table if exists partition_table, tmp_partition_table") + + tk.MustExec("drop table if exists foreign_key_table1, foreign_key_table2, foreign_key_tmp;") + tk.MustExec("create table foreign_key_table1 (a int, b int);") + tk.MustExec("create table foreign_key_table2 (c int,d int,foreign key (d) references foreign_key_table1 (b));") + tk.MustExec("create temporary table foreign_key_tmp like foreign_key_table2") + is = tk.Se.(sessionctx.Context).GetInfoSchema().(infoschema.InfoSchema) + table, err = is.TableByName(model.NewCIStr("test"), model.NewCIStr("foreign_key_tmp")) + c.Assert(err, IsNil) + tableInfo = table.Meta() + c.Assert(len(tableInfo.ForeignKeys), Equals, 0) + defer tk.MustExec("drop table if exists foreign_key_table1, foreign_key_table2, foreign_key_tmp;") } // TestCancelAddIndex1 tests canceling ddl job when the add index worker is not started. diff --git a/executor/ddl.go b/executor/ddl.go index dada99a3e60ed..13d5f3c1b6900 100644 --- a/executor/ddl.go +++ b/executor/ddl.go @@ -339,7 +339,7 @@ func (e *DDLExec) createSessionTemporaryTable(s *ast.CreateTableStmt) error { if !ok { return infoschema.ErrDatabaseNotExists.GenWithStackByArgs(s.Table.Schema.O) } - tbInfo, err := ddl.BuildTableInfoWithCheck(e.ctx, s, dbInfo.Charset, dbInfo.Collate) + tbInfo, err := ddl.BuildSessionTemporaryTableInfo(e.ctx, is, s, dbInfo.Charset, dbInfo.Collate) if err != nil { return err }