From 39e6083e35459c9c8b22d37aaa2b74545884c7b0 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Sun, 23 Mar 2014 17:00:29 +0200 Subject: [PATCH] MDEV-5818: MySQL WL#6145: Separate the dependence of DATA DIRECTORY from symbolic links Copied relevant test cases and code from the MySQL 5.6 tree Testing of my_use_symdir moved to engines. mysql-test/r/partition_windows.result: Updated result file mysql-test/suite/archive/archive_no_symlink-master.opt: Testing of symlinks with archive mysql-test/suite/archive/archive_no_symlink.result: Testing of symlinks with archive mysql-test/suite/archive/archive_no_symlink.test: Testing of symlinks with archive mysql-test/suite/archive/archive_symlink.result: Testing of symlinks with archive mysql-test/suite/archive/archive_symlink.test: Testing of symlinks with archive sql/log_event.cc: Updated comment sql/partition_info.cc: Don't test my_use_symdir here sql/sql_parse.cc: Updated comment sql/sql_table.cc: Don't test my_use_symdir here sql/table.cc: Added more DBUG_PRINT storage/archive/ha_archive.cc: Give warnings for index_file_name and if we can't use data directory storage/myisam/ha_myisam.cc: Give warnings if we can't use data directory or index directory --- mysql-test/r/partition_windows.result | 4 ++ .../archive/archive_no_symlink-master.opt | 1 + .../suite/archive/archive_no_symlink.result | 26 +++++++ .../suite/archive/archive_no_symlink.test | 26 +++++++ .../suite/archive/archive_symlink.result | 57 +++++++++++++++ mysql-test/suite/archive/archive_symlink.test | 72 +++++++++++++++++++ sql/log_event.cc | 6 +- sql/partition_info.cc | 4 +- sql/sql_parse.cc | 5 +- sql/sql_table.cc | 2 +- sql/table.cc | 1 + storage/archive/ha_archive.cc | 31 ++++++-- storage/myisam/ha_myisam.cc | 21 +++++- 13 files changed, 238 insertions(+), 18 deletions(-) create mode 100644 mysql-test/suite/archive/archive_no_symlink-master.opt create mode 100644 mysql-test/suite/archive/archive_no_symlink.result create mode 100644 mysql-test/suite/archive/archive_no_symlink.test create mode 100644 mysql-test/suite/archive/archive_symlink.result create mode 100644 mysql-test/suite/archive/archive_symlink.test diff --git a/mysql-test/r/partition_windows.result b/mysql-test/r/partition_windows.result index 756690925f8..dabcedcb3f9 100644 --- a/mysql-test/r/partition_windows.result +++ b/mysql-test/r/partition_windows.result @@ -26,5 +26,9 @@ ALTER TABLE t1 ADD PARTITION (PARTITION p3 DATA DIRECTORY = 'G:/mysqltest/p3Data Warnings: Warning 1618 option ignored Warning 1618 option ignored +Warning 1618 option ignored +Warning 1618 option ignored +Warning 1618 option ignored +Warning 1618 option ignored INSERT INTO t1 VALUES (NULL, "last", 4); DROP TABLE t1; diff --git a/mysql-test/suite/archive/archive_no_symlink-master.opt b/mysql-test/suite/archive/archive_no_symlink-master.opt new file mode 100644 index 00000000000..c7844699cdb --- /dev/null +++ b/mysql-test/suite/archive/archive_no_symlink-master.opt @@ -0,0 +1 @@ +--skip-symbolic-links diff --git a/mysql-test/suite/archive/archive_no_symlink.result b/mysql-test/suite/archive/archive_no_symlink.result new file mode 100644 index 00000000000..9ee114ae90f --- /dev/null +++ b/mysql-test/suite/archive/archive_no_symlink.result @@ -0,0 +1,26 @@ +# +# This test shows that DATA DIRECTORY and INDEX DIRECTORY are +# ignored where symbolic links are not supported such as Windows. +# +CREATE TABLE t1 ( +c1 int(10) unsigned NOT NULL AUTO_INCREMENT, +c2 varchar(30) NOT NULL, +c3 smallint(5) unsigned DEFAULT NULL, +PRIMARY KEY (c1)) +ENGINE = archive +DATA DIRECTORY = 'MYSQL_TMP_DIR/archive' INDEX DIRECTORY = 'MYSQL_TMP_DIR/archive'; +Warnings: +Warning 1618 option ignored +Warning 1618 option ignored +INSERT INTO t1 VALUES (NULL, "first", 1); +INSERT INTO t1 VALUES (NULL, "second", 2); +INSERT INTO t1 VALUES (NULL, "third", 3); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(10) unsigned NOT NULL AUTO_INCREMENT, + `c2` varchar(30) NOT NULL, + `c3` smallint(5) unsigned DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=ARCHIVE AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 +DROP TABLE t1; diff --git a/mysql-test/suite/archive/archive_no_symlink.test b/mysql-test/suite/archive/archive_no_symlink.test new file mode 100644 index 00000000000..737b8444007 --- /dev/null +++ b/mysql-test/suite/archive/archive_no_symlink.test @@ -0,0 +1,26 @@ +# Test archive engine when symbolic links are not available. +--source include/have_archive.inc + +--echo # +--echo # This test shows that DATA DIRECTORY and INDEX DIRECTORY are +--echo # ignored where symbolic links are not supported such as Windows. +--echo # + +let $data_directory = DATA DIRECTORY = '$MYSQL_TMP_DIR/archive'; +let $index_directory = INDEX DIRECTORY = '$MYSQL_TMP_DIR/archive'; + +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +eval CREATE TABLE t1 ( + c1 int(10) unsigned NOT NULL AUTO_INCREMENT, + c2 varchar(30) NOT NULL, + c3 smallint(5) unsigned DEFAULT NULL, + PRIMARY KEY (c1)) +ENGINE = archive +$data_directory $index_directory; + +INSERT INTO t1 VALUES (NULL, "first", 1); +INSERT INTO t1 VALUES (NULL, "second", 2); +INSERT INTO t1 VALUES (NULL, "third", 3); +SHOW CREATE TABLE t1; +DROP TABLE t1; + diff --git a/mysql-test/suite/archive/archive_symlink.result b/mysql-test/suite/archive/archive_symlink.result new file mode 100644 index 00000000000..de5c4c071d6 --- /dev/null +++ b/mysql-test/suite/archive/archive_symlink.result @@ -0,0 +1,57 @@ +# +# Archive can only use an existing directory for DATA DIRECTORY. +# +CREATE TABLE t1 (a int AUTO_INCREMENT KEY, b char(30)) +ENGINE archive DATA DIRECTORY = 'MYSQL_TMP_DIR/archive' INDEX DIRECTORY = 'MYSQL_TMP_DIR/archive'; +ERROR HY000: Can't create table `test`.`t1` (errno: 2 "No such file or directory") +# +# mkdir MYSQL_TMP_DIR/archive and try again... +# Archive will use a symlink for DATA DIRECTORY but ignore INDEX DIRECTORY. +# +CREATE TABLE t1 (a int AUTO_INCREMENT KEY, b char(30)) +ENGINE archive DATA DIRECTORY = 'MYSQL_TMP_DIR/archive' INDEX DIRECTORY = 'MYSQL_TMP_DIR/archive'; +Warnings: +Warning 1618 option ignored +INSERT INTO t1 VALUES (NULL, "blue"); +INSERT INTO t1 VALUES (NULL, "red"); +INSERT INTO t1 VALUES (NULL, "yellow"); +# Checking if archive file exists where we specified in DATA DIRECTORY +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL AUTO_INCREMENT, + `b` char(30) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=ARCHIVE AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQL_TMP_DIR/archive/' +DROP TABLE t1; +# +# Be sure SQL MODE "NO_DIR_IN_CREATE" prevents the use of DATA DIRECTORY +# +SET @org_mode=@@sql_mode; +SET @@sql_mode='NO_DIR_IN_CREATE'; +SELECT @@sql_mode; +@@sql_mode +NO_DIR_IN_CREATE +CREATE TABLE t1 (a int AUTO_INCREMENT KEY, b char(30)) +ENGINE archive DATA DIRECTORY = 'MYSQL_TMP_DIR/archive'; +Warnings: +Warning 1618 option ignored +INSERT INTO t1 VALUES (NULL, "blue"); +INSERT INTO t1 VALUES (NULL, "red"); +INSERT INTO t1 VALUES (NULL, "yellow"); +# Checking if archive file exists in --datadir since DATA DIRECTORY was ignored. +DROP TABLE t1; +set @@sql_mode=@org_mode; +# +# MySQL engine does not allow DATA DIRECTORY to be +# within --datadir for any engine, including Archive +# +CREATE TABLE t1 (a int AUTO_INCREMENT KEY, b char(30)) +ENGINE archive DATA DIRECTORY 'MYSQLD_DATADIR/test'; +ERROR HY000: Incorrect arguments to DATA DIRECTORY +CREATE TABLE t1 (c1 int(10), PRIMARY KEY (c1)) +ENGINE archive INDEX DIRECTORY 'MYSQLD_DATADIR/test'; +ERROR HY000: Incorrect arguments to INDEX DIRECTORY +# +# Cleanup +# diff --git a/mysql-test/suite/archive/archive_symlink.test b/mysql-test/suite/archive/archive_symlink.test new file mode 100644 index 00000000000..1c79e153146 --- /dev/null +++ b/mysql-test/suite/archive/archive_symlink.test @@ -0,0 +1,72 @@ +# Test archive engine when symbolic links are available. +--source include/not_windows.inc +--source include/have_archive.inc + +# DATA DIRECTORY/INDEX DIRECTORY require symbolic link support +--source include/have_symlink.inc + +let $MYSQLD_DATADIR= `select @@datadir`; +let $data_directory = DATA DIRECTORY = '$MYSQL_TMP_DIR/archive'; +let $index_directory = INDEX DIRECTORY = '$MYSQL_TMP_DIR/archive'; + +--echo # +--echo # Archive can only use an existing directory for DATA DIRECTORY. +--echo # +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +--error ER_CANT_CREATE_TABLE +eval CREATE TABLE t1 (a int AUTO_INCREMENT KEY, b char(30)) + ENGINE archive $data_directory $index_directory; + +--echo # +--echo # mkdir MYSQL_TMP_DIR/archive and try again... +--echo # Archive will use a symlink for DATA DIRECTORY but ignore INDEX DIRECTORY. +--echo # +--mkdir $MYSQL_TMP_DIR/archive +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +eval CREATE TABLE t1 (a int AUTO_INCREMENT KEY, b char(30)) + ENGINE archive $data_directory $index_directory; +INSERT INTO t1 VALUES (NULL, "blue"); +INSERT INTO t1 VALUES (NULL, "red"); +INSERT INTO t1 VALUES (NULL, "yellow"); +--echo # Checking if archive file exists where we specified in DATA DIRECTORY +--file_exists $MYSQL_TMP_DIR/archive/t1.ARZ +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--echo # +--echo # Be sure SQL MODE "NO_DIR_IN_CREATE" prevents the use of DATA DIRECTORY +--echo # +SET @org_mode=@@sql_mode; +SET @@sql_mode='NO_DIR_IN_CREATE'; +SELECT @@sql_mode; +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +eval CREATE TABLE t1 (a int AUTO_INCREMENT KEY, b char(30)) + ENGINE archive $data_directory; +INSERT INTO t1 VALUES (NULL, "blue"); +INSERT INTO t1 VALUES (NULL, "red"); +INSERT INTO t1 VALUES (NULL, "yellow"); +--echo # Checking if archive file exists in --datadir since DATA DIRECTORY was ignored. +--file_exists $MYSQLD_DATADIR/test/t1.ARZ +DROP TABLE t1; +set @@sql_mode=@org_mode; + +--echo # +--echo # MySQL engine does not allow DATA DIRECTORY to be +--echo # within --datadir for any engine, including Archive +--echo # +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +--error ER_WRONG_ARGUMENTS +eval CREATE TABLE t1 (a int AUTO_INCREMENT KEY, b char(30)) + ENGINE archive DATA DIRECTORY '$MYSQLD_DATADIR/test'; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +--error ER_WRONG_ARGUMENTS +eval CREATE TABLE t1 (c1 int(10), PRIMARY KEY (c1)) +ENGINE archive INDEX DIRECTORY '$MYSQLD_DATADIR/test'; + +--echo # +--echo # Cleanup +--echo # +--rmdir $MYSQL_TMP_DIR/archive + diff --git a/sql/log_event.cc b/sql/log_event.cc index 42b2a2206ae..7e2b82ae923 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4140,11 +4140,11 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, nothing to do. */ /* - We do not replicate IGNORE_DIR_IN_CREATE. That is, if the master is a - slave which runs with SQL_MODE=IGNORE_DIR_IN_CREATE, this should not + We do not replicate MODE_NO_DIR_IN_CREATE. That is, if the master is a + slave which runs with SQL_MODE=MODE_NO_DIR_IN_CREATE, this should not force us to ignore the dir too. Imagine you are a ring of machines, and one has a disk problem so that you temporarily need - IGNORE_DIR_IN_CREATE on this machine; you don't want it to propagate + MODE_NO_DIR_IN_CREATE on this machine; you don't want it to propagate elsewhere (you don't want all slaves to start ignoring the dirs). */ if (sql_mode_inited) diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 1ae62011b43..98e796879ad 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1574,9 +1574,7 @@ end: */ static void warn_if_dir_in_part_elem(THD *thd, partition_element *part_elem) { -#ifdef HAVE_READLINK - if (!my_use_symdir || (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)) -#endif + if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) { if (part_elem->data_file_name) push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 1891aa6147b..830661a5b81 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2854,14 +2854,13 @@ case SQLCOM_PREPARE: /* Might have been updated in create_table_precheck */ create_info.alias= create_table->alias; -#ifdef HAVE_READLINK - /* Fix names if symlinked tables */ + /* Fix names if symlinked or relocated tables */ if (append_file_to_dir(thd, &create_info.data_file_name, create_table->table_name) || append_file_to_dir(thd, &create_info.index_file_name, create_table->table_name)) goto end_with_restore_list; -#endif + /* If no engine type was given, work out the default now rather than at parse-time. diff --git a/sql/sql_table.cc b/sql/sql_table.cc index ee3b954168d..3d78727b4da 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4666,7 +4666,7 @@ int create_table_impl(THD *thd, DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d", db, table_name, internal_tmp_table)); - if (!my_use_symdir || (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)) + if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) { if (create_info->data_file_name) push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, diff --git a/sql/table.cc b/sql/table.cc index 268b35c409e..20343a108f6 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3024,6 +3024,7 @@ void open_table_error(TABLE_SHARE *share, enum open_frm_error error, char buff[FN_REFLEN]; const myf errortype= ME_ERROR+ME_WAITTANG; // Write fatals error to log DBUG_ENTER("open_table_error"); + DBUG_PRINT("info", ("error: %d db_errno: %d", error, db_errno)); switch (error) { case OPEN_FRM_OPEN_ERROR: diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index b30f1339510..fe6b611d1c6 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -104,7 +104,6 @@ >5.1.15 - v.3 */ - /* The file extension */ #define ARZ ".ARZ" // The data file #define ARN ".ARN" // Files used during an optimize call @@ -171,14 +170,14 @@ static void init_archive_psi_keys(void) const char* category= "archive"; int count; - if (PSI_server == NULL) + if (!PSI_server) return; - + count= array_elements(all_archive_mutexes); - PSI_server->register_mutex(category, all_archive_mutexes, count); + mysql_mutex_register(category, all_archive_mutexes, count); count= array_elements(all_archive_files); - PSI_server->register_file(category, all_archive_files, count); + mysql_file_register(category, all_archive_files, count); } #endif /* HAVE_PSI_INTERFACE */ @@ -765,7 +764,10 @@ int ha_archive::create(const char *name, TABLE *table_arg, /* We reuse name_buff since it is available. */ - if (create_info->data_file_name && create_info->data_file_name[0] != '#') +#ifdef HAVE_READLINK + if (my_use_symdir && + create_info->data_file_name && + create_info->data_file_name[0] != '#') { DBUG_PRINT("ha_archive", ("archive will create stream file %s", create_info->data_file_name)); @@ -776,12 +778,29 @@ int ha_archive::create(const char *name, TABLE *table_arg, MY_REPLACE_EXT | MY_UNPACK_FILENAME); } else +#endif /* HAVE_READLINK */ { + if (create_info->data_file_name) + { + push_warning_printf(table_arg->in_use, Sql_condition::WARN_LEVEL_WARN, + WARN_OPTION_IGNORED, + ER_DEFAULT(WARN_OPTION_IGNORED), + "DATA DIRECTORY"); + } fn_format(name_buff, name, "", ARZ, MY_REPLACE_EXT | MY_UNPACK_FILENAME); linkname[0]= 0; } + /* Archive engine never uses INDEX DIRECTORY. */ + if (create_info->index_file_name) + { + push_warning_printf(table_arg->in_use, Sql_condition::WARN_LEVEL_WARN, + WARN_OPTION_IGNORED, + ER_DEFAULT(WARN_OPTION_IGNORED), + "INDEX DIRECTORY"); + } + /* There is a chance that the file was "discovered". In this case just use whatever file is there. diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 18f0c3b7f60..c997f03463a 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -2006,10 +2006,27 @@ int ha_myisam::create(const char *name, register TABLE *table_arg, (ulonglong) 0); create_info.data_file_length= ((ulonglong) share->max_rows * share->avg_row_length); - create_info.data_file_name= ha_create_info->data_file_name; - create_info.index_file_name= ha_create_info->index_file_name; create_info.language= share->table_charset->number; +#ifdef HAVE_READLINK + if (my_use_symdir) + { + create_info.data_file_name= ha_create_info->data_file_name; + create_info.index_file_name= ha_create_info->index_file_name; + } + else +#endif /* HAVE_READLINK */ + { + if (ha_create_info->data_file_name) + push_warning_printf(table_arg->in_use, Sql_condition::WARN_LEVEL_WARN, + WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED), + "DATA DIRECTORY"); + if (ha_create_info->index_file_name) + push_warning_printf(table_arg->in_use, Sql_condition::WARN_LEVEL_WARN, + WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED), + "INDEX DIRECTORY"); + } + if (ha_create_info->tmp_table()) create_flags|= HA_CREATE_TMP_TABLE | HA_CREATE_DELAY_KEY_WRITE; if (ha_create_info->options & HA_CREATE_KEEP_FILES)