From 1abab6c7c7461bac95afd424e80b9a953fdf897b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 11 Jul 2007 10:49:54 +0300 Subject: [PATCH] Bug #29325: By default MyISAM overwrites .MYD and .MYI files no DATA DIRECTORY option is used. This can lead to two tables using the same .MYD and .MYI files (that can't be dropped). To prevent CREATE TABLE from overwriting a file a new option is introduced : keep_files_on_create When this is on the CREATE TABLE throws an error if either the .MYD or .MYI exists for a MyISAM table. The option is off by default (resulting in compatible behavior). include/my_base.h: Bug #29325: introduce keep_files_on_create myisam/mi_create.c: Bug #29325: introduce keep_files_on_create mysql-test/r/create.result: Bug #29325: test case mysql-test/t/create.test: Bug #29325: test case sql/ha_myisam.cc: Bug #29325: introduce keep_files_on_create sql/set_var.cc: Bug #29325: introduce keep_files_on_create sql/sql_class.h: Bug #29325: introduce keep_files_on_create sql/sql_table.cc: Bug #29325: introduce keep_files_on_create sql/unireg.cc: Bug #29325: introduce keep_files_on_create --- include/my_base.h | 1 + myisam/mi_create.c | 6 ++++-- mysql-test/r/create.result | 17 +++++++++++++++++ mysql-test/t/create.test | 31 +++++++++++++++++++++++++++++++ sql/ha_myisam.cc | 2 ++ sql/set_var.cc | 6 ++++++ sql/sql_class.h | 1 + sql/sql_table.cc | 2 ++ sql/unireg.cc | 2 ++ 9 files changed, 66 insertions(+), 2 deletions(-) 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));