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
|
/** @brief
|
||||||
This should return ENOENT if the file doesn't exists.
|
This should return ENOENT if the file doesn't exists.
|
||||||
The .frm file will be deleted only if we return 0 or ENOENT
|
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
|
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
|
we use an internal error handler to intercept it and store the text
|
||||||
be able to get hold of the error message.
|
in a temporary buffer. Later the message will be presented to user
|
||||||
(We should in the future either rewrite handler::print_error() or make
|
as a warning.
|
||||||
a nice method of this.
|
|
||||||
*/
|
*/
|
||||||
bool is_slave_error= thd->is_slave_error;
|
Ha_delete_table_error_handler ha_delete_table_error_handler;
|
||||||
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;
|
|
||||||
|
|
||||||
/* Fill up strucutures that print_error may need */
|
/* Fill up strucutures that print_error may need */
|
||||||
dummy_share.path.str= (char*) path;
|
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_share= &dummy_share;
|
||||||
file->table= &dummy_table;
|
file->table= &dummy_table;
|
||||||
file->print_error(error, 0);
|
|
||||||
strmake(new_error, thd->net.last_error, sizeof(buff)-1);
|
|
||||||
|
|
||||||
/* restore thd */
|
thd->push_internal_handler(&ha_delete_table_error_handler);
|
||||||
thd->is_slave_error= is_slave_error;
|
file->print_error(error, 0);
|
||||||
thd->spcont= spcont;
|
|
||||||
thd->lex->current_select= current_select;
|
thd->pop_internal_handler();
|
||||||
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);
|
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;
|
delete file;
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
@ -2203,7 +2223,7 @@ void handler::print_error(int error, myf errflag)
|
|||||||
case HA_ERR_NO_SUCH_TABLE:
|
case HA_ERR_NO_SUCH_TABLE:
|
||||||
my_error(ER_NO_SUCH_TABLE, MYF(0), table_share->db.str,
|
my_error(ER_NO_SUCH_TABLE, MYF(0), table_share->db.str,
|
||||||
table_share->table_name.str);
|
table_share->table_name.str);
|
||||||
break;
|
DBUG_VOID_RETURN;
|
||||||
case HA_ERR_RBR_LOGGING_FAILED:
|
case HA_ERR_RBR_LOGGING_FAILED:
|
||||||
textno= ER_BINLOG_ROW_LOGGING_FAILED;
|
textno= ER_BINLOG_ROW_LOGGING_FAILED;
|
||||||
break;
|
break;
|
||||||
|
@ -72,13 +72,14 @@ public:
|
|||||||
|
|
||||||
virtual ~Silence_log_table_errors() {}
|
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,
|
MYSQL_ERROR::enum_warning_level level,
|
||||||
THD *thd);
|
THD *thd);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Silence_log_table_errors::handle_error(uint /* sql_errno */,
|
Silence_log_table_errors::handle_error(uint /* sql_errno */,
|
||||||
|
const char * /* message */,
|
||||||
MYSQL_ERROR::enum_warning_level /* level */,
|
MYSQL_ERROR::enum_warning_level /* level */,
|
||||||
THD * /* thd */)
|
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),
|
TODO: There are two exceptions mechanism (THD and sp_rcontext),
|
||||||
this could be improved by having a common stack of handlers.
|
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))
|
MYSQL_ERROR::WARN_LEVEL_ERROR))
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ public:
|
|||||||
|
|
||||||
virtual ~Prelock_error_handler() {}
|
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,
|
MYSQL_ERROR::enum_warning_level level,
|
||||||
THD *thd);
|
THD *thd);
|
||||||
|
|
||||||
@ -58,6 +58,7 @@ private:
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
Prelock_error_handler::handle_error(uint sql_errno,
|
Prelock_error_handler::handle_error(uint sql_errno,
|
||||||
|
const char * /* message */,
|
||||||
MYSQL_ERROR::enum_warning_level /* level */,
|
MYSQL_ERROR::enum_warning_level /* level */,
|
||||||
THD * /* thd */)
|
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)
|
MYSQL_ERROR::enum_warning_level level)
|
||||||
{
|
{
|
||||||
if (m_internal_handler)
|
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
|
return FALSE; // 'FALSE', as per coding style
|
||||||
|
@ -969,6 +969,7 @@ public:
|
|||||||
@return true if the error is handled
|
@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,
|
MYSQL_ERROR::enum_warning_level level,
|
||||||
THD *thd) = 0;
|
THD *thd) = 0;
|
||||||
};
|
};
|
||||||
@ -1923,7 +1924,7 @@ public:
|
|||||||
@param level the error level
|
@param level the error level
|
||||||
@return true if the error is handled
|
@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);
|
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;
|
level= MYSQL_ERROR::WARN_LEVEL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thd->handle_error(code, level))
|
if (thd->handle_error(code, msg, level))
|
||||||
DBUG_RETURN(NULL);
|
DBUG_RETURN(NULL);
|
||||||
|
|
||||||
if (thd->spcont &&
|
if (thd->spcont &&
|
||||||
|
Loading…
x
Reference in New Issue
Block a user