#At file:///Users/kgeorge/mysql/work/B11746029-trunk/ based on revid:alexander.nozdrin@stripped3cemadwrnzsbgdf
3366 Georgi Kodinov 2011-05-23
Bug #11746029: MYSQL SERVER INCORRECTLY CATOGORIZES THE
LOST+FOUND DIRECTORY AS A DATABA
Implemented an --ignore-db-directories option that takes a
comma separated list of values (possibly quoted by double quotes).
It then checks if the directory shown by I_S and the SHOW commands
is one of the disabled ones before returning it.
Test case and unit test for the parsing function added.
added:
mysql-test/suite/sys_vars/r/ignore_db_directories_basic.result
mysql-test/suite/sys_vars/t/ignore_db_directories_basic.test
unittest/gunit/sql_show-t.cc
modified:
mysql-test/r/mysqld--help-notwin.result
mysql-test/r/mysqld--help-win.result
sql/mysqld.cc
sql/sql_show.cc
sql/sql_show.h
sql/sys_vars.cc
unittest/gunit/CMakeLists.txt
=== modified file 'mysql-test/r/mysqld--help-notwin.result'
--- a/mysql-test/r/mysqld--help-notwin.result 2011-04-28 08:28:18 +0000
+++ b/mysql-test/r/mysqld--help-notwin.result 2011-05-23 16:09:39 +0000
@@ -189,6 +189,9 @@ The following options may be given as th
-?, --help Display this help and exit.
--ignore-builtin-innodb
Disable initialization of builtin InnoDB plugin
+ --ignore-db-directories=name
+ The list of directories to ignore when collecting
+ database lists
--init-connect=name Command(s) that are executed for each new connection
--init-file=name Read SQL commands from this file at startup
--init-slave=name Command(s) that are executed by a slave server each time
@@ -812,6 +815,7 @@ general-log FALSE
group-concat-max-len 1024
help TRUE
ignore-builtin-innodb FALSE
+ignore-db-directories (No default value)
init-connect
init-file (No default value)
init-slave
=== modified file 'mysql-test/r/mysqld--help-win.result'
--- a/mysql-test/r/mysqld--help-win.result 2011-04-28 08:28:18 +0000
+++ b/mysql-test/r/mysqld--help-win.result 2011-05-23 16:09:39 +0000
@@ -190,6 +190,9 @@ The following options may be given as th
--ignore-builtin-innodb
Disable initialization of builtin InnoDB plugin
--init-connect=name Command(s) that are executed for each new connection
+ --ignore-db-directories=name
+ The list of directories to ignore when collecting
+ database lists
--init-file=name Read SQL commands from this file at startup
--init-slave=name Command(s) that are executed by a slave server each time
the SQL thread starts
=== added file 'mysql-test/suite/sys_vars/r/ignore_db_directories_basic.result'
--- a/mysql-test/suite/sys_vars/r/ignore_db_directories_basic.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/sys_vars/r/ignore_db_directories_basic.result 2011-05-23 16:09:39 +0000
@@ -0,0 +1,12 @@
+select @@ignore_db_directories;
+@@ignore_db_directories
+test
+SHOW DATABASES;
+Database
+information_schema
+mtr
+mysql
+performance_schema
+SELECT DATABASE();
+DATABASE()
+test
=== added file 'mysql-test/suite/sys_vars/t/ignore_db_directories_basic.test'
--- a/mysql-test/suite/sys_vars/t/ignore_db_directories_basic.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/sys_vars/t/ignore_db_directories_basic.test 2011-05-23 16:09:39 +0000
@@ -0,0 +1,3 @@
+select @@ignore_db_directories;
+SHOW DATABASES;
+SELECT DATABASE();
=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc 2011-04-28 16:50:10 +0000
+++ b/sql/mysqld.cc 2011-05-23 16:09:39 +0000
@@ -1443,6 +1443,7 @@ void clean_up(bool print_message)
#endif
my_tz_free();
my_dboptions_cache_free();
+ ignore_db_directories_free();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
servers_free(1);
acl_free(1);
@@ -3647,6 +3648,9 @@ You should consider changing lower_case_
return 1;
}
+ if (ignore_db_directories_init())
+ return 1;
+
return 0;
}
=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc 2011-05-04 07:51:15 +0000
+++ b/sql/sql_show.cc 2011-05-23 16:09:39 +0000
@@ -382,6 +382,199 @@ bool mysqld_show_privileges(THD *thd)
}
+char *opt_ignore_db_directories;
+static HASH ignore_db_directories_hash;
+
+
+static uchar *
+db_directories_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;
+}
+
+
+static bool
+push_ignored_db_directory(char *path, char *path_end)
+{
+ LEX_STRING *new_elt;
+ char *new_elt_buffer;
+ size_t path_len= path_end - path;
+
+ DBUG_ASSERT(path_len && path_len < FN_REFLEN);
+
+ 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;
+
+ if (my_hash_insert(&ignore_db_directories_hash, (uchar *) new_elt))
+ {
+ my_free(new_elt);
+ return true;
+ }
+
+ return false;
+}
+
+
+bool
+parse_comma_separated_value_list(const char *src,
+ bool (*process_entry)(char *src,
+ char *src_end))
+{
+ const char *ptr;
+ char path[FN_REFLEN], *path_end= path + FN_REFLEN - 1, *file_ptr= path;
+ enum { WHITESPACE, QUOTED, UNQUOTED, COMMA_NEEDED } state= WHITESPACE;
+
+ if (!src)
+ return false;
+
+ for (ptr= src; *ptr; ptr++)
+ {
+ switch (*ptr)
+ {
+ case ' ':
+ if (state == UNQUOTED)
+ {
+ state= COMMA_NEEDED;
+ if (process_entry(path, file_ptr))
+ return true;
+ }
+ break;
+
+ case ',':
+ switch (state)
+ {
+ case UNQUOTED:
+ if (process_entry(path, file_ptr))
+ return true;
+ case COMMA_NEEDED:
+ state= WHITESPACE;
+ break;
+ case WHITESPACE:
+ return true;
+ case QUOTED: // make gcc happy
+ break;
+ }
+ break;
+
+ case '"':
+ switch (state)
+ {
+ case WHITESPACE:
+ state= QUOTED;
+ file_ptr= &path[0];
+ continue;
+ case COMMA_NEEDED:
+ case UNQUOTED:
+ return true;
+ case QUOTED:
+ state= COMMA_NEEDED;
+ if (process_entry(path, file_ptr))
+ return true;
+ break;
+ }
+ break;
+
+ case '\\':
+ if (state == QUOTED)
+ ptr++;
+ break;
+
+ default:
+ switch (state)
+ {
+ case WHITESPACE:
+ state= UNQUOTED;
+ file_ptr= &path[0];
+ break;
+
+ case COMMA_NEEDED:
+ return true;
+
+ case QUOTED:
+ case UNQUOTED:
+ if (ptr[1] && !strchr("\"\\ ,", ptr[1]))
+ {
+ /* skip until the next "special" char for faster processing */
+ size_t nchars= strcspn(ptr + 1, "\"\\ ,");
+ if (nchars > 0 && file_ptr + nchars + 1 < path_end)
+ {
+ memcpy(file_ptr, ptr, nchars + 1);
+ file_ptr+= nchars + 1;
+ /* should have been + 1, but the addition of 1 is left to the for() command */
+ ptr+= nchars;
+ }
+ continue;
+ }
+ break;
+ }
+ break;
+ }
+
+ if (state == QUOTED || state == UNQUOTED)
+ {
+ if (file_ptr >= path_end)
+ return true;
+ *file_ptr++= *ptr;
+ }
+ }
+
+ if (state == QUOTED)
+ return true;
+ else if (state == UNQUOTED)
+ {
+ if (process_entry(path, file_ptr))
+ return true;
+ }
+
+ return false;
+
+}
+
+
+bool
+ignore_db_directories_init()
+{
+ if (my_hash_init(&ignore_db_directories_hash, files_charset_info,
+ 0, 0, 0, db_directories_hash_get_key,
+ my_free,
+ HASH_UNIQUE))
+ return true;
+
+ return parse_comma_separated_value_list(opt_ignore_db_directories,
+ push_ignored_db_directory);
+}
+
+
+void
+ignore_db_directories_free()
+{
+ my_hash_free(&ignore_db_directories_hash);
+}
+
+
+static inline bool
+is_in_ignore_db_directories_list(const char *directory)
+{
+ return NULL !=
+ my_hash_search(&ignore_db_directories_hash, (const uchar *) directory,
+ strlen(directory));
+}
+
+
/*
find_files() - find files in a given directory.
@@ -427,8 +620,6 @@ find_files(THD *thd, List<LEX_STRING> *f
wild_length= strlen(wild);
}
-
-
bzero((char*) &table_list,sizeof(table_list));
if (!(dirp = my_dir(path,MYF(dir ? MY_WANT_STAT : 0))))
@@ -469,20 +660,6 @@ find_files(THD *thd, List<LEX_STRING> *f
if (!MY_S_ISDIR(file->mystat->st_mode))
continue;
- file_name_len= filename_to_tablename(file->name, uname, sizeof(uname));
- if (wild)
- {
- if (lower_case_table_names)
- {
- if (my_wildcmp(files_charset_info,
- uname, uname + file_name_len,
- wild, wild + wild_length,
- wild_prefix, wild_one,wild_many))
- continue;
- }
- else if (wild_compare(uname, wild, 0))
- continue;
- }
}
else
{
@@ -491,21 +668,28 @@ find_files(THD *thd, List<LEX_STRING> *f
is_prefix(file->name, tmp_file_prefix))
continue;
*ext=0;
- file_name_len= filename_to_tablename(file->name, uname, sizeof(uname));
- if (wild)
+ }
+
+ file_name_len= filename_to_tablename(file->name, uname, sizeof(uname));
+
+ if (dir && ignore_db_directories_hash.records &&
+ is_in_ignore_db_directories_list(file->name))
+ continue;
+
+ if (wild)
+ {
+ if (lower_case_table_names)
{
- if (lower_case_table_names)
- {
- if (my_wildcmp(files_charset_info,
- uname, uname + file_name_len,
- wild, wild + wild_length,
- wild_prefix, wild_one,wild_many))
- continue;
- }
- else if (wild_compare(uname, wild, 0))
- continue;
+ if (my_wildcmp(files_charset_info,
+ uname, uname + file_name_len,
+ wild, wild + wild_length,
+ wild_prefix, wild_one,wild_many))
+ continue;
}
+ else if (wild_compare(uname, wild, 0))
+ continue;
}
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Don't show tables where we don't have any privileges */
if (db && !(col_access & TABLE_ACLS))
=== modified file 'sql/sql_show.h'
--- a/sql/sql_show.h 2010-10-22 12:37:58 +0000
+++ b/sql/sql_show.h 2011-05-23 16:09:39 +0000
@@ -130,5 +130,12 @@ enum enum_schema_tables get_schema_table
/* These functions were under INNODB_COMPATIBILITY_HOOKS */
int get_quote_char_for_identifier(THD *thd, const char *name, uint length);
+bool ignore_db_directories_init();
+void ignore_db_directories_free();
+extern char *opt_ignore_db_directories;
+bool
+parse_comma_separated_value_list(const char *src,
+ bool (*process_entry)(char *src,
+ char *src_end));
#endif /* SQL_SHOW_H */
=== modified file 'sql/sys_vars.cc'
--- a/sql/sys_vars.cc 2011-04-11 10:28:36 +0000
+++ b/sql/sys_vars.cc 2011-05-23 16:09:39 +0000
@@ -47,6 +47,7 @@
// mysql_user_table_is_in_short_password_format
#include "derror.h" // read_texts
#include "sql_base.h" // close_cached_tables
+#include "sql_show.h" // opt_ignore_db_directories
#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
#include "../storage/perfschema/pfs_server.h"
@@ -3372,6 +3373,7 @@ static bool check_locale(sys_var *self,
}
mysql_mutex_unlock(&LOCK_error_messages);
}
+
return false;
}
static Sys_var_struct Sys_lc_messages(
@@ -3392,3 +3394,9 @@ static Sys_var_tz Sys_time_zone(
SESSION_VAR(time_zone), NO_CMD_LINE,
DEFAULT(&default_tz), NO_MUTEX_GUARD, IN_BINLOG);
+static Sys_var_charptr Sys_ignore_db_directories(
+ "ignore_db_directories",
+ "The list of directories to ignore when collecting database lists",
+ READ_ONLY GLOBAL_VAR(opt_ignore_db_directories),
+ CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(0));
=== modified file 'unittest/gunit/CMakeLists.txt'
--- a/unittest/gunit/CMakeLists.txt 2011-04-13 11:31:44 +0000
+++ b/unittest/gunit/CMakeLists.txt 2011-05-23 16:09:39 +0000
@@ -219,6 +219,7 @@ SET(TESTS
# Add tests (link them with gunit library and the server libraries)
SET(SERVER_TESTS
item
+ sql_show
)
FOREACH(test ${TESTS})
=== added file 'unittest/gunit/sql_show-t.cc'
--- a/unittest/gunit/sql_show-t.cc 1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/sql_show-t.cc 2011-05-23 16:09:39 +0000
@@ -0,0 +1,275 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Testing the Csv parser in sql_show.cc
+
+ For an introduction to the constructs used below, see:
+ http://code.google.com/p/googletest/wiki/GoogleTestPrimer
+*/
+
+// First include (the generated) my_config.h, to get correct platform defines,
+// then gtest.h (before any other MySQL headers), to avoid min() macros etc ...
+#include "my_config.h"
+#include <gtest/gtest.h>
+
+#include "sql_show.h"
+
+namespace {
+
+static char dirs[256][10];
+static int dir_idx= 0;
+
+bool process_entry(char *src, char *src_end)
+{
+ if (src_end - src > 256)
+ return true;
+ memcpy(dirs[dir_idx], src, src_end - src);
+ dirs[dir_idx][src_end - src]= 0;
+ dir_idx++;
+ return false;
+}
+
+TEST(CsvTest, empty)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list("", process_entry));
+ ASSERT_EQ(dir_idx, 0);
+}
+
+TEST(CsvTest, unquoted)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list("one", process_entry));
+ ASSERT_EQ(dir_idx, 1);
+ ASSERT_STREQ("one", dirs[0]);
+}
+
+TEST(CsvTest, quoted)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list("\"one\"", process_entry));
+ ASSERT_EQ(dir_idx, 1);
+ ASSERT_STREQ("one", dirs[0]);
+}
+
+TEST(CsvTest, quoted_with_escape)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list("\"o\\ne\"", process_entry));
+ ASSERT_EQ(dir_idx, 1);
+ ASSERT_STREQ("one", dirs[0]);
+}
+
+TEST(CsvTest, quoted_with_comma)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list("\"o,ne\"", process_entry));
+ ASSERT_EQ(dir_idx, 1);
+ ASSERT_STREQ("o,ne", dirs[0]);
+}
+
+TEST(CsvTest, quoted_with_escaped_comma)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list("\"o\\,ne\"", process_entry));
+ ASSERT_EQ(dir_idx, 1);
+ ASSERT_STREQ("o,ne", dirs[0]);
+}
+
+TEST(CsvTest, quoted_with_space)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list("\" o ne \"", process_entry));
+ ASSERT_EQ(dir_idx, 1);
+ ASSERT_STREQ(" o ne ", dirs[0]);
+}
+
+TEST(CsvTest, quoted_with_escaped_quote)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list("\"o\\\"ne\"", process_entry));
+ ASSERT_EQ(dir_idx, 1);
+ ASSERT_STREQ("o\"ne", dirs[0]);
+}
+
+TEST(CsvTest, quoted_with_escaped_escape)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list("\"o\\\\ne\"", process_entry));
+ ASSERT_EQ(dir_idx, 1);
+ ASSERT_STREQ("o\\ne", dirs[0]);
+}
+
+TEST(CsvTest, quoted_with_escaped_rquote)
+{
+ dir_idx= 0;
+ EXPECT_TRUE(parse_comma_separated_value_list("\"o\\\"", process_entry));
+}
+
+TEST(CsvTest, missing_rquote)
+{
+ dir_idx= 0;
+ EXPECT_TRUE(parse_comma_separated_value_list("\"one", process_entry));
+}
+
+TEST(CsvTest, missing_lquote)
+{
+ dir_idx= 0;
+ EXPECT_TRUE(parse_comma_separated_value_list("one\"", process_entry));
+}
+
+TEST(CsvTest, starting_comma_unquoted)
+{
+ dir_idx= 0;
+ EXPECT_TRUE(parse_comma_separated_value_list(",one", process_entry));
+}
+
+TEST(CsvTest, starting_comma_quoted)
+{
+ dir_idx= 0;
+ EXPECT_TRUE(parse_comma_separated_value_list(",\"one\"", process_entry));
+}
+
+TEST(CsvTest, leading_space_unquoted)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list(" one", process_entry));
+ ASSERT_EQ(dir_idx, 1);
+ ASSERT_STREQ("one", dirs[0]);
+}
+
+TEST(CsvTest, leading_space_quoted)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list(" \"one\"", process_entry));
+ ASSERT_EQ(dir_idx, 1);
+ ASSERT_STREQ("one", dirs[0]);
+}
+
+TEST(CsvTest, unquoted_with_space)
+{
+ dir_idx= 0;
+ EXPECT_TRUE(parse_comma_separated_value_list("o ne", process_entry));
+}
+
+TEST(CsvTest, trailing_space_unquoted)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list("one ", process_entry));
+ ASSERT_EQ(dir_idx, 1);
+ ASSERT_STREQ("one", dirs[0]);
+}
+
+TEST(CsvTest, trailing_space_quoted)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list("\"one\" ", process_entry));
+ ASSERT_EQ(dir_idx, 1);
+ ASSERT_STREQ("one", dirs[0]);
+}
+
+TEST(CsvTest, two_unquoted)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list("one,two", process_entry));
+ ASSERT_EQ(dir_idx, 2);
+ ASSERT_STREQ("one", dirs[0]);
+ ASSERT_STREQ("two", dirs[1]);
+}
+
+TEST(CsvTest, two_unquoted_space)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list(" one , two ", process_entry));
+ ASSERT_EQ(dir_idx, 2);
+ ASSERT_STREQ("one", dirs[0]);
+ ASSERT_STREQ("two", dirs[1]);
+}
+
+TEST(CsvTest, two_quoted)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list("\"one\",\"two\"", process_entry));
+ ASSERT_EQ(dir_idx, 2);
+ ASSERT_STREQ("one", dirs[0]);
+ ASSERT_STREQ("two", dirs[1]);
+}
+
+TEST(CsvTest, two_quoted_space)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list(" \"one\" , \"two\" ", process_entry));
+ ASSERT_EQ(dir_idx, 2);
+ ASSERT_STREQ("one", dirs[0]);
+ ASSERT_STREQ("two", dirs[1]);
+}
+
+TEST(CsvTest, two_quoted_unquoted)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list("\"one\",two", process_entry));
+ ASSERT_EQ(dir_idx, 2);
+ ASSERT_STREQ("one", dirs[0]);
+ ASSERT_STREQ("two", dirs[1]);
+}
+
+TEST(CsvTest, two_unquoted_quoted)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list("one,\"two\"", process_entry));
+ ASSERT_EQ(dir_idx, 2);
+ ASSERT_STREQ("one", dirs[0]);
+ ASSERT_STREQ("two", dirs[1]);
+}
+
+TEST(CsvTest, two_commas)
+{
+ dir_idx= 0;
+ EXPECT_TRUE(parse_comma_separated_value_list("one,,two", process_entry));
+}
+
+TEST(CsvTest, two_commas_space)
+{
+ dir_idx= 0;
+ EXPECT_TRUE(parse_comma_separated_value_list(" one , , two ", process_entry));
+}
+
+TEST(CsvTest, utf8_unquoted)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list(" едно , две ", process_entry));
+ ASSERT_EQ(dir_idx, 2);
+ ASSERT_STREQ("едно", dirs[0]);
+ ASSERT_STREQ("две", dirs[1]);
+}
+
+TEST(CsvTest, utf8_quoted)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list(" \"ir_idx, 2);
+ ASSERT_STREQ("едно", dirs[0]);
+ ASSERT_STREQ("две", dirs[1]);
+}
+
+TEST(CsvTest, null)
+{
+ dir_idx= 0;
+ EXPECT_FALSE(parse_comma_separated_value_list(NULL, process_entry));
+ ASSERT_EQ(dir_idx, 0);
+}
+
+} // namespace
Attachment: [text/bzr-bundle] bzr/georgi.kodinov@oracle.com-20110523160939-sf2kz9ywyvia6v0w.bundle
| Thread |
|---|
| • bzr commit into mysql-trunk branch (Georgi.Kodinov:3366) Bug#11746029 | Georgi Kodinov | 23 May |