diff options
author | Alexey Botchkov <holyfoot@askmonty.org> | 2012-09-27 13:18:07 +0500 |
---|---|---|
committer | Alexey Botchkov <holyfoot@askmonty.org> | 2012-09-27 13:18:07 +0500 |
commit | 8c2bb705f11956cdc0acb67182466a903dcdd19b (patch) | |
tree | c8f487bd40b036025a218c2815730a826dde75a5 /sql | |
parent | 2f5f360f17856d5a8aed28ead468542bdb63861e (diff) | |
download | mariadb-git-8c2bb705f11956cdc0acb67182466a903dcdd19b.tar.gz |
MDEV-495 backport --ignore-db-dir.
The feature was backported from MySQL 5.6.
Some code was added to make commands as
SELECT * FROM ignored_db.t1;
CALL ignored_db.proc();
USE ignored_db;
to take that option into account.
per-file comments:
mysql-test/r/ignore_db_dirs_basic.result
test result added.
mysql-test/t/ignore_db_dirs_basic-master.opt
options for the test,
actually the set of --ignore-db-dir lines.
mysql-test/t/ignore_db_dirs_basic.test
test for the feature.
Same test from 5.6 was taken as a basis,
then tests for SELECT, CALL etc were added.
per-file comments:
sql/mysql_priv.h
MDEV-495 backport --ignore-db-dir.
interface for db_name_is_in_ignore_list() added.
sql/mysqld.cc
MDEV-495 backport --ignore-db-dir.
--ignore-db-dir handling.
sql/set_var.cc
MDEV-495 backport --ignore-db-dir.
the @@ignore_db_dirs variable added.
sql/sql_show.cc
MDEV-495 backport --ignore-db-dir.
check if the directory is ignored.
sql/sql_show.h
MDEV-495 backport --ignore-db-dir.
interface added for opt_ignored_db_dirs.
sql/table.cc
MDEV-495 backport --ignore-db-dir.
check if the directory is ignored.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/mysql_priv.h | 2 | ||||
-rw-r--r-- | sql/mysqld.cc | 35 | ||||
-rw-r--r-- | sql/set_var.cc | 3 | ||||
-rw-r--r-- | sql/sql_show.cc | 281 | ||||
-rw-r--r-- | sql/sql_show.h | 9 | ||||
-rw-r--r-- | sql/table.cc | 3 |
6 files changed, 332 insertions, 1 deletions
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 14810fc7119..5f20e9f0591 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -2834,6 +2834,8 @@ bool load_collation(MEM_ROOT *mem_root, CHARSET_INFO *dflt_cl, CHARSET_INFO **cl); +bool db_name_is_in_ignore_db_dirs_list(const char *dbase); + #endif /* MYSQL_SERVER */ extern "C" int test_if_data_home_dir(const char *dir); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 26fd22ef95b..e6653e410cb 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -33,6 +33,7 @@ #include <waiting_threads.h> #include "debug_sync.h" #include "log_event.h" +#include "sql_show.h" #include "../storage/myisam/ha_myisam.h" @@ -1447,6 +1448,7 @@ void clean_up(bool print_message) #endif my_tz_free(); my_database_names_free(); + ignore_db_dirs_free(); #ifndef NO_EMBEDDED_ACCESS_CHECKS servers_free(1); acl_free(1); @@ -3332,6 +3334,9 @@ static int init_common_variables(const char *conf_file_name, int argc, mysql_init_variables()) return 1; + if (ignore_db_dirs_init()) + return 1; + #ifdef HAVE_TZNAME { struct tm tm_tmp; @@ -3677,6 +3682,12 @@ You should consider changing lower_case_table_names to 1 or 2", files_charset_info : &my_charset_bin); + if (ignore_db_dirs_process_additions()) + { + sql_print_error("An error occurred while storing ignore_db_dirs to a hash."); + return 1; + } + return 0; } @@ -5999,7 +6010,8 @@ enum options_mysqld OPT_MAX_LONG_DATA_SIZE, OPT_MASTER_VERIFY_CHECKSUM, OPT_SLAVE_SQL_VERIFY_CHECKSUM, - OPT_QUERY_CACHE_STRIP_COMMENTS + OPT_QUERY_CACHE_STRIP_COMMENTS, + OPT_IGNORE_DB_DIRECTORY }; @@ -6288,6 +6300,11 @@ struct my_option my_long_options[] = each time the SQL thread starts.", &opt_init_slave, &opt_init_slave, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"ignore-db-dir", OPT_IGNORE_DB_DIRECTORY, + "Specifies a directory to add to the ignore list when collecting " + "database names from the datadir. Put a blank argument to reset " + "the list accumulated so far.", 0, 0, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, {"language", 'L', "Client error messages in given language. May be given as a full path.", &language_ptr, &language_ptr, 0, GET_STR, REQUIRED_ARG, @@ -9286,6 +9303,22 @@ mysqld_get_one_option(int optid, case OPT_MAX_LONG_DATA_SIZE: max_long_data_size_used= true; break; + + + case OPT_IGNORE_DB_DIRECTORY: + if (*argument == 0) + ignore_db_dirs_reset(); + else + { + if (push_ignored_db_dir(argument)) + { + sql_print_error("Can't start server: " + "cannot process --ignore-db-dir=%.*s", + FN_REFLEN, argument); + return 1; + } + } + break; } return 0; } diff --git a/sql/set_var.cc b/sql/set_var.cc index c52e415e657..94a1b6a1cef 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -67,6 +67,7 @@ #include <my_dir.h> #include <waiting_threads.h> #include "events.h" +#include "sql_show.h" // opt_ignore_db_dirs /* WITH_NDBCLUSTER_STORAGE_ENGINE */ #ifdef WITH_NDBCLUSTER_STORAGE_ENGINE @@ -1013,6 +1014,8 @@ static sys_var_readonly sys_in_transaction(&vars, "in_transaction", OPT_SESSION, SHOW_BOOL, in_transaction); +static sys_var_const_str_ptr sys_ignore_db_dirs(&vars, "ignore_db_dirs", + &opt_ignore_db_dirs); bool sys_var::check(THD *thd, set_var *var) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 0a23a95bbcf..562ccea488f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -379,6 +379,284 @@ bool mysqld_show_privileges(THD *thd) } +/** Hash of LEX_STRINGs used to search for ignored db directories. */ +static HASH ignore_db_dirs_hash; + +/** + An array of LEX_STRING pointers to collect the options at + option parsing time. +*/ +static DYNAMIC_ARRAY ignore_db_dirs_array; + +/** + A value for the read only system variable to show a list of + ignored directories. +*/ +char *opt_ignore_db_dirs= NULL; + +/** + This flag is ON if: + - the list of ignored directories is not empty + + - and some of the ignored directory names + need no tablename-to-filename conversion. + Otherwise, if the name of the directory contains + unconditional characters like '+' or '.', they + never can match the database directory name. So the + db_name_is_in_ignore_db_dirs_list() can just return at once. +*/ +static bool skip_ignored_dir_check= TRUE; + +/** + Sets up the data structures for collection of directories at option + processing time. + We need to collect the directories in an array first, because + we need the character sets initialized before setting up the hash. + + @return state + @retval TRUE failed + @retval FALSE success +*/ + +bool +ignore_db_dirs_init() +{ + return my_init_dynamic_array(&ignore_db_dirs_array, sizeof(LEX_STRING *), + 0, 0); +} + + +/** + Retrieves the key (the string itself) from the LEX_STRING hash members. + + Needed by hash_init(). + + @param data the data element from the hash + @param out len_ret Placeholder to return the length of the key + @param unused + @return a pointer to the key +*/ + +static uchar * +db_dirs_hash_get_key(const uchar *data, size_t *len_ret, + my_bool __attribute__((unused))) +{ + LEX_STRING *e= (LEX_STRING *) data; + + *len_ret= e->length; + return (uchar *) e->str; +} + + +/** + Wrap a directory name into a LEX_STRING and push it to the array. + + Called at option processing time for each --ignore-db-dir option. + + @param path the name of the directory to push + @return state + @retval TRUE failed + @retval FALSE success +*/ + +bool +push_ignored_db_dir(char *path) +{ + LEX_STRING *new_elt; + char *new_elt_buffer; + size_t path_len= strlen(path); + + if (!path_len || path_len >= FN_REFLEN) + return true; + + // No need to normalize, it's only a directory name, not a path. + if (!my_multi_malloc(0, + &new_elt, sizeof(LEX_STRING), + &new_elt_buffer, path_len + 1, + NullS)) + return true; + new_elt->str= new_elt_buffer; + memcpy(new_elt_buffer, path, path_len); + new_elt_buffer[path_len]= 0; + new_elt->length= path_len; + return insert_dynamic(&ignore_db_dirs_array, (uchar*) &new_elt); +} + + +/** + Clean up the directory ignore options accumulated so far. + + Called at option processing time for each --ignore-db-dir option + with an empty argument. +*/ + +void +ignore_db_dirs_reset() +{ + LEX_STRING **elt; + while (NULL!= (elt= (LEX_STRING **) pop_dynamic(&ignore_db_dirs_array))) + if (elt && *elt) + my_free(*elt, MYF(0)); +} + + +/** + Free the directory ignore option variables. + + Called at server shutdown. +*/ + +void +ignore_db_dirs_free() +{ + if (opt_ignore_db_dirs) + { + my_free(opt_ignore_db_dirs, MYF(0)); + opt_ignore_db_dirs= NULL; + } + ignore_db_dirs_reset(); + delete_dynamic(&ignore_db_dirs_array); + my_hash_free(&ignore_db_dirs_hash); +} + + +/** + Initialize the ignore db directories hash and status variable from + the options collected in the array. + + Called when option processing is over and the server's in-memory + structures are fully initialized. + + @return state + @retval TRUE failed + @retval FALSE success +*/ + +static void dispose_db_dir(void *ptr) +{ + my_free(ptr, MYF(0)); +} + + +bool +ignore_db_dirs_process_additions() +{ + ulong i; + size_t len; + char *ptr; + LEX_STRING *dir; + + + DBUG_ASSERT(opt_ignore_db_dirs == NULL); + + skip_ignored_dir_check= TRUE; + + if (my_hash_init(&ignore_db_dirs_hash, + lower_case_table_names ? + character_set_filesystem : &my_charset_bin, + 0, 0, 0, db_dirs_hash_get_key, + dispose_db_dir, + HASH_UNIQUE)) + return true; + + /* len starts from 1 because of the terminating zero. */ + len= 1; + for (i= 0; i < ignore_db_dirs_array.elements; i++) + { + get_dynamic(&ignore_db_dirs_array, (uchar *) &dir, i); + len+= dir->length + 1; // +1 for the comma + if (skip_ignored_dir_check) + { + char buff[FN_REFLEN]; + uint buff_len; + buff_len= tablename_to_filename(dir->str, buff, sizeof(buff)); + skip_ignored_dir_check= strcmp(dir->str, buff) != 0; + } + } + + /* No delimiter for the last directory. */ + if (len > 1) + len--; + + /* +1 the terminating zero */ + ptr= opt_ignore_db_dirs= (char *) my_malloc(len + 1, MYF(0)); + if (!ptr) + return true; + + /* Make sure we have an empty string to start with. */ + *ptr= 0; + + for (i= 0; i < ignore_db_dirs_array.elements; i++) + { + get_dynamic(&ignore_db_dirs_array, (uchar *) &dir, i); + if (my_hash_insert(&ignore_db_dirs_hash, (uchar *) dir)) + return true; + ptr= strnmov(ptr, dir->str, dir->length); + if (i + 1 < ignore_db_dirs_array.elements) + ptr= strmov(ptr, ","); + + /* + Set the transferred array element to NULL to avoid double free + in case of error. + */ + dir= NULL; + set_dynamic(&ignore_db_dirs_array, (uchar *) &dir, i); + } + + /* make sure the string is terminated */ + DBUG_ASSERT(ptr - opt_ignore_db_dirs <= (ptrdiff_t) len); + *ptr= 0; + + /* + It's OK to empty the array here as the allocated elements are + referenced through the hash now. + */ + reset_dynamic(&ignore_db_dirs_array); + + return false; +} + + +/** + Check if a directory name is in the hash of ignored directories. + + @return search result + @retval TRUE found + @retval FALSE not found +*/ + +static inline bool +is_in_ignore_db_dirs_list(const char *directory) +{ + return ignore_db_dirs_hash.records && + NULL != my_hash_search(&ignore_db_dirs_hash, (const uchar *) directory, + strlen(directory)); +} + + +/** + Check if a database name is in the hash of ignored directories. + + @return search result + @retval TRUE found + @retval FALSE not found +*/ + +bool +db_name_is_in_ignore_db_dirs_list(const char *directory) +{ + char buff[FN_REFLEN]; + uint buff_len; + + if (skip_ignored_dir_check) + return 0; + + buff_len= tablename_to_filename(directory, buff, sizeof(buff)); + + return my_hash_search(&ignore_db_dirs_hash, (uchar *) buff, buff_len)!=NULL; +} + + /*************************************************************************** List all column types ***************************************************************************/ @@ -552,6 +830,9 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db, if (!MY_S_ISDIR(file->mystat->st_mode)) continue; + if (is_in_ignore_db_dirs_list(file->name)) + continue; + file_name_len= filename_to_tablename(file->name, uname, sizeof(uname)); if (wild) { diff --git a/sql/sql_show.h b/sql/sql_show.h index fec73122e8b..e3077c560d7 100644 --- a/sql/sql_show.h +++ b/sql/sql_show.h @@ -41,4 +41,13 @@ int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff); int copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table); + +/* Handle the ignored database directories list for SHOW/I_S. */ +bool ignore_db_dirs_init(); +void ignore_db_dirs_free(); +void ignore_db_dirs_reset(); +bool ignore_db_dirs_process_additions(); +bool push_ignored_db_dir(char *path); +extern char *opt_ignore_db_dirs; + #endif /* SQL_SHOW_H */ diff --git a/sql/table.cc b/sql/table.cc index 2be94c55205..0247dc167ee 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3197,6 +3197,9 @@ bool check_db_name(LEX_STRING *org_name) if (lower_case_table_names && name != any_db) my_casedn_str(files_charset_info, name); + if (db_name_is_in_ignore_db_dirs_list(name)) + return 1; + return check_table_name(name, name_length, check_for_path_chars); } |