You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1867 lines
55 KiB

26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
Fixed Bug#11756013 (formerly known as bug#47870): BOGUS "THE TABLE MYSQL.PROC IS MISSING,..." There was a race condition between loading a stored routine (function/procedure/trigger) specified by fully qualified name SCHEMA_NAME.PROC_NAME and dropping the stored routine database. The problem was that there is a window for race condition when one server thread tries to load a stored routine being executed and the other thread tries to drop the stored routine schema. This condition race window exists in implementation of function mysql_change_db() called by db_load_routine() during loading of stored routine to cache. Function mysql_change_db() calls check_db_dir_existence() that might failed because specified database was dropped during concurrent execution of DROP SCHEMA statement. db_load_routine() calls mysql_change_db() with flag 'force_switch' set to 'true' value so when referenced db is not found then my_error() is not called and function mysql_change_db() returns ok. This shadows information about schema opening error in db_load_routine(). Then db_load_routine() makes attempt to parse stored routine that is failed. This makes to return error to sp_cache_routines_and_add_tables_aux() but since during error generation a call to my_error wasn't made and hence THD::main_da wasn't set we set the generic "mysql.proc table corrupt" error when running sp_cache_routines_and_add_tables_aux(). The fix is to install an error handler inside db_load_routine() for the mysql_op_change_db() call, and check later if the ER_BAD_DB_ERROR was caught.
15 years ago
26 years ago
21 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
21 years ago
21 years ago
Bug#34043: Server loops excessively in _checkchunk() when safemalloc is enabled Essentially, the problem is that safemalloc is excruciatingly slow as it checks all allocated blocks for overrun at each memory management primitive, yielding a almost exponential slowdown for the memory management functions (malloc, realloc, free). The overrun check basically consists of verifying some bytes of a block for certain magic keys, which catches some simple forms of overrun. Another minor problem is violation of aliasing rules and that its own internal list of blocks is prone to corruption. Another issue with safemalloc is rather the maintenance cost as the tool has a significant impact on the server code. Given the magnitude of memory debuggers available nowadays, especially those that are provided with the platform malloc implementation, maintenance of a in-house and largely obsolete memory debugger becomes a burden that is not worth the effort due to its slowness and lack of support for detecting more common forms of heap corruption. Since there are third-party tools that can provide the same functionality at a lower or comparable performance cost, the solution is to simply remove safemalloc. Third-party tools can provide the same functionality at a lower or comparable performance cost. The removal of safemalloc also allows a simplification of the malloc wrappers, removing quite a bit of kludge: redefinition of my_malloc, my_free and the removal of the unused second argument of my_free. Since free() always check whether the supplied pointer is null, redudant checks are also removed. Also, this patch adds unit testing for my_malloc and moves my_realloc implementation into the same file as the other memory allocation primitives.
16 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
Bug#34043: Server loops excessively in _checkchunk() when safemalloc is enabled Essentially, the problem is that safemalloc is excruciatingly slow as it checks all allocated blocks for overrun at each memory management primitive, yielding a almost exponential slowdown for the memory management functions (malloc, realloc, free). The overrun check basically consists of verifying some bytes of a block for certain magic keys, which catches some simple forms of overrun. Another minor problem is violation of aliasing rules and that its own internal list of blocks is prone to corruption. Another issue with safemalloc is rather the maintenance cost as the tool has a significant impact on the server code. Given the magnitude of memory debuggers available nowadays, especially those that are provided with the platform malloc implementation, maintenance of a in-house and largely obsolete memory debugger becomes a burden that is not worth the effort due to its slowness and lack of support for detecting more common forms of heap corruption. Since there are third-party tools that can provide the same functionality at a lower or comparable performance cost, the solution is to simply remove safemalloc. Third-party tools can provide the same functionality at a lower or comparable performance cost. The removal of safemalloc also allows a simplification of the malloc wrappers, removing quite a bit of kludge: redefinition of my_malloc, my_free and the removal of the unused second argument of my_free. Since free() always check whether the supplied pointer is null, redudant checks are also removed. Also, this patch adds unit testing for my_malloc and moves my_realloc implementation into the same file as the other memory allocation primitives.
16 years ago
26 years ago
20 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
20 years ago
20 years ago
20 years ago
26 years ago
26 years ago
26 years ago
20 years ago
26 years ago
merge mysql-5.1-rep+2-delivery1 --> mysql-5.1-rpl-merge Conflicts: Text conflict in .bzr-mysql/default.conf Text conflict in mysql-test/extra/rpl_tests/rpl_loaddata.test Text conflict in mysql-test/r/mysqlbinlog2.result Text conflict in mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result Text conflict in mysql-test/suite/binlog/r/binlog_unsafe.result Text conflict in mysql-test/suite/rpl/r/rpl_insert_id.result Text conflict in mysql-test/suite/rpl/r/rpl_loaddata.result Text conflict in mysql-test/suite/rpl/r/rpl_stm_auto_increment_bug33029.result Text conflict in mysql-test/suite/rpl/r/rpl_udf.result Text conflict in mysql-test/suite/rpl/t/rpl_slow_query_log.test Text conflict in sql/field.h Text conflict in sql/log.cc Text conflict in sql/log_event.cc Text conflict in sql/log_event_old.cc Text conflict in sql/mysql_priv.h Text conflict in sql/share/errmsg.txt Text conflict in sql/sp.cc Text conflict in sql/sql_acl.cc Text conflict in sql/sql_base.cc Text conflict in sql/sql_class.h Text conflict in sql/sql_db.cc Text conflict in sql/sql_delete.cc Text conflict in sql/sql_insert.cc Text conflict in sql/sql_lex.cc Text conflict in sql/sql_lex.h Text conflict in sql/sql_load.cc Text conflict in sql/sql_table.cc Text conflict in sql/sql_update.cc Text conflict in sql/sql_view.cc Conflict adding files to storage/innobase. Created directory. Conflict because storage/innobase is not versioned, but has versioned children. Versioned directory. Conflict adding file storage/innobase. Moved existing file to storage/innobase.moved. Conflict adding files to storage/innobase/handler. Created directory. Conflict because storage/innobase/handler is not versioned, but has versioned children. Versioned directory. Contents conflict in storage/innobase/handler/ha_innodb.cc
16 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
21 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
22 years ago
26 years ago
Patch that refactors global read lock implementation and fixes bug #57006 "Deadlock between HANDLER and FLUSH TABLES WITH READ LOCK" and bug #54673 "It takes too long to get readlock for 'FLUSH TABLES WITH READ LOCK'". The first bug manifested itself as a deadlock which occurred when a connection, which had some table open through HANDLER statement, tried to update some data through DML statement while another connection tried to execute FLUSH TABLES WITH READ LOCK concurrently. What happened was that FTWRL in the second connection managed to perform first step of GRL acquisition and thus blocked all upcoming DML. After that it started to wait for table open through HANDLER statement to be flushed. When the first connection tried to execute DML it has started to wait for GRL/the second connection creating deadlock. The second bug manifested itself as starvation of FLUSH TABLES WITH READ LOCK statements in cases when there was a constant stream of concurrent DML statements (in two or more connections). This has happened because requests for protection against GRL which were acquired by DML statements were ignoring presence of pending GRL and thus the latter was starved. This patch solves both these problems by re-implementing GRL using metadata locks. Similar to the old implementation acquisition of GRL in new implementation is two-step. During the first step we block all concurrent DML and DDL statements by acquiring global S metadata lock (each DML and DDL statement acquires global IX lock for its duration). During the second step we block commits by acquiring global S lock in COMMIT namespace (commit code acquires global IX lock in this namespace). Note that unlike in old implementation acquisition of protection against GRL in DML and DDL is semi-automatic. We assume that any statement which should be blocked by GRL will either open and acquires write-lock on tables or acquires metadata locks on objects it is going to modify. For any such statement global IX metadata lock is automatically acquired for its duration. The first problem is solved because waits for GRL become visible to deadlock detector in metadata locking subsystem and thus deadlocks like one in the first bug become impossible. The second problem is solved because global S locks which are used for GRL implementation are given preference over IX locks which are acquired by concurrent DML (and we can switch to fair scheduling in future if needed). Important change: FTWRL/GRL no longer blocks DML and DDL on temporary tables. Before this patch behavior was not consistent in this respect: in some cases DML/DDL statements on temporary tables were blocked while in others they were not. Since the main use cases for FTWRL are various forms of backups and temporary tables are not preserved during backups we have opted for consistently allowing DML/DDL on temporary tables during FTWRL/GRL. Important change: This patch changes thread state names which are used when DML/DDL of FTWRL is waiting for global read lock. It is now either "Waiting for global read lock" or "Waiting for commit lock" depending on the stage on which FTWRL is. Incompatible change: To solve deadlock in events code which was exposed by this patch we have to replace LOCK_event_metadata mutex with metadata locks on events. As result we have to prohibit DDL on events under LOCK TABLES. This patch also adds extensive test coverage for interaction of DML/DDL and FTWRL. Performance of new and old global read lock implementations in sysbench tests were compared. There were no significant difference between new and old implementations.
15 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
Bug#34043: Server loops excessively in _checkchunk() when safemalloc is enabled Essentially, the problem is that safemalloc is excruciatingly slow as it checks all allocated blocks for overrun at each memory management primitive, yielding a almost exponential slowdown for the memory management functions (malloc, realloc, free). The overrun check basically consists of verifying some bytes of a block for certain magic keys, which catches some simple forms of overrun. Another minor problem is violation of aliasing rules and that its own internal list of blocks is prone to corruption. Another issue with safemalloc is rather the maintenance cost as the tool has a significant impact on the server code. Given the magnitude of memory debuggers available nowadays, especially those that are provided with the platform malloc implementation, maintenance of a in-house and largely obsolete memory debugger becomes a burden that is not worth the effort due to its slowness and lack of support for detecting more common forms of heap corruption. Since there are third-party tools that can provide the same functionality at a lower or comparable performance cost, the solution is to simply remove safemalloc. Third-party tools can provide the same functionality at a lower or comparable performance cost. The removal of safemalloc also allows a simplification of the malloc wrappers, removing quite a bit of kludge: redefinition of my_malloc, my_free and the removal of the unused second argument of my_free. Since free() always check whether the supplied pointer is null, redudant checks are also removed. Also, this patch adds unit testing for my_malloc and moves my_realloc implementation into the same file as the other memory allocation primitives.
16 years ago
26 years ago
26 years ago
26 years ago
26 years ago
A fix and a teset case for Bug#28551 The warning 'No database selected' is reported when calling stored procedures Remove the offending warning introduced by the fix for Bug 25082 This minimal patch relies on the intrinsic knowledge of the fact that mysql_change_db is never called with 'force_switch' set to TRUE when such a warning may be needed: * every stored routine belongs to a database (unlike, e.g., a user defined function, which does not), so if we're activating the database of a stored routine, it can never be NULL. Therefore, this branch is never called for activation. * if we're restoring the 'old' current database after routine execution is complete, we should not issue a warning, since it's OK to call a routine without having previously selected the current database. TODO: 'force_switch' is an ambiguous flag, since we do not actually have to 'force' the switch in case of stored routines at all. When we activate the routine's database, we should perform all the checks as in case of 'use db', and so we already do (in this case 'force_switch' is unused). When we load a routine into cache, we should not use mysql_change_db at all, since there it's enough to call thd->reset_db(). We do it this way for triggers, but code for routines is different (wrongly). TODO: bugs are lurking in replication, since it bypasses mysql_change_db and calls thd->[re_]set_db to set the current database. The latter does not change thd->db_charset, thd->sctx->db_access and thd->variables.collation_database (and this may have nasty side effects). These todo items are to be addressed in a separate patch, if at all.
19 years ago
A fix and a teset case for Bug#28551 The warning 'No database selected' is reported when calling stored procedures Remove the offending warning introduced by the fix for Bug 25082 This minimal patch relies on the intrinsic knowledge of the fact that mysql_change_db is never called with 'force_switch' set to TRUE when such a warning may be needed: * every stored routine belongs to a database (unlike, e.g., a user defined function, which does not), so if we're activating the database of a stored routine, it can never be NULL. Therefore, this branch is never called for activation. * if we're restoring the 'old' current database after routine execution is complete, we should not issue a warning, since it's OK to call a routine without having previously selected the current database. TODO: 'force_switch' is an ambiguous flag, since we do not actually have to 'force' the switch in case of stored routines at all. When we activate the routine's database, we should perform all the checks as in case of 'use db', and so we already do (in this case 'force_switch' is unused). When we load a routine into cache, we should not use mysql_change_db at all, since there it's enough to call thd->reset_db(). We do it this way for triggers, but code for routines is different (wrongly). TODO: bugs are lurking in replication, since it bypasses mysql_change_db and calls thd->[re_]set_db to set the current database. The latter does not change thd->db_charset, thd->sctx->db_access and thd->variables.collation_database (and this may have nasty side effects). These todo items are to be addressed in a separate patch, if at all.
19 years ago
26 years ago
26 years ago
Bug#34043: Server loops excessively in _checkchunk() when safemalloc is enabled Essentially, the problem is that safemalloc is excruciatingly slow as it checks all allocated blocks for overrun at each memory management primitive, yielding a almost exponential slowdown for the memory management functions (malloc, realloc, free). The overrun check basically consists of verifying some bytes of a block for certain magic keys, which catches some simple forms of overrun. Another minor problem is violation of aliasing rules and that its own internal list of blocks is prone to corruption. Another issue with safemalloc is rather the maintenance cost as the tool has a significant impact on the server code. Given the magnitude of memory debuggers available nowadays, especially those that are provided with the platform malloc implementation, maintenance of a in-house and largely obsolete memory debugger becomes a burden that is not worth the effort due to its slowness and lack of support for detecting more common forms of heap corruption. Since there are third-party tools that can provide the same functionality at a lower or comparable performance cost, the solution is to simply remove safemalloc. Third-party tools can provide the same functionality at a lower or comparable performance cost. The removal of safemalloc also allows a simplification of the malloc wrappers, removing quite a bit of kludge: redefinition of my_malloc, my_free and the removal of the unused second argument of my_free. Since free() always check whether the supplied pointer is null, redudant checks are also removed. Also, this patch adds unit testing for my_malloc and moves my_realloc implementation into the same file as the other memory allocation primitives.
16 years ago
Bug#34043: Server loops excessively in _checkchunk() when safemalloc is enabled Essentially, the problem is that safemalloc is excruciatingly slow as it checks all allocated blocks for overrun at each memory management primitive, yielding a almost exponential slowdown for the memory management functions (malloc, realloc, free). The overrun check basically consists of verifying some bytes of a block for certain magic keys, which catches some simple forms of overrun. Another minor problem is violation of aliasing rules and that its own internal list of blocks is prone to corruption. Another issue with safemalloc is rather the maintenance cost as the tool has a significant impact on the server code. Given the magnitude of memory debuggers available nowadays, especially those that are provided with the platform malloc implementation, maintenance of a in-house and largely obsolete memory debugger becomes a burden that is not worth the effort due to its slowness and lack of support for detecting more common forms of heap corruption. Since there are third-party tools that can provide the same functionality at a lower or comparable performance cost, the solution is to simply remove safemalloc. Third-party tools can provide the same functionality at a lower or comparable performance cost. The removal of safemalloc also allows a simplification of the malloc wrappers, removing quite a bit of kludge: redefinition of my_malloc, my_free and the removal of the unused second argument of my_free. Since free() always check whether the supplied pointer is null, redudant checks are also removed. Also, this patch adds unit testing for my_malloc and moves my_realloc implementation into the same file as the other memory allocation primitives.
16 years ago
Fixed Bug#11756013 (formerly known as bug#47870): BOGUS "THE TABLE MYSQL.PROC IS MISSING,..." There was a race condition between loading a stored routine (function/procedure/trigger) specified by fully qualified name SCHEMA_NAME.PROC_NAME and dropping the stored routine database. The problem was that there is a window for race condition when one server thread tries to load a stored routine being executed and the other thread tries to drop the stored routine schema. This condition race window exists in implementation of function mysql_change_db() called by db_load_routine() during loading of stored routine to cache. Function mysql_change_db() calls check_db_dir_existence() that might failed because specified database was dropped during concurrent execution of DROP SCHEMA statement. db_load_routine() calls mysql_change_db() with flag 'force_switch' set to 'true' value so when referenced db is not found then my_error() is not called and function mysql_change_db() returns ok. This shadows information about schema opening error in db_load_routine(). Then db_load_routine() makes attempt to parse stored routine that is failed. This makes to return error to sp_cache_routines_and_add_tables_aux() but since during error generation a call to my_error wasn't made and hence THD::main_da wasn't set we set the generic "mysql.proc table corrupt" error when running sp_cache_routines_and_add_tables_aux(). The fix is to install an error handler inside db_load_routine() for the mysql_op_change_db() call, and check later if the ER_BAD_DB_ERROR was caught.
15 years ago
Bug#34043: Server loops excessively in _checkchunk() when safemalloc is enabled Essentially, the problem is that safemalloc is excruciatingly slow as it checks all allocated blocks for overrun at each memory management primitive, yielding a almost exponential slowdown for the memory management functions (malloc, realloc, free). The overrun check basically consists of verifying some bytes of a block for certain magic keys, which catches some simple forms of overrun. Another minor problem is violation of aliasing rules and that its own internal list of blocks is prone to corruption. Another issue with safemalloc is rather the maintenance cost as the tool has a significant impact on the server code. Given the magnitude of memory debuggers available nowadays, especially those that are provided with the platform malloc implementation, maintenance of a in-house and largely obsolete memory debugger becomes a burden that is not worth the effort due to its slowness and lack of support for detecting more common forms of heap corruption. Since there are third-party tools that can provide the same functionality at a lower or comparable performance cost, the solution is to simply remove safemalloc. Third-party tools can provide the same functionality at a lower or comparable performance cost. The removal of safemalloc also allows a simplification of the malloc wrappers, removing quite a bit of kludge: redefinition of my_malloc, my_free and the removal of the unused second argument of my_free. Since free() always check whether the supplied pointer is null, redudant checks are also removed. Also, this patch adds unit testing for my_malloc and moves my_realloc implementation into the same file as the other memory allocation primitives.
16 years ago
Bug#34043: Server loops excessively in _checkchunk() when safemalloc is enabled Essentially, the problem is that safemalloc is excruciatingly slow as it checks all allocated blocks for overrun at each memory management primitive, yielding a almost exponential slowdown for the memory management functions (malloc, realloc, free). The overrun check basically consists of verifying some bytes of a block for certain magic keys, which catches some simple forms of overrun. Another minor problem is violation of aliasing rules and that its own internal list of blocks is prone to corruption. Another issue with safemalloc is rather the maintenance cost as the tool has a significant impact on the server code. Given the magnitude of memory debuggers available nowadays, especially those that are provided with the platform malloc implementation, maintenance of a in-house and largely obsolete memory debugger becomes a burden that is not worth the effort due to its slowness and lack of support for detecting more common forms of heap corruption. Since there are third-party tools that can provide the same functionality at a lower or comparable performance cost, the solution is to simply remove safemalloc. Third-party tools can provide the same functionality at a lower or comparable performance cost. The removal of safemalloc also allows a simplification of the malloc wrappers, removing quite a bit of kludge: redefinition of my_malloc, my_free and the removal of the unused second argument of my_free. Since free() always check whether the supplied pointer is null, redudant checks are also removed. Also, this patch adds unit testing for my_malloc and moves my_realloc implementation into the same file as the other memory allocation primitives.
16 years ago
26 years ago
Bug#18775 - Temporary table from alter table visible to other threads Continued implementation of WL#1324 (table name to filename encoding) The intermediate (not temporary) files of the new table during ALTER TABLE was visible for SHOW TABLES. These intermediate files are copies of the original table with the changes done by ALTER TABLE. After all the data is copied over from the original table, these files are renamed to the original tables file names. So they are not temporary files. They persist after ALTER TABLE, but just with another name. In 5.0 the intermediate files are invisible for SHOW TABLES because all file names beginning with "#sql" were suppressed. This failed since 5.1.6 because even temporary table names were converted when making file names from them. The prefix became converted to "@0023sql". Converting the prefix during SHOW TABLES would suppress the listing of user tables that start with "#sql". The solution of the problem is to continue the implementation of the table name to file name conversion feature. One requirement is to suppress the conversion for temporary table names. This change is straightforward for real temporary tables as there is a function that creates temporary file names. But the generated path names are located in TMPDIR and have no relation to the internal table name. This cannot be used for ALTER TABLE. Its intermediate files need to be in the same directory as the old table files. And it is necessary to be able to deduce the same path from the same table name repeatedly. Consequently the intermediate table files must be handled like normal tables. Their internal names shall start with tmp_file_prefix (#sql) and they shall not be converted like normal table names. I added a flags parameter to all relevant functions that are called from ALTER TABLE. It is used to suppress the conversion for the intermediate table files. The outcome is that the suppression of #sql in SHOW TABLES works again. It does not suppress user tables as these are converted to @0023sql on file level. This patch does also fix ALTER TABLE ... RENAME, which could not rename a table with non-ASCII characters in its name. It does also fix the problem that a user could create a table like `#sql-xxxx-yyyy`, where xxxx is mysqld's pid and yyyy is the thread ID of some other thread, which prevented this thread from running ALTER TABLE. Some of the above problems are mentioned in Bug 1405, which can be closed with this patch. This patch does also contain some minor fixes for other forgotten conversions. Still known problems are reported as bugs 21370, 21373, and 21387.
20 years ago
Bug#18775 - Temporary table from alter table visible to other threads Continued implementation of WL#1324 (table name to filename encoding) The intermediate (not temporary) files of the new table during ALTER TABLE was visible for SHOW TABLES. These intermediate files are copies of the original table with the changes done by ALTER TABLE. After all the data is copied over from the original table, these files are renamed to the original tables file names. So they are not temporary files. They persist after ALTER TABLE, but just with another name. In 5.0 the intermediate files are invisible for SHOW TABLES because all file names beginning with "#sql" were suppressed. This failed since 5.1.6 because even temporary table names were converted when making file names from them. The prefix became converted to "@0023sql". Converting the prefix during SHOW TABLES would suppress the listing of user tables that start with "#sql". The solution of the problem is to continue the implementation of the table name to file name conversion feature. One requirement is to suppress the conversion for temporary table names. This change is straightforward for real temporary tables as there is a function that creates temporary file names. But the generated path names are located in TMPDIR and have no relation to the internal table name. This cannot be used for ALTER TABLE. Its intermediate files need to be in the same directory as the old table files. And it is necessary to be able to deduce the same path from the same table name repeatedly. Consequently the intermediate table files must be handled like normal tables. Their internal names shall start with tmp_file_prefix (#sql) and they shall not be converted like normal table names. I added a flags parameter to all relevant functions that are called from ALTER TABLE. It is used to suppress the conversion for the intermediate table files. The outcome is that the suppression of #sql in SHOW TABLES works again. It does not suppress user tables as these are converted to @0023sql on file level. This patch does also fix ALTER TABLE ... RENAME, which could not rename a table with non-ASCII characters in its name. It does also fix the problem that a user could create a table like `#sql-xxxx-yyyy`, where xxxx is mysqld's pid and yyyy is the thread ID of some other thread, which prevented this thread from running ALTER TABLE. Some of the above problems are mentioned in Bug 1405, which can be closed with this patch. This patch does also contain some minor fixes for other forgotten conversions. Still known problems are reported as bugs 21370, 21373, and 21387.
20 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
Bug#18775 - Temporary table from alter table visible to other threads Continued implementation of WL#1324 (table name to filename encoding) The intermediate (not temporary) files of the new table during ALTER TABLE was visible for SHOW TABLES. These intermediate files are copies of the original table with the changes done by ALTER TABLE. After all the data is copied over from the original table, these files are renamed to the original tables file names. So they are not temporary files. They persist after ALTER TABLE, but just with another name. In 5.0 the intermediate files are invisible for SHOW TABLES because all file names beginning with "#sql" were suppressed. This failed since 5.1.6 because even temporary table names were converted when making file names from them. The prefix became converted to "@0023sql". Converting the prefix during SHOW TABLES would suppress the listing of user tables that start with "#sql". The solution of the problem is to continue the implementation of the table name to file name conversion feature. One requirement is to suppress the conversion for temporary table names. This change is straightforward for real temporary tables as there is a function that creates temporary file names. But the generated path names are located in TMPDIR and have no relation to the internal table name. This cannot be used for ALTER TABLE. Its intermediate files need to be in the same directory as the old table files. And it is necessary to be able to deduce the same path from the same table name repeatedly. Consequently the intermediate table files must be handled like normal tables. Their internal names shall start with tmp_file_prefix (#sql) and they shall not be converted like normal table names. I added a flags parameter to all relevant functions that are called from ALTER TABLE. It is used to suppress the conversion for the intermediate table files. The outcome is that the suppression of #sql in SHOW TABLES works again. It does not suppress user tables as these are converted to @0023sql on file level. This patch does also fix ALTER TABLE ... RENAME, which could not rename a table with non-ASCII characters in its name. It does also fix the problem that a user could create a table like `#sql-xxxx-yyyy`, where xxxx is mysqld's pid and yyyy is the thread ID of some other thread, which prevented this thread from running ALTER TABLE. Some of the above problems are mentioned in Bug 1405, which can be closed with this patch. This patch does also contain some minor fixes for other forgotten conversions. Still known problems are reported as bugs 21370, 21373, and 21387.
20 years ago
Bug#18775 - Temporary table from alter table visible to other threads Continued implementation of WL#1324 (table name to filename encoding) The intermediate (not temporary) files of the new table during ALTER TABLE was visible for SHOW TABLES. These intermediate files are copies of the original table with the changes done by ALTER TABLE. After all the data is copied over from the original table, these files are renamed to the original tables file names. So they are not temporary files. They persist after ALTER TABLE, but just with another name. In 5.0 the intermediate files are invisible for SHOW TABLES because all file names beginning with "#sql" were suppressed. This failed since 5.1.6 because even temporary table names were converted when making file names from them. The prefix became converted to "@0023sql". Converting the prefix during SHOW TABLES would suppress the listing of user tables that start with "#sql". The solution of the problem is to continue the implementation of the table name to file name conversion feature. One requirement is to suppress the conversion for temporary table names. This change is straightforward for real temporary tables as there is a function that creates temporary file names. But the generated path names are located in TMPDIR and have no relation to the internal table name. This cannot be used for ALTER TABLE. Its intermediate files need to be in the same directory as the old table files. And it is necessary to be able to deduce the same path from the same table name repeatedly. Consequently the intermediate table files must be handled like normal tables. Their internal names shall start with tmp_file_prefix (#sql) and they shall not be converted like normal table names. I added a flags parameter to all relevant functions that are called from ALTER TABLE. It is used to suppress the conversion for the intermediate table files. The outcome is that the suppression of #sql in SHOW TABLES works again. It does not suppress user tables as these are converted to @0023sql on file level. This patch does also fix ALTER TABLE ... RENAME, which could not rename a table with non-ASCII characters in its name. It does also fix the problem that a user could create a table like `#sql-xxxx-yyyy`, where xxxx is mysqld's pid and yyyy is the thread ID of some other thread, which prevented this thread from running ALTER TABLE. Some of the above problems are mentioned in Bug 1405, which can be closed with this patch. This patch does also contain some minor fixes for other forgotten conversions. Still known problems are reported as bugs 21370, 21373, and 21387.
20 years ago
  1. /*
  2. Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; version 2 of the License.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program; if not, write to the Free Software
  12. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
  13. /* create and drop of databases */
  14. #include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
  15. #include "sql_priv.h"
  16. #include "unireg.h"
  17. #include "sql_db.h"
  18. #include "sql_cache.h" // query_cache_*
  19. #include "lock.h" // lock_schema_name
  20. #include "sql_table.h" // build_table_filename,
  21. // filename_to_tablename
  22. #include "sql_rename.h" // mysql_rename_tables
  23. #include "sql_acl.h" // SELECT_ACL, DB_ACLS,
  24. // acl_get, check_grant_db
  25. #include "log_event.h" // Query_log_event
  26. #include "sql_base.h" // lock_table_names, tdc_remove_table
  27. #include "sql_handler.h" // mysql_ha_rm_tables
  28. #include <mysys_err.h>
  29. #include "sp.h"
  30. #include "events.h"
  31. #include <my_dir.h>
  32. #include <m_ctype.h>
  33. #include "log.h"
  34. #ifdef __WIN__
  35. #include <direct.h>
  36. #endif
  37. #include "debug_sync.h"
  38. #define MAX_DROP_TABLE_Q_LEN 1024
  39. const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NullS};
  40. static TYPELIB deletable_extentions=
  41. {array_elements(del_exts)-1,"del_exts", del_exts, NULL};
  42. static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp,
  43. const char *db,
  44. const char *path,
  45. TABLE_LIST **tables,
  46. bool *found_other_files);
  47. long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path);
  48. static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error);
  49. static void mysql_change_db_impl(THD *thd,
  50. LEX_STRING *new_db_name,
  51. ulong new_db_access,
  52. CHARSET_INFO *new_db_charset);
  53. /* Database options hash */
  54. static HASH dboptions;
  55. static my_bool dboptions_init= 0;
  56. static mysql_rwlock_t LOCK_dboptions;
  57. /* Structure for database options */
  58. typedef struct my_dbopt_st
  59. {
  60. char *name; /* Database name */
  61. uint name_length; /* Database length name */
  62. CHARSET_INFO *charset; /* Database default character set */
  63. } my_dbopt_t;
  64. /*
  65. Function we use in the creation of our hash to get key.
  66. */
  67. extern "C" uchar* dboptions_get_key(my_dbopt_t *opt, size_t *length,
  68. my_bool not_used);
  69. uchar* dboptions_get_key(my_dbopt_t *opt, size_t *length,
  70. my_bool not_used __attribute__((unused)))
  71. {
  72. *length= opt->name_length;
  73. return (uchar*) opt->name;
  74. }
  75. /*
  76. Helper function to write a query to binlog used by mysql_rm_db()
  77. */
  78. static inline int write_to_binlog(THD *thd, char *query, uint q_len,
  79. char *db, uint db_len)
  80. {
  81. Query_log_event qinfo(thd, query, q_len, FALSE, TRUE, FALSE, 0);
  82. qinfo.db= db;
  83. qinfo.db_len= db_len;
  84. return mysql_bin_log.write(&qinfo);
  85. }
  86. /*
  87. Function to free dboptions hash element
  88. */
  89. extern "C" void free_dbopt(void *dbopt);
  90. void free_dbopt(void *dbopt)
  91. {
  92. my_free(dbopt);
  93. }
  94. #ifdef HAVE_PSI_INTERFACE
  95. static PSI_rwlock_key key_rwlock_LOCK_dboptions;
  96. static PSI_rwlock_info all_database_names_rwlocks[]=
  97. {
  98. { &key_rwlock_LOCK_dboptions, "LOCK_dboptions", PSI_FLAG_GLOBAL}
  99. };
  100. static void init_database_names_psi_keys(void)
  101. {
  102. const char* category= "sql";
  103. int count;
  104. if (PSI_server == NULL)
  105. return;
  106. count= array_elements(all_database_names_rwlocks);
  107. PSI_server->register_rwlock(category, all_database_names_rwlocks, count);
  108. }
  109. #endif
  110. /**
  111. Initialize database option cache.
  112. @note Must be called before any other database function is called.
  113. @retval 0 ok
  114. @retval 1 Fatal error
  115. */
  116. bool my_dboptions_cache_init(void)
  117. {
  118. #ifdef HAVE_PSI_INTERFACE
  119. init_database_names_psi_keys();
  120. #endif
  121. bool error= 0;
  122. mysql_rwlock_init(key_rwlock_LOCK_dboptions, &LOCK_dboptions);
  123. if (!dboptions_init)
  124. {
  125. dboptions_init= 1;
  126. error= my_hash_init(&dboptions, lower_case_table_names ?
  127. &my_charset_bin : system_charset_info,
  128. 32, 0, 0, (my_hash_get_key) dboptions_get_key,
  129. free_dbopt,0);
  130. }
  131. return error;
  132. }
  133. /**
  134. Free database option hash and locked databases hash.
  135. */
  136. void my_dboptions_cache_free(void)
  137. {
  138. if (dboptions_init)
  139. {
  140. dboptions_init= 0;
  141. my_hash_free(&dboptions);
  142. mysql_rwlock_destroy(&LOCK_dboptions);
  143. }
  144. }
  145. /**
  146. Cleanup cached options.
  147. */
  148. void my_dbopt_cleanup(void)
  149. {
  150. mysql_rwlock_wrlock(&LOCK_dboptions);
  151. my_hash_free(&dboptions);
  152. my_hash_init(&dboptions, lower_case_table_names ?
  153. &my_charset_bin : system_charset_info,
  154. 32, 0, 0, (my_hash_get_key) dboptions_get_key,
  155. free_dbopt,0);
  156. mysql_rwlock_unlock(&LOCK_dboptions);
  157. }
  158. /*
  159. Find database options in the hash.
  160. DESCRIPTION
  161. Search a database options in the hash, usings its path.
  162. Fills "create" on success.
  163. RETURN VALUES
  164. 0 on success.
  165. 1 on error.
  166. */
  167. static my_bool get_dbopt(const char *dbname, HA_CREATE_INFO *create)
  168. {
  169. my_dbopt_t *opt;
  170. uint length;
  171. my_bool error= 1;
  172. length= (uint) strlen(dbname);
  173. mysql_rwlock_rdlock(&LOCK_dboptions);
  174. if ((opt= (my_dbopt_t*) my_hash_search(&dboptions, (uchar*) dbname, length)))
  175. {
  176. create->default_table_charset= opt->charset;
  177. error= 0;
  178. }
  179. mysql_rwlock_unlock(&LOCK_dboptions);
  180. return error;
  181. }
  182. /*
  183. Writes database options into the hash.
  184. DESCRIPTION
  185. Inserts database options into the hash, or updates
  186. options if they are already in the hash.
  187. RETURN VALUES
  188. 0 on success.
  189. 1 on error.
  190. */
  191. static my_bool put_dbopt(const char *dbname, HA_CREATE_INFO *create)
  192. {
  193. my_dbopt_t *opt;
  194. uint length;
  195. my_bool error= 0;
  196. DBUG_ENTER("put_dbopt");
  197. length= (uint) strlen(dbname);
  198. mysql_rwlock_wrlock(&LOCK_dboptions);
  199. if (!(opt= (my_dbopt_t*) my_hash_search(&dboptions, (uchar*) dbname,
  200. length)))
  201. {
  202. /* Options are not in the hash, insert them */
  203. char *tmp_name;
  204. if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
  205. &opt, (uint) sizeof(*opt), &tmp_name, (uint) length+1,
  206. NullS))
  207. {
  208. error= 1;
  209. goto end;
  210. }
  211. opt->name= tmp_name;
  212. strmov(opt->name, dbname);
  213. opt->name_length= length;
  214. if ((error= my_hash_insert(&dboptions, (uchar*) opt)))
  215. {
  216. my_free(opt);
  217. goto end;
  218. }
  219. }
  220. /* Update / write options in hash */
  221. opt->charset= create->default_table_charset;
  222. end:
  223. mysql_rwlock_unlock(&LOCK_dboptions);
  224. DBUG_RETURN(error);
  225. }
  226. /*
  227. Deletes database options from the hash.
  228. */
  229. static void del_dbopt(const char *path)
  230. {
  231. my_dbopt_t *opt;
  232. mysql_rwlock_wrlock(&LOCK_dboptions);
  233. if ((opt= (my_dbopt_t *)my_hash_search(&dboptions, (const uchar*) path,
  234. strlen(path))))
  235. my_hash_delete(&dboptions, (uchar*) opt);
  236. mysql_rwlock_unlock(&LOCK_dboptions);
  237. }
  238. /*
  239. Create database options file:
  240. DESCRIPTION
  241. Currently database default charset is only stored there.
  242. RETURN VALUES
  243. 0 ok
  244. 1 Could not create file or write to it. Error sent through my_error()
  245. */
  246. static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
  247. {
  248. register File file;
  249. char buf[256]; // Should be enough for one option
  250. bool error=1;
  251. if (!create->default_table_charset)
  252. create->default_table_charset= thd->variables.collation_server;
  253. if (put_dbopt(path, create))
  254. return 1;
  255. if ((file= mysql_file_create(key_file_dbopt, path, CREATE_MODE,
  256. O_RDWR | O_TRUNC, MYF(MY_WME))) >= 0)
  257. {
  258. ulong length;
  259. length= (ulong) (strxnmov(buf, sizeof(buf)-1, "default-character-set=",
  260. create->default_table_charset->csname,
  261. "\ndefault-collation=",
  262. create->default_table_charset->name,
  263. "\n", NullS) - buf);
  264. /* Error is written by mysql_file_write */
  265. if (!mysql_file_write(file, (uchar*) buf, length, MYF(MY_NABP+MY_WME)))
  266. error=0;
  267. mysql_file_close(file, MYF(0));
  268. }
  269. return error;
  270. }
  271. /*
  272. Load database options file
  273. load_db_opt()
  274. path Path for option file
  275. create Where to store the read options
  276. DESCRIPTION
  277. RETURN VALUES
  278. 0 File found
  279. 1 No database file or could not open it
  280. */
  281. bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
  282. {
  283. File file;
  284. char buf[256];
  285. DBUG_ENTER("load_db_opt");
  286. bool error=1;
  287. uint nbytes;
  288. bzero((char*) create,sizeof(*create));
  289. create->default_table_charset= thd->variables.collation_server;
  290. /* Check if options for this database are already in the hash */
  291. if (!get_dbopt(path, create))
  292. DBUG_RETURN(0);
  293. /* Otherwise, load options from the .opt file */
  294. if ((file= mysql_file_open(key_file_dbopt,
  295. path, O_RDONLY | O_SHARE, MYF(0))) < 0)
  296. goto err1;
  297. IO_CACHE cache;
  298. if (init_io_cache(&cache, file, IO_SIZE, READ_CACHE, 0, 0, MYF(0)))
  299. goto err2;
  300. while ((int) (nbytes= my_b_gets(&cache, (char*) buf, sizeof(buf))) > 0)
  301. {
  302. char *pos= buf+nbytes-1;
  303. /* Remove end space and control characters */
  304. while (pos > buf && !my_isgraph(&my_charset_latin1, pos[-1]))
  305. pos--;
  306. *pos=0;
  307. if ((pos= strchr(buf, '=')))
  308. {
  309. if (!strncmp(buf,"default-character-set", (pos-buf)))
  310. {
  311. /*
  312. Try character set name, and if it fails
  313. try collation name, probably it's an old
  314. 4.1.0 db.opt file, which didn't have
  315. separate default-character-set and
  316. default-collation commands.
  317. */
  318. if (!(create->default_table_charset=
  319. get_charset_by_csname(pos+1, MY_CS_PRIMARY, MYF(0))) &&
  320. !(create->default_table_charset=
  321. get_charset_by_name(pos+1, MYF(0))))
  322. {
  323. sql_print_error("Error while loading database options: '%s':",path);
  324. sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET),pos+1);
  325. create->default_table_charset= default_charset_info;
  326. }
  327. }
  328. else if (!strncmp(buf,"default-collation", (pos-buf)))
  329. {
  330. if (!(create->default_table_charset= get_charset_by_name(pos+1,
  331. MYF(0))))
  332. {
  333. sql_print_error("Error while loading database options: '%s':",path);
  334. sql_print_error(ER(ER_UNKNOWN_COLLATION),pos+1);
  335. create->default_table_charset= default_charset_info;
  336. }
  337. }
  338. }
  339. }
  340. /*
  341. Put the loaded value into the hash.
  342. Note that another thread could've added the same
  343. entry to the hash after we called get_dbopt(),
  344. but it's not an error, as put_dbopt() takes this
  345. possibility into account.
  346. */
  347. error= put_dbopt(path, create);
  348. end_io_cache(&cache);
  349. err2:
  350. mysql_file_close(file, MYF(0));
  351. err1:
  352. DBUG_RETURN(error);
  353. }
  354. /*
  355. Retrieve database options by name. Load database options file or fetch from
  356. cache.
  357. SYNOPSIS
  358. load_db_opt_by_name()
  359. db_name Database name
  360. db_create_info Where to store the database options
  361. DESCRIPTION
  362. load_db_opt_by_name() is a shortcut for load_db_opt().
  363. NOTE
  364. Although load_db_opt_by_name() (and load_db_opt()) returns status of
  365. the operation, it is useless usually and should be ignored. The problem
  366. is that there are 1) system databases ("mysql") and 2) virtual
  367. databases ("information_schema"), which do not contain options file.
  368. So, load_db_opt[_by_name]() returns FALSE for these databases, but this
  369. is not an error.
  370. load_db_opt[_by_name]() clears db_create_info structure in any case, so
  371. even on failure it contains valid data. So, common use case is just
  372. call load_db_opt[_by_name]() without checking return value and use
  373. db_create_info right after that.
  374. RETURN VALUES (read NOTE!)
  375. FALSE Success
  376. TRUE Failed to retrieve options
  377. */
  378. bool load_db_opt_by_name(THD *thd, const char *db_name,
  379. HA_CREATE_INFO *db_create_info)
  380. {
  381. char db_opt_path[FN_REFLEN + 1];
  382. /*
  383. Pass an empty file name, and the database options file name as extension
  384. to avoid table name to file name encoding.
  385. */
  386. (void) build_table_filename(db_opt_path, sizeof(db_opt_path) - 1,
  387. db_name, "", MY_DB_OPT_FILE, 0);
  388. return load_db_opt(thd, db_opt_path, db_create_info);
  389. }
  390. /**
  391. Return default database collation.
  392. @param thd Thread context.
  393. @param db_name Database name.
  394. @return CHARSET_INFO object. The operation always return valid character
  395. set, even if the database does not exist.
  396. */
  397. CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name)
  398. {
  399. HA_CREATE_INFO db_info;
  400. if (thd->db != NULL && strcmp(db_name, thd->db) == 0)
  401. return thd->db_charset;
  402. load_db_opt_by_name(thd, db_name, &db_info);
  403. /*
  404. NOTE: even if load_db_opt_by_name() fails,
  405. db_info.default_table_charset contains valid character set
  406. (collation_server). We should not fail if load_db_opt_by_name() fails,
  407. because it is valid case. If a database has been created just by
  408. "mkdir", it does not contain db.opt file, but it is valid database.
  409. */
  410. return db_info.default_table_charset;
  411. }
  412. /*
  413. Create a database
  414. SYNOPSIS
  415. mysql_create_db()
  416. thd Thread handler
  417. db Name of database to create
  418. Function assumes that this is already validated.
  419. create_info Database create options (like character set)
  420. silent Used by replication when internally creating a database.
  421. In this case the entry should not be logged.
  422. SIDE-EFFECTS
  423. 1. Report back to client that command succeeded (my_ok)
  424. 2. Report errors to client
  425. 3. Log event to binary log
  426. (The 'silent' flags turns off 1 and 3.)
  427. RETURN VALUES
  428. FALSE ok
  429. TRUE Error
  430. */
  431. int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
  432. bool silent)
  433. {
  434. char path[FN_REFLEN+16];
  435. char tmp_query[FN_REFLEN+16];
  436. long result= 1;
  437. int error= 0;
  438. MY_STAT stat_info;
  439. uint create_options= create_info ? create_info->options : 0;
  440. uint path_len;
  441. DBUG_ENTER("mysql_create_db");
  442. /* do not create 'information_schema' db */
  443. if (is_infoschema_db(db))
  444. {
  445. my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
  446. DBUG_RETURN(-1);
  447. }
  448. if (lock_schema_name(thd, db))
  449. DBUG_RETURN(-1);
  450. /* Check directory */
  451. path_len= build_table_filename(path, sizeof(path) - 1, db, "", "", 0);
  452. path[path_len-1]= 0; // Remove last '/' from path
  453. if (mysql_file_stat(key_file_misc, path, &stat_info, MYF(0)))
  454. {
  455. if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS))
  456. {
  457. my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
  458. error= -1;
  459. goto exit;
  460. }
  461. push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
  462. ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db);
  463. error= 0;
  464. goto not_silent;
  465. }
  466. else
  467. {
  468. if (my_errno != ENOENT)
  469. {
  470. my_error(EE_STAT, MYF(0), path, my_errno);
  471. goto exit;
  472. }
  473. if (my_mkdir(path,0777,MYF(0)) < 0)
  474. {
  475. my_error(ER_CANT_CREATE_DB, MYF(0), db, my_errno);
  476. error= -1;
  477. goto exit;
  478. }
  479. }
  480. path[path_len-1]= FN_LIBCHAR;
  481. strmake(path+path_len, MY_DB_OPT_FILE, sizeof(path)-path_len-1);
  482. if (write_db_opt(thd, path, create_info))
  483. {
  484. /*
  485. Could not create options file.
  486. Restore things to beginning.
  487. */
  488. path[path_len]= 0;
  489. if (rmdir(path) >= 0)
  490. {
  491. error= -1;
  492. goto exit;
  493. }
  494. /*
  495. We come here when we managed to create the database, but not the option
  496. file. In this case it's best to just continue as if nothing has
  497. happened. (This is a very unlikely senario)
  498. */
  499. thd->clear_error();
  500. }
  501. not_silent:
  502. if (!silent)
  503. {
  504. char *query;
  505. uint query_length;
  506. if (!thd->query()) // Only in replication
  507. {
  508. query= tmp_query;
  509. query_length= (uint) (strxmov(tmp_query,"create database `",
  510. db, "`", NullS) - tmp_query);
  511. }
  512. else
  513. {
  514. query= thd->query();
  515. query_length= thd->query_length();
  516. }
  517. ha_binlog_log_query(thd, 0, LOGCOM_CREATE_DB,
  518. query, query_length,
  519. db, "");
  520. if (mysql_bin_log.is_open())
  521. {
  522. int errcode= query_error_code(thd, TRUE);
  523. Query_log_event qinfo(thd, query, query_length, FALSE, TRUE,
  524. /* suppress_use */ TRUE, errcode);
  525. /*
  526. Write should use the database being created as the "current
  527. database" and not the threads current database, which is the
  528. default. If we do not change the "current database" to the
  529. database being created, the CREATE statement will not be
  530. replicated when using --binlog-do-db to select databases to be
  531. replicated.
  532. An example (--binlog-do-db=sisyfos):
  533. CREATE DATABASE bob; # Not replicated
  534. USE bob; # 'bob' is the current database
  535. CREATE DATABASE sisyfos; # Not replicated since 'bob' is
  536. # current database.
  537. USE sisyfos; # Will give error on slave since
  538. # database does not exist.
  539. */
  540. qinfo.db = db;
  541. qinfo.db_len = strlen(db);
  542. /*
  543. These DDL methods and logging are protected with the exclusive
  544. metadata lock on the schema
  545. */
  546. if (mysql_bin_log.write(&qinfo))
  547. {
  548. error= -1;
  549. goto exit;
  550. }
  551. }
  552. my_ok(thd, result);
  553. }
  554. exit:
  555. DBUG_RETURN(error);
  556. }
  557. /* db-name is already validated when we come here */
  558. bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
  559. {
  560. char path[FN_REFLEN+16];
  561. long result=1;
  562. int error= 0;
  563. DBUG_ENTER("mysql_alter_db");
  564. if (lock_schema_name(thd, db))
  565. DBUG_RETURN(TRUE);
  566. /*
  567. Recreate db options file: /dbpath/.db.opt
  568. We pass MY_DB_OPT_FILE as "extension" to avoid
  569. "table name to file name" encoding.
  570. */
  571. build_table_filename(path, sizeof(path) - 1, db, "", MY_DB_OPT_FILE, 0);
  572. if ((error=write_db_opt(thd, path, create_info)))
  573. goto exit;
  574. /* Change options if current database is being altered. */
  575. if (thd->db && !strcmp(thd->db,db))
  576. {
  577. thd->db_charset= create_info->default_table_charset ?
  578. create_info->default_table_charset :
  579. thd->variables.collation_server;
  580. thd->variables.collation_database= thd->db_charset;
  581. }
  582. ha_binlog_log_query(thd, 0, LOGCOM_ALTER_DB,
  583. thd->query(), thd->query_length(),
  584. db, "");
  585. if (mysql_bin_log.is_open())
  586. {
  587. int errcode= query_error_code(thd, TRUE);
  588. Query_log_event qinfo(thd, thd->query(), thd->query_length(), FALSE, TRUE,
  589. /* suppress_use */ TRUE, errcode);
  590. /*
  591. Write should use the database being created as the "current
  592. database" and not the threads current database, which is the
  593. default.
  594. */
  595. qinfo.db = db;
  596. qinfo.db_len = strlen(db);
  597. /*
  598. These DDL methods and logging are protected with the exclusive
  599. metadata lock on the schema.
  600. */
  601. if ((error= mysql_bin_log.write(&qinfo)))
  602. goto exit;
  603. }
  604. my_ok(thd, result);
  605. exit:
  606. DBUG_RETURN(error);
  607. }
  608. /**
  609. Drop all tables, routines and events in a database and the database itself.
  610. @param thd Thread handle
  611. @param db Database name in the case given by user
  612. It's already validated and set to lower case
  613. (if needed) when we come here
  614. @param if_exists Don't give error if database doesn't exists
  615. @param silent Don't write the statement to the binary log and don't
  616. send ok packet to the client
  617. @retval false OK (Database dropped)
  618. @retval true Error
  619. */
  620. bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
  621. {
  622. ulong deleted_tables= 0;
  623. bool error= true;
  624. char path[FN_REFLEN+16];
  625. MY_DIR *dirp;
  626. uint length;
  627. bool found_other_files= false;
  628. TABLE_LIST *tables= NULL;
  629. TABLE_LIST *table;
  630. Drop_table_error_handler err_handler;
  631. DBUG_ENTER("mysql_rm_db");
  632. if (lock_schema_name(thd, db))
  633. DBUG_RETURN(true);
  634. length= build_table_filename(path, sizeof(path) - 1, db, "", "", 0);
  635. strmov(path+length, MY_DB_OPT_FILE); // Append db option file name
  636. del_dbopt(path); // Remove dboption hash entry
  637. path[length]= '\0'; // Remove file name
  638. /* See if the directory exists */
  639. if (!(dirp= my_dir(path,MYF(MY_DONT_SORT))))
  640. {
  641. if (!if_exists)
  642. {
  643. my_error(ER_DB_DROP_EXISTS, MYF(0), db);
  644. DBUG_RETURN(true);
  645. }
  646. else
  647. {
  648. push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
  649. ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS), db);
  650. error= false;
  651. goto update_binlog;
  652. }
  653. }
  654. if (find_db_tables_and_rm_known_files(thd, dirp, db, path, &tables,
  655. &found_other_files))
  656. goto exit;
  657. /*
  658. Disable drop of enabled log tables, must be done before name locking.
  659. This check is only needed if we are dropping the "mysql" database.
  660. */
  661. if ((my_strcasecmp(system_charset_info, MYSQL_SCHEMA_NAME.str, db) == 0))
  662. {
  663. for (table= tables; table; table= table->next_local)
  664. {
  665. if (check_if_log_table(table->db_length, table->db,
  666. table->table_name_length, table->table_name, true))
  667. {
  668. my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP");
  669. goto exit;
  670. }
  671. }
  672. }
  673. /* Lock all tables and stored routines about to be dropped. */
  674. if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout,
  675. MYSQL_OPEN_SKIP_TEMPORARY) ||
  676. lock_db_routines(thd, db))
  677. goto exit;
  678. /* mysql_ha_rm_tables() requires a non-null TABLE_LIST. */
  679. if (tables)
  680. mysql_ha_rm_tables(thd, tables);
  681. for (table= tables; table; table= table->next_local)
  682. {
  683. tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
  684. false);
  685. deleted_tables++;
  686. }
  687. thd->push_internal_handler(&err_handler);
  688. if (!thd->killed &&
  689. !(tables &&
  690. mysql_rm_table_no_locks(thd, tables, true, false, true, true)))
  691. {
  692. /*
  693. We temporarily disable the binary log while dropping the objects
  694. in the database. Since the DROP DATABASE statement is always
  695. replicated as a statement, execution of it will drop all objects
  696. in the database on the slave as well, so there is no need to
  697. replicate the removal of the individual objects in the database
  698. as well.
  699. This is more of a safety precaution, since normally no objects
  700. should be dropped while the database is being cleaned, but in
  701. the event that a change in the code to remove other objects is
  702. made, these drops should still not be logged.
  703. Notice that the binary log have to be enabled over the call to
  704. ha_drop_database(), since NDB otherwise detects the binary log
  705. as disabled and will not log the drop database statement on any
  706. other connected server.
  707. */
  708. ha_drop_database(path);
  709. tmp_disable_binlog(thd);
  710. query_cache_invalidate1(db);
  711. (void) sp_drop_db_routines(thd, db); /* @todo Do not ignore errors */
  712. #ifdef HAVE_EVENT_SCHEDULER
  713. Events::drop_schema_events(thd, db);
  714. #endif
  715. reenable_binlog(thd);
  716. /*
  717. If the directory is a symbolic link, remove the link first, then
  718. remove the directory the symbolic link pointed at
  719. */
  720. if (found_other_files)
  721. my_error(ER_DB_DROP_RMDIR, MYF(0), path, EEXIST);
  722. else
  723. error= rm_dir_w_symlink(path, true);
  724. }
  725. thd->pop_internal_handler();
  726. update_binlog:
  727. if (!silent && !error)
  728. {
  729. const char *query;
  730. ulong query_length;
  731. if (!thd->query())
  732. {
  733. /* The client used the old obsolete mysql_drop_db() call */
  734. query= path;
  735. query_length= (uint) (strxmov(path, "drop database `", db, "`",
  736. NullS) - path);
  737. }
  738. else
  739. {
  740. query= thd->query();
  741. query_length= thd->query_length();
  742. }
  743. if (mysql_bin_log.is_open())
  744. {
  745. int errcode= query_error_code(thd, TRUE);
  746. Query_log_event qinfo(thd, query, query_length, FALSE, TRUE,
  747. /* suppress_use */ TRUE, errcode);
  748. /*
  749. Write should use the database being created as the "current
  750. database" and not the threads current database, which is the
  751. default.
  752. */
  753. qinfo.db = db;
  754. qinfo.db_len = strlen(db);
  755. /*
  756. These DDL methods and logging are protected with the exclusive
  757. metadata lock on the schema.
  758. */
  759. if (mysql_bin_log.write(&qinfo))
  760. {
  761. error= true;
  762. goto exit;
  763. }
  764. }
  765. thd->clear_error();
  766. thd->server_status|= SERVER_STATUS_DB_DROPPED;
  767. my_ok(thd, deleted_tables);
  768. }
  769. else if (mysql_bin_log.is_open() && !silent)
  770. {
  771. char *query, *query_pos, *query_end, *query_data_start;
  772. TABLE_LIST *tbl;
  773. uint db_len;
  774. if (!(query= (char*) thd->alloc(MAX_DROP_TABLE_Q_LEN)))
  775. goto exit; /* not much else we can do */
  776. query_pos= query_data_start= strmov(query,"drop table ");
  777. query_end= query + MAX_DROP_TABLE_Q_LEN;
  778. db_len= strlen(db);
  779. for (tbl= tables; tbl; tbl= tbl->next_local)
  780. {
  781. uint tbl_name_len;
  782. bool exists;
  783. // Only write drop table to the binlog for tables that no longer exist.
  784. if (check_if_table_exists(thd, tbl, &exists))
  785. {
  786. error= true;
  787. goto exit;
  788. }
  789. if (exists)
  790. continue;
  791. /* 3 for the quotes and the comma*/
  792. tbl_name_len= strlen(tbl->table_name) + 3;
  793. if (query_pos + tbl_name_len + 1 >= query_end)
  794. {
  795. /*
  796. These DDL methods and logging are protected with the exclusive
  797. metadata lock on the schema.
  798. */
  799. if (write_to_binlog(thd, query, query_pos -1 - query, db, db_len))
  800. {
  801. error= true;
  802. goto exit;
  803. }
  804. query_pos= query_data_start;
  805. }
  806. *query_pos++ = '`';
  807. query_pos= strmov(query_pos,tbl->table_name);
  808. *query_pos++ = '`';
  809. *query_pos++ = ',';
  810. }
  811. if (query_pos != query_data_start)
  812. {
  813. /*
  814. These DDL methods and logging are protected with the exclusive
  815. metadata lock on the schema.
  816. */
  817. if (write_to_binlog(thd, query, query_pos -1 - query, db, db_len))
  818. {
  819. error= true;
  820. goto exit;
  821. }
  822. }
  823. }
  824. exit:
  825. /*
  826. If this database was the client's selected database, we silently
  827. change the client's selected database to nothing (to have an empty
  828. SELECT DATABASE() in the future). For this we free() thd->db and set
  829. it to 0.
  830. */
  831. if (thd->db && !strcmp(thd->db, db) && !error)
  832. mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
  833. my_dirend(dirp);
  834. DBUG_RETURN(error);
  835. }
  836. static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp,
  837. const char *db,
  838. const char *path,
  839. TABLE_LIST **tables,
  840. bool *found_other_files)
  841. {
  842. char filePath[FN_REFLEN];
  843. TABLE_LIST *tot_list=0, **tot_list_next_local, **tot_list_next_global;
  844. DBUG_ENTER("find_db_tables_and_rm_known_files");
  845. DBUG_PRINT("enter",("path: %s", path));
  846. tot_list_next_local= tot_list_next_global= &tot_list;
  847. for (uint idx=0 ;
  848. idx < (uint) dirp->number_off_files && !thd->killed ;
  849. idx++)
  850. {
  851. FILEINFO *file=dirp->dir_entry+idx;
  852. char *extension;
  853. DBUG_PRINT("info",("Examining: %s", file->name));
  854. /* skiping . and .. */
  855. if (file->name[0] == '.' && (!file->name[1] ||
  856. (file->name[1] == '.' && !file->name[2])))
  857. continue;
  858. if (file->name[0] == 'a' && file->name[1] == 'r' &&
  859. file->name[2] == 'c' && file->name[3] == '\0')
  860. {
  861. /* .frm archive:
  862. Those archives are obsolete, but following code should
  863. exist to remove existent "arc" directories.
  864. */
  865. char newpath[FN_REFLEN];
  866. MY_DIR *new_dirp;
  867. strxmov(newpath, path, "/", "arc", NullS);
  868. (void) unpack_filename(newpath, newpath);
  869. if ((new_dirp = my_dir(newpath, MYF(MY_DONT_SORT))))
  870. {
  871. DBUG_PRINT("my",("Archive subdir found: %s", newpath));
  872. if ((mysql_rm_arc_files(thd, new_dirp, newpath)) < 0)
  873. DBUG_RETURN(true);
  874. continue;
  875. }
  876. *found_other_files= true;
  877. continue;
  878. }
  879. if (!(extension= strrchr(file->name, '.')))
  880. extension= strend(file->name);
  881. if (find_type(extension, &deletable_extentions, FIND_TYPE_NO_PREFIX) <= 0)
  882. {
  883. if (find_type(extension, ha_known_exts(), FIND_TYPE_NO_PREFIX) <= 0)
  884. *found_other_files= true;
  885. continue;
  886. }
  887. /* just for safety we use files_charset_info */
  888. if (db && !my_strcasecmp(files_charset_info,
  889. extension, reg_ext))
  890. {
  891. /* Drop the table nicely */
  892. *extension= 0; // Remove extension
  893. TABLE_LIST *table_list=(TABLE_LIST*)
  894. thd->calloc(sizeof(*table_list) +
  895. strlen(db) + 1 +
  896. MYSQL50_TABLE_NAME_PREFIX_LENGTH +
  897. strlen(file->name) + 1);
  898. if (!table_list)
  899. DBUG_RETURN(true);
  900. table_list->db= (char*) (table_list+1);
  901. table_list->db_length= strmov(table_list->db, db) - table_list->db;
  902. table_list->table_name= table_list->db + table_list->db_length + 1;
  903. table_list->table_name_length= filename_to_tablename(file->name,
  904. table_list->table_name,
  905. MYSQL50_TABLE_NAME_PREFIX_LENGTH +
  906. strlen(file->name) + 1);
  907. table_list->open_type= OT_BASE_ONLY;
  908. /* To be able to correctly look up the table in the table cache. */
  909. if (lower_case_table_names)
  910. table_list->table_name_length= my_casedn_str(files_charset_info,
  911. table_list->table_name);
  912. table_list->alias= table_list->table_name; // If lower_case_table_names=2
  913. table_list->internal_tmp_table= is_prefix(file->name, tmp_file_prefix);
  914. table_list->mdl_request.init(MDL_key::TABLE, table_list->db,
  915. table_list->table_name, MDL_EXCLUSIVE,
  916. MDL_TRANSACTION);
  917. /* Link into list */
  918. (*tot_list_next_local)= table_list;
  919. (*tot_list_next_global)= table_list;
  920. tot_list_next_local= &table_list->next_local;
  921. tot_list_next_global= &table_list->next_global;
  922. }
  923. else
  924. {
  925. strxmov(filePath, path, "/", file->name, NullS);
  926. /*
  927. We ignore ENOENT error in order to skip files that was deleted
  928. by concurrently running statement like REAPIR TABLE ...
  929. */
  930. if (my_delete_with_symlink(filePath, MYF(0)) &&
  931. my_errno != ENOENT)
  932. {
  933. my_error(EE_DELETE, MYF(0), filePath, my_errno);
  934. DBUG_RETURN(true);
  935. }
  936. }
  937. }
  938. *tables= tot_list;
  939. DBUG_RETURN(false);
  940. }
  941. /*
  942. Remove directory with symlink
  943. SYNOPSIS
  944. rm_dir_w_symlink()
  945. org_path path of derictory
  946. send_error send errors
  947. RETURN
  948. 0 OK
  949. 1 ERROR
  950. */
  951. static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error)
  952. {
  953. char tmp_path[FN_REFLEN], *pos;
  954. char *path= tmp_path;
  955. DBUG_ENTER("rm_dir_w_symlink");
  956. unpack_filename(tmp_path, org_path);
  957. #ifdef HAVE_READLINK
  958. int error;
  959. char tmp2_path[FN_REFLEN];
  960. /* Remove end FN_LIBCHAR as this causes problem on Linux in readlink */
  961. pos= strend(path);
  962. if (pos > path && pos[-1] == FN_LIBCHAR)
  963. *--pos=0;
  964. if ((error= my_readlink(tmp2_path, path, MYF(MY_WME))) < 0)
  965. DBUG_RETURN(1);
  966. if (!error)
  967. {
  968. if (mysql_file_delete(key_file_misc, path, MYF(send_error ? MY_WME : 0)))
  969. {
  970. DBUG_RETURN(send_error);
  971. }
  972. /* Delete directory symbolic link pointed at */
  973. path= tmp2_path;
  974. }
  975. #endif
  976. /* Remove last FN_LIBCHAR to not cause a problem on OS/2 */
  977. pos= strend(path);
  978. if (pos > path && pos[-1] == FN_LIBCHAR)
  979. *--pos=0;
  980. if (rmdir(path) < 0 && send_error)
  981. {
  982. my_error(ER_DB_DROP_RMDIR, MYF(0), path, errno);
  983. DBUG_RETURN(1);
  984. }
  985. DBUG_RETURN(0);
  986. }
  987. /*
  988. Remove .frm archives from directory
  989. SYNOPSIS
  990. thd thread handler
  991. dirp list of files in archive directory
  992. db data base name
  993. org_path path of archive directory
  994. RETURN
  995. > 0 number of removed files
  996. -1 error
  997. NOTE
  998. A support of "arc" directories is obsolete, however this
  999. function should exist to remove existent "arc" directories.
  1000. */
  1001. long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path)
  1002. {
  1003. long deleted= 0;
  1004. ulong found_other_files= 0;
  1005. char filePath[FN_REFLEN];
  1006. DBUG_ENTER("mysql_rm_arc_files");
  1007. DBUG_PRINT("enter", ("path: %s", org_path));
  1008. for (uint idx=0 ;
  1009. idx < (uint) dirp->number_off_files && !thd->killed ;
  1010. idx++)
  1011. {
  1012. FILEINFO *file=dirp->dir_entry+idx;
  1013. char *extension, *revision;
  1014. DBUG_PRINT("info",("Examining: %s", file->name));
  1015. /* skiping . and .. */
  1016. if (file->name[0] == '.' && (!file->name[1] ||
  1017. (file->name[1] == '.' && !file->name[2])))
  1018. continue;
  1019. extension= fn_ext(file->name);
  1020. if (extension[0] != '.' ||
  1021. extension[1] != 'f' || extension[2] != 'r' ||
  1022. extension[3] != 'm' || extension[4] != '-')
  1023. {
  1024. found_other_files++;
  1025. continue;
  1026. }
  1027. revision= extension+5;
  1028. while (*revision && my_isdigit(system_charset_info, *revision))
  1029. revision++;
  1030. if (*revision)
  1031. {
  1032. found_other_files++;
  1033. continue;
  1034. }
  1035. strxmov(filePath, org_path, "/", file->name, NullS);
  1036. if (mysql_file_delete_with_symlink(key_file_misc, filePath, MYF(MY_WME)))
  1037. {
  1038. goto err;
  1039. }
  1040. deleted++;
  1041. }
  1042. if (thd->killed)
  1043. goto err;
  1044. my_dirend(dirp);
  1045. /*
  1046. If the directory is a symbolic link, remove the link first, then
  1047. remove the directory the symbolic link pointed at
  1048. */
  1049. if (!found_other_files &&
  1050. rm_dir_w_symlink(org_path, 0))
  1051. DBUG_RETURN(-1);
  1052. DBUG_RETURN(deleted);
  1053. err:
  1054. my_dirend(dirp);
  1055. DBUG_RETURN(-1);
  1056. }
  1057. /**
  1058. @brief Internal implementation: switch current database to a valid one.
  1059. @param thd Thread context.
  1060. @param new_db_name Name of the database to switch to. The function will
  1061. take ownership of the name (the caller must not free
  1062. the allocated memory). If the name is NULL, we're
  1063. going to switch to NULL db.
  1064. @param new_db_access Privileges of the new database.
  1065. @param new_db_charset Character set of the new database.
  1066. */
  1067. static void mysql_change_db_impl(THD *thd,
  1068. LEX_STRING *new_db_name,
  1069. ulong new_db_access,
  1070. CHARSET_INFO *new_db_charset)
  1071. {
  1072. /* 1. Change current database in THD. */
  1073. if (new_db_name == NULL)
  1074. {
  1075. /*
  1076. THD::set_db() does all the job -- it frees previous database name and
  1077. sets the new one.
  1078. */
  1079. thd->set_db(NULL, 0);
  1080. }
  1081. else if (new_db_name == &INFORMATION_SCHEMA_NAME)
  1082. {
  1083. /*
  1084. Here we must use THD::set_db(), because we want to copy
  1085. INFORMATION_SCHEMA_NAME constant.
  1086. */
  1087. thd->set_db(INFORMATION_SCHEMA_NAME.str, INFORMATION_SCHEMA_NAME.length);
  1088. }
  1089. else
  1090. {
  1091. /*
  1092. Here we already have a copy of database name to be used in THD. So,
  1093. we just call THD::reset_db(). Since THD::reset_db() does not releases
  1094. the previous database name, we should do it explicitly.
  1095. */
  1096. my_free(thd->db);
  1097. thd->reset_db(new_db_name->str, new_db_name->length);
  1098. }
  1099. /* 2. Update security context. */
  1100. #ifndef NO_EMBEDDED_ACCESS_CHECKS
  1101. thd->security_ctx->db_access= new_db_access;
  1102. #endif
  1103. /* 3. Update db-charset environment variables. */
  1104. thd->db_charset= new_db_charset;
  1105. thd->variables.collation_database= new_db_charset;
  1106. }
  1107. /**
  1108. Backup the current database name before switch.
  1109. @param[in] thd thread handle
  1110. @param[in, out] saved_db_name IN: "str" points to a buffer where to store
  1111. the old database name, "length" contains the
  1112. buffer size
  1113. OUT: if the current (default) database is
  1114. not NULL, its name is copied to the
  1115. buffer pointed at by "str"
  1116. and "length" is updated accordingly.
  1117. Otherwise "str" is set to NULL and
  1118. "length" is set to 0.
  1119. */
  1120. static void backup_current_db_name(THD *thd,
  1121. LEX_STRING *saved_db_name)
  1122. {
  1123. if (!thd->db)
  1124. {
  1125. /* No current (default) database selected. */
  1126. saved_db_name->str= NULL;
  1127. saved_db_name->length= 0;
  1128. }
  1129. else
  1130. {
  1131. strmake(saved_db_name->str, thd->db, saved_db_name->length - 1);
  1132. saved_db_name->length= thd->db_length;
  1133. }
  1134. }
  1135. /**
  1136. Return TRUE if db1_name is equal to db2_name, FALSE otherwise.
  1137. The function allows to compare database names according to the MySQL
  1138. rules. The database names db1 and db2 are equal if:
  1139. - db1 is NULL and db2 is NULL;
  1140. or
  1141. - db1 is not-NULL, db2 is not-NULL, db1 is equal (ignoring case) to
  1142. db2 in system character set (UTF8).
  1143. */
  1144. static inline bool
  1145. cmp_db_names(const char *db1_name,
  1146. const char *db2_name)
  1147. {
  1148. return
  1149. /* db1 is NULL and db2 is NULL */
  1150. (!db1_name && !db2_name) ||
  1151. /* db1 is not-NULL, db2 is not-NULL, db1 == db2. */
  1152. (db1_name && db2_name &&
  1153. my_strcasecmp(system_charset_info, db1_name, db2_name) == 0);
  1154. }
  1155. /**
  1156. @brief Change the current database and its attributes unconditionally.
  1157. @param thd thread handle
  1158. @param new_db_name database name
  1159. @param force_switch if force_switch is FALSE, then the operation will fail if
  1160. - new_db_name is NULL or empty;
  1161. - OR new database name is invalid
  1162. (check_db_name() failed);
  1163. - OR user has no privilege on the new database;
  1164. - OR new database does not exist;
  1165. if force_switch is TRUE, then
  1166. - if new_db_name is NULL or empty, the current
  1167. database will be NULL, @@collation_database will
  1168. be set to @@collation_server, the operation will
  1169. succeed.
  1170. - if new database name is invalid
  1171. (check_db_name() failed), the current database
  1172. will be NULL, @@collation_database will be set to
  1173. @@collation_server, but the operation will fail;
  1174. - user privileges will not be checked
  1175. (THD::db_access however is updated);
  1176. TODO: is this really the intention?
  1177. (see sp-security.test).
  1178. - if new database does not exist,the current database
  1179. will be NULL, @@collation_database will be set to
  1180. @@collation_server, a warning will be thrown, the
  1181. operation will succeed.
  1182. @details The function checks that the database name corresponds to a
  1183. valid and existent database, checks access rights and changes the current
  1184. database with database attributes (@@collation_database session variable,
  1185. THD::db_access).
  1186. This function is not the only way to switch the database that is
  1187. currently employed. When the replication slave thread switches the
  1188. database before executing a query, it calls thd->set_db directly.
  1189. However, if the query, in turn, uses a stored routine, the stored routine
  1190. will use this function, even if it's run on the slave.
  1191. This function allocates the name of the database on the system heap: this
  1192. is necessary to be able to uniformly change the database from any module
  1193. of the server. Up to 5.0 different modules were using different memory to
  1194. store the name of the database, and this led to memory corruption:
  1195. a stack pointer set by Stored Procedures was used by replication after
  1196. the stack address was long gone.
  1197. @return Operation status
  1198. @retval FALSE Success
  1199. @retval TRUE Error
  1200. */
  1201. bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
  1202. {
  1203. LEX_STRING new_db_file_name;
  1204. Security_context *sctx= thd->security_ctx;
  1205. ulong db_access= sctx->db_access;
  1206. CHARSET_INFO *db_default_cl;
  1207. DBUG_ENTER("mysql_change_db");
  1208. DBUG_PRINT("enter",("name: '%s'", new_db_name->str));
  1209. if (new_db_name == NULL ||
  1210. new_db_name->length == 0)
  1211. {
  1212. if (force_switch)
  1213. {
  1214. /*
  1215. This can happen only if we're switching the current database back
  1216. after loading stored program. The thing is that loading of stored
  1217. program can happen when there is no current database.
  1218. TODO: actually, new_db_name and new_db_name->str seem to be always
  1219. non-NULL. In case of stored program, new_db_name->str == "" and
  1220. new_db_name->length == 0.
  1221. */
  1222. mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
  1223. DBUG_RETURN(FALSE);
  1224. }
  1225. else
  1226. {
  1227. my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
  1228. DBUG_RETURN(TRUE);
  1229. }
  1230. }
  1231. if (is_infoschema_db(new_db_name->str, new_db_name->length))
  1232. {
  1233. /* Switch the current database to INFORMATION_SCHEMA. */
  1234. mysql_change_db_impl(thd, &INFORMATION_SCHEMA_NAME, SELECT_ACL,
  1235. system_charset_info);
  1236. DBUG_RETURN(FALSE);
  1237. }
  1238. /*
  1239. Now we need to make a copy because check_db_name requires a
  1240. non-constant argument. Actually, it takes database file name.
  1241. TODO: fix check_db_name().
  1242. */
  1243. new_db_file_name.str= my_strndup(new_db_name->str, new_db_name->length,
  1244. MYF(MY_WME));
  1245. new_db_file_name.length= new_db_name->length;
  1246. if (new_db_file_name.str == NULL)
  1247. DBUG_RETURN(TRUE); /* the error is set */
  1248. /*
  1249. NOTE: if check_db_name() fails, we should throw an error in any case,
  1250. even if we are called from sp_head::execute().
  1251. It's next to impossible however to get this error when we are called
  1252. from sp_head::execute(). But let's switch the current database to NULL
  1253. in this case to be sure.
  1254. */
  1255. if (check_db_name(&new_db_file_name))
  1256. {
  1257. my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str);
  1258. my_free(new_db_file_name.str);
  1259. if (force_switch)
  1260. mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
  1261. DBUG_RETURN(TRUE);
  1262. }
  1263. DBUG_PRINT("info",("Use database: %s", new_db_file_name.str));
  1264. #ifndef NO_EMBEDDED_ACCESS_CHECKS
  1265. db_access=
  1266. test_all_bits(sctx->master_access, DB_ACLS) ?
  1267. DB_ACLS :
  1268. acl_get(sctx->host,
  1269. sctx->ip,
  1270. sctx->priv_user,
  1271. new_db_file_name.str,
  1272. FALSE) | sctx->master_access;
  1273. if (!force_switch &&
  1274. !(db_access & DB_ACLS) &&
  1275. check_grant_db(thd, new_db_file_name.str))
  1276. {
  1277. my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
  1278. sctx->priv_user,
  1279. sctx->priv_host,
  1280. new_db_file_name.str);
  1281. general_log_print(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR),
  1282. sctx->priv_user, sctx->priv_host, new_db_file_name.str);
  1283. my_free(new_db_file_name.str);
  1284. DBUG_RETURN(TRUE);
  1285. }
  1286. #endif
  1287. DEBUG_SYNC(thd, "before_db_dir_check");
  1288. if (check_db_dir_existence(new_db_file_name.str))
  1289. {
  1290. if (force_switch)
  1291. {
  1292. /* Throw a warning and free new_db_file_name. */
  1293. push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
  1294. ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR),
  1295. new_db_file_name.str);
  1296. my_free(new_db_file_name.str);
  1297. /* Change db to NULL. */
  1298. mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
  1299. /* The operation succeed. */
  1300. DBUG_RETURN(FALSE);
  1301. }
  1302. else
  1303. {
  1304. /* Report an error and free new_db_file_name. */
  1305. my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str);
  1306. my_free(new_db_file_name.str);
  1307. /* The operation failed. */
  1308. DBUG_RETURN(TRUE);
  1309. }
  1310. }
  1311. /*
  1312. NOTE: in mysql_change_db_impl() new_db_file_name is assigned to THD
  1313. attributes and will be freed in THD::~THD().
  1314. */
  1315. db_default_cl= get_default_db_collation(thd, new_db_file_name.str);
  1316. mysql_change_db_impl(thd, &new_db_file_name, db_access, db_default_cl);
  1317. DBUG_RETURN(FALSE);
  1318. }
  1319. /**
  1320. Change the current database and its attributes if needed.
  1321. @param thd thread handle
  1322. @param new_db_name database name
  1323. @param[in, out] saved_db_name IN: "str" points to a buffer where to store
  1324. the old database name, "length" contains the
  1325. buffer size
  1326. OUT: if the current (default) database is
  1327. not NULL, its name is copied to the
  1328. buffer pointed at by "str"
  1329. and "length" is updated accordingly.
  1330. Otherwise "str" is set to NULL and
  1331. "length" is set to 0.
  1332. @param force_switch @see mysql_change_db()
  1333. @param[out] cur_db_changed out-flag to indicate whether the current
  1334. database has been changed (valid only if
  1335. the function suceeded)
  1336. */
  1337. bool mysql_opt_change_db(THD *thd,
  1338. const LEX_STRING *new_db_name,
  1339. LEX_STRING *saved_db_name,
  1340. bool force_switch,
  1341. bool *cur_db_changed)
  1342. {
  1343. *cur_db_changed= !cmp_db_names(thd->db, new_db_name->str);
  1344. if (!*cur_db_changed)
  1345. return FALSE;
  1346. backup_current_db_name(thd, saved_db_name);
  1347. return mysql_change_db(thd, new_db_name, force_switch);
  1348. }
  1349. /**
  1350. Upgrade a 5.0 database.
  1351. This function is invoked whenever an ALTER DATABASE UPGRADE query is executed:
  1352. ALTER DATABASE 'olddb' UPGRADE DATA DIRECTORY NAME.
  1353. If we have managed to rename (move) tables to the new database
  1354. but something failed on a later step, then we store the
  1355. RENAME DATABASE event in the log. mysql_rename_db() is atomic in
  1356. the sense that it will rename all or none of the tables.
  1357. @param thd Current thread
  1358. @param old_db 5.0 database name, in #mysql50#name format
  1359. @return 0 on success, 1 on error
  1360. */
  1361. bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
  1362. {
  1363. int error= 0, change_to_newdb= 0;
  1364. char path[FN_REFLEN+16];
  1365. uint length;
  1366. HA_CREATE_INFO create_info;
  1367. MY_DIR *dirp;
  1368. TABLE_LIST *table_list;
  1369. SELECT_LEX *sl= thd->lex->current_select;
  1370. LEX_STRING new_db;
  1371. DBUG_ENTER("mysql_upgrade_db");
  1372. if ((old_db->length <= MYSQL50_TABLE_NAME_PREFIX_LENGTH) ||
  1373. (strncmp(old_db->str,
  1374. MYSQL50_TABLE_NAME_PREFIX,
  1375. MYSQL50_TABLE_NAME_PREFIX_LENGTH) != 0))
  1376. {
  1377. my_error(ER_WRONG_USAGE, MYF(0),
  1378. "ALTER DATABASE UPGRADE DATA DIRECTORY NAME",
  1379. "name");
  1380. DBUG_RETURN(1);
  1381. }
  1382. /* `#mysql50#<name>` converted to encoded `<name>` */
  1383. new_db.str= old_db->str + MYSQL50_TABLE_NAME_PREFIX_LENGTH;
  1384. new_db.length= old_db->length - MYSQL50_TABLE_NAME_PREFIX_LENGTH;
  1385. /* Lock the old name, the new name will be locked by mysql_create_db().*/
  1386. if (lock_schema_name(thd, old_db->str))
  1387. DBUG_RETURN(-1);
  1388. /*
  1389. Let's remember if we should do "USE newdb" afterwards.
  1390. thd->db will be cleared in mysql_rename_db()
  1391. */
  1392. if (thd->db && !strcmp(thd->db, old_db->str))
  1393. change_to_newdb= 1;
  1394. build_table_filename(path, sizeof(path)-1,
  1395. old_db->str, "", MY_DB_OPT_FILE, 0);
  1396. if ((load_db_opt(thd, path, &create_info)))
  1397. create_info.default_table_charset= thd->variables.collation_server;
  1398. length= build_table_filename(path, sizeof(path)-1, old_db->str, "", "", 0);
  1399. if (length && path[length-1] == FN_LIBCHAR)
  1400. path[length-1]=0; // remove ending '\'
  1401. if ((error= my_access(path,F_OK)))
  1402. {
  1403. my_error(ER_BAD_DB_ERROR, MYF(0), old_db->str);
  1404. goto exit;
  1405. }
  1406. /* Step1: Create the new database */
  1407. if ((error= mysql_create_db(thd, new_db.str, &create_info, 1)))
  1408. goto exit;
  1409. /* Step2: Move tables to the new database */
  1410. if ((dirp = my_dir(path,MYF(MY_DONT_SORT))))
  1411. {
  1412. uint nfiles= (uint) dirp->number_off_files;
  1413. for (uint idx=0 ; idx < nfiles && !thd->killed ; idx++)
  1414. {
  1415. FILEINFO *file= dirp->dir_entry + idx;
  1416. char *extension, tname[FN_REFLEN + 1];
  1417. LEX_STRING table_str;
  1418. DBUG_PRINT("info",("Examining: %s", file->name));
  1419. /* skiping non-FRM files */
  1420. if (my_strcasecmp(files_charset_info,
  1421. (extension= fn_rext(file->name)), reg_ext))
  1422. continue;
  1423. /* A frm file found, add the table info rename list */
  1424. *extension= '\0';
  1425. table_str.length= filename_to_tablename(file->name,
  1426. tname, sizeof(tname)-1);
  1427. table_str.str= (char*) sql_memdup(tname, table_str.length + 1);
  1428. Table_ident *old_ident= new Table_ident(thd, *old_db, table_str, 0);
  1429. Table_ident *new_ident= new Table_ident(thd, new_db, table_str, 0);
  1430. if (!old_ident || !new_ident ||
  1431. !sl->add_table_to_list(thd, old_ident, NULL,
  1432. TL_OPTION_UPDATING, TL_IGNORE,
  1433. MDL_EXCLUSIVE) ||
  1434. !sl->add_table_to_list(thd, new_ident, NULL,
  1435. TL_OPTION_UPDATING, TL_IGNORE,
  1436. MDL_EXCLUSIVE))
  1437. {
  1438. error= 1;
  1439. my_dirend(dirp);
  1440. goto exit;
  1441. }
  1442. }
  1443. my_dirend(dirp);
  1444. }
  1445. if ((table_list= thd->lex->query_tables) &&
  1446. (error= mysql_rename_tables(thd, table_list, 1)))
  1447. {
  1448. /*
  1449. Failed to move all tables from the old database to the new one.
  1450. In the best case mysql_rename_tables() moved all tables back to the old
  1451. database. In the worst case mysql_rename_tables() moved some tables
  1452. to the new database, then failed, then started to move the tables back,
  1453. and then failed again. In this situation we have some tables in the
  1454. old database and some tables in the new database.
  1455. Let's delete the option file, and then the new database directory.
  1456. If some tables were left in the new directory, rmdir() will fail.
  1457. It garantees we never loose any tables.
  1458. */
  1459. build_table_filename(path, sizeof(path)-1,
  1460. new_db.str,"",MY_DB_OPT_FILE, 0);
  1461. mysql_file_delete(key_file_dbopt, path, MYF(MY_WME));
  1462. length= build_table_filename(path, sizeof(path)-1, new_db.str, "", "", 0);
  1463. if (length && path[length-1] == FN_LIBCHAR)
  1464. path[length-1]=0; // remove ending '\'
  1465. rmdir(path);
  1466. goto exit;
  1467. }
  1468. /*
  1469. Step3: move all remaining files to the new db's directory.
  1470. Skip db opt file: it's been created by mysql_create_db() in
  1471. the new directory, and will be dropped by mysql_rm_db() in the old one.
  1472. Trigger TRN and TRG files are be moved as regular files at the moment,
  1473. without any special treatment.
  1474. Triggers without explicit database qualifiers in table names work fine:
  1475. use d1;
  1476. create trigger trg1 before insert on t2 for each row set @a:=1
  1477. rename database d1 to d2;
  1478. TODO: Triggers, having the renamed database explicitely written
  1479. in the table qualifiers.
  1480. 1. when the same database is renamed:
  1481. create trigger d1.trg1 before insert on d1.t1 for each row set @a:=1;
  1482. rename database d1 to d2;
  1483. Problem: After database renaming, the trigger's body
  1484. still points to the old database d1.
  1485. 2. when another database is renamed:
  1486. create trigger d3.trg1 before insert on d3.t1 for each row
  1487. insert into d1.t1 values (...);
  1488. rename database d1 to d2;
  1489. Problem: After renaming d1 to d2, the trigger's body
  1490. in the database d3 still points to database d1.
  1491. */
  1492. if ((dirp = my_dir(path,MYF(MY_DONT_SORT))))
  1493. {
  1494. uint nfiles= (uint) dirp->number_off_files;
  1495. for (uint idx=0 ; idx < nfiles ; idx++)
  1496. {
  1497. FILEINFO *file= dirp->dir_entry + idx;
  1498. char oldname[FN_REFLEN + 1], newname[FN_REFLEN + 1];
  1499. DBUG_PRINT("info",("Examining: %s", file->name));
  1500. /* skiping . and .. and MY_DB_OPT_FILE */
  1501. if ((file->name[0] == '.' &&
  1502. (!file->name[1] || (file->name[1] == '.' && !file->name[2]))) ||
  1503. !my_strcasecmp(files_charset_info, file->name, MY_DB_OPT_FILE))
  1504. continue;
  1505. /* pass empty file name, and file->name as extension to avoid encoding */
  1506. build_table_filename(oldname, sizeof(oldname)-1,
  1507. old_db->str, "", file->name, 0);
  1508. build_table_filename(newname, sizeof(newname)-1,
  1509. new_db.str, "", file->name, 0);
  1510. mysql_file_rename(key_file_misc, oldname, newname, MYF(MY_WME));
  1511. }
  1512. my_dirend(dirp);
  1513. }
  1514. /*
  1515. Step7: drop the old database.
  1516. query_cache_invalidate(olddb) is done inside mysql_rm_db(), no need
  1517. to execute them again.
  1518. mysql_rm_db() also "unuses" if we drop the current database.
  1519. */
  1520. error= mysql_rm_db(thd, old_db->str, 0, 1);
  1521. /* Step8: logging */
  1522. if (mysql_bin_log.is_open())
  1523. {
  1524. int errcode= query_error_code(thd, TRUE);
  1525. Query_log_event qinfo(thd, thd->query(), thd->query_length(),
  1526. FALSE, TRUE, TRUE, errcode);
  1527. thd->clear_error();
  1528. error|= mysql_bin_log.write(&qinfo);
  1529. }
  1530. /* Step9: Let's do "use newdb" if we renamed the current database */
  1531. if (change_to_newdb)
  1532. error|= mysql_change_db(thd, & new_db, FALSE);
  1533. exit:
  1534. DBUG_RETURN(error);
  1535. }
  1536. /*
  1537. Check if there is directory for the database name.
  1538. SYNOPSIS
  1539. check_db_dir_existence()
  1540. db_name database name
  1541. RETURN VALUES
  1542. FALSE There is directory for the specified database name.
  1543. TRUE The directory does not exist.
  1544. */
  1545. bool check_db_dir_existence(const char *db_name)
  1546. {
  1547. char db_dir_path[FN_REFLEN + 1];
  1548. uint db_dir_path_len;
  1549. db_dir_path_len= build_table_filename(db_dir_path, sizeof(db_dir_path) - 1,
  1550. db_name, "", "", 0);
  1551. if (db_dir_path_len && db_dir_path[db_dir_path_len - 1] == FN_LIBCHAR)
  1552. db_dir_path[db_dir_path_len - 1]= 0;
  1553. /* Check access. */
  1554. return my_access(db_dir_path, F_OK);
  1555. }