#At file:///home/dlenev/src/bzr/mysql-6.1-mil7-ctl/
2682 Dmitry Lenev 2008-08-14
Tentative patch for the 7th milestone of WL#148 "Foreign keys"
("DDL checks and changes CREATE, CREATE TABLE SELECT, CREATE
TABLE LIKE") implementing necessary changes in CREATE TABLE LIKE.
Per LLD CREATE TABLE LIKE statement should not copy foreign keys
from source table to the new table.
Since we store information about foreign keys in .FRM files
and there is no simple way to modify this information without
recreating .FRM file we have to change our implementation of
CREATE TABLE LIKE. Instead of directly copying .FRMs file we
now use the same code as simple CREATE TABLE.
I.e. we generate structures describing table being created
from source table and the pass these structures after minor
tweaks to the mysql_create_table_no_lock() function.
A side effect of this change is that CREATE TABLE LIKE now
follows the same rules as CREATE TABLE and thus bug#22909
should be solved.
Questions for reviewer are marked by QQ.
modified:
mysql-test/r/foreign_key_all_engines.result
mysql-test/r/foreign_key_all_engines_2.result
mysql-test/t/foreign_key_all_engines.test
mysql-test/t/foreign_key_all_engines_2.test
sql/mysql_priv.h
sql/sql_insert.cc
sql/sql_parse.cc
sql/sql_partition.cc
sql/sql_table.cc
per-file messages:
mysql-test/r/foreign_key_all_engines.result
Added test coverage for handling of foreign keys by CREATE TABLE
LIKE statement in --foreign-key-all-engines mode.
mysql-test/r/foreign_key_all_engines_2.result
Added test coverage for handling of foreign keys by CREATE TABLE
LIKE statement in --foreign-key-all-engines mode.
mysql-test/t/foreign_key_all_engines.test
Added test coverage for handling of foreign keys by CREATE TABLE
LIKE statement in --foreign-key-all-engines mode.
mysql-test/t/foreign_key_all_engines_2.test
Added test coverage for handling of foreign keys by CREATE TABLE
LIKE statement in --foreign-key-all-engines mode.
sql/mysql_priv.h
Got rid of two unused mysql_create_table() arguments.
sql/sql_insert.cc
Since mysql_create_table_no_lock() no longer writes statement to
the binary log there is no reason to disable this functionality
in CREATE TABLE SELECT implementation.
sql/sql_parse.cc
New metadata locking logic in CREATE TABLE LIKE statement
requires table to be created present in statement's table
list (in case if we create non-temporary table) with special
flag which says that this table should be either open or we should obtain an exclusive metadata lock on it.
sql/sql_partition.cc
Since CREATE TABLE LIKE implementation now uses the same code
as ordinary CREATE TABLE we no longer need special branch in
mysql_unpack_partition() that handles this statement.
sql/sql_table.cc
mysql_create_table_no_lock():
Make logging statement to the binary log responsibility
of the caller of this function.
mysql_create_table():
Log statement to the binary log if it succeeds.
mysql_create_like_table():
Changed implementation of CREATE TABLE LIKE to use mostly
the same code as ordinary CREATE TABLE. To do this we
generate structures describing table being created from
source table and the pass these structures (after minor
tweaks, particularly removing info about foreign keys) to
the mysql_create_table_no_lock() function.
Also disallowed creation of non-temporary table under
LOCK TABLES as in ordinary CREATE TABLE. This allowed
to simplify metadata locking logic for this statement.
=== modified file 'mysql-test/r/foreign_key_all_engines.result'
--- a/mysql-test/r/foreign_key_all_engines.result 2008-06-27 05:11:56 +0000
+++ b/mysql-test/r/foreign_key_all_engines.result 2008-08-14 10:14:41 +0000
@@ -280,6 +280,16 @@ drop table t3;
use test;
drop database mysqltest;
drop table t1, t2;
+drop tables if exists t1, t2, t3;
+create table t1 (pk int primary key);
+create table t2 (fk int constraint c references t1 (pk));
+create table t3 like t2;
+show create table t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `fk` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t3, t2, t1;
set @@rand_seed1=10000000,@@rand_seed2=1000000;
drop tables if exists t1, t2;
create table t2 (a int primary key);
=== modified file 'mysql-test/r/foreign_key_all_engines_2.result'
--- a/mysql-test/r/foreign_key_all_engines_2.result 2008-08-06 08:09:35 +0000
+++ b/mysql-test/r/foreign_key_all_engines_2.result 2008-08-14 10:14:41 +0000
@@ -134,6 +134,19 @@ delete from t1 where pk=2;
unlock tables;
# Switching to connection 'default'
drop tables t1, t2, t3;
+drop tables if exists t1, t2, t3;
+create table t1 (pk int primary key);
+create table t2 (fk int constraint c references t1 (pk) on delete set null);
+create table t3 like t1;
+insert into t3 values (1);
+# Switching to connection 'blocker'
+lock tables t2 read;
+# Switching to connection 'default'
+delete from t3 where pk = 1;
+# Switching to connection 'blocker'
+unlock tables;
+# Switching to connection 'default'
+drop table t3, t2, t1;
drop tables if exists t1, t2;
create table t1 (s1 int primary key) engine=innodb;
create table t2 (s1 int, foreign key (s1) references t1 (s1)) engine=innodb;
=== modified file 'mysql-test/t/foreign_key_all_engines.test'
--- a/mysql-test/t/foreign_key_all_engines.test 2008-06-27 05:11:56 +0000
+++ b/mysql-test/t/foreign_key_all_engines.test 2008-08-14 10:14:41 +0000
@@ -195,6 +195,24 @@ drop table t1, t2;
#
+# Coverage for the 7th milestone of WL#148 "Foreign keys" ("DDL checks
+# and changes CREATE, CREATE TABLE SELECT, CREATE TABLE LIKE").
+#
+--disable_warnings
+drop tables if exists t1, t2, t3;
+--enable_warnings
+# Test of how CREATE TABLE LIKE works with foreign keys
+create table t1 (pk int primary key);
+create table t2 (fk int constraint c references t1 (pk));
+create table t3 like t2;
+# Check that we don't copy foreign key information when creating table like
+# a child table.
+# See also similar test for parent table in foreign_key_all_engines_2.test
+show create table t3;
+drop table t3, t2, t1;
+
+
+#
# Test for bug #35522 "Foreign keys: 'foreign key without name' errors"
# In --foreign-key-all-engines mode we should not replace names of FKs
# in error messages with 'foreign key without name' even if though names
=== modified file 'mysql-test/t/foreign_key_all_engines_2.test'
--- a/mysql-test/t/foreign_key_all_engines_2.test 2008-08-06 08:09:35 +0000
+++ b/mysql-test/t/foreign_key_all_engines_2.test 2008-08-14 10:14:41 +0000
@@ -275,6 +275,37 @@ drop tables t1, t2, t3;
#
+# Additional coverage for the 7th milestone of WL#148 "Foreign keys"
+# ("DDL checks and changes CREATE, CREATE TABLE SELECT, CREATE TABLE LIKE").
+#
+--disable_warnings
+drop tables if exists t1, t2, t3;
+--enable_warnings
+# Check how CREATE TABLE LIKE works with table which is parent in foreign key
+create table t1 (pk int primary key);
+create table t2 (fk int constraint c references t1 (pk) on delete set null);
+create table t3 like t1;
+# Since we can't directly check that newly created table does not contain
+# information about our foreign key, we have to resort to check relying on
+# prelocking algorithm.
+insert into t3 values (1);
+--echo # Switching to connection 'blocker'
+connection blocker;
+lock tables t2 read;
+--echo # Switching to connection 'default'
+connection default;
+# Should not be blocked by above LOCK TABLES since t3's .FRM should
+# not contain record about referencing foreign key.
+delete from t3 where pk = 1;
+--echo # Switching to connection 'blocker'
+connection blocker;
+unlock tables;
+--echo # Switching to connection 'default'
+connection default;
+drop table t3, t2, t1;
+
+
+#
# Bug #35519 "Foreign keys: create fails with InnoDB"
#
# In --foreign-key-all-engines mode attempt to create foreign key on
=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h 2008-08-06 08:09:35 +0000
+++ b/sql/mysql_priv.h 2008-08-14 10:14:41 +0000
@@ -1260,8 +1260,7 @@ int prepare_create_field(Create_field *s
bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
TABLE_LIST *fkey_tables,
HA_CREATE_INFO *create_info,
- Alter_info *alter_info,
- bool tmp_table, uint select_field_count);
+ Alter_info *alter_info);
bool mysql_create_table_no_lock(THD *thd, const char *db,
const char *table_name,
HA_CREATE_INFO *create_info,
=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc 2008-06-27 05:11:56 +0000
+++ b/sql/sql_insert.cc 2008-08-14 10:14:41 +0000
@@ -3442,7 +3442,6 @@ static TABLE *create_table_from_items(TH
open_table().
*/
{
- tmp_disable_binlog(thd);
if (!mysql_create_table_no_lock(thd, create_table->db,
create_table->table_name,
create_info, alter_info, 0,
@@ -3498,7 +3497,6 @@ static TABLE *create_table_from_items(TH
table= create_table->table;
}
}
- reenable_binlog(thd);
if (!table) // open failed
DBUG_RETURN(0);
}
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2008-08-03 10:13:01 +0000
+++ b/sql/sql_parse.cc 2008-08-14 10:14:41 +0000
@@ -2431,15 +2431,32 @@ mysql_execute_command(THD *thd)
/* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
thd->options|= OPTION_KEEP_LOG;
- /* regular create */
if (create_info.options & HA_LEX_CREATE_TABLE_LIKE)
+ {
+ /* CREATE TABLE ... LIKE ... */
+ if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
+ {
+ /*
+ QQ: Should we rearrange to code to avoid these manipulations
+ with table list ? But in this case we will probably have
+ to add some ugly code to open_tables() ?
+ */
+ lex->link_first_table_back(create_table, link_to_local);
+ create_table->open_type= TABLE_LIST::OPEN_OR_CREATE;
+ }
+
res= mysql_create_like_table(thd, create_table, select_tables,
&create_info);
+
+ if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
+ create_table= lex->unlink_first_table(&link_to_local);
+ }
else
{
+ /* Regular CREATE TABLE */
res= mysql_create_table(thd, create_table,
lex->create_foreign_key_tables,
- &create_info, &alter_info, 0, 0);
+ &create_info, &alter_info);
}
if (!res)
my_ok(thd);
=== modified file 'sql/sql_partition.cc'
--- a/sql/sql_partition.cc 2008-06-11 11:49:58 +0000
+++ b/sql/sql_partition.cc 2008-08-14 10:14:41 +0000
@@ -3812,39 +3812,22 @@ bool mysql_unpack_partition(THD *thd,
ha_resolve_storage_engine_name(default_db_type)));
if (is_create_table_ind && old_lex->sql_command == SQLCOM_CREATE_TABLE)
{
- if (old_lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
- {
- /*
- This code is executed when we create table in CREATE TABLE t1 LIKE t2.
- old_lex->query_tables contains table list element for t2 and the table
- we are opening has name t1.
- */
- if (partition_default_handling(table, part_info, FALSE,
- old_lex->query_tables->table->s->path.str))
- {
- result= TRUE;
- goto end;
- }
- }
- else
- {
- /*
- When we come here we are doing a create table. In this case we
- have already done some preparatory work on the old part_info
- object. We don't really need this new partition_info object.
- Thus we go back to the old partition info object.
- We need to free any memory objects allocated on item_free_list
- by the parser since we are keeping the old info from the first
- parser call in CREATE TABLE.
- We'll ensure that this object isn't put into table cache also
- just to ensure we don't get into strange situations with the
- item objects.
- */
- thd->free_items();
- part_info= thd->work_part_info;
- table->s->version= 0UL;
- *work_part_info_used= true;
- }
+ /*
+ When we come here we are doing a create table. In this case we
+ have already done some preparatory work on the old part_info
+ object. We don't really need this new partition_info object.
+ Thus we go back to the old partition info object.
+ We need to free any memory objects allocated on item_free_list
+ by the parser since we are keeping the old info from the first
+ parser call in CREATE TABLE.
+ We'll ensure that this object isn't put into table cache also
+ just to ensure we don't get into strange situations with the
+ item objects.
+ */
+ thd->free_items();
+ part_info= thd->work_part_info;
+ table->s->version= 0UL;
+ *work_part_info_used= true;
}
table->part_info= part_info;
part_info->table= table;
=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc 2008-08-06 08:09:35 +0000
+++ b/sql/sql_table.cc 2008-08-14 10:14:41 +0000
@@ -3325,11 +3325,12 @@ void sp_prepare_create_field(THD *thd, C
way to ensure that concurrent operations won't intervene.
mysql_create_table() is a wrapper that can be used for this.
- no_log is needed for the case of CREATE ... SELECT,
- as the logging will be done later in sql_insert.cc
select_field_count is also used for CREATE ... SELECT,
and must be zero for standard create of table.
+ Note that it is responsibility of a caller to write (or not to write)
+ statement which involves creation of this table into binlog.
+
RETURN VALUES
FALSE OK
TRUE error
@@ -3709,18 +3710,6 @@ bool mysql_create_table_no_lock(THD *thd
thd->thread_specific_used= TRUE;
}
- /*
- Don't write statement if:
- - It is an internal temporary table,
- - Row-based logging is used and it we are creating a temporary table, or
- - The binary log is not open.
- Otherwise, the statement shall be binlogged.
- */
- if (!internal_tmp_table &&
- (!thd->current_stmt_binlog_row_based ||
- (thd->current_stmt_binlog_row_based &&
- !(create_info->options & HA_LEX_CREATE_TMP_TABLE))))
- write_bin_log(thd, TRUE, thd->query, thd->query_length);
error= FALSE;
unlock_and_end:
pthread_mutex_unlock(&LOCK_open);
@@ -4030,16 +4019,14 @@ error_remove_new_frm:
/**
- Database locking and foreign keys aware wrapper for
+ Database locking, foreign keys and binary log aware wrapper for
mysql_create_table_no_lock().
*/
bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
TABLE_LIST *fkey_tables,
HA_CREATE_INFO *create_info,
- Alter_info *alter_info,
- bool internal_tmp_table,
- uint select_field_count)
+ Alter_info *alter_info)
{
TABLE_LIST *tab;
bool result;
@@ -4113,8 +4100,7 @@ bool mysql_create_table(THD *thd, TABLE_
create_table->table_name,
create_info,
alter_info,
- internal_tmp_table,
- select_field_count);
+ FALSE, 0);
if (opt_fk_all_engines &&
!(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
@@ -4126,6 +4112,20 @@ bool mysql_create_table(THD *thd, TABLE_
result= TRUE;
}
+ /*
+ Don't write statement if:
+ - Table creation has failed
+ - Table has already existed
+ - Row-based logging is used and we are creating a temporary table
+ Otherwise, the statement shall be binlogged.
+ */
+ if (!result &&
+ !create_info->table_existed &&
+ (!thd->current_stmt_binlog_row_based ||
+ (thd->current_stmt_binlog_row_based &&
+ !(create_info->options & HA_LEX_CREATE_TMP_TABLE))))
+ write_bin_log(thd, TRUE, thd->query, thd->query_length);
+
close_and_unlock:
if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
{
@@ -5031,58 +5031,6 @@ bool mysql_preload_keys(THD* thd, TABLE_
}
-
-/**
- @brief Create frm file based on I_S table
-
- @param[in] thd thread handler
- @param[in] schema_table I_S table
- @param[in] dst_path path where frm should be created
- @param[in] create_info Create info
-
- @return Operation status
- @retval 0 success
- @retval 1 error
-*/
-
-
-bool mysql_create_like_schema_frm(THD* thd,
- TABLE_LIST* schema_table,
- char *dst_path, HA_CREATE_INFO *create_info)
-{
- HA_CREATE_INFO local_create_info;
- Alter_info alter_info;
- bool tmp_table= (create_info->options & HA_LEX_CREATE_TMP_TABLE);
- uint keys= schema_table->table->s->keys;
- uint db_options= 0;
- DBUG_ENTER("mysql_create_like_schema_frm");
-
- bzero((char*) &local_create_info, sizeof(local_create_info));
- local_create_info.db_type= schema_table->table->s->db_type();
- local_create_info.row_type= schema_table->table->s->row_type;
- local_create_info.default_table_charset=default_charset_info;
- alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
- schema_table->table->use_all_columns();
- if (mysql_prepare_alter_table(thd, schema_table, &local_create_info,
- &alter_info))
- DBUG_RETURN(1);
- if (mysql_prepare_create_table(thd, &local_create_info, &alter_info,
- tmp_table, &db_options,
- schema_table->table->file,
- &schema_table->table->s->key_info, &keys, 0))
- DBUG_RETURN(1);
- local_create_info.max_rows= 0;
- if (mysql_create_frm(thd, dst_path, NullS, NullS,
- &local_create_info, alter_info.create_list,
- keys, schema_table->table->s->key_info,
- alter_info.foreign_key_list,
- alter_info.parent_foreign_key_list,
- schema_table->table->file))
- DBUG_RETURN(1);
- DBUG_RETURN(0);
-}
-
-
/*
Create a table identical to the specified table
@@ -5101,142 +5049,76 @@ bool mysql_create_like_schema_frm(THD* t
bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
HA_CREATE_INFO *create_info)
{
- MDL_LOCK_DATA *target_lock_data= 0;
- char src_path[FN_REFLEN], dst_path[FN_REFLEN];
- uint dst_path_length;
- char *db= table->db;
- char *table_name= table->table_name;
- int err;
+
+ HA_CREATE_INFO local_create_info;
+ Alter_info local_alter_info;
bool res= TRUE;
uint not_used;
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- char tmp_path[FN_REFLEN];
-#endif
DBUG_ENTER("mysql_create_like_table");
-
- /*
- By opening source table and thus acquiring shared metadata lock on it
- we guarantee that it exists and no concurrent DDL operation will mess
- with it. Later we also take an exclusive metadata lock on target table
- name, which makes copying of .frm file, call to ha_create_table() and
- binlogging atomic against concurrent DML and DDL operations on target
- table. Thus by holding both these "locks" we ensure that our statement
- is properly isolated from all concurrent operations which matter.
- */
- if (open_tables(thd, &src_table, ¬_used, 0))
- DBUG_RETURN(TRUE);
-
- strxmov(src_path, src_table->table->s->path.str, reg_ext, NullS);
-
- DBUG_EXECUTE_IF("sleep_create_like_before_check_if_exists", my_sleep(6000000););
-
- /*
- Check that destination tables does not exist. Note that its name
- was already checked when it was added to the table list.
- */
- if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
+ if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
+ thd->locked_tables_mode)
{
- if (find_temporary_table(thd, db, table_name))
- goto table_exists;
- dst_path_length= build_tmptable_filename(thd, dst_path, sizeof(dst_path));
- create_info->table_options|= HA_CREATE_DELAY_KEY_WRITE;
- }
- else
- {
- if (lock_table_name_if_not_cached(thd, db, table_name, &target_lock_data))
- goto err;
- if (!target_lock_data)
- goto table_exists;
- dst_path_length= build_table_filename(dst_path, sizeof(dst_path),
- db, table_name, reg_ext, 0);
- if (!access(dst_path, F_OK))
- goto table_exists;
/*
- Make the metadata lock available to open_table() called to
- reopen the table down the road.
+ Since under LOCK TABLES attempt to acquire exclusive metadata lock
+ on the table to be created (and thus not locked) can lead to deadlock
+ we prohibit creation of non-temporary tables under LOCK TABLES.
*/
- table->mdl_lock_data= target_lock_data;
- }
-
- DBUG_EXECUTE_IF("sleep_create_like_before_copy", my_sleep(6000000););
-
- /*
- Create a new table by copying from source table
-
- TODO: Obtaining LOCK_open mutex here is actually a legacy from the
- times when some operations (e.g. I_S implementation) ignored
- exclusive metadata lock on target table. Also some engines
- (e.g. NDB cluster) require that LOCK_open should be held
- during the call to ha_create_table() (See bug #28614 for more
- info). So we should double check and probably fix this code
- to not acquire this mutex.
- */
- pthread_mutex_lock(&LOCK_open);
- if (src_table->schema_table)
- {
- if (mysql_create_like_schema_frm(thd, src_table, dst_path,
- create_info))
- {
- pthread_mutex_unlock(&LOCK_open);
- goto err;
- }
- }
- else if (my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE)))
- {
- if (my_errno == ENOENT)
- my_error(ER_BAD_DB_ERROR,MYF(0),db);
- else
- my_error(ER_CANT_CREATE_FILE,MYF(0),dst_path,my_errno);
- pthread_mutex_unlock(&LOCK_open);
+ my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
goto err;
}
/*
- As mysql_truncate don't work on a new table at this stage of
- creation, instead create the table directly (for both normal
- and temporary tables).
+ We open source table to get its description in HA_CREATE_INFO and
+ Alter_info objects. This also acquires a shared metadata lock on
+ this table which ensures that no concurrent DDL operation will
+ mess with it.
+ Also in case when we create non-temporary table open_tables()
+ call obtains an exclusive metadata lock on target table ensuring
+ that we can safely perform table creation.
+ Thus by holding both these "locks" we ensure that our statement
+ is properly isolated from all concurrent operations which matter.
*/
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- /*
- For partitioned tables we need to copy the .par file as well since
- it is used in open_table_def to even be able to create a new handler.
- There is no way to find out here if the original table is a
- partitioned table so we copy the file and ignore any errors.
- */
- fn_format(tmp_path, dst_path, reg_ext, ".par", MYF(MY_REPLACE_EXT));
- strmov(dst_path, tmp_path);
- fn_format(tmp_path, src_path, reg_ext, ".par", MYF(MY_REPLACE_EXT));
- strmov(src_path, tmp_path);
- my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE));
-#endif
-
- DBUG_EXECUTE_IF("sleep_create_like_before_ha_create", my_sleep(6000000););
+ if (open_tables(thd, &thd->lex->query_tables, ¬_used, 0))
+ goto err;
+ src_table->table->use_all_columns();
- dst_path[dst_path_length - reg_ext_length]= '\0'; // Remove .frm
- if (thd->variables.keep_files_on_create)
- create_info->options|= HA_CREATE_KEEP_FILES;
- err= ha_create_table(thd, dst_path, db, table_name, create_info, 1);
- pthread_mutex_unlock(&LOCK_open);
+ /* Fill HA_CREATE_INFO and Alter_info with description of source table. */
+ bzero((char*) &local_create_info, sizeof(local_create_info));
+ local_create_info.db_type= src_table->table->s->db_type();
+ local_create_info.row_type= src_table->table->s->row_type;
+ if (mysql_prepare_alter_table(thd, src_table, &local_create_info,
+ &local_alter_info))
+ goto err;
+ /* Partition info is not handled by mysql_prepare_alter_table() call. */
+ if (src_table->table->part_info)
+ thd->work_part_info= src_table->table->part_info->get_clone();
- if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
- {
- if (err || !open_temporary_table(thd, dst_path, db, table_name, 1,
- OTM_OPEN))
- {
- (void) rm_temporary_table(create_info->db_type,
- dst_path, false); /* purecov: inspected */
- goto err; /* purecov: inspected */
- }
- }
- else if (err)
- {
- (void) quick_rm_table(create_info->db_type, db,
- table_name, 0); /* purecov: inspected */
- goto err; /* purecov: inspected */
- }
+ /*
+ Adjust description of source table before using it for creation of
+ target table.
- DBUG_EXECUTE_IF("sleep_create_like_before_binlogging", my_sleep(6000000););
+ Similarly to SHOW CREATE TABLE we ignore MAX_ROWS attribute of
+ temporary table which represents I_S table.
+ */
+ if (src_table->schema_table)
+ local_create_info.max_rows= 0;
+ /* Set IF NOT EXISTS option as in the CREATE TABLE LIKE statement. */
+ local_create_info.options|= create_info->options&HA_LEX_CREATE_IF_NOT_EXISTS;
+ /* Replace type of source table with one specified in the statement. */
+ local_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
+ local_create_info.options|= create_info->options & HA_LEX_CREATE_TMP_TABLE;
+ /* Reset auto-increment counter for the new table. */
+ local_create_info.auto_increment_value= 0;
+ /* Remove info about foreign keys in which original table participates. */
+ local_alter_info.foreign_key_list.empty();
+ local_alter_info.parent_foreign_key_list.empty();
+
+ if ((res= mysql_create_table_no_lock(thd, table->db, table->table_name,
+ &local_create_info, &local_alter_info,
+ FALSE, 0)) ||
+ create_info->table_existed)
+ goto err;
/*
We have to write the query before we unlock the tables.
@@ -5302,28 +5184,7 @@ bool mysql_create_like_table(THD* thd, T
else
write_bin_log(thd, TRUE, thd->query, thd->query_length);
- res= FALSE;
- goto err;
-
-table_exists:
- if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
- {
- char warn_buff[MYSQL_ERRMSG_SIZE];
- my_snprintf(warn_buff, sizeof(warn_buff),
- ER(ER_TABLE_EXISTS_ERROR), table_name);
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_TABLE_EXISTS_ERROR,warn_buff);
- res= FALSE;
- }
- else
- my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
-
err:
- if (target_lock_data)
- {
- mdl_release_lock(&thd->mdl_context, target_lock_data);
- mdl_remove_lock(&thd->mdl_context, target_lock_data);
- }
DBUG_RETURN(res);
}
@@ -5990,12 +5851,9 @@ int create_temporary_table(THD *thd,
/*
Create a table with a temporary name.
With create_info->frm_only == 1 this creates a .frm file only.
- We don't log the statement, it will be logged later.
*/
- tmp_disable_binlog(thd);
error= mysql_create_table_no_lock(thd, new_db, tmp_name,
create_info, alter_info, 1, 0);
- reenable_binlog(thd);
DBUG_RETURN(error);
}