diff --git a/include/my_base.h b/include/my_base.h index d07a4de8e6a..d8732808cee 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -279,6 +279,7 @@ enum ha_base_keytype { #define HA_PACK_RECORD 2 /* Request packed record format */ #define HA_CREATE_TMP_TABLE 4 #define HA_CREATE_CHECKSUM 8 +#define HA_CREATE_KEEP_FILES 16 /* don't overwrite .MYD and MYI */ #define HA_CREATE_DELAY_KEY_WRITE 64 /* diff --git a/myisam/mi_create.c b/myisam/mi_create.c index ea1d8c7b83e..dd8a5b0d525 100644 --- a/myisam/mi_create.c +++ b/myisam/mi_create.c @@ -586,7 +586,8 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, 32 : 0)); linkname_ptr=0; /* Replace the current file */ - create_flag=MY_DELETE_OLD; + if (!(flags & HA_CREATE_KEEP_FILES)) + create_flag=MY_DELETE_OLD; } /* @@ -647,7 +648,8 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, { fn_format(filename,name,"",MI_NAME_DEXT,4); linkname_ptr=0; - create_flag=MY_DELETE_OLD; + if (!(flags & HA_CREATE_KEEP_FILES)) + create_flag=MY_DELETE_OLD; } if ((dfile= my_create_with_symlink(linkname_ptr, filename, 0, create_mode, diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index e692dbf3938..16bc534ba92 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -1503,4 +1503,21 @@ t1 CREATE TABLE `t1` ( `c17` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +CREATE DATABASE db1; +CREATE DATABASE db2; +USE db2; +INSERT INTO db2.t1 VALUES (1); +SELECT * FROM db2.t1; +b +1 +RESET QUERY CACHE; +USE db1; +SET SESSION keep_files_on_create = TRUE; +CREATE TABLE t1 (a INT) ENGINE MYISAM; +ERROR HY000: Can't create/write to file './db1/t1.MYD' (Errcode: 17) +SET SESSION keep_files_on_create = DEFAULT; +DROP TABLE db2.t1; +DROP DATABASE db1; +DROP DATABASE db2; +USE test; End of 5.0 tests diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 99f3fea416a..610a208ebf0 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -1118,5 +1118,36 @@ show create table t1; drop table t1; +# +# Bug #29325: create table overwrites .MYD file of other table (datadir) +# + +CREATE DATABASE db1; +CREATE DATABASE db2; + +USE db2; +--disable_query_log +eval CREATE TABLE t1 (b INT) ENGINE MYISAM +DATA DIRECTORY = '$MYSQLTEST_VARDIR/master-data/db1/'; +--enable_query_log + +INSERT INTO db2.t1 VALUES (1); +SELECT * FROM db2.t1; +RESET QUERY CACHE; + +USE db1; + +#no warning from create table +SET SESSION keep_files_on_create = TRUE; +--disable_abort_on_error +CREATE TABLE t1 (a INT) ENGINE MYISAM; +--enable_abort_on_error +SET SESSION keep_files_on_create = DEFAULT; + +DROP TABLE db2.t1; +DROP DATABASE db1; +DROP DATABASE db2; +USE test; + --echo End of 5.0 tests diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 5e953092436..4efa19bad78 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -1809,6 +1809,8 @@ int ha_myisam::create(const char *name, register TABLE *table_arg, if (ha_create_info->options & HA_LEX_CREATE_TMP_TABLE) create_flags|= HA_CREATE_TMP_TABLE; + if (ha_create_info->options & HA_CREATE_KEEP_FILES) + create_flags|= HA_CREATE_KEEP_FILES; if (options & HA_OPTION_PACK_RECORD) create_flags|= HA_PACK_RECORD; if (options & HA_OPTION_CHECKSUM) diff --git a/sql/set_var.cc b/sql/set_var.cc index 09cdc34f803..b30aa008366 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -592,6 +592,10 @@ sys_var_const_str sys_license("license", STRINGIFY_ARG(LICENSE)); /* Global read-only variable containing hostname */ sys_var_const_str sys_hostname("hostname", glob_hostname); +sys_var_thd_bool sys_keep_files_on_create("keep_files_on_create", + &SV::keep_files_on_create); + + /* @@ -637,6 +641,7 @@ sys_var *sys_variables[]= &sys_delayed_insert_limit, &sys_delayed_insert_timeout, &sys_delayed_queue_size, + &sys_keep_files_on_create, &sys_error_count, &sys_expire_logs_days, &sys_flush, @@ -849,6 +854,7 @@ struct show_var_st init_vars[]= { {sys_delayed_insert_timeout.name, (char*) &sys_delayed_insert_timeout, SHOW_SYS}, {sys_delayed_queue_size.name,(char*) &sys_delayed_queue_size, SHOW_SYS}, {sys_div_precincrement.name,(char*) &sys_div_precincrement,SHOW_SYS}, + {sys_keep_files_on_create.name,(char*) &sys_keep_files_on_create, SHOW_SYS}, {sys_engine_condition_pushdown.name, (char*) &sys_engine_condition_pushdown, SHOW_SYS}, {sys_expire_logs_days.name, (char*) &sys_expire_logs_days, SHOW_SYS}, diff --git a/sql/sql_class.h b/sql/sql_class.h index a5cbc21684f..112538cbe95 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -566,6 +566,7 @@ struct system_variables my_bool new_mode; my_bool query_cache_wlock_invalidate; my_bool engine_condition_pushdown; + my_bool keep_files_on_create; #ifdef HAVE_INNOBASE_DB my_bool innodb_table_locks; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 87f23097a66..e02595836ca 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2841,6 +2841,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST *src_table, and temporary tables). */ *fn_ext(dst_path)= 0; + if (thd->variables.keep_files_on_create) + create_info->options|= HA_CREATE_KEEP_FILES; err= ha_create_table(dst_path, create_info, 1); if (create_info->options & HA_LEX_CREATE_TMP_TABLE) diff --git a/sql/unireg.cc b/sql/unireg.cc index c01e6a0f00c..d8e63bb78e1 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -285,6 +285,8 @@ int rea_create_table(THD *thd, my_string file_name, if (mysql_create_frm(thd, file_name, db, table, create_info, create_fields, keys, key_info, NULL)) DBUG_RETURN(1); + if (thd->variables.keep_files_on_create) + create_info->options|= HA_CREATE_KEEP_FILES; if (!create_info->frm_only && ha_create_table(file_name,create_info,0)) { my_delete(file_name,MYF(0));