diff options
author | Dmitry Shulga <Dmitry.Shulga@oracle.com> | 2011-06-23 20:41:04 +0700 |
---|---|---|
committer | Dmitry Shulga <Dmitry.Shulga@oracle.com> | 2011-06-23 20:41:04 +0700 |
commit | bc7af1757939f1ec3c389da73176c7c68a8bafd5 (patch) | |
tree | ade6ce3b5681ea2fa357915b4210ff12d7af9d9c /sql/sp.cc | |
parent | e60e65052f4a1310a2a725652c195ef74dee046e (diff) | |
download | mariadb-git-bc7af1757939f1ec3c389da73176c7c68a8bafd5.tar.gz |
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.
sql/sql_db.cc:
Added synchronization point "before_db_dir_check" to emulate a race condition during
processing of CALL/DROP SCHEMA.
Diffstat (limited to 'sql/sp.cc')
-rw-r--r-- | sql/sp.cc | 42 |
1 files changed, 41 insertions, 1 deletions
diff --git a/sql/sp.cc b/sql/sp.cc index ddddaee2e10..78d1dc7e22c 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -708,6 +708,37 @@ Silence_deprecated_warning::handle_error(uint sql_errno, const char *message, } +class Bad_db_error_handler : public Internal_error_handler +{ +public: + Bad_db_error_handler() + :m_error_caught(false) + {} + + virtual bool handle_error(uint sql_errno, const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd); + + bool error_caught() const { return m_error_caught; } + +private: + bool m_error_caught; +}; + +bool +Bad_db_error_handler::handle_error(uint sql_errno, const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd) +{ + if (sql_errno == ER_BAD_DB_ERROR) + { + m_error_caught= true; + return true; + } + return false; +} + + static int db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, ulong sql_mode, const char *params, const char *returns, @@ -725,7 +756,7 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, ha_rows old_select_limit= thd->variables.select_limit; sp_rcontext *old_spcont= thd->spcont; Silence_deprecated_warning warning_handler; - + Bad_db_error_handler db_not_exists_handler; char definer_user_name_holder[USERNAME_LENGTH + 1]; LEX_STRING definer_user_name= { definer_user_name_holder, USERNAME_LENGTH }; @@ -766,6 +797,7 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, goto end; } + thd->push_internal_handler(&db_not_exists_handler); /* Change the current database (if needed). @@ -776,9 +808,17 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, &cur_db_changed)) { ret= SP_INTERNAL_ERROR; + thd->pop_internal_handler(); goto end; } + thd->pop_internal_handler(); + if (db_not_exists_handler.error_caught()) + { + ret= SP_INTERNAL_ERROR; + my_error(ER_BAD_DB_ERROR, MYF(0), name->m_db.str); + goto end; + } thd->spcont= NULL; { |