Commit 53a0372d authored by bar@mysql.com's avatar bar@mysql.com

Merge abarkov@bk-internal.mysql.com:/home/bk/mysql-5.1-new

into  mysql.com:/usr/home/bar/mysql-5.1-new.fscs
parents fd2b90d1 611cbc2f
drop database if exists testdb1;
create database testdb1 default character set latin2;
use testdb1;
create table t1 (a int);
insert into t1 values (1),(2),(3);
show create database testdb1;
Database Create Database
testdb1 CREATE DATABASE `testdb1` /*!40100 DEFAULT CHARACTER SET latin2 */
show tables;
Tables_in_testdb1
t1
rename database testdb1 to testdb2;
show create database testdb1;
ERROR 42000: Unknown database 'testdb1'
show create database testdb2;
Database Create Database
testdb2 CREATE DATABASE `testdb2` /*!40100 DEFAULT CHARACTER SET latin2 */
select database();
database()
testdb2
show tables;
Tables_in_testdb2
t1
select a from t1 order by a;
a
1
2
3
drop database testdb2;
--disable_warnings
drop database if exists testdb1;
--enable_warnings
create database testdb1 default character set latin2;
use testdb1;
create table t1 (a int);
insert into t1 values (1),(2),(3);
show create database testdb1;
show tables;
rename database testdb1 to testdb2;
--error 1049
show create database testdb1;
show create database testdb2;
select database();
show tables;
select a from t1 order by a;
drop database testdb2;
......@@ -611,6 +611,7 @@ void write_bin_log(THD *thd, bool clear_error,
bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent);
bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create);
bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db);
void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags);
void mysql_client_binlog_statement(THD *thd);
bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
......@@ -623,7 +624,7 @@ int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables,
bool quick_rm_table(handlerton *base,const char *db,
const char *table_name);
void close_cached_table(THD *thd, TABLE *table);
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent);
bool mysql_change_db(THD *thd,const char *name,bool no_access_check);
void mysql_parse(THD *thd,char *inBuf,uint length);
bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
......@@ -1228,10 +1229,12 @@ uint check_word(TYPELIB *lib, const char *val, const char *end,
bool is_keyword(const char *name, uint len);
#define MY_DB_OPT_FILE "db.opt"
bool my_database_names_init(void);
void my_database_names_free(void);
bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create);
bool my_dbopt_init(void);
void my_dbopt_cleanup(void);
void my_dbopt_free(void);
extern int creating_database; // How many database locks are made
extern int creating_table; // How many mysql_create_table() are running
/*
External variables
......@@ -1333,7 +1336,7 @@ extern FILE *bootstrap_file;
extern int bootstrap_error;
extern FILE *stderror_file;
extern pthread_key(MEM_ROOT**,THR_MALLOC);
extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open,
extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open, LOCK_lock_db,
LOCK_thread_count,LOCK_mapped_file,LOCK_user_locks, LOCK_status,
LOCK_error_log, LOCK_delayed_insert, LOCK_uuid_generator,
LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
......@@ -1364,7 +1367,7 @@ extern const char *opt_date_time_formats[];
extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[];
extern String null_string;
extern HASH open_cache;
extern HASH open_cache, lock_db_cache;
extern TABLE *unused_tables;
extern const char* any_db;
extern struct my_option my_long_options[];
......
......@@ -1170,7 +1170,7 @@ void clean_up(bool print_message)
bitmap_free(&slave_error_mask);
#endif
my_tz_free();
my_dbopt_free();
my_database_names_free();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
acl_free(1);
grant_free();
......@@ -1283,6 +1283,7 @@ static void wait_for_signal_thread_to_end()
static void clean_up_mutexes()
{
(void) pthread_mutex_destroy(&LOCK_mysql_create_db);
(void) pthread_mutex_destroy(&LOCK_lock_db);
(void) pthread_mutex_destroy(&LOCK_Acl);
(void) rwlock_destroy(&LOCK_grant);
(void) pthread_mutex_destroy(&LOCK_open);
......@@ -2838,7 +2839,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1))
return 1;
if (my_dbopt_init())
if (my_database_names_init())
return 1;
/*
......@@ -2892,6 +2893,7 @@ You should consider changing lower_case_table_names to 1 or 2",
static int init_thread_environment()
{
(void) pthread_mutex_init(&LOCK_mysql_create_db,MY_MUTEX_INIT_SLOW);
(void) pthread_mutex_init(&LOCK_lock_db,MY_MUTEX_INIT_SLOW);
(void) pthread_mutex_init(&LOCK_Acl,MY_MUTEX_INIT_SLOW);
(void) pthread_mutex_init(&LOCK_open, NULL);
(void) pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST);
......
......@@ -38,6 +38,107 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp,
static 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);
/* Database lock hash */
HASH lock_db_cache;
pthread_mutex_t LOCK_lock_db;
int creating_database= 0; // how many database locks are made
/* Structure for database lock */
typedef struct my_dblock_st
{
char *name; /* Database name */
uint name_length; /* Database length name */
} my_dblock_t;
/*
lock_db key.
*/
static byte* lock_db_get_key(my_dblock_t *ptr, uint *length,
my_bool not_used __attribute__((unused)))
{
*length= ptr->name_length;
return (byte*) ptr->name;
}
/*
Free lock_db hash element.
*/
static void lock_db_free_element(void *ptr)
{
my_free((gptr) ptr, MYF(0));
}
/*
Put a database lock entry into the hash.
DESCRIPTION
Insert a database lock entry into hash.
LOCK_db_lock must be previously locked.
RETURN VALUES
0 on success.
1 on error.
*/
static my_bool lock_db_insert(const char *dbname, uint length)
{
my_dblock_t *opt;
my_bool error= 0;
DBUG_ENTER("lock_db_insert");
safe_mutex_assert_owner(&LOCK_lock_db);
if (!(opt= (my_dblock_t*) hash_search(&lock_db_cache,
(byte*) dbname, length)))
{
/* Db is not in the hash, insert it */
char *tmp_name;
if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
&opt, (uint) sizeof(*opt), &tmp_name, length+1,
NullS))
{
error= 1;
goto end;
}
opt->name= tmp_name;
strmov(opt->name, dbname);
opt->name_length= length;
if ((error= my_hash_insert(&lock_db_cache, (byte*) opt)))
{
my_free((gptr) opt, MYF(0));
goto end;
}
}
end:
DBUG_RETURN(error);
}
/*
Delete a database lock entry from hash.
*/
void lock_db_delete(const char *name, uint length)
{
my_dblock_t *opt;
safe_mutex_assert_owner(&LOCK_lock_db);
opt= (my_dblock_t *)hash_search(&lock_db_cache, (const byte*) name, length);
DBUG_ASSERT(opt != NULL);
hash_delete(&lock_db_cache, (byte*) opt);
}
/* Database options hash */
static HASH dboptions;
static my_bool dboptions_init= 0;
......@@ -90,10 +191,10 @@ static void free_dbopt(void *dbopt)
/*
Initialize database option hash
Initialize database option hash and locked database hash.
SYNOPSIS
my_dbopt_init()
my_database_names()
NOTES
Must be called before any other database function is called.
......@@ -103,7 +204,7 @@ static void free_dbopt(void *dbopt)
1 Fatal error
*/
bool my_dbopt_init(void)
bool my_database_names_init(void)
{
bool error= 0;
(void) my_rwlock_init(&LOCK_dboptions, NULL);
......@@ -113,27 +214,38 @@ bool my_dbopt_init(void)
error= hash_init(&dboptions, lower_case_table_names ?
&my_charset_bin : system_charset_info,
32, 0, 0, (hash_get_key) dboptions_get_key,
free_dbopt,0);
free_dbopt,0) ||
hash_init(&lock_db_cache, lower_case_table_names ?
&my_charset_bin : system_charset_info,
32, 0, 0, (hash_get_key) lock_db_get_key,
lock_db_free_element,0);
}
return error;
}
/*
Free database option hash.
Free database option hash and locked databases hash.
*/
void my_dbopt_free(void)
void my_database_names_free(void)
{
if (dboptions_init)
{
dboptions_init= 0;
hash_free(&dboptions);
(void) rwlock_destroy(&LOCK_dboptions);
hash_free(&lock_db_cache);
}
}
/*
Cleanup cached options
*/
void my_dbopt_cleanup(void)
{
rw_wrlock(&LOCK_dboptions);
......@@ -1219,3 +1331,312 @@ end:
}
DBUG_RETURN(0);
}
static int
lock_databases(THD *thd, const char *db1, uint length1,
const char *db2, uint length2)
{
pthread_mutex_lock(&LOCK_lock_db);
while (!thd->killed &&
(hash_search(&lock_db_cache,(byte*) db1, length1) ||
hash_search(&lock_db_cache,(byte*) db2, length2)))
{
wait_for_condition(thd, &LOCK_lock_db, &COND_refresh);
pthread_mutex_lock(&LOCK_lock_db);
}
if (thd->killed)
{
pthread_mutex_unlock(&LOCK_lock_db);
return 1;
}
lock_db_insert(db1, length1);
lock_db_insert(db2, length2);
creating_database++;
/*
Wait if a concurent thread is creating a table at the same time.
The assumption here is that it will not take too long until
there is a point in time when a table is not created.
*/
while (!thd->killed && creating_table)
{
wait_for_condition(thd, &LOCK_lock_db, &COND_refresh);
pthread_mutex_lock(&LOCK_lock_db);
}
if (thd->killed)
{
lock_db_delete(db1, length1);
lock_db_delete(db2, length2);
creating_database--;
pthread_mutex_unlock(&LOCK_lock_db);
pthread_cond_signal(&COND_refresh);
return(1);
}
/*
We can unlock now as the hash will protect against anyone creating a table
in the databases we are using
*/
pthread_mutex_unlock(&LOCK_lock_db);
return 0;
}
/*
Rename database.
SYNOPSIS
mysql_rename_db()
thd Thread handler
olddb Old database name
newdb New database name
DESCRIPTION
This function is invoked whenever a RENAME DATABASE query is executed:
RENAME DATABASE 'olddb' TO 'newdb'.
NOTES
If we have managed to rename (move) tables to the new database
but something failed on a later step, then we store the
RENAME DATABASE event in the log. mysql_rename_db() is atomic in
the sense that it will rename all or none of the tables.
TODO:
- Better trigger, stored procedure, event, grant handling,
see the comments below.
NOTE: It's probably a good idea to call wait_if_global_read_lock()
once in mysql_rename_db(), instead of locking inside all
the required functions for renaming triggerts, SP, events, grants, etc.
RETURN VALUES
0 ok
1 error
*/
bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db)
{
int error= 0, change_to_newdb= 0;
char path[FN_REFLEN+16];
uint length;
HA_CREATE_INFO create_info;
MY_DIR *dirp;
TABLE_LIST *table_list;
SELECT_LEX *sl= thd->lex->current_select;
DBUG_ENTER("mysql_rename_db");
if (lock_databases(thd, old_db->str, old_db->length,
new_db->str, new_db->length))
return 1;
/*
Let's remember if we should do "USE newdb" afterwards.
thd->db will be cleared in mysql_rename_db()
*/
if (thd->db && !strcmp(thd->db, old_db->str))
change_to_newdb= 1;
build_table_filename(path, sizeof(path)-1, old_db->str, "", MY_DB_OPT_FILE);
if ((load_db_opt(thd, path, &create_info)))
create_info.default_table_charset= thd->variables.collation_server;
length= build_table_filename(path, sizeof(path)-1, old_db->str, "", "");
if (length && path[length-1] == FN_LIBCHAR)
path[length-1]=0; // remove ending '\'
if ((error= my_access(path,F_OK)))
{
my_error(ER_BAD_DB_ERROR, MYF(0), old_db->str);
goto exit;
}
/* Step1: Create the new database */
if ((error= mysql_create_db(thd, new_db->str, &create_info, 1)))
goto exit;
/* Step2: Move tables to the new database */
if ((dirp = my_dir(path,MYF(MY_DONT_SORT))))
{
uint nfiles= (uint) dirp->number_off_files;
for (uint idx=0 ; idx < nfiles && !thd->killed ; idx++)
{
FILEINFO *file= dirp->dir_entry + idx;
char *extension, tname[FN_REFLEN];
LEX_STRING table_str;
DBUG_PRINT("info",("Examining: %s", file->name));
/* skiping non-FRM files */
if (my_strcasecmp(files_charset_info,
(extension= fn_rext(file->name)), reg_ext))
continue;
/* A frm file found, add the table info rename list */
*extension= '\0';
table_str.length= filename_to_tablename(file->name,
tname, sizeof(tname)-1);
table_str.str= sql_memdup(tname, table_str.length + 1);
Table_ident *old_ident= new Table_ident(thd, *old_db, table_str, 0);
Table_ident *new_ident= new Table_ident(thd, *new_db, table_str, 0);
if (!old_ident || !new_ident ||
!sl->add_table_to_list(thd, old_ident, NULL,
TL_OPTION_UPDATING, TL_IGNORE) ||
!sl->add_table_to_list(thd, new_ident, NULL,
TL_OPTION_UPDATING, TL_IGNORE))
{
error= 1;
my_dirend(dirp);
goto exit;
}
}
my_dirend(dirp);
}
if ((table_list= thd->lex->query_tables) &&
(error= mysql_rename_tables(thd, table_list, 1)))
{
/*
Failed to move all tables from the old database to the new one.
In the best case mysql_rename_tables() moved all tables back to the old
database. In the worst case mysql_rename_tables() moved some tables
to the new database, then failed, then started to move the tables back, and
then failed again. In this situation we have some tables in the
old database and some tables in the new database.
Let's delete the option file, and then the new database directory.
If some tables were left in the new directory, rmdir() will fail.
It garantees we never loose any tables.
*/
build_table_filename(path, sizeof(path)-1, new_db->str,"",MY_DB_OPT_FILE);
my_delete(path, MYF(MY_WME));
length= build_table_filename(path, sizeof(path)-1, new_db->str, "", "");
if (length && path[length-1] == FN_LIBCHAR)
path[length-1]=0; // remove ending '\'
rmdir(path);
goto exit;
}
/*
Step3: move all remaining files to the new db's directory.
Skip db opt file: it's been created by mysql_create_db() in
the new directory, and will be dropped by mysql_rm_db() in the old one.
Trigger TRN and TRG files are be moved as regular files at the moment,
without any special treatment.
Triggers without explicit database qualifiers in table names work fine:
use d1;
create trigger trg1 before insert on t2 for each row set @a:=1
rename database d1 to d2;
TODO: Triggers, having the renamed database explicitely written
in the table qualifiers.
1. when the same database is renamed:
create trigger d1.trg1 before insert on d1.t1 for each row set @a:=1;
rename database d1 to d2;
Problem: After database renaming, the trigger's body
still points to the old database d1.
2. when another database is renamed:
create trigger d3.trg1 before insert on d3.t1 for each row
insert into d1.t1 values (...);
rename database d1 to d2;
Problem: After renaming d1 to d2, the trigger's body
in the database d3 still points to database d1.
*/
if ((dirp = my_dir(path,MYF(MY_DONT_SORT))))
{
uint nfiles= (uint) dirp->number_off_files;
for (uint idx=0 ; idx < nfiles ; idx++)
{
FILEINFO *file= dirp->dir_entry + idx;
char oldname[FN_REFLEN], newname[FN_REFLEN];
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))
continue;
/* pass empty file name, and file->name as extension to avoid encoding */
build_table_filename(oldname, sizeof(oldname)-1,
old_db->str, "", file->name);
build_table_filename(newname, sizeof(newname)-1,
new_db->str, "", file->name);
my_rename(oldname, newname, MYF(MY_WME));
}
my_dirend(dirp);
}
/*
Step4: TODO: moving stored procedures in the 'proc' system table
We need a new function: sp_move_db_routines(thd, olddb, newdb)
Which will basically have the same effect with:
UPDATE proc SET db='newdb' WHERE db='olddb'
Note, for 5.0 to 5.1 upgrade purposes we don't really need it.
The biggest problem here is that we can't have a lock on LOCK_open() while
calling open_table() for 'proc'.
Two solutions:
- Start by opening the 'event' and 'proc' (and other) tables for write
even before creating the 'to' database. (This will have the nice
effect of blocking another 'rename database' while the lock is active).
- Use the solution "Disable create of new tables during lock table"
For an example of how to read through all rows, see:
sql_help.cc::search_topics()
*/
/*
Step5: TODO: moving events in the 'event' system table
We need a new function evex_move_db_events(thd, olddb, newdb)
Which will have the same effect with:
UPDATE event SET db='newdb' WHERE db='olddb'
Note, for 5.0 to 5.1 upgrade purposes we don't really need it.
*/
/*
Step6: TODO: moving grants in the 'db', 'tables_priv', 'columns_priv'.
Update each grant table, doing the same with:
UPDATE system_table SET db='newdb' WHERE db='olddb'
*/
/*
Step7: drop the old database.
remove_db_from_cache(olddb) and query_cache_invalidate(olddb)
are done inside mysql_rm_db(), no needs to execute them again.
mysql_rm_db() also "unuses" if we drop the current database.
*/
error= mysql_rm_db(thd, old_db->str, 0, 1);
/* Step8: logging */
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, TRUE);
thd->clear_error();
mysql_bin_log.write(&qinfo);
}
/* Step9: Let's do "use newdb" if we renamed the current database */
if (change_to_newdb)
error|= mysql_change_db(thd, new_db->str, 0);
exit:
pthread_mutex_lock(&LOCK_lock_db);
/* Remove the databases from db lock cache */
lock_db_delete(old_db->str, old_db->length);
lock_db_delete(new_db->str, new_db->length);
creating_database--;
/* Signal waiting CREATE TABLE's to continue */
pthread_cond_signal(&COND_refresh);
pthread_mutex_unlock(&LOCK_lock_db);
DBUG_RETURN(error);
}
......@@ -67,6 +67,7 @@ enum enum_sql_command {
SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES,
SQLCOM_GRANT,
SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB, SQLCOM_ALTER_DB,
SQLCOM_RENAME_DB,
SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT,
SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION,
SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK,
......@@ -818,6 +819,7 @@ typedef struct st_lex
required a local context, the parser pops the top-most context.
*/
List<Name_resolution_context> context_stack;
List<LEX_STRING> db_list;
SQL_LIST proc_list, auxilliary_table_list, save_list;
create_field *last_field;
......
......@@ -3073,7 +3073,7 @@ end_with_restore_list:
}
}
query_cache_invalidate3(thd, first_table, 0);
if (end_active_trans(thd) || mysql_rename_tables(thd, first_table))
if (end_active_trans(thd) || mysql_rename_tables(thd, first_table, 0))
goto error;
break;
}
......@@ -3663,6 +3663,48 @@ end_with_restore_list:
res= mysql_rm_db(thd, lex->name, lex->drop_if_exists, 0);
break;
}
case SQLCOM_RENAME_DB:
{
LEX_STRING *olddb, *newdb;
List_iterator <LEX_STRING> db_list(lex->db_list);
olddb= db_list++;
newdb= db_list++;
if (end_active_trans(thd))
{
res= 1;
break;
}
#ifdef HAVE_REPLICATION
if (thd->slave_thread &&
(!rpl_filter->db_ok(olddb->str) ||
!rpl_filter->db_ok(newdb->str) ||
!rpl_filter->db_ok_with_wild_table(olddb->str) ||
!rpl_filter->db_ok_with_wild_table(newdb->str)))
{
res= 1;
my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
break;
}
#endif
if (check_access(thd,ALTER_ACL,olddb->str,0,1,0,is_schema_db(olddb->str)) ||
check_access(thd,DROP_ACL,olddb->str,0,1,0,is_schema_db(olddb->str)) ||
check_access(thd,CREATE_ACL,newdb->str,0,1,0,is_schema_db(newdb->str)))
{
res= 1;
break;
}
if (thd->locked_tables || thd->active_transaction())
{
res= 1;
my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
res= mysql_rename_db(thd, olddb, newdb);
if (!res)
send_ok(thd);
break;
}
case SQLCOM_ALTER_DB:
{
char *db= lex->name ? lex->name : thd->db;
......
......@@ -31,7 +31,7 @@ static TABLE_LIST *reverse_table_list(TABLE_LIST *table_list);
second entry is the new name.
*/
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent)
{
bool error= 1;
TABLE_LIST *ren_table= 0;
......@@ -79,7 +79,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
}
/* Lets hope this doesn't fail as the result will be messy */
if (!error)
if (!silent && !error)
{
if (mysql_bin_log.is_open())
{
......
......@@ -28,6 +28,8 @@
#include <io.h>
#endif
int creating_table= 0; // How many mysql_create_table are running
const char *primary_key_name="PRIMARY";
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
......@@ -1973,7 +1975,7 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field)
Create a table
SYNOPSIS
mysql_create_table()
mysql_create_table_internal()
thd Thread object
db Database
table_name Table name
......@@ -1996,11 +1998,12 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field)
TRUE error
*/
bool mysql_create_table(THD *thd,const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
List<create_field> &fields,
List<Key> &keys,bool internal_tmp_table,
uint select_field_count)
bool mysql_create_table_internal(THD *thd,
const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
List<create_field> &fields,
List<Key> &keys,bool internal_tmp_table,
uint select_field_count)
{
char path[FN_REFLEN];
uint path_length;
......@@ -2009,7 +2012,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
KEY *key_info_buffer;
handler *file;
bool error= TRUE;
DBUG_ENTER("mysql_create_table");
DBUG_ENTER("mysql_create_table_internal");
/* Check for duplicate fields and check type of table to create */
if (!fields.elements)
......@@ -2289,6 +2292,49 @@ warn:
goto unlock_and_end;
}
/*
Database locking aware wrapper for mysql_create_table_internal(),
*/
bool mysql_create_table(THD *thd, const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
List<create_field> &fields,
List<Key> &keys,bool internal_tmp_table,
uint select_field_count)
{
bool result;
DBUG_ENTER("mysql_create_table");
/* Wait for any database locks */
pthread_mutex_lock(&LOCK_lock_db);
while (!thd->killed &&
hash_search(&lock_db_cache,(byte*) db, strlen(db)))
{
wait_for_condition(thd, &LOCK_lock_db, &COND_refresh);
pthread_mutex_lock(&LOCK_lock_db);
}
if (thd->killed)
{
pthread_mutex_unlock(&LOCK_lock_db);
DBUG_RETURN(TRUE);
}
creating_table++;
pthread_mutex_unlock(&LOCK_lock_db);
result= mysql_create_table_internal(thd, db, table_name, create_info,
fields, keys, internal_tmp_table,
select_field_count);
pthread_mutex_lock(&LOCK_lock_db);
if (!--creating_table && creating_database)
pthread_cond_signal(&COND_refresh);
pthread_mutex_unlock(&LOCK_lock_db);
DBUG_RETURN(result);
}
/*
** Give the key name after the first field with an optional '_#' after
**/
......
......@@ -863,7 +863,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
clear_privileges flush_options flush_option
equal optional_braces opt_key_definition key_usage_list2
opt_mi_check_type opt_to mi_check_types normal_join
table_to_table_list table_to_table opt_table_list opt_as
db_to_db table_to_table_list table_to_table opt_table_list opt_as
handler_rkey_function handler_read_or_scan
single_multi table_wild_list table_wild_one opt_wild
union_clause union_list
......@@ -5485,6 +5485,13 @@ rename:
}
table_to_table_list
{}
| RENAME DATABASE
{
Lex->db_list.empty();
Lex->sql_command= SQLCOM_RENAME_DB;
}
db_to_db
{}
| RENAME USER clear_privileges rename_list
{
Lex->sql_command = SQLCOM_RENAME_USER;
......@@ -5520,6 +5527,17 @@ table_to_table:
YYABORT;
};
db_to_db:
ident TO_SYM ident
{
LEX *lex=Lex;
if (Lex->db_list.push_back((LEX_STRING*)
sql_memdup(&$1, sizeof(LEX_STRING))) ||
Lex->db_list.push_back((LEX_STRING*)
sql_memdup(&$3, sizeof(LEX_STRING))))
YYABORT;
};
keycache:
CACHE_SYM INDEX_SYM keycache_list IN_SYM key_cache_name
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment