[Commits] Rev 3578: MDEV-495 backport --ignore-db-dir. in file:///home/hf/wmar/mdev495/

holyfoot at askmonty.org holyfoot at askmonty.org
Wed Sep 26 14:04:46 EEST 2012


At file:///home/hf/wmar/mdev495/

------------------------------------------------------------
revno: 3578
revision-id: holyfoot at askmonty.org-20120926095326-nkl0531j7xp3lobo
parent: sanja at montyprogram.com-20120920094859-lcrxe8lr1mtg8h10
committer: Alexey Botchkov <holyfoot at askmonty.org>
branch nick: mdev495
timestamp: Wed 2012-09-26 14:53:26 +0500
message:
  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.
-------------- next part --------------
=== added file 'mysql-test/r/ignore_db_dirs_basic.result'
--- a/mysql-test/r/ignore_db_dirs_basic.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/ignore_db_dirs_basic.result	2012-09-26 09:53:26 +0000
@@ -0,0 +1,47 @@
+select @@ignore_db_dirs;
+@@ignore_db_dirs
+e,lost+found,.mysqlgui,ignored_db
+# Check that SHOW DATABASES ignores all directories from
+# @@ignore_db_dirs and all directories with names starting
+# with '.'
+SHOW DATABASES;
+Database
+information_schema
+#mysql50#.otherdir
+mtr
+mysql
+test
+USE ignored_db;
+ERROR 42000: Incorrect database name 'ignored_db'
+SELECT * FROM ignored_db.t1;
+ERROR 42000: Incorrect database name 'ignored_db'
+CALL ignored_db.p1();
+ERROR 42000: Incorrect database name 'ignored_db'
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='ignored_db';
+COUNT(*)
+1
+CREATE DATABASE ignored_db;
+ERROR 42000: Incorrect database name 'ignored_db'
+CREATE DATABASE `lost+found`;
+USE `lost+found`;
+CREATE TABLE t1(id INT);
+INSERT INTO t1 VALUES (1), (2);
+SELECT * FROM `lost+found`.t1;
+id
+1
+2
+SHOW DATABASES;
+Database
+information_schema
+#mysql50#.otherdir
+lost+found
+mtr
+mysql
+test
+DROP DATABASE `lost+found`;
+SET @@global.ignore_db_dirs = 'aha';
+ERROR HY000: Variable 'ignore_db_dirs' is a read only variable
+SET @@local.ignore_db_dirs = 'aha';
+ERROR HY000: Variable 'ignore_db_dirs' is a read only variable
+SET @@ignore_db_dirs = 'aha';
+ERROR HY000: Variable 'ignore_db_dirs' is a read only variable

=== added file 'mysql-test/t/ignore_db_dirs_basic-master.opt'
--- a/mysql-test/t/ignore_db_dirs_basic-master.opt	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/ignore_db_dirs_basic-master.opt	2012-09-26 09:53:26 +0000
@@ -0,0 +1,11 @@
+--ignore-db-dir=a
+--ignore-db-dir=b
+--ignore-db-dir=c
+--ignore-db-dir=
+--ignore-db-dir=d
+--ignore-db-dir x
+--ignore-db-dir=
+--ignore-db-dir=e
+--ignore-db-dir=lost+found
+--ignore-db-dir=.mysqlgui
+--ignore-db-dir=ignored_db

=== added file 'mysql-test/t/ignore_db_dirs_basic.test'
--- a/mysql-test/t/ignore_db_dirs_basic.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/ignore_db_dirs_basic.test	2012-09-26 09:53:26 +0000
@@ -0,0 +1,38 @@
+select @@ignore_db_dirs;
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+mkdir $MYSQLD_DATADIR/.mysqlgui;
+mkdir $MYSQLD_DATADIR/.otherdir;
+mkdir $MYSQLD_DATADIR/lost+found;
+mkdir $MYSQLD_DATADIR/ignored_db;
+--echo # Check that SHOW DATABASES ignores all directories from
+--echo # @@ignore_db_dirs and all directories with names starting
+--echo # with '.'
+SHOW DATABASES;
+--error ER_WRONG_DB_NAME
+USE ignored_db;
+--error ER_WRONG_DB_NAME
+SELECT * FROM ignored_db.t1;
+--error ER_WRONG_DB_NAME
+CALL ignored_db.p1();
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='ignored_db';
+--error ER_WRONG_DB_NAME
+CREATE DATABASE ignored_db;
+CREATE DATABASE `lost+found`;
+USE `lost+found`;
+CREATE TABLE t1(id INT);
+INSERT INTO t1 VALUES (1), (2);
+SELECT * FROM `lost+found`.t1;
+SHOW DATABASES;
+DROP DATABASE `lost+found`;
+rmdir $MYSQLD_DATADIR/.mysqlgui;
+rmdir $MYSQLD_DATADIR/.otherdir;
+rmdir $MYSQLD_DATADIR/lost+found;
+rmdir $MYSQLD_DATADIR/ignored_db;
+
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@global.ignore_db_dirs = 'aha';
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@local.ignore_db_dirs = 'aha';
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@ignore_db_dirs = 'aha';

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2012-08-29 08:59:51 +0000
+++ b/sql/mysql_priv.h	2012-09-26 09:53:26 +0000
@@ -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);
 

=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc	2012-08-22 14:45:25 +0000
+++ b/sql/mysqld.cc	2012-09-26 09:53:26 +0000
@@ -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 c
       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_
                         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;
 }

=== modified file 'sql/set_var.cc'
--- a/sql/set_var.cc	2012-08-22 14:45:25 +0000
+++ b/sql/set_var.cc	2012-09-26 09:53:26 +0000
@@ -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_tra
                                                  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)

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2012-08-24 13:39:34 +0000
+++ b/sql/sql_show.cc	2012-09-26 09:53:26 +0000
@@ -379,6 +379,262 @@ 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;
+
+
+/**
+  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);
+
+  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
+  }
+
+  /* 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 (!ignore_db_dirs_hash.records)
+    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 +808,9 @@ find_files(THD *thd, List<LEX_STRING> *f
       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)
       {

=== modified file 'sql/sql_show.h'
--- a/sql/sql_show.h	2011-06-30 15:37:13 +0000
+++ b/sql/sql_show.h	2012-09-26 09:53:26 +0000
@@ -41,4 +41,13 @@ int view_store_create_info(THD *thd, TAB
 
 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 */

=== modified file 'sql/table.cc'
--- a/sql/table.cc	2012-09-05 20:23:58 +0000
+++ b/sql/table.cc	2012-09-26 09:53:26 +0000
@@ -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);
 }
 



More information about the commits mailing list