mirror of
https://github.com/MariaDB/server.git
synced 2026-01-06 05:22:24 +03:00
5.5-merge
This commit is contained in:
286
sql/sql_db.cc
286
sql/sql_db.cc
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
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
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "sql_acl.h" // SELECT_ACL, DB_ACLS,
|
||||
// acl_get, check_grant_db
|
||||
#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 <mysys_err.h>
|
||||
#include "sp.h"
|
||||
#include "events.h"
|
||||
@@ -44,10 +46,12 @@ const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NullS};
|
||||
static TYPELIB deletable_extentions=
|
||||
{array_elements(del_exts)-1,"del_exts", del_exts, NULL};
|
||||
|
||||
static long mysql_rm_known_files(THD *thd, MY_DIR *dirp,
|
||||
const char *db, const char *path, uint level,
|
||||
TABLE_LIST **dropped_tables);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
static void mysql_change_db_impl(THD *thd,
|
||||
@@ -736,36 +740,37 @@ exit:
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Drop all tables in a database and the database itself
|
||||
/**
|
||||
Drop all tables, routines and events in a database and the database itself.
|
||||
|
||||
SYNOPSIS
|
||||
mysql_rm_db()
|
||||
thd Thread handle
|
||||
db Database name in the case given by user
|
||||
It's already validated and set to lower case
|
||||
(if needed) when we come here
|
||||
if_exists Don't give error if database doesn't exists
|
||||
silent Don't generate errors
|
||||
@param thd Thread handle
|
||||
@param db Database name in the case given by user
|
||||
It's already validated and set to lower case
|
||||
(if needed) when we come here
|
||||
@param if_exists Don't give error if database doesn't exists
|
||||
@param silent Don't write the statement to the binary log and don't
|
||||
send ok packet to the client
|
||||
|
||||
RETURN
|
||||
FALSE ok (Database dropped)
|
||||
ERROR Error
|
||||
@retval false OK (Database dropped)
|
||||
@retval true Error
|
||||
*/
|
||||
|
||||
bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
|
||||
{
|
||||
long deleted=0;
|
||||
int error= 0;
|
||||
ulong deleted_tables= 0;
|
||||
bool error= true;
|
||||
char path[FN_REFLEN+16];
|
||||
MY_DIR *dirp;
|
||||
uint length;
|
||||
TABLE_LIST* dropped_tables= 0;
|
||||
bool found_other_files= false;
|
||||
TABLE_LIST *tables= NULL;
|
||||
TABLE_LIST *table;
|
||||
Drop_table_error_handler err_handler;
|
||||
DBUG_ENTER("mysql_rm_db");
|
||||
|
||||
|
||||
if (lock_schema_name(thd, db))
|
||||
DBUG_RETURN(TRUE);
|
||||
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
|
||||
@@ -777,20 +782,61 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
|
||||
{
|
||||
if (!if_exists)
|
||||
{
|
||||
error= -1;
|
||||
my_error(ER_DB_DROP_EXISTS, MYF(0), db);
|
||||
goto exit;
|
||||
DBUG_RETURN(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS), db);
|
||||
error= false;
|
||||
goto update_binlog;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Drop_table_error_handler err_handler;
|
||||
thd->push_internal_handler(&err_handler);
|
||||
|
||||
error= -1;
|
||||
if (find_db_tables_and_rm_known_files(thd, dirp, db, path, &tables,
|
||||
&found_other_files))
|
||||
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))
|
||||
{
|
||||
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");
|
||||
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))
|
||||
goto exit;
|
||||
|
||||
/* 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)))
|
||||
{
|
||||
/*
|
||||
We temporarily disable the binary log while dropping the objects
|
||||
in the database. Since the DROP DATABASE statement is always
|
||||
@@ -808,23 +854,30 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
|
||||
ha_drop_database(), since NDB otherwise detects the binary log
|
||||
as disabled and will not log the drop database statement on any
|
||||
other connected server.
|
||||
*/
|
||||
if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0,
|
||||
&dropped_tables)) >= 0)
|
||||
{
|
||||
ha_drop_database(path);
|
||||
tmp_disable_binlog(thd);
|
||||
query_cache_invalidate1(db);
|
||||
(void) sp_drop_db_routines(thd, db); /* @todo Do not ignore errors */
|
||||
*/
|
||||
|
||||
ha_drop_database(path);
|
||||
tmp_disable_binlog(thd);
|
||||
query_cache_invalidate1(db);
|
||||
(void) sp_drop_db_routines(thd, db); /* @todo Do not ignore errors */
|
||||
#ifdef HAVE_EVENT_SCHEDULER
|
||||
Events::drop_schema_events(thd, db);
|
||||
Events::drop_schema_events(thd, db);
|
||||
#endif
|
||||
error = 0;
|
||||
reenable_binlog(thd);
|
||||
}
|
||||
thd->pop_internal_handler();
|
||||
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);
|
||||
}
|
||||
if (!silent && deleted>=0)
|
||||
thd->pop_internal_handler();
|
||||
|
||||
update_binlog:
|
||||
if (!silent && !error)
|
||||
{
|
||||
const char *query;
|
||||
ulong query_length;
|
||||
@@ -859,16 +912,15 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
|
||||
*/
|
||||
if (mysql_bin_log.write(&qinfo))
|
||||
{
|
||||
error= -1;
|
||||
error= true;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
thd->clear_error();
|
||||
thd->server_status|= SERVER_STATUS_DB_DROPPED;
|
||||
my_ok(thd, (ulong) deleted);
|
||||
thd->server_status&= ~SERVER_STATUS_DB_DROPPED;
|
||||
my_ok(thd, deleted_tables);
|
||||
}
|
||||
else if (mysql_bin_log.is_open())
|
||||
else if (mysql_bin_log.is_open() && !silent)
|
||||
{
|
||||
char *query, *query_pos, *query_end, *query_data_start;
|
||||
TABLE_LIST *tbl;
|
||||
@@ -880,9 +932,19 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
|
||||
query_end= query + MAX_DROP_TABLE_Q_LEN;
|
||||
db_len= strlen(db);
|
||||
|
||||
for (tbl= dropped_tables; tbl; tbl= tbl->next_local)
|
||||
for (tbl= tables; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
uint tbl_name_len;
|
||||
bool exists;
|
||||
|
||||
// Only write drop table to the binlog for tables that no longer exist.
|
||||
if (check_if_table_exists(thd, tbl, &exists))
|
||||
{
|
||||
error= true;
|
||||
goto exit;
|
||||
}
|
||||
if (exists)
|
||||
continue;
|
||||
|
||||
/* 3 for the quotes and the comma*/
|
||||
tbl_name_len= strlen(tbl->table_name) + 3;
|
||||
@@ -894,7 +956,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
|
||||
*/
|
||||
if (write_to_binlog(thd, query, query_pos -1 - query, db, db_len))
|
||||
{
|
||||
error= -1;
|
||||
error= true;
|
||||
goto exit;
|
||||
}
|
||||
query_pos= query_data_start;
|
||||
@@ -914,7 +976,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
|
||||
*/
|
||||
if (write_to_binlog(thd, query, query_pos -1 - query, db, db_len))
|
||||
{
|
||||
error= -1;
|
||||
error= true;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
@@ -927,28 +989,23 @@ 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 == 0)
|
||||
if (thd->db && !strcmp(thd->db, db) && !error)
|
||||
mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
|
||||
my_dirend(dirp);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
/*
|
||||
Removes files with known extensions plus all found subdirectories that
|
||||
are 2 hex digits (raid directories).
|
||||
thd MUST be set when calling this function!
|
||||
*/
|
||||
|
||||
static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
|
||||
const char *org_path, uint level,
|
||||
TABLE_LIST **dropped_tables)
|
||||
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)
|
||||
{
|
||||
long deleted=0;
|
||||
ulong found_other_files=0;
|
||||
char filePath[FN_REFLEN];
|
||||
TABLE_LIST *tot_list=0, **tot_list_next_local, **tot_list_next_global;
|
||||
List<String> raid_dirs;
|
||||
DBUG_ENTER("mysql_rm_known_files");
|
||||
DBUG_PRINT("enter",("path: %s", org_path));
|
||||
DBUG_ENTER("find_db_tables_and_rm_known_files");
|
||||
DBUG_PRINT("enter",("path: %s", path));
|
||||
|
||||
tot_list_next_local= tot_list_next_global= &tot_list;
|
||||
|
||||
@@ -965,36 +1022,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
|
||||
(file->name[1] == '.' && !file->name[2])))
|
||||
continue;
|
||||
|
||||
/* Check if file is a raid directory */
|
||||
if ((my_isdigit(system_charset_info, file->name[0]) ||
|
||||
(file->name[0] >= 'a' && file->name[0] <= 'f')) &&
|
||||
(my_isdigit(system_charset_info, file->name[1]) ||
|
||||
(file->name[1] >= 'a' && file->name[1] <= 'f')) &&
|
||||
!file->name[2] && !level)
|
||||
{
|
||||
char newpath[FN_REFLEN], *copy_of_path;
|
||||
MY_DIR *new_dirp;
|
||||
String *dir;
|
||||
uint length;
|
||||
|
||||
strxmov(newpath,org_path,"/",file->name,NullS);
|
||||
length= unpack_filename(newpath,newpath);
|
||||
if ((new_dirp = my_dir(newpath,MYF(MY_DONT_SORT))))
|
||||
{
|
||||
DBUG_PRINT("my",("New subdir found: %s", newpath));
|
||||
if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1,0)) < 0)
|
||||
goto err;
|
||||
if (!(copy_of_path= (char*) thd->memdup(newpath, length+1)) ||
|
||||
!(dir= new (thd->mem_root) String(copy_of_path, length,
|
||||
&my_charset_bin)) ||
|
||||
raid_dirs.push_back(dir))
|
||||
goto err;
|
||||
continue;
|
||||
}
|
||||
found_other_files++;
|
||||
continue;
|
||||
}
|
||||
else if (file->name[0] == 'a' && file->name[1] == 'r' &&
|
||||
if (file->name[0] == 'a' && file->name[1] == 'r' &&
|
||||
file->name[2] == 'c' && file->name[3] == '\0')
|
||||
{
|
||||
/* .frm archive:
|
||||
@@ -1003,24 +1031,24 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
|
||||
*/
|
||||
char newpath[FN_REFLEN];
|
||||
MY_DIR *new_dirp;
|
||||
strxmov(newpath, org_path, "/", "arc", NullS);
|
||||
strxmov(newpath, path, "/", "arc", NullS);
|
||||
(void) unpack_filename(newpath, newpath);
|
||||
if ((new_dirp = my_dir(newpath, MYF(MY_DONT_SORT))))
|
||||
{
|
||||
DBUG_PRINT("my",("Archive subdir found: %s", newpath));
|
||||
if ((mysql_rm_arc_files(thd, new_dirp, newpath)) < 0)
|
||||
goto err;
|
||||
DBUG_RETURN(true);
|
||||
continue;
|
||||
}
|
||||
found_other_files++;
|
||||
*found_other_files= true;
|
||||
continue;
|
||||
}
|
||||
if (!(extension= strrchr(file->name, '.')))
|
||||
extension= strend(file->name);
|
||||
if (find_type(extension, &deletable_extentions,1+2) <= 0)
|
||||
if (find_type(extension, &deletable_extentions, FIND_TYPE_NO_PREFIX) <= 0)
|
||||
{
|
||||
if (find_type(extension, ha_known_exts(),1+2) <= 0)
|
||||
found_other_files++;
|
||||
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 */
|
||||
@@ -1036,7 +1064,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
|
||||
strlen(file->name) + 1);
|
||||
|
||||
if (!table_list)
|
||||
goto err;
|
||||
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;
|
||||
@@ -1054,61 +1082,31 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
|
||||
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);
|
||||
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;
|
||||
deleted++;
|
||||
}
|
||||
else
|
||||
{
|
||||
strxmov(filePath, org_path, "/", file->name, NullS);
|
||||
if (mysql_file_delete_with_symlink(key_file_misc, filePath, MYF(MY_WME)))
|
||||
strxmov(filePath, path, "/", file->name, NullS);
|
||||
/*
|
||||
We ignore ENOENT error in order to skip files that was deleted
|
||||
by concurrently running statement like REAPIR TABLE ...
|
||||
*/
|
||||
if (my_delete_with_symlink(filePath, MYF(0)) &&
|
||||
my_errno != ENOENT)
|
||||
{
|
||||
goto err;
|
||||
my_error(EE_DELETE, MYF(0), filePath, my_errno);
|
||||
DBUG_RETURN(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (thd->killed ||
|
||||
(tot_list && mysql_rm_table_part2(thd, tot_list, 1, 0, 1, 1)))
|
||||
goto err;
|
||||
|
||||
/* Remove RAID directories */
|
||||
{
|
||||
List_iterator<String> it(raid_dirs);
|
||||
String *dir;
|
||||
while ((dir= it++))
|
||||
if (rmdir(dir->c_ptr()) < 0)
|
||||
found_other_files++;
|
||||
}
|
||||
my_dirend(dirp);
|
||||
|
||||
if (dropped_tables)
|
||||
*dropped_tables= tot_list;
|
||||
|
||||
/*
|
||||
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), org_path, EEXIST);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Don't give errors if we can't delete 'RAID' directory */
|
||||
if (rm_dir_w_symlink(org_path, level == 0))
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
DBUG_RETURN(deleted);
|
||||
|
||||
err:
|
||||
my_dirend(dirp);
|
||||
DBUG_RETURN(-1);
|
||||
*tables= tot_list;
|
||||
DBUG_RETURN(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user