summaryrefslogtreecommitdiff
path: root/sql/sql_db.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_db.cc')
-rw-r--r--sql/sql_db.cc308
1 files changed, 159 insertions, 149 deletions
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index c09ad51a824..71558e68067 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -18,7 +18,7 @@
/* create and drop of databases */
-#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */
#include "sql_priv.h"
#include "unireg.h"
#include "sql_db.h"
@@ -32,11 +32,13 @@
#include "log_event.h" // Query_log_event
#include "sql_base.h" // lock_table_names, tdc_remove_table
#include "sql_handler.h" // mysql_ha_rm_tables
+#include "sql_class.h"
#include <mysys_err.h>
#include "sp_head.h"
#include "sp.h"
#include "events.h"
#include "sql_handler.h"
+#include "sql_statistics.h"
#include <my_dir.h>
#include <m_ctype.h>
#include "log.h"
@@ -47,15 +49,12 @@
#define MAX_DROP_TABLE_Q_LEN 1024
-const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NullS};
+const char *del_exts[]= {".BAK", ".opt", NullS};
static TYPELIB deletable_extentions=
{array_elements(del_exts)-1,"del_exts", del_exts, NULL};
-static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp,
- const char *db,
- const char *path,
- TABLE_LIST **tables,
- bool *found_other_files);
+static bool find_db_tables_and_rm_known_files(THD *, MY_DIR *, char *,
+ const char *, TABLE_LIST **);
long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path);
static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error);
@@ -79,6 +78,29 @@ typedef struct my_dbopt_st
} my_dbopt_t;
+/**
+ Return TRUE if db1_name is equal to db2_name, FALSE otherwise.
+
+ The function allows to compare database names according to the MariaDB
+ rules. The database names db1 and db2 are equal if:
+ - db1 is NULL and db2 is NULL;
+ or
+ - db1 is not-NULL, db2 is not-NULL, db1 is equal to db2 in
+ table_alias_charset
+
+ This is the same rules as we use for filenames.
+*/
+
+static inline bool
+cmp_db_names(const char *db1_name,
+ const char *db2_name)
+{
+ return ((!db1_name && !db2_name) ||
+ (db1_name && db2_name &&
+ my_strcasecmp(table_alias_charset, db1_name, db2_name) == 0));
+}
+
+
/*
Function we use in the creation of our hash to get key.
*/
@@ -160,8 +182,7 @@ bool my_dboptions_cache_init(void)
if (!dboptions_init)
{
dboptions_init= 1;
- error= my_hash_init(&dboptions, lower_case_table_names ?
- &my_charset_bin : system_charset_info,
+ error= my_hash_init(&dboptions, table_alias_charset,
32, 0, 0, (my_hash_get_key) dboptions_get_key,
free_dbopt,0);
}
@@ -193,8 +214,7 @@ void my_dbopt_cleanup(void)
{
mysql_rwlock_wrlock(&LOCK_dboptions);
my_hash_free(&dboptions);
- my_hash_init(&dboptions, lower_case_table_names ?
- &my_charset_bin : system_charset_info,
+ my_hash_init(&dboptions, table_alias_charset,
32, 0, 0, (my_hash_get_key) dboptions_get_key,
free_dbopt,0);
mysql_rwlock_unlock(&LOCK_dboptions);
@@ -559,7 +579,17 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
DBUG_RETURN(-1);
}
- if (lock_schema_name(thd, db))
+ char db_tmp[SAFE_NAME_LEN], *dbnorm;
+ if (lower_case_table_names)
+ {
+ strmake_buf(db_tmp, db);
+ my_casedn_str(system_charset_info, db_tmp);
+ dbnorm= db_tmp;
+ }
+ else
+ dbnorm= db;
+
+ if (lock_schema_name(thd, dbnorm))
DBUG_RETURN(-1);
/* Check directory */
@@ -574,7 +604,7 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
error= -1;
goto exit;
}
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db);
error= 0;
goto not_silent;
@@ -754,23 +784,44 @@ exit:
bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
{
ulong deleted_tables= 0;
- bool error= true;
+ bool error= true, rm_mysql_schema;
char path[FN_REFLEN + 16];
MY_DIR *dirp;
uint length;
- bool found_other_files= false;
TABLE_LIST *tables= NULL;
TABLE_LIST *table;
Drop_table_error_handler err_handler;
DBUG_ENTER("mysql_rm_db");
+ char db_tmp[SAFE_NAME_LEN], *dbnorm;
+ if (lower_case_table_names)
+ {
+ strmake_buf(db_tmp, db);
+ my_casedn_str(system_charset_info, db_tmp);
+ dbnorm= db_tmp;
+ }
+ else
+ dbnorm= db;
- if (lock_schema_name(thd, db))
+ if (lock_schema_name(thd, dbnorm))
DBUG_RETURN(true);
length= build_table_filename(path, sizeof(path) - 1, db, "", "", 0);
strmov(path+length, MY_DB_OPT_FILE); // Append db option file name
del_dbopt(path); // Remove dboption hash entry
+ /*
+ Now remove the db.opt file.
+ The 'find_db_tables_and_rm_known_files' doesn't remove this file
+ if there exists a table with the name 'db', so let's just do it
+ separately. We know this file exists and needs to be deleted anyway.
+ */
+ if (mysql_file_delete_with_symlink(key_file_misc, path, "", MYF(0)) &&
+ my_errno != ENOENT)
+ {
+ my_error(EE_DELETE, MYF(0), path, my_errno);
+ DBUG_RETURN(true);
+ }
+
path[length]= '\0'; // Remove file name
/* See if the directory exists */
@@ -783,55 +834,56 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
}
else
{
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS), db);
error= false;
goto update_binlog;
}
}
- if (find_db_tables_and_rm_known_files(thd, dirp, db, path, &tables,
- &found_other_files))
+ if (find_db_tables_and_rm_known_files(thd, dirp, dbnorm, path, &tables))
goto exit;
/*
Disable drop of enabled log tables, must be done before name locking.
This check is only needed if we are dropping the "mysql" database.
*/
- if ((my_strcasecmp(system_charset_info, MYSQL_SCHEMA_NAME.str, db) == 0))
+ if ((rm_mysql_schema=
+ (my_strcasecmp(system_charset_info, MYSQL_SCHEMA_NAME.str, db) == 0)))
{
for (table= tables; table; table= table->next_local)
- {
- if (check_if_log_table(table->db_length, table->db,
- table->table_name_length, table->table_name, true))
- {
- my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP");
+ if (check_if_log_table(table, TRUE, "DROP"))
goto exit;
- }
- }
}
/* Lock all tables and stored routines about to be dropped. */
if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout,
- MYSQL_OPEN_SKIP_TEMPORARY) ||
- lock_db_routines(thd, db))
+ 0) ||
+ lock_db_routines(thd, dbnorm))
goto exit;
+ if (!in_bootstrap && !rm_mysql_schema)
+ {
+ for (table= tables; table; table= table->next_local)
+ {
+ LEX_STRING db_name= { table->db, table->db_length };
+ LEX_STRING table_name= { table->table_name, table->table_name_length };
+ if (table->open_type == OT_BASE_ONLY || !find_temporary_table(thd, table))
+ (void) delete_statistics_for_table(thd, &db_name, &table_name);
+ }
+ }
+
/* mysql_ha_rm_tables() requires a non-null TABLE_LIST. */
if (tables)
mysql_ha_rm_tables(thd, tables);
for (table= tables; table; table= table->next_local)
- {
- tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
- false);
deleted_tables++;
- }
thd->push_internal_handler(&err_handler);
if (!thd->killed &&
!(tables &&
- mysql_rm_table_no_locks(thd, tables, true, false, true, true)))
+ mysql_rm_table_no_locks(thd, tables, true, false, true, true, false)))
{
/*
We temporarily disable the binary log while dropping the objects
@@ -854,21 +906,21 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
ha_drop_database(path);
tmp_disable_binlog(thd);
- query_cache_invalidate1(thd, db);
- (void) sp_drop_db_routines(thd, db); /* @todo Do not ignore errors */
+ query_cache_invalidate1(thd, dbnorm);
+ if (!rm_mysql_schema)
+ {
+ (void) sp_drop_db_routines(thd, dbnorm); /* @todo Do not ignore errors */
#ifdef HAVE_EVENT_SCHEDULER
- Events::drop_schema_events(thd, db);
+ Events::drop_schema_events(thd, dbnorm);
#endif
+ }
reenable_binlog(thd);
/*
If the directory is a symbolic link, remove the link first, then
remove the directory the symbolic link pointed at
*/
- if (found_other_files)
- my_error(ER_DB_DROP_RMDIR, MYF(0), path, EEXIST);
- else
- error= rm_dir_w_symlink(path, true);
+ error= rm_dir_w_symlink(path, true);
}
thd->pop_internal_handler();
@@ -924,16 +976,10 @@ update_binlog:
for (tbl= tables; tbl; tbl= tbl->next_local)
{
uint tbl_name_len;
- bool exists;
char quoted_name[FN_REFLEN+3];
// Only write drop table to the binlog for tables that no longer exist.
- if (check_if_table_exists(thd, tbl, 0, &exists))
- {
- error= true;
- goto exit;
- }
- if (exists)
+ if (ha_table_exists(thd, tbl->db, tbl->table_name))
continue;
my_snprintf(quoted_name, sizeof(quoted_name), "%`s", tbl->table_name);
@@ -977,7 +1023,7 @@ exit:
SELECT DATABASE() in the future). For this we free() thd->db and set
it to 0.
*/
- if (thd->db && !strcmp(thd->db, db) && !error)
+ if (thd->db && cmp_db_names(thd->db, db) && !error)
mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
my_dirend(dirp);
DBUG_RETURN(error);
@@ -985,31 +1031,66 @@ exit:
static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp,
- const char *db,
+ char *dbname,
const char *path,
- TABLE_LIST **tables,
- bool *found_other_files)
+ TABLE_LIST **tables)
{
char filePath[FN_REFLEN];
+ LEX_STRING db= { dbname, strlen(dbname) };
TABLE_LIST *tot_list=0, **tot_list_next_local, **tot_list_next_global;
DBUG_ENTER("find_db_tables_and_rm_known_files");
DBUG_PRINT("enter",("path: %s", path));
+ /* first, get the list of tables */
+ Dynamic_array<LEX_STRING*> files(dirp->number_of_files);
+ Discovered_table_list tl(thd, &files);
+ if (ha_discover_table_names(thd, &db, dirp, &tl, true))
+ DBUG_RETURN(1);
+
+ /* Now put the tables in the list */
tot_list_next_local= tot_list_next_global= &tot_list;
+ for (size_t idx=0; idx < files.elements(); idx++)
+ {
+ LEX_STRING *table= files.at(idx);
+
+ /* Drop the table nicely */
+ TABLE_LIST *table_list=(TABLE_LIST*)thd->calloc(sizeof(*table_list));
+
+ if (!table_list)
+ DBUG_RETURN(true);
+ table_list->db= db.str;
+ table_list->db_length= db.length;
+ table_list->table_name= table->str;
+ table_list->table_name_length= table->length;
+ table_list->open_type= OT_BASE_ONLY;
+
+ /* To be able to correctly look up the table in the table cache. */
+ if (lower_case_table_names)
+ table_list->table_name_length= my_casedn_str(files_charset_info,
+ table_list->table_name);
+
+ table_list->alias= table_list->table_name; // If lower_case_table_names=2
+ table_list->mdl_request.init(MDL_key::TABLE, table_list->db,
+ table_list->table_name, MDL_EXCLUSIVE,
+ MDL_TRANSACTION);
+ /* Link into list */
+ (*tot_list_next_local)= table_list;
+ (*tot_list_next_global)= table_list;
+ tot_list_next_local= &table_list->next_local;
+ tot_list_next_global= &table_list->next_global;
+ }
+ *tables= tot_list;
+
+ /* and at last delete all non-table files */
for (uint idx=0 ;
- idx < (uint) dirp->number_off_files && !thd->killed ;
+ idx < (uint) dirp->number_of_files && !thd->killed ;
idx++)
{
FILEINFO *file=dirp->dir_entry+idx;
char *extension;
DBUG_PRINT("info",("Examining: %s", file->name));
- /* skiping . and .. */
- if (file->name[0] == '.' && (!file->name[1] ||
- (file->name[1] == '.' && !file->name[2])))
- continue;
-
if (file->name[0] == 'a' && file->name[1] == 'r' &&
file->name[2] == 'c' && file->name[3] == '\0')
{
@@ -1026,59 +1107,12 @@ static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp,
DBUG_PRINT("my",("Archive subdir found: %s", newpath));
if ((mysql_rm_arc_files(thd, new_dirp, newpath)) < 0)
DBUG_RETURN(true);
- continue;
}
- *found_other_files= true;
continue;
}
if (!(extension= strrchr(file->name, '.')))
extension= strend(file->name);
- if (find_type(extension, &deletable_extentions, FIND_TYPE_NO_PREFIX) <= 0)
- {
- if (find_type(extension, ha_known_exts(), FIND_TYPE_NO_PREFIX) <= 0)
- *found_other_files= true;
- continue;
- }
- /* just for safety we use files_charset_info */
- if (db && !my_strcasecmp(files_charset_info,
- extension, reg_ext))
- {
- /* Drop the table nicely */
- *extension= 0; // Remove extension
- TABLE_LIST *table_list=(TABLE_LIST*)
- thd->calloc(sizeof(*table_list) +
- strlen(db) + 1 +
- MYSQL50_TABLE_NAME_PREFIX_LENGTH +
- strlen(file->name) + 1);
-
- if (!table_list)
- DBUG_RETURN(true);
- table_list->db= (char*) (table_list+1);
- table_list->db_length= strmov(table_list->db, db) - table_list->db;
- table_list->table_name= table_list->db + table_list->db_length + 1;
- table_list->table_name_length= filename_to_tablename(file->name,
- table_list->table_name,
- MYSQL50_TABLE_NAME_PREFIX_LENGTH +
- strlen(file->name) + 1);
- table_list->open_type= OT_BASE_ONLY;
-
- /* To be able to correctly look up the table in the table cache. */
- if (lower_case_table_names)
- table_list->table_name_length= my_casedn_str(files_charset_info,
- table_list->table_name);
-
- table_list->alias= table_list->table_name; // If lower_case_table_names=2
- table_list->internal_tmp_table= is_prefix(file->name, tmp_file_prefix);
- table_list->mdl_request.init(MDL_key::TABLE, table_list->db,
- table_list->table_name, MDL_EXCLUSIVE,
- MDL_TRANSACTION);
- /* Link into list */
- (*tot_list_next_local)= table_list;
- (*tot_list_next_global)= table_list;
- tot_list_next_local= &table_list->next_local;
- tot_list_next_global= &table_list->next_global;
- }
- else
+ if (find_type(extension, &deletable_extentions, FIND_TYPE_NO_PREFIX) > 0)
{
strxmov(filePath, path, "/", file->name, NullS);
/*
@@ -1093,7 +1127,7 @@ static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp,
}
}
}
- *tables= tot_list;
+
DBUG_RETURN(false);
}
@@ -1177,18 +1211,13 @@ long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path)
DBUG_PRINT("enter", ("path: %s", org_path));
for (uint idx=0 ;
- idx < (uint) dirp->number_off_files && !thd->killed ;
+ idx < (uint) dirp->number_of_files && !thd->killed ;
idx++)
{
FILEINFO *file=dirp->dir_entry+idx;
char *extension, *revision;
DBUG_PRINT("info",("Examining: %s", file->name));
- /* skiping . and .. */
- if (file->name[0] == '.' && (!file->name[1] ||
- (file->name[1] == '.' && !file->name[2])))
- continue;
-
extension= fn_ext(file->name);
if (extension[0] != '.' ||
extension[1] != 'f' || extension[2] != 'r' ||
@@ -1328,27 +1357,6 @@ static void backup_current_db_name(THD *thd,
/**
- Return TRUE if db1_name is equal to db2_name, FALSE otherwise.
-
- The function allows to compare database names according to the MySQL
- rules. The database names db1 and db2 are equal if:
- - db1 is NULL and db2 is NULL;
- or
- - db1 is not-NULL, db2 is not-NULL, db1 is equal (ignoring case) to
- db2 in system character set (UTF8).
-*/
-
-static inline bool
-cmp_db_names(const char *db1_name,
- const char *db2_name)
-{
- return ((!db1_name && !db2_name) ||
- (db1_name && db2_name &&
- my_strcasecmp(system_charset_info, db1_name, db2_name) == 0));
-}
-
-
-/**
@brief Change the current database and its attributes unconditionally.
@param thd thread handle
@@ -1492,14 +1500,18 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
DBUG_PRINT("info",("Use database: %s", new_db_file_name.str));
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- db_access=
- test_all_bits(sctx->master_access, DB_ACLS) ?
- DB_ACLS :
- acl_get(sctx->host,
- sctx->ip,
- sctx->priv_user,
- new_db_file_name.str,
- FALSE) | sctx->master_access;
+ if (test_all_bits(sctx->master_access, DB_ACLS))
+ db_access= DB_ACLS;
+ else
+ {
+ db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user,
+ new_db_file_name.str, FALSE) | sctx->master_access;
+ if (sctx->priv_role[0])
+ {
+ /* include a possible currently set role for access */
+ db_access|= acl_get("", "", sctx->priv_role, new_db_file_name.str, FALSE);
+ }
+ }
if (!force_switch &&
!(db_access & DB_ACLS) &&
@@ -1524,7 +1536,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
{
/* Throw a warning and free new_db_file_name. */
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR),
new_db_file_name.str);
@@ -1674,7 +1686,7 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
/* Step2: Move tables to the new database */
if ((dirp = my_dir(path,MYF(MY_DONT_SORT))))
{
- uint nfiles= (uint) dirp->number_off_files;
+ uint nfiles= (uint) dirp->number_of_files;
for (uint idx=0 ; idx < nfiles && !thd->killed ; idx++)
{
FILEINFO *file= dirp->dir_entry + idx;
@@ -1765,17 +1777,15 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
if ((dirp = my_dir(path,MYF(MY_DONT_SORT))))
{
- uint nfiles= (uint) dirp->number_off_files;
+ uint nfiles= (uint) dirp->number_of_files;
for (uint idx=0 ; idx < nfiles ; idx++)
{
FILEINFO *file= dirp->dir_entry + idx;
char oldname[FN_REFLEN + 1], newname[FN_REFLEN + 1];
DBUG_PRINT("info",("Examining: %s", file->name));
- /* skiping . and .. and MY_DB_OPT_FILE */
- if ((file->name[0] == '.' &&
- (!file->name[1] || (file->name[1] == '.' && !file->name[2]))) ||
- !my_strcasecmp(files_charset_info, file->name, MY_DB_OPT_FILE))
+ /* skiping MY_DB_OPT_FILE */
+ if (!my_strcasecmp(files_charset_info, file->name, MY_DB_OPT_FILE))
continue;
/* pass empty file name, and file->name as extension to avoid encoding */