mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
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.
This commit is contained in:
47
mysql-test/r/ignore_db_dirs_basic.result
Normal file
47
mysql-test/r/ignore_db_dirs_basic.result
Normal file
@ -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
|
11
mysql-test/t/ignore_db_dirs_basic-master.opt
Normal file
11
mysql-test/t/ignore_db_dirs_basic-master.opt
Normal file
@ -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
|
38
mysql-test/t/ignore_db_dirs_basic.test
Normal file
38
mysql-test/t/ignore_db_dirs_basic.test
Normal file
@ -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';
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
281
sql/sql_show.cc
281
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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user