In ha_delete_table, use a standard mechanism to intercept the error message
and convert it to a warning instead of direct manipulation with the thread error stack. Fix a bug in handler::print_erorr when a garbled message was printed for HA_ERR_NO_SUCH_TABLE. This is a pre-requisite patch for the fix for Bug#12713 Error in a stored function called from a SELECT doesn't cause ROLLBACK of statem sql/handler.cc: Use a standard mechanism to intercept the error message, instead of direct manipulation with thread error stack. Fix a bug when for HA_ERR_NO_SUCH_TABLE handler::print_error() would print a garbled message. sql/log.cc: Extend internal error handler interface to carry the message text. sql/mysqld.cc: Extend internal error handler interface to carry the message text. sql/sql_base.cc: Extend internal error handler interface to carry the message text. sql/sql_class.cc: Extend internal error handler interface to carry the message text. sql/sql_class.h: Extend internal error handler interface to carry the message text. sql/sql_error.cc: Extend internal error handler interface to carry the message text.
This commit is contained in:
parent
1430f4ded2
commit
8365a74e47
@ -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;
|
||||
|
@ -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 */)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 */)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
|
@ -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 &&
|
||||
|
Loading…
x
Reference in New Issue
Block a user