summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexey Botchkov <holyfoot@askmonty.org>2012-09-27 13:18:07 +0500
committerAlexey Botchkov <holyfoot@askmonty.org>2012-09-27 13:18:07 +0500
commit8c2bb705f11956cdc0acb67182466a903dcdd19b (patch)
treec8f487bd40b036025a218c2815730a826dde75a5 /sql
parent2f5f360f17856d5a8aed28ead468542bdb63861e (diff)
downloadmariadb-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.h2
-rw-r--r--sql/mysqld.cc35
-rw-r--r--sql/set_var.cc3
-rw-r--r--sql/sql_show.cc281
-rw-r--r--sql/sql_show.h9
-rw-r--r--sql/table.cc3
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);
}