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:
unknown 2007-10-30 22:35:14 +03:00
parent 1430f4ded2
commit 8365a74e47
7 changed files with 56 additions and 33 deletions

View File

@ -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;

View File

@ -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 */)
{

View File

@ -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);

View File

@ -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 */)
{

View File

@ -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

View File

@ -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);
/**

View File

@ -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 &&