00001 /* Copyright (C) 2000-2003 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 00018 /* create and drop of databases */ 00019 00020 #include "mysql_priv.h" 00021 #include <mysys_err.h> 00022 #include "sp.h" 00023 #include "events.h" 00024 #include <my_dir.h> 00025 #include <m_ctype.h> 00026 #ifdef __WIN__ 00027 #include <direct.h> 00028 #endif 00029 00030 #define MAX_DROP_TABLE_Q_LEN 1024 00031 00032 const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NullS}; 00033 static TYPELIB deletable_extentions= 00034 {array_elements(del_exts)-1,"del_exts", del_exts, NULL}; 00035 00036 static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, 00037 const char *db, const char *path, uint level, 00038 TABLE_LIST **dropped_tables); 00039 00040 static long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path); 00041 static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error); 00042 00043 00044 /* Database lock hash */ 00045 HASH lock_db_cache; 00046 pthread_mutex_t LOCK_lock_db; 00047 int creating_database= 0; // how many database locks are made 00048 00049 00050 /* Structure for database lock */ 00051 typedef struct my_dblock_st 00052 { 00053 char *name; /* Database name */ 00054 uint name_length; /* Database length name */ 00055 } my_dblock_t; 00056 00057 00058 /* 00059 lock_db key. 00060 */ 00061 00062 static byte* lock_db_get_key(my_dblock_t *ptr, uint *length, 00063 my_bool not_used __attribute__((unused))) 00064 { 00065 *length= ptr->name_length; 00066 return (byte*) ptr->name; 00067 } 00068 00069 00070 /* 00071 Free lock_db hash element. 00072 */ 00073 00074 static void lock_db_free_element(void *ptr) 00075 { 00076 my_free((gptr) ptr, MYF(0)); 00077 } 00078 00079 00080 /* 00081 Put a database lock entry into the hash. 00082 00083 DESCRIPTION 00084 Insert a database lock entry into hash. 00085 LOCK_db_lock must be previously locked. 00086 00087 RETURN VALUES 00088 0 on success. 00089 1 on error. 00090 */ 00091 00092 static my_bool lock_db_insert(const char *dbname, uint length) 00093 { 00094 my_dblock_t *opt; 00095 my_bool error= 0; 00096 DBUG_ENTER("lock_db_insert"); 00097 00098 safe_mutex_assert_owner(&LOCK_lock_db); 00099 00100 if (!(opt= (my_dblock_t*) hash_search(&lock_db_cache, 00101 (byte*) dbname, length))) 00102 { 00103 /* Db is not in the hash, insert it */ 00104 char *tmp_name; 00105 if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), 00106 &opt, (uint) sizeof(*opt), &tmp_name, length+1, 00107 NullS)) 00108 { 00109 error= 1; 00110 goto end; 00111 } 00112 00113 opt->name= tmp_name; 00114 strmov(opt->name, dbname); 00115 opt->name_length= length; 00116 00117 if ((error= my_hash_insert(&lock_db_cache, (byte*) opt))) 00118 { 00119 my_free((gptr) opt, MYF(0)); 00120 goto end; 00121 } 00122 } 00123 00124 end: 00125 DBUG_RETURN(error); 00126 } 00127 00128 00129 /* 00130 Delete a database lock entry from hash. 00131 */ 00132 00133 void lock_db_delete(const char *name, uint length) 00134 { 00135 my_dblock_t *opt; 00136 safe_mutex_assert_owner(&LOCK_lock_db); 00137 if ((opt= (my_dblock_t *)hash_search(&lock_db_cache, 00138 (const byte*) name, length))) 00139 hash_delete(&lock_db_cache, (byte*) opt); 00140 } 00141 00142 00143 /* Database options hash */ 00144 static HASH dboptions; 00145 static my_bool dboptions_init= 0; 00146 static rw_lock_t LOCK_dboptions; 00147 00148 /* Structure for database options */ 00149 typedef struct my_dbopt_st 00150 { 00151 char *name; /* Database name */ 00152 uint name_length; /* Database length name */ 00153 CHARSET_INFO *charset; /* Database default character set */ 00154 } my_dbopt_t; 00155 00156 00157 /* 00158 Function we use in the creation of our hash to get key. 00159 */ 00160 00161 static byte* dboptions_get_key(my_dbopt_t *opt, uint *length, 00162 my_bool not_used __attribute__((unused))) 00163 { 00164 *length= opt->name_length; 00165 return (byte*) opt->name; 00166 } 00167 00168 00169 /* 00170 Helper function to write a query to binlog used by mysql_rm_db() 00171 */ 00172 00173 static inline void write_to_binlog(THD *thd, char *query, uint q_len, 00174 char *db, uint db_len) 00175 { 00176 Query_log_event qinfo(thd, query, q_len, 0, 0); 00177 qinfo.error_code= 0; 00178 qinfo.db= db; 00179 qinfo.db_len= db_len; 00180 mysql_bin_log.write(&qinfo); 00181 } 00182 00183 00184 /* 00185 Function to free dboptions hash element 00186 */ 00187 00188 static void free_dbopt(void *dbopt) 00189 { 00190 my_free((gptr) dbopt, MYF(0)); 00191 } 00192 00193 00194 /* 00195 Initialize database option hash and locked database hash. 00196 00197 SYNOPSIS 00198 my_database_names() 00199 00200 NOTES 00201 Must be called before any other database function is called. 00202 00203 RETURN 00204 0 ok 00205 1 Fatal error 00206 */ 00207 00208 bool my_database_names_init(void) 00209 { 00210 bool error= 0; 00211 (void) my_rwlock_init(&LOCK_dboptions, NULL); 00212 if (!dboptions_init) 00213 { 00214 dboptions_init= 1; 00215 error= hash_init(&dboptions, lower_case_table_names ? 00216 &my_charset_bin : system_charset_info, 00217 32, 0, 0, (hash_get_key) dboptions_get_key, 00218 free_dbopt,0) || 00219 hash_init(&lock_db_cache, lower_case_table_names ? 00220 &my_charset_bin : system_charset_info, 00221 32, 0, 0, (hash_get_key) lock_db_get_key, 00222 lock_db_free_element,0); 00223 00224 } 00225 return error; 00226 } 00227 00228 00229 00230 /* 00231 Free database option hash and locked databases hash. 00232 */ 00233 00234 void my_database_names_free(void) 00235 { 00236 if (dboptions_init) 00237 { 00238 dboptions_init= 0; 00239 hash_free(&dboptions); 00240 (void) rwlock_destroy(&LOCK_dboptions); 00241 hash_free(&lock_db_cache); 00242 } 00243 } 00244 00245 00246 /* 00247 Cleanup cached options 00248 */ 00249 00250 void my_dbopt_cleanup(void) 00251 { 00252 rw_wrlock(&LOCK_dboptions); 00253 hash_free(&dboptions); 00254 hash_init(&dboptions, lower_case_table_names ? 00255 &my_charset_bin : system_charset_info, 00256 32, 0, 0, (hash_get_key) dboptions_get_key, 00257 free_dbopt,0); 00258 rw_unlock(&LOCK_dboptions); 00259 } 00260 00261 00262 /* 00263 Find database options in the hash. 00264 00265 DESCRIPTION 00266 Search a database options in the hash, usings its path. 00267 Fills "create" on success. 00268 00269 RETURN VALUES 00270 0 on success. 00271 1 on error. 00272 */ 00273 00274 static my_bool get_dbopt(const char *dbname, HA_CREATE_INFO *create) 00275 { 00276 my_dbopt_t *opt; 00277 uint length; 00278 my_bool error= 1; 00279 00280 length= (uint) strlen(dbname); 00281 00282 rw_rdlock(&LOCK_dboptions); 00283 if ((opt= (my_dbopt_t*) hash_search(&dboptions, (byte*) dbname, length))) 00284 { 00285 create->default_table_charset= opt->charset; 00286 error= 0; 00287 } 00288 rw_unlock(&LOCK_dboptions); 00289 return error; 00290 } 00291 00292 00293 /* 00294 Writes database options into the hash. 00295 00296 DESCRIPTION 00297 Inserts database options into the hash, or updates 00298 options if they are already in the hash. 00299 00300 RETURN VALUES 00301 0 on success. 00302 1 on error. 00303 */ 00304 00305 static my_bool put_dbopt(const char *dbname, HA_CREATE_INFO *create) 00306 { 00307 my_dbopt_t *opt; 00308 uint length; 00309 my_bool error= 0; 00310 DBUG_ENTER("put_dbopt"); 00311 00312 length= (uint) strlen(dbname); 00313 00314 rw_wrlock(&LOCK_dboptions); 00315 if (!(opt= (my_dbopt_t*) hash_search(&dboptions, (byte*) dbname, length))) 00316 { 00317 /* Options are not in the hash, insert them */ 00318 char *tmp_name; 00319 if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), 00320 &opt, (uint) sizeof(*opt), &tmp_name, length+1, 00321 NullS)) 00322 { 00323 error= 1; 00324 goto end; 00325 } 00326 00327 opt->name= tmp_name; 00328 strmov(opt->name, dbname); 00329 opt->name_length= length; 00330 00331 if ((error= my_hash_insert(&dboptions, (byte*) opt))) 00332 { 00333 my_free((gptr) opt, MYF(0)); 00334 goto end; 00335 } 00336 } 00337 00338 /* Update / write options in hash */ 00339 opt->charset= create->default_table_charset; 00340 00341 end: 00342 rw_unlock(&LOCK_dboptions); 00343 DBUG_RETURN(error); 00344 } 00345 00346 00347 /* 00348 Deletes database options from the hash. 00349 */ 00350 00351 void del_dbopt(const char *path) 00352 { 00353 my_dbopt_t *opt; 00354 rw_wrlock(&LOCK_dboptions); 00355 if ((opt= (my_dbopt_t *)hash_search(&dboptions, (const byte*) path, 00356 strlen(path)))) 00357 hash_delete(&dboptions, (byte*) opt); 00358 rw_unlock(&LOCK_dboptions); 00359 } 00360 00361 00362 /* 00363 Create database options file: 00364 00365 DESCRIPTION 00366 Currently database default charset is only stored there. 00367 00368 RETURN VALUES 00369 0 ok 00370 1 Could not create file or write to it. Error sent through my_error() 00371 */ 00372 00373 static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create) 00374 { 00375 register File file; 00376 char buf[256]; // Should be enough for one option 00377 bool error=1; 00378 00379 if (!create->default_table_charset) 00380 create->default_table_charset= thd->variables.collation_server; 00381 00382 if (put_dbopt(path, create)) 00383 return 1; 00384 00385 if ((file=my_create(path, CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0) 00386 { 00387 ulong length; 00388 length= (ulong) (strxnmov(buf, sizeof(buf)-1, "default-character-set=", 00389 create->default_table_charset->csname, 00390 "\ndefault-collation=", 00391 create->default_table_charset->name, 00392 "\n", NullS) - buf); 00393 00394 /* Error is written by my_write */ 00395 if (!my_write(file,(byte*) buf, length, MYF(MY_NABP+MY_WME))) 00396 error=0; 00397 my_close(file,MYF(0)); 00398 } 00399 return error; 00400 } 00401 00402 00403 /* 00404 Load database options file 00405 00406 load_db_opt() 00407 path Path for option file 00408 create Where to store the read options 00409 00410 DESCRIPTION 00411 00412 RETURN VALUES 00413 0 File found 00414 1 No database file or could not open it 00415 00416 */ 00417 00418 bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create) 00419 { 00420 File file; 00421 char buf[256]; 00422 DBUG_ENTER("load_db_opt"); 00423 bool error=1; 00424 uint nbytes; 00425 00426 bzero((char*) create,sizeof(*create)); 00427 create->default_table_charset= thd->variables.collation_server; 00428 00429 /* Check if options for this database are already in the hash */ 00430 if (!get_dbopt(path, create)) 00431 DBUG_RETURN(0); 00432 00433 /* Otherwise, load options from the .opt file */ 00434 if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0) 00435 goto err1; 00436 00437 IO_CACHE cache; 00438 if (init_io_cache(&cache, file, IO_SIZE, READ_CACHE, 0, 0, MYF(0))) 00439 goto err2; 00440 00441 while ((int) (nbytes= my_b_gets(&cache, (char*) buf, sizeof(buf))) > 0) 00442 { 00443 char *pos= buf+nbytes-1; 00444 /* Remove end space and control characters */ 00445 while (pos > buf && !my_isgraph(&my_charset_latin1, pos[-1])) 00446 pos--; 00447 *pos=0; 00448 if ((pos= strchr(buf, '='))) 00449 { 00450 if (!strncmp(buf,"default-character-set", (pos-buf))) 00451 { 00452 /* 00453 Try character set name, and if it fails 00454 try collation name, probably it's an old 00455 4.1.0 db.opt file, which didn't have 00456 separate default-character-set and 00457 default-collation commands. 00458 */ 00459 if (!(create->default_table_charset= 00460 get_charset_by_csname(pos+1, MY_CS_PRIMARY, MYF(0))) && 00461 !(create->default_table_charset= 00462 get_charset_by_name(pos+1, MYF(0)))) 00463 { 00464 sql_print_error("Error while loading database options: '%s':",path); 00465 sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET),pos+1); 00466 create->default_table_charset= default_charset_info; 00467 } 00468 } 00469 else if (!strncmp(buf,"default-collation", (pos-buf))) 00470 { 00471 if (!(create->default_table_charset= get_charset_by_name(pos+1, 00472 MYF(0)))) 00473 { 00474 sql_print_error("Error while loading database options: '%s':",path); 00475 sql_print_error(ER(ER_UNKNOWN_COLLATION),pos+1); 00476 create->default_table_charset= default_charset_info; 00477 } 00478 } 00479 } 00480 } 00481 /* 00482 Put the loaded value into the hash. 00483 Note that another thread could've added the same 00484 entry to the hash after we called get_dbopt(), 00485 but it's not an error, as put_dbopt() takes this 00486 possibility into account. 00487 */ 00488 error= put_dbopt(path, create); 00489 00490 end_io_cache(&cache); 00491 err2: 00492 my_close(file,MYF(0)); 00493 err1: 00494 DBUG_RETURN(error); 00495 } 00496 00497 00498 /* 00499 Retrieve database options by name. Load database options file or fetch from 00500 cache. 00501 00502 SYNOPSIS 00503 load_db_opt_by_name() 00504 db_name Database name 00505 db_create_info Where to store the database options 00506 00507 DESCRIPTION 00508 load_db_opt_by_name() is a shortcut for load_db_opt(). 00509 00510 NOTE 00511 Although load_db_opt_by_name() (and load_db_opt()) returns status of 00512 the operation, it is useless usually and should be ignored. The problem 00513 is that there are 1) system databases ("mysql") and 2) virtual 00514 databases ("information_schema"), which do not contain options file. 00515 So, load_db_opt[_by_name]() returns FALSE for these databases, but this 00516 is not an error. 00517 00518 load_db_opt[_by_name]() clears db_create_info structure in any case, so 00519 even on failure it contains valid data. So, common use case is just 00520 call load_db_opt[_by_name]() without checking return value and use 00521 db_create_info right after that. 00522 00523 RETURN VALUES (read NOTE!) 00524 FALSE Success 00525 TRUE Failed to retrieve options 00526 */ 00527 00528 bool load_db_opt_by_name(THD *thd, const char *db_name, 00529 HA_CREATE_INFO *db_create_info) 00530 { 00531 char db_opt_path[FN_REFLEN]; 00532 00533 /* 00534 Pass an empty file name, and the database options file name as extension 00535 to avoid table name to file name encoding. 00536 */ 00537 (void) build_table_filename(db_opt_path, sizeof(db_opt_path), 00538 db_name, "", MY_DB_OPT_FILE, 0); 00539 00540 return load_db_opt(thd, db_opt_path, db_create_info); 00541 } 00542 00543 00544 /* 00545 Create a database 00546 00547 SYNOPSIS 00548 mysql_create_db() 00549 thd Thread handler 00550 db Name of database to create 00551 Function assumes that this is already validated. 00552 create_info Database create options (like character set) 00553 silent Used by replication when internally creating a database. 00554 In this case the entry should not be logged. 00555 00556 SIDE-EFFECTS 00557 1. Report back to client that command succeeded (send_ok) 00558 2. Report errors to client 00559 3. Log event to binary log 00560 (The 'silent' flags turns off 1 and 3.) 00561 00562 RETURN VALUES 00563 FALSE ok 00564 TRUE Error 00565 00566 */ 00567 00568 bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, 00569 bool silent) 00570 { 00571 char path[FN_REFLEN+16]; 00572 char tmp_query[FN_REFLEN+16]; 00573 long result= 1; 00574 int error= 0; 00575 MY_STAT stat_info; 00576 uint create_options= create_info ? create_info->options : 0; 00577 uint path_len; 00578 DBUG_ENTER("mysql_create_db"); 00579 00580 /* do not create 'information_schema' db */ 00581 if (!my_strcasecmp(system_charset_info, db, information_schema_name.str)) 00582 { 00583 my_error(ER_DB_CREATE_EXISTS, MYF(0), db); 00584 DBUG_RETURN(-1); 00585 } 00586 00587 /* 00588 Do not create database if another thread is holding read lock. 00589 Wait for global read lock before acquiring LOCK_mysql_create_db. 00590 After wait_if_global_read_lock() we have protection against another 00591 global read lock. If we would acquire LOCK_mysql_create_db first, 00592 another thread could step in and get the global read lock before we 00593 reach wait_if_global_read_lock(). If this thread tries the same as we 00594 (admin a db), it would then go and wait on LOCK_mysql_create_db... 00595 Furthermore wait_if_global_read_lock() checks if the current thread 00596 has the global read lock and refuses the operation with 00597 ER_CANT_UPDATE_WITH_READLOCK if applicable. 00598 */ 00599 if (wait_if_global_read_lock(thd, 0, 1)) 00600 { 00601 error= -1; 00602 goto exit2; 00603 } 00604 00605 VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); 00606 00607 /* Check directory */ 00608 path_len= build_table_filename(path, sizeof(path), db, "", "", 0); 00609 path[path_len-1]= 0; // Remove last '/' from path 00610 00611 if (my_stat(path,&stat_info,MYF(0))) 00612 { 00613 if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS)) 00614 { 00615 my_error(ER_DB_CREATE_EXISTS, MYF(0), db); 00616 error= -1; 00617 goto exit; 00618 } 00619 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, 00620 ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db); 00621 if (!silent) 00622 send_ok(thd); 00623 error= 0; 00624 goto exit; 00625 } 00626 else 00627 { 00628 if (my_errno != ENOENT) 00629 { 00630 my_error(EE_STAT, MYF(0), path, my_errno); 00631 goto exit; 00632 } 00633 if (my_mkdir(path,0777,MYF(0)) < 0) 00634 { 00635 my_error(ER_CANT_CREATE_DB, MYF(0), db, my_errno); 00636 error= -1; 00637 goto exit; 00638 } 00639 } 00640 00641 path[path_len-1]= FN_LIBCHAR; 00642 strmake(path+path_len, MY_DB_OPT_FILE, sizeof(path)-path_len-1); 00643 if (write_db_opt(thd, path, create_info)) 00644 { 00645 /* 00646 Could not create options file. 00647 Restore things to beginning. 00648 */ 00649 path[path_len]= 0; 00650 if (rmdir(path) >= 0) 00651 { 00652 error= -1; 00653 goto exit; 00654 } 00655 /* 00656 We come here when we managed to create the database, but not the option 00657 file. In this case it's best to just continue as if nothing has 00658 happened. (This is a very unlikely senario) 00659 */ 00660 } 00661 00662 if (!silent) 00663 { 00664 char *query; 00665 uint query_length; 00666 00667 if (!thd->query) // Only in replication 00668 { 00669 query= tmp_query; 00670 query_length= (uint) (strxmov(tmp_query,"create database `", 00671 db, "`", NullS) - tmp_query); 00672 } 00673 else 00674 { 00675 query= thd->query; 00676 query_length= thd->query_length; 00677 } 00678 00679 ha_binlog_log_query(thd, 0, LOGCOM_CREATE_DB, 00680 query, query_length, 00681 db, ""); 00682 00683 if (mysql_bin_log.is_open()) 00684 { 00685 Query_log_event qinfo(thd, query, query_length, 0, 00686 /* suppress_use */ TRUE); 00687 00688 /* 00689 Write should use the database being created as the "current 00690 database" and not the threads current database, which is the 00691 default. If we do not change the "current database" to the 00692 database being created, the CREATE statement will not be 00693 replicated when using --binlog-do-db to select databases to be 00694 replicated. 00695 00696 An example (--binlog-do-db=sisyfos): 00697 00698 CREATE DATABASE bob; # Not replicated 00699 USE bob; # 'bob' is the current database 00700 CREATE DATABASE sisyfos; # Not replicated since 'bob' is 00701 # current database. 00702 USE sisyfos; # Will give error on slave since 00703 # database does not exist. 00704 */ 00705 qinfo.db = db; 00706 qinfo.db_len = strlen(db); 00707 00708 mysql_bin_log.write(&qinfo); 00709 } 00710 send_ok(thd, result); 00711 } 00712 00713 exit: 00714 VOID(pthread_mutex_unlock(&LOCK_mysql_create_db)); 00715 start_waiting_global_read_lock(thd); 00716 exit2: 00717 DBUG_RETURN(error); 00718 } 00719 00720 00721 /* db-name is already validated when we come here */ 00722 00723 bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) 00724 { 00725 char path[FN_REFLEN+16]; 00726 long result=1; 00727 int error= 0; 00728 DBUG_ENTER("mysql_alter_db"); 00729 00730 /* 00731 Do not alter database if another thread is holding read lock. 00732 Wait for global read lock before acquiring LOCK_mysql_create_db. 00733 After wait_if_global_read_lock() we have protection against another 00734 global read lock. If we would acquire LOCK_mysql_create_db first, 00735 another thread could step in and get the global read lock before we 00736 reach wait_if_global_read_lock(). If this thread tries the same as we 00737 (admin a db), it would then go and wait on LOCK_mysql_create_db... 00738 Furthermore wait_if_global_read_lock() checks if the current thread 00739 has the global read lock and refuses the operation with 00740 ER_CANT_UPDATE_WITH_READLOCK if applicable. 00741 */ 00742 if ((error=wait_if_global_read_lock(thd,0,1))) 00743 goto exit2; 00744 00745 VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); 00746 00747 /* 00748 Recreate db options file: /dbpath/.db.opt 00749 We pass MY_DB_OPT_FILE as "extension" to avoid 00750 "table name to file name" encoding. 00751 */ 00752 build_table_filename(path, sizeof(path), db, "", MY_DB_OPT_FILE, 0); 00753 if ((error=write_db_opt(thd, path, create_info))) 00754 goto exit; 00755 00756 /* 00757 Change options if current database is being altered 00758 TODO: Delete this code 00759 */ 00760 if (thd->db && !strcmp(thd->db,db)) 00761 { 00762 thd->db_charset= create_info->default_table_charset ? 00763 create_info->default_table_charset : 00764 thd->variables.collation_server; 00765 thd->variables.collation_database= thd->db_charset; 00766 } 00767 00768 ha_binlog_log_query(thd, 0, LOGCOM_ALTER_DB, 00769 thd->query, thd->query_length, 00770 db, ""); 00771 00772 if (mysql_bin_log.is_open()) 00773 { 00774 Query_log_event qinfo(thd, thd->query, thd->query_length, 0, 00775 /* suppress_use */ TRUE); 00776 00777 /* 00778 Write should use the database being created as the "current 00779 database" and not the threads current database, which is the 00780 default. 00781 */ 00782 qinfo.db = db; 00783 qinfo.db_len = strlen(db); 00784 00785 thd->clear_error(); 00786 mysql_bin_log.write(&qinfo); 00787 } 00788 send_ok(thd, result); 00789 00790 exit: 00791 VOID(pthread_mutex_unlock(&LOCK_mysql_create_db)); 00792 start_waiting_global_read_lock(thd); 00793 exit2: 00794 DBUG_RETURN(error); 00795 } 00796 00797 00798 /* 00799 Drop all tables in a database and the database itself 00800 00801 SYNOPSIS 00802 mysql_rm_db() 00803 thd Thread handle 00804 db Database name in the case given by user 00805 It's already validated and set to lower case 00806 (if needed) when we come here 00807 if_exists Don't give error if database doesn't exists 00808 silent Don't generate errors 00809 00810 RETURN 00811 FALSE ok (Database dropped) 00812 ERROR Error 00813 */ 00814 00815 bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) 00816 { 00817 long deleted=0; 00818 int error= 0; 00819 char path[FN_REFLEN+16]; 00820 MY_DIR *dirp; 00821 uint length; 00822 TABLE_LIST* dropped_tables= 0; 00823 DBUG_ENTER("mysql_rm_db"); 00824 00825 /* 00826 Do not drop database if another thread is holding read lock. 00827 Wait for global read lock before acquiring LOCK_mysql_create_db. 00828 After wait_if_global_read_lock() we have protection against another 00829 global read lock. If we would acquire LOCK_mysql_create_db first, 00830 another thread could step in and get the global read lock before we 00831 reach wait_if_global_read_lock(). If this thread tries the same as we 00832 (admin a db), it would then go and wait on LOCK_mysql_create_db... 00833 Furthermore wait_if_global_read_lock() checks if the current thread 00834 has the global read lock and refuses the operation with 00835 ER_CANT_UPDATE_WITH_READLOCK if applicable. 00836 */ 00837 if (wait_if_global_read_lock(thd, 0, 1)) 00838 { 00839 error= -1; 00840 goto exit2; 00841 } 00842 00843 VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); 00844 00845 length= build_table_filename(path, sizeof(path), db, "", "", 0); 00846 strmov(path+length, MY_DB_OPT_FILE); // Append db option file name 00847 del_dbopt(path); // Remove dboption hash entry 00848 path[length]= '\0'; // Remove file name 00849 00850 /* See if the directory exists */ 00851 if (!(dirp= my_dir(path,MYF(MY_DONT_SORT)))) 00852 { 00853 if (!if_exists) 00854 { 00855 error= -1; 00856 my_error(ER_DB_DROP_EXISTS, MYF(0), db); 00857 goto exit; 00858 } 00859 else 00860 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, 00861 ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS), db); 00862 } 00863 else 00864 { 00865 pthread_mutex_lock(&LOCK_open); 00866 remove_db_from_cache(db); 00867 pthread_mutex_unlock(&LOCK_open); 00868 00869 00870 error= -1; 00871 if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0, 00872 &dropped_tables)) >= 0) 00873 { 00874 ha_drop_database(path); 00875 query_cache_invalidate1(db); 00876 error = 0; 00877 } 00878 } 00879 if (!silent && deleted>=0) 00880 { 00881 const char *query; 00882 ulong query_length; 00883 if (!thd->query) 00884 { 00885 /* The client used the old obsolete mysql_drop_db() call */ 00886 query= path; 00887 query_length= (uint) (strxmov(path, "drop database `", db, "`", 00888 NullS) - path); 00889 } 00890 else 00891 { 00892 query =thd->query; 00893 query_length= thd->query_length; 00894 } 00895 if (mysql_bin_log.is_open()) 00896 { 00897 Query_log_event qinfo(thd, query, query_length, 0, 00898 /* suppress_use */ TRUE); 00899 /* 00900 Write should use the database being created as the "current 00901 database" and not the threads current database, which is the 00902 default. 00903 */ 00904 qinfo.db = db; 00905 qinfo.db_len = strlen(db); 00906 00907 thd->clear_error(); 00908 mysql_bin_log.write(&qinfo); 00909 } 00910 thd->server_status|= SERVER_STATUS_DB_DROPPED; 00911 send_ok(thd, (ulong) deleted); 00912 thd->server_status&= ~SERVER_STATUS_DB_DROPPED; 00913 } 00914 else if (mysql_bin_log.is_open()) 00915 { 00916 char *query, *query_pos, *query_end, *query_data_start; 00917 TABLE_LIST *tbl; 00918 uint db_len; 00919 00920 if (!(query= thd->alloc(MAX_DROP_TABLE_Q_LEN))) 00921 goto exit; /* not much else we can do */ 00922 query_pos= query_data_start= strmov(query,"drop table "); 00923 query_end= query + MAX_DROP_TABLE_Q_LEN; 00924 db_len= strlen(db); 00925 00926 for (tbl= dropped_tables; tbl; tbl= tbl->next_local) 00927 { 00928 uint tbl_name_len; 00929 00930 /* 3 for the quotes and the comma*/ 00931 tbl_name_len= strlen(tbl->table_name) + 3; 00932 if (query_pos + tbl_name_len + 1 >= query_end) 00933 { 00934 write_to_binlog(thd, query, query_pos -1 - query, db, db_len); 00935 query_pos= query_data_start; 00936 } 00937 00938 *query_pos++ = '`'; 00939 query_pos= strmov(query_pos,tbl->table_name); 00940 *query_pos++ = '`'; 00941 *query_pos++ = ','; 00942 } 00943 00944 if (query_pos != query_data_start) 00945 { 00946 write_to_binlog(thd, query, query_pos -1 - query, db, db_len); 00947 } 00948 } 00949 00950 exit: 00951 (void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */ 00952 error= Events::drop_schema_events(thd, db); 00953 /* 00954 If this database was the client's selected database, we silently 00955 change the client's selected database to nothing (to have an empty 00956 SELECT DATABASE() in the future). For this we free() thd->db and set 00957 it to 0. 00958 */ 00959 if (thd->db && !strcmp(thd->db, db)) 00960 thd->set_db(NULL, 0); 00961 VOID(pthread_mutex_unlock(&LOCK_mysql_create_db)); 00962 start_waiting_global_read_lock(thd); 00963 exit2: 00964 DBUG_RETURN(error); 00965 } 00966 00967 /* 00968 Removes files with known extensions plus all found subdirectories that 00969 are 2 hex digits (raid directories). 00970 thd MUST be set when calling this function! 00971 */ 00972 00973 static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, 00974 const char *org_path, uint level, 00975 TABLE_LIST **dropped_tables) 00976 { 00977 long deleted=0; 00978 ulong found_other_files=0; 00979 char filePath[FN_REFLEN]; 00980 TABLE_LIST *tot_list=0, **tot_list_next; 00981 List<String> raid_dirs; 00982 DBUG_ENTER("mysql_rm_known_files"); 00983 DBUG_PRINT("enter",("path: %s", org_path)); 00984 00985 tot_list_next= &tot_list; 00986 00987 for (uint idx=0 ; 00988 idx < (uint) dirp->number_off_files && !thd->killed ; 00989 idx++) 00990 { 00991 FILEINFO *file=dirp->dir_entry+idx; 00992 char *extension; 00993 DBUG_PRINT("info",("Examining: %s", file->name)); 00994 00995 /* skiping . and .. */ 00996 if (file->name[0] == '.' && (!file->name[1] || 00997 (file->name[1] == '.' && !file->name[2]))) 00998 continue; 00999 01000 /* Check if file is a raid directory */ 01001 if ((my_isdigit(system_charset_info, file->name[0]) || 01002 (file->name[0] >= 'a' && file->name[0] <= 'f')) && 01003 (my_isdigit(system_charset_info, file->name[1]) || 01004 (file->name[1] >= 'a' && file->name[1] <= 'f')) && 01005 !file->name[2] && !level) 01006 { 01007 char newpath[FN_REFLEN], *copy_of_path; 01008 MY_DIR *new_dirp; 01009 String *dir; 01010 uint length; 01011 01012 strxmov(newpath,org_path,"/",file->name,NullS); 01013 length= unpack_filename(newpath,newpath); 01014 if ((new_dirp = my_dir(newpath,MYF(MY_DONT_SORT)))) 01015 { 01016 DBUG_PRINT("my",("New subdir found: %s", newpath)); 01017 if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1,0)) < 0) 01018 goto err; 01019 if (!(copy_of_path= thd->memdup(newpath, length+1)) || 01020 !(dir= new (thd->mem_root) String(copy_of_path, length, 01021 &my_charset_bin)) || 01022 raid_dirs.push_back(dir)) 01023 goto err; 01024 continue; 01025 } 01026 found_other_files++; 01027 continue; 01028 } 01029 else if (file->name[0] == 'a' && file->name[1] == 'r' && 01030 file->name[2] == 'c' && file->name[3] == '\0') 01031 { 01032 /* .frm archive */ 01033 char newpath[FN_REFLEN]; 01034 MY_DIR *new_dirp; 01035 strxmov(newpath, org_path, "/", "arc", NullS); 01036 (void) unpack_filename(newpath, newpath); 01037 if ((new_dirp = my_dir(newpath, MYF(MY_DONT_SORT)))) 01038 { 01039 DBUG_PRINT("my",("Archive subdir found: %s", newpath)); 01040 if ((mysql_rm_arc_files(thd, new_dirp, newpath)) < 0) 01041 goto err; 01042 continue; 01043 } 01044 found_other_files++; 01045 continue; 01046 } 01047 if (!(extension= strrchr(file->name, '.'))) 01048 extension= strend(file->name); 01049 if (find_type(extension, &deletable_extentions,1+2) <= 0) 01050 { 01051 if (find_type(extension, ha_known_exts(),1+2) <= 0) 01052 found_other_files++; 01053 continue; 01054 } 01055 /* just for safety we use files_charset_info */ 01056 if (db && !my_strcasecmp(files_charset_info, 01057 extension, reg_ext)) 01058 { 01059 /* Drop the table nicely */ 01060 *extension= 0; // Remove extension 01061 TABLE_LIST *table_list=(TABLE_LIST*) 01062 thd->calloc(sizeof(*table_list)+ strlen(db)+strlen(file->name)+2); 01063 if (!table_list) 01064 goto err; 01065 table_list->db= (char*) (table_list+1); 01066 table_list->table_name= strmov(table_list->db, db) + 1; 01067 VOID(filename_to_tablename(file->name, table_list->table_name, 01068 strlen(file->name) + 1)); 01069 table_list->alias= table_list->table_name; // If lower_case_table_names=2 01070 /* Link into list */ 01071 (*tot_list_next)= table_list; 01072 tot_list_next= &table_list->next_local; 01073 deleted++; 01074 } 01075 else 01076 { 01077 strxmov(filePath, org_path, "/", file->name, NullS); 01078 if (my_delete_with_symlink(filePath,MYF(MY_WME))) 01079 { 01080 goto err; 01081 } 01082 } 01083 } 01084 if (thd->killed || 01085 (tot_list && mysql_rm_table_part2_with_lock(thd, tot_list, 1, 0, 1))) 01086 goto err; 01087 01088 /* Remove RAID directories */ 01089 { 01090 List_iterator<String> it(raid_dirs); 01091 String *dir; 01092 while ((dir= it++)) 01093 if (rmdir(dir->c_ptr()) < 0) 01094 found_other_files++; 01095 } 01096 my_dirend(dirp); 01097 01098 if (dropped_tables) 01099 *dropped_tables= tot_list; 01100 01101 /* 01102 If the directory is a symbolic link, remove the link first, then 01103 remove the directory the symbolic link pointed at 01104 */ 01105 if (found_other_files) 01106 { 01107 my_error(ER_DB_DROP_RMDIR, MYF(0), org_path, EEXIST); 01108 DBUG_RETURN(-1); 01109 } 01110 else 01111 { 01112 /* Don't give errors if we can't delete 'RAID' directory */ 01113 if (rm_dir_w_symlink(org_path, level == 0)) 01114 DBUG_RETURN(-1); 01115 } 01116 01117 DBUG_RETURN(deleted); 01118 01119 err: 01120 my_dirend(dirp); 01121 DBUG_RETURN(-1); 01122 } 01123 01124 01125 /* 01126 Remove directory with symlink 01127 01128 SYNOPSIS 01129 rm_dir_w_symlink() 01130 org_path path of derictory 01131 send_error send errors 01132 RETURN 01133 0 OK 01134 1 ERROR 01135 */ 01136 01137 static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error) 01138 { 01139 char tmp_path[FN_REFLEN], *pos; 01140 char *path= tmp_path; 01141 DBUG_ENTER("rm_dir_w_symlink"); 01142 unpack_filename(tmp_path, org_path); 01143 #ifdef HAVE_READLINK 01144 int error; 01145 char tmp2_path[FN_REFLEN]; 01146 01147 /* Remove end FN_LIBCHAR as this causes problem on Linux in readlink */ 01148 pos= strend(path); 01149 if (pos > path && pos[-1] == FN_LIBCHAR) 01150 *--pos=0; 01151 01152 if ((error= my_readlink(tmp2_path, path, MYF(MY_WME))) < 0) 01153 DBUG_RETURN(1); 01154 if (!error) 01155 { 01156 if (my_delete(path, MYF(send_error ? MY_WME : 0))) 01157 { 01158 DBUG_RETURN(send_error); 01159 } 01160 /* Delete directory symbolic link pointed at */ 01161 path= tmp2_path; 01162 } 01163 #endif 01164 /* Remove last FN_LIBCHAR to not cause a problem on OS/2 */ 01165 pos= strend(path); 01166 01167 if (pos > path && pos[-1] == FN_LIBCHAR) 01168 *--pos=0; 01169 if (rmdir(path) < 0 && send_error) 01170 { 01171 my_error(ER_DB_DROP_RMDIR, MYF(0), path, errno); 01172 DBUG_RETURN(1); 01173 } 01174 DBUG_RETURN(0); 01175 } 01176 01177 01178 /* 01179 Remove .frm archives from directory 01180 01181 SYNOPSIS 01182 thd thread handler 01183 dirp list of files in archive directory 01184 db data base name 01185 org_path path of archive directory 01186 01187 RETURN 01188 > 0 number of removed files 01189 -1 error 01190 */ 01191 static long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, 01192 const char *org_path) 01193 { 01194 long deleted= 0; 01195 ulong found_other_files= 0; 01196 char filePath[FN_REFLEN]; 01197 DBUG_ENTER("mysql_rm_arc_files"); 01198 DBUG_PRINT("enter", ("path: %s", org_path)); 01199 01200 for (uint idx=0 ; 01201 idx < (uint) dirp->number_off_files && !thd->killed ; 01202 idx++) 01203 { 01204 FILEINFO *file=dirp->dir_entry+idx; 01205 char *extension, *revision; 01206 DBUG_PRINT("info",("Examining: %s", file->name)); 01207 01208 /* skiping . and .. */ 01209 if (file->name[0] == '.' && (!file->name[1] || 01210 (file->name[1] == '.' && !file->name[2]))) 01211 continue; 01212 01213 extension= fn_ext(file->name); 01214 if (extension[0] != '.' || 01215 extension[1] != 'f' || extension[2] != 'r' || 01216 extension[3] != 'm' || extension[4] != '-') 01217 { 01218 found_other_files++; 01219 continue; 01220 } 01221 revision= extension+5; 01222 while (*revision && my_isdigit(system_charset_info, *revision)) 01223 revision++; 01224 if (*revision) 01225 { 01226 found_other_files++; 01227 continue; 01228 } 01229 strxmov(filePath, org_path, "/", file->name, NullS); 01230 if (my_delete_with_symlink(filePath,MYF(MY_WME))) 01231 { 01232 goto err; 01233 } 01234 } 01235 if (thd->killed) 01236 goto err; 01237 01238 my_dirend(dirp); 01239 01240 /* 01241 If the directory is a symbolic link, remove the link first, then 01242 remove the directory the symbolic link pointed at 01243 */ 01244 if (!found_other_files && 01245 rm_dir_w_symlink(org_path, 0)) 01246 DBUG_RETURN(-1); 01247 DBUG_RETURN(deleted); 01248 01249 err: 01250 my_dirend(dirp); 01251 DBUG_RETURN(-1); 01252 } 01253 01254 01255 /* 01256 Change the current database. 01257 01258 SYNOPSIS 01259 mysql_change_db() 01260 thd thread handle 01261 name database name 01262 no_access_check if TRUE, don't do access check. In this 01263 case name may be "" 01264 01265 DESCRIPTION 01266 Check that the database name corresponds to a valid and 01267 existent database, check access rights (unless called with 01268 no_access_check), and set the current database. This function 01269 is called to change the current database upon user request 01270 (COM_CHANGE_DB command) or temporarily, to execute a stored 01271 routine. 01272 01273 NOTES 01274 This function is not the only way to switch the database that 01275 is currently employed. When the replication slave thread 01276 switches the database before executing a query, it calls 01277 thd->set_db directly. However, if the query, in turn, uses 01278 a stored routine, the stored routine will use this function, 01279 even if it's run on the slave. 01280 01281 This function allocates the name of the database on the system 01282 heap: this is necessary to be able to uniformly change the 01283 database from any module of the server. Up to 5.0 different 01284 modules were using different memory to store the name of the 01285 database, and this led to memory corruption: a stack pointer 01286 set by Stored Procedures was used by replication after the 01287 stack address was long gone. 01288 01289 This function does not send anything, including error 01290 messages, to the client. If that should be sent to the client, 01291 call net_send_error after this function. 01292 01293 RETURN VALUES 01294 0 OK 01295 1 error 01296 */ 01297 01298 bool mysql_change_db(THD *thd, const char *name, bool no_access_check) 01299 { 01300 int path_length, db_length; 01301 char *db_name; 01302 bool system_db= 0; 01303 #ifndef NO_EMBEDDED_ACCESS_CHECKS 01304 ulong db_access; 01305 Security_context *sctx= thd->security_ctx; 01306 LINT_INIT(db_access); 01307 #endif 01308 DBUG_ENTER("mysql_change_db"); 01309 DBUG_PRINT("enter",("name: '%s'",name)); 01310 01311 if (name == NULL || name[0] == '\0' && no_access_check == FALSE) 01312 { 01313 my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); 01314 DBUG_RETURN(1); /* purecov: inspected */ 01315 } 01316 else if (name[0] == '\0') 01317 { 01318 /* Called from SP to restore the original database, which was NULL */ 01319 DBUG_ASSERT(no_access_check); 01320 system_db= 1; 01321 db_name= NULL; 01322 db_length= 0; 01323 goto end; 01324 } 01325 /* 01326 Now we need to make a copy because check_db_name requires a 01327 non-constant argument. TODO: fix check_db_name. 01328 */ 01329 if ((db_name= my_strdup(name, MYF(MY_WME))) == NULL) 01330 DBUG_RETURN(1); /* the error is set */ 01331 db_length= strlen(db_name); 01332 if (check_db_name(db_name)) 01333 { 01334 my_error(ER_WRONG_DB_NAME, MYF(0), db_name); 01335 my_free(db_name, MYF(0)); 01336 DBUG_RETURN(1); 01337 } 01338 DBUG_PRINT("info",("Use database: %s", db_name)); 01339 if (!my_strcasecmp(system_charset_info, db_name, information_schema_name.str)) 01340 { 01341 system_db= 1; 01342 #ifndef NO_EMBEDDED_ACCESS_CHECKS 01343 db_access= SELECT_ACL; 01344 #endif 01345 goto end; 01346 } 01347 01348 #ifndef NO_EMBEDDED_ACCESS_CHECKS 01349 if (!no_access_check) 01350 { 01351 if (test_all_bits(sctx->master_access, DB_ACLS)) 01352 db_access=DB_ACLS; 01353 else 01354 db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name, 0) | 01355 sctx->master_access); 01356 if (!(db_access & DB_ACLS) && (!grant_option || 01357 check_grant_db(thd,db_name))) 01358 { 01359 my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), 01360 sctx->priv_user, 01361 sctx->priv_host, 01362 db_name); 01363 general_log_print(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR), 01364 sctx->priv_user, sctx->priv_host, db_name); 01365 my_free(db_name,MYF(0)); 01366 DBUG_RETURN(1); 01367 } 01368 } 01369 #endif 01370 01371 if (check_db_dir_existence(db_name)) 01372 { 01373 my_error(ER_BAD_DB_ERROR, MYF(0), db_name); 01374 my_free(db_name, MYF(0)); 01375 DBUG_RETURN(1); 01376 } 01377 01378 end: 01379 x_free(thd->db); 01380 DBUG_ASSERT(db_name == NULL || db_name[0] != '\0'); 01381 thd->reset_db(db_name, db_length); // THD::~THD will free this 01382 #ifndef NO_EMBEDDED_ACCESS_CHECKS 01383 if (!no_access_check) 01384 sctx->db_access= db_access; 01385 #endif 01386 if (system_db) 01387 { 01388 thd->db_charset= system_charset_info; 01389 thd->variables.collation_database= system_charset_info; 01390 } 01391 else 01392 { 01393 HA_CREATE_INFO create; 01394 01395 load_db_opt_by_name(thd, db_name, &create); 01396 01397 thd->db_charset= create.default_table_charset ? 01398 create.default_table_charset : 01399 thd->variables.collation_server; 01400 thd->variables.collation_database= thd->db_charset; 01401 } 01402 DBUG_RETURN(0); 01403 } 01404 01405 01406 static int 01407 lock_databases(THD *thd, const char *db1, uint length1, 01408 const char *db2, uint length2) 01409 { 01410 pthread_mutex_lock(&LOCK_lock_db); 01411 while (!thd->killed && 01412 (hash_search(&lock_db_cache,(byte*) db1, length1) || 01413 hash_search(&lock_db_cache,(byte*) db2, length2))) 01414 { 01415 wait_for_condition(thd, &LOCK_lock_db, &COND_refresh); 01416 pthread_mutex_lock(&LOCK_lock_db); 01417 } 01418 01419 if (thd->killed) 01420 { 01421 pthread_mutex_unlock(&LOCK_lock_db); 01422 return 1; 01423 } 01424 01425 lock_db_insert(db1, length1); 01426 lock_db_insert(db2, length2); 01427 creating_database++; 01428 01429 /* 01430 Wait if a concurent thread is creating a table at the same time. 01431 The assumption here is that it will not take too long until 01432 there is a point in time when a table is not created. 01433 */ 01434 01435 while (!thd->killed && creating_table) 01436 { 01437 wait_for_condition(thd, &LOCK_lock_db, &COND_refresh); 01438 pthread_mutex_lock(&LOCK_lock_db); 01439 } 01440 01441 if (thd->killed) 01442 { 01443 lock_db_delete(db1, length1); 01444 lock_db_delete(db2, length2); 01445 creating_database--; 01446 pthread_mutex_unlock(&LOCK_lock_db); 01447 pthread_cond_signal(&COND_refresh); 01448 return(1); 01449 } 01450 01451 /* 01452 We can unlock now as the hash will protect against anyone creating a table 01453 in the databases we are using 01454 */ 01455 pthread_mutex_unlock(&LOCK_lock_db); 01456 return 0; 01457 } 01458 01459 01460 /* 01461 Rename database. 01462 01463 SYNOPSIS 01464 mysql_rename_db() 01465 thd Thread handler 01466 olddb Old database name 01467 newdb New database name 01468 01469 DESCRIPTION 01470 This function is invoked whenever a RENAME DATABASE query is executed: 01471 01472 RENAME DATABASE 'olddb' TO 'newdb'. 01473 01474 NOTES 01475 01476 If we have managed to rename (move) tables to the new database 01477 but something failed on a later step, then we store the 01478 RENAME DATABASE event in the log. mysql_rename_db() is atomic in 01479 the sense that it will rename all or none of the tables. 01480 01481 TODO: 01482 - Better trigger, stored procedure, event, grant handling, 01483 see the comments below. 01484 NOTE: It's probably a good idea to call wait_if_global_read_lock() 01485 once in mysql_rename_db(), instead of locking inside all 01486 the required functions for renaming triggerts, SP, events, grants, etc. 01487 01488 RETURN VALUES 01489 0 ok 01490 1 error 01491 */ 01492 01493 01494 bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db) 01495 { 01496 int error= 0, change_to_newdb= 0; 01497 char path[FN_REFLEN+16]; 01498 uint length; 01499 HA_CREATE_INFO create_info; 01500 MY_DIR *dirp; 01501 TABLE_LIST *table_list; 01502 SELECT_LEX *sl= thd->lex->current_select; 01503 DBUG_ENTER("mysql_rename_db"); 01504 01505 if (lock_databases(thd, old_db->str, old_db->length, 01506 new_db->str, new_db->length)) 01507 return 1; 01508 01509 /* 01510 Let's remember if we should do "USE newdb" afterwards. 01511 thd->db will be cleared in mysql_rename_db() 01512 */ 01513 if (thd->db && !strcmp(thd->db, old_db->str)) 01514 change_to_newdb= 1; 01515 01516 build_table_filename(path, sizeof(path)-1, 01517 old_db->str, "", MY_DB_OPT_FILE, 0); 01518 if ((load_db_opt(thd, path, &create_info))) 01519 create_info.default_table_charset= thd->variables.collation_server; 01520 01521 length= build_table_filename(path, sizeof(path)-1, old_db->str, "", "", 0); 01522 if (length && path[length-1] == FN_LIBCHAR) 01523 path[length-1]=0; // remove ending '\' 01524 if ((error= my_access(path,F_OK))) 01525 { 01526 my_error(ER_BAD_DB_ERROR, MYF(0), old_db->str); 01527 goto exit; 01528 } 01529 01530 /* Step1: Create the new database */ 01531 if ((error= mysql_create_db(thd, new_db->str, &create_info, 1))) 01532 goto exit; 01533 01534 /* Step2: Move tables to the new database */ 01535 if ((dirp = my_dir(path,MYF(MY_DONT_SORT)))) 01536 { 01537 uint nfiles= (uint) dirp->number_off_files; 01538 for (uint idx=0 ; idx < nfiles && !thd->killed ; idx++) 01539 { 01540 FILEINFO *file= dirp->dir_entry + idx; 01541 char *extension, tname[FN_REFLEN]; 01542 LEX_STRING table_str; 01543 DBUG_PRINT("info",("Examining: %s", file->name)); 01544 01545 /* skiping non-FRM files */ 01546 if (my_strcasecmp(files_charset_info, 01547 (extension= fn_rext(file->name)), reg_ext)) 01548 continue; 01549 01550 /* A frm file found, add the table info rename list */ 01551 *extension= '\0'; 01552 01553 table_str.length= filename_to_tablename(file->name, 01554 tname, sizeof(tname)-1); 01555 table_str.str= sql_memdup(tname, table_str.length + 1); 01556 Table_ident *old_ident= new Table_ident(thd, *old_db, table_str, 0); 01557 Table_ident *new_ident= new Table_ident(thd, *new_db, table_str, 0); 01558 if (!old_ident || !new_ident || 01559 !sl->add_table_to_list(thd, old_ident, NULL, 01560 TL_OPTION_UPDATING, TL_IGNORE) || 01561 !sl->add_table_to_list(thd, new_ident, NULL, 01562 TL_OPTION_UPDATING, TL_IGNORE)) 01563 { 01564 error= 1; 01565 my_dirend(dirp); 01566 goto exit; 01567 } 01568 } 01569 my_dirend(dirp); 01570 } 01571 01572 if ((table_list= thd->lex->query_tables) && 01573 (error= mysql_rename_tables(thd, table_list, 1))) 01574 { 01575 /* 01576 Failed to move all tables from the old database to the new one. 01577 In the best case mysql_rename_tables() moved all tables back to the old 01578 database. In the worst case mysql_rename_tables() moved some tables 01579 to the new database, then failed, then started to move the tables back, and 01580 then failed again. In this situation we have some tables in the 01581 old database and some tables in the new database. 01582 Let's delete the option file, and then the new database directory. 01583 If some tables were left in the new directory, rmdir() will fail. 01584 It garantees we never loose any tables. 01585 */ 01586 build_table_filename(path, sizeof(path)-1, 01587 new_db->str,"",MY_DB_OPT_FILE, 0); 01588 my_delete(path, MYF(MY_WME)); 01589 length= build_table_filename(path, sizeof(path)-1, new_db->str, "", "", 0); 01590 if (length && path[length-1] == FN_LIBCHAR) 01591 path[length-1]=0; // remove ending '\' 01592 rmdir(path); 01593 goto exit; 01594 } 01595 01596 01597 /* 01598 Step3: move all remaining files to the new db's directory. 01599 Skip db opt file: it's been created by mysql_create_db() in 01600 the new directory, and will be dropped by mysql_rm_db() in the old one. 01601 Trigger TRN and TRG files are be moved as regular files at the moment, 01602 without any special treatment. 01603 01604 Triggers without explicit database qualifiers in table names work fine: 01605 use d1; 01606 create trigger trg1 before insert on t2 for each row set @a:=1 01607 rename database d1 to d2; 01608 01609 TODO: Triggers, having the renamed database explicitely written 01610 in the table qualifiers. 01611 1. when the same database is renamed: 01612 create trigger d1.trg1 before insert on d1.t1 for each row set @a:=1; 01613 rename database d1 to d2; 01614 Problem: After database renaming, the trigger's body 01615 still points to the old database d1. 01616 2. when another database is renamed: 01617 create trigger d3.trg1 before insert on d3.t1 for each row 01618 insert into d1.t1 values (...); 01619 rename database d1 to d2; 01620 Problem: After renaming d1 to d2, the trigger's body 01621 in the database d3 still points to database d1. 01622 */ 01623 01624 if ((dirp = my_dir(path,MYF(MY_DONT_SORT)))) 01625 { 01626 uint nfiles= (uint) dirp->number_off_files; 01627 for (uint idx=0 ; idx < nfiles ; idx++) 01628 { 01629 FILEINFO *file= dirp->dir_entry + idx; 01630 char oldname[FN_REFLEN], newname[FN_REFLEN]; 01631 DBUG_PRINT("info",("Examining: %s", file->name)); 01632 01633 /* skiping . and .. and MY_DB_OPT_FILE */ 01634 if ((file->name[0] == '.' && 01635 (!file->name[1] || (file->name[1] == '.' && !file->name[2]))) || 01636 !my_strcasecmp(files_charset_info, file->name, MY_DB_OPT_FILE)) 01637 continue; 01638 01639 /* pass empty file name, and file->name as extension to avoid encoding */ 01640 build_table_filename(oldname, sizeof(oldname)-1, 01641 old_db->str, "", file->name, 0); 01642 build_table_filename(newname, sizeof(newname)-1, 01643 new_db->str, "", file->name, 0); 01644 my_rename(oldname, newname, MYF(MY_WME)); 01645 } 01646 my_dirend(dirp); 01647 } 01648 01649 /* 01650 Step4: TODO: moving stored procedures in the 'proc' system table 01651 We need a new function: sp_move_db_routines(thd, olddb, newdb) 01652 Which will basically have the same effect with: 01653 UPDATE proc SET db='newdb' WHERE db='olddb' 01654 Note, for 5.0 to 5.1 upgrade purposes we don't really need it. 01655 01656 The biggest problem here is that we can't have a lock on LOCK_open() while 01657 calling open_table() for 'proc'. 01658 01659 Two solutions: 01660 - Start by opening the 'event' and 'proc' (and other) tables for write 01661 even before creating the 'to' database. (This will have the nice 01662 effect of blocking another 'rename database' while the lock is active). 01663 - Use the solution "Disable create of new tables during lock table" 01664 01665 For an example of how to read through all rows, see: 01666 sql_help.cc::search_topics() 01667 */ 01668 01669 /* 01670 Step5: TODO: moving events in the 'event' system table 01671 We need a new function evex_move_db_events(thd, olddb, newdb) 01672 Which will have the same effect with: 01673 UPDATE event SET db='newdb' WHERE db='olddb' 01674 Note, for 5.0 to 5.1 upgrade purposes we don't really need it. 01675 */ 01676 01677 /* 01678 Step6: TODO: moving grants in the 'db', 'tables_priv', 'columns_priv'. 01679 Update each grant table, doing the same with: 01680 UPDATE system_table SET db='newdb' WHERE db='olddb' 01681 */ 01682 01683 /* 01684 Step7: drop the old database. 01685 remove_db_from_cache(olddb) and query_cache_invalidate(olddb) 01686 are done inside mysql_rm_db(), no needs to execute them again. 01687 mysql_rm_db() also "unuses" if we drop the current database. 01688 */ 01689 error= mysql_rm_db(thd, old_db->str, 0, 1); 01690 01691 /* Step8: logging */ 01692 if (mysql_bin_log.is_open()) 01693 { 01694 Query_log_event qinfo(thd, thd->query, thd->query_length, 0, TRUE); 01695 thd->clear_error(); 01696 mysql_bin_log.write(&qinfo); 01697 } 01698 01699 /* Step9: Let's do "use newdb" if we renamed the current database */ 01700 if (change_to_newdb) 01701 error|= mysql_change_db(thd, new_db->str, 0); 01702 01703 exit: 01704 pthread_mutex_lock(&LOCK_lock_db); 01705 /* Remove the databases from db lock cache */ 01706 lock_db_delete(old_db->str, old_db->length); 01707 lock_db_delete(new_db->str, new_db->length); 01708 creating_database--; 01709 /* Signal waiting CREATE TABLE's to continue */ 01710 pthread_cond_signal(&COND_refresh); 01711 pthread_mutex_unlock(&LOCK_lock_db); 01712 01713 DBUG_RETURN(error); 01714 } 01715 01716 /* 01717 Check if there is directory for the database name. 01718 01719 SYNOPSIS 01720 check_db_dir_existence() 01721 db_name database name 01722 01723 RETURN VALUES 01724 FALSE There is directory for the specified database name. 01725 TRUE The directory does not exist. 01726 */ 01727 01728 bool check_db_dir_existence(const char *db_name) 01729 { 01730 char db_dir_path[FN_REFLEN]; 01731 uint db_dir_path_len; 01732 01733 db_dir_path_len= build_table_filename(db_dir_path, sizeof(db_dir_path), 01734 db_name, "", "", 0); 01735 01736 if (db_dir_path_len && db_dir_path[db_dir_path_len - 1] == FN_LIBCHAR) 01737 db_dir_path[db_dir_path_len - 1]= 0; 01738 01739 /* Check access. */ 01740 01741 return my_access(db_dir_path, F_OK); 01742 }
1.4.7

