diff --git a/sql/handler.cc b/sql/handler.cc index 3ba52ca1c71..22374d57e99 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1414,6 +1414,36 @@ static const char *check_lowercase_names(handler *file, const char *path, } +/** + An interceptor to hijack the text of the error message without + setting an error in the thread. We need the text to present it + in the form of a warning to the user. +*/ + +struct Ha_delete_table_error_handler: public Internal_error_handler +{ +public: + virtual bool handle_error(uint sql_errno, + const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd); + char buff[MYSQL_ERRMSG_SIZE]; +}; + + +bool +Ha_delete_table_error_handler:: +handle_error(uint sql_errno, + const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd) +{ + /* Grab the error message */ + strmake(buff, message, sizeof(buff)-1); + return TRUE; +} + + /** @brief This should return ENOENT if the file doesn't exists. The .frm file will be deleted only if we return 0 or ENOENT @@ -1442,23 +1472,11 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, { /* Because file->print_error() use my_error() to generate the error message - we must store the error state in thd, reset it and restore it to - be able to get hold of the error message. - (We should in the future either rewrite handler::print_error() or make - a nice method of this. + we use an internal error handler to intercept it and store the text + in a temporary buffer. Later the message will be presented to user + as a warning. */ - bool is_slave_error= thd->is_slave_error; - sp_rcontext *spcont= thd->spcont; - SELECT_LEX *current_select= thd->lex->current_select; - char buff[sizeof(thd->net.last_error)]; - char new_error[sizeof(thd->net.last_error)]; - int last_errno= thd->net.last_errno; - - strmake(buff, thd->net.last_error, sizeof(buff)-1); - thd->is_slave_error= 0; - thd->spcont= NULL; - thd->lex->current_select= 0; - thd->net.last_error[0]= 0; + Ha_delete_table_error_handler ha_delete_table_error_handler; /* Fill up strucutures that print_error may need */ dummy_share.path.str= (char*) path; @@ -1471,16 +1489,18 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, file->table_share= &dummy_share; file->table= &dummy_table; - file->print_error(error, 0); - strmake(new_error, thd->net.last_error, sizeof(buff)-1); - /* restore thd */ - thd->is_slave_error= is_slave_error; - thd->spcont= spcont; - thd->lex->current_select= current_select; - thd->net.last_errno= last_errno; - strmake(thd->net.last_error, buff, sizeof(buff)-1); - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, new_error); + thd->push_internal_handler(&ha_delete_table_error_handler); + file->print_error(error, 0); + + thd->pop_internal_handler(); + + /* + XXX: should we convert *all* errors to warnings here? + What if the error is fatal? + */ + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, + ha_delete_table_error_handler.buff); } delete file; DBUG_RETURN(error); @@ -2203,7 +2223,7 @@ void handler::print_error(int error, myf errflag) case HA_ERR_NO_SUCH_TABLE: my_error(ER_NO_SUCH_TABLE, MYF(0), table_share->db.str, table_share->table_name.str); - break; + DBUG_VOID_RETURN; case HA_ERR_RBR_LOGGING_FAILED: textno= ER_BINLOG_ROW_LOGGING_FAILED; break; diff --git a/sql/log.cc b/sql/log.cc index 02986bef493..688ed03d5d1 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -72,13 +72,14 @@ public: virtual ~Silence_log_table_errors() {} - virtual bool handle_error(uint sql_errno, + virtual bool handle_error(uint sql_errno, const char *message, MYSQL_ERROR::enum_warning_level level, THD *thd); }; bool Silence_log_table_errors::handle_error(uint /* sql_errno */, + const char * /* message */, MYSQL_ERROR::enum_warning_level /* level */, THD * /* thd */) { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index cc964e417bf..c76bd8bd712 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2583,7 +2583,7 @@ int my_message_sql(uint error, const char *str, myf MyFlags) TODO: There are two exceptions mechanism (THD and sp_rcontext), this could be improved by having a common stack of handlers. */ - if (thd->handle_error(error, + if (thd->handle_error(error, str, MYSQL_ERROR::WARN_LEVEL_ERROR)) DBUG_RETURN(0); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 223485f1e42..2584390d756 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -44,7 +44,7 @@ public: virtual ~Prelock_error_handler() {} - virtual bool handle_error(uint sql_errno, + virtual bool handle_error(uint sql_errno, const char *message, MYSQL_ERROR::enum_warning_level level, THD *thd); @@ -58,6 +58,7 @@ private: bool Prelock_error_handler::handle_error(uint sql_errno, + const char * /* message */, MYSQL_ERROR::enum_warning_level /* level */, THD * /* thd */) { diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 707c8e83007..b5a29783044 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -498,12 +498,12 @@ void THD::push_internal_handler(Internal_error_handler *handler) } -bool THD::handle_error(uint sql_errno, +bool THD::handle_error(uint sql_errno, const char *message, MYSQL_ERROR::enum_warning_level level) { if (m_internal_handler) { - return m_internal_handler->handle_error(sql_errno, level, this); + return m_internal_handler->handle_error(sql_errno, message, level, this); } return FALSE; // 'FALSE', as per coding style diff --git a/sql/sql_class.h b/sql/sql_class.h index a3e71e183f3..db847c814a0 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -969,6 +969,7 @@ public: @return true if the error is handled */ virtual bool handle_error(uint sql_errno, + const char *message, MYSQL_ERROR::enum_warning_level level, THD *thd) = 0; }; @@ -1923,7 +1924,7 @@ public: @param level the error level @return true if the error is handled */ - virtual bool handle_error(uint sql_errno, + virtual bool handle_error(uint sql_errno, const char *message, MYSQL_ERROR::enum_warning_level level); /** diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 8bdb2e59ed5..89cff73d153 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -137,7 +137,7 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, level= MYSQL_ERROR::WARN_LEVEL_ERROR; } - if (thd->handle_error(code, level)) + if (thd->handle_error(code, msg, level)) DBUG_RETURN(NULL); if (thd->spcont &&