1
0
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:
Sergei Golubchik
2011-07-02 22:08:51 +02:00
3220 changed files with 94894 additions and 422456 deletions

View File

@@ -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);
}