Commit 230604f3 authored by kostja@bodhi.(none)'s avatar kostja@bodhi.(none)

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
parent cd72fffa
......@@ -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;
thd->push_internal_handler(&ha_delete_table_error_handler);
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->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 &&
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment