1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

Bug#12713 "Error in a stored function called from a SELECT doesn't

cause ROLLBACK of statement", part 1. Review fixes.

Do not send OK/EOF packets to the client until we reached the end of 
the current statement.
This is a consolidation, to keep the functionality that is shared by all 
SQL statements in one place in the server.
Currently this functionality includes:
- close_thread_tables()
- log_slow_statement().

After this patch and the subsequent patch for Bug#12713, it shall also include:
- ha_autocommit_or_rollback()
- net_end_statement()
- query_cache_end_of_result().

In future it may also include:
- mysql_reset_thd_for_next_command().
This commit is contained in:
kostja@bodhi.(none)
2007-12-12 18:21:01 +03:00
parent aa5786eb0f
commit ebb9c5d983
51 changed files with 983 additions and 540 deletions

View File

@ -351,6 +351,124 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length,
return thd->strmake(str.ptr(), str.length());
}
/**
Clear this diagnostics area.
Normally called at the end of a statement.
*/
void
Diagnostics_area::reset_diagnostics_area()
{
#ifdef DBUG_OFF
can_overwrite_status= FALSE;
/** Don't take chances in production */
m_message[0]= '\0';
m_sql_errno= 0;
m_server_status= 0;
m_affected_rows= 0;
m_last_insert_id= 0;
m_total_warn_count= 0;
#endif
is_sent= FALSE;
/** Tiny reset in debug mode to see garbage right away */
m_status= DA_EMPTY;
}
/**
Set OK status -- ends commands that do not return a
result set, e.g. INSERT/UPDATE/DELETE.
*/
void
Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg,
ulong last_insert_id_arg,
const char *message_arg)
{
DBUG_ASSERT(! is_set());
#ifdef DBUG_OFF
/* In production, refuse to overwrite an error with an OK packet. */
if (is_error())
return;
#endif
/** Only allowed to report success if has not yet reported an error */
m_server_status= thd->server_status;
m_total_warn_count= thd->total_warn_count;
m_affected_rows= affected_rows_arg;
m_last_insert_id= last_insert_id_arg;
if (message_arg)
strmake(m_message, message_arg, sizeof(m_message));
else
m_message[0]= '\0';
m_status= DA_OK;
}
/**
Set EOF status.
*/
void
Diagnostics_area::set_eof_status(THD *thd)
{
/** Only allowed to report eof if has not yet reported an error */
DBUG_ASSERT(! is_set());
#ifdef DBUG_OFF
/* In production, refuse to overwrite an error with an EOF packet. */
if (is_error())
return;
#endif
m_server_status= thd->server_status;
/*
If inside a stored procedure, do not return the total
number of warnings, since they are not available to the client
anyway.
*/
m_total_warn_count= thd->spcont ? 0 : thd->total_warn_count;
m_status= DA_EOF;
}
/**
Set ERROR status.
*/
void
Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg,
const char *message_arg)
{
/*
Only allowed to report error if has not yet reported a success
The only exception is when we flush the message to the client,
an error can happen during the flush.
*/
DBUG_ASSERT(! is_set() || can_overwrite_status);
m_sql_errno= sql_errno_arg;
strmake(m_message, message_arg, sizeof(m_message));
m_status= DA_ERROR;
}
/**
Mark the diagnostics area as 'DISABLED'.
This is used in rare cases when the COM_ command at hand sends a response
in a custom format. One example is the query cache, another is
COM_STMT_PREPARE.
*/
void
Diagnostics_area::disable_status()
{
DBUG_ASSERT(! is_set());
m_status= DA_DISABLED;
}
THD::THD()
@ -431,7 +549,6 @@ THD::THD()
net.vio=0;
#endif
client_capabilities= 0; // minimalistic client
net.last_error[0]=0; // If error on boot
#ifdef HAVE_QUERY_CACHE
query_cache_init_query(&net); // If error on boot
#endif
@ -1324,12 +1441,12 @@ void select_send::abort()
{
DBUG_ENTER("select_send::abort");
if (is_result_set_started && thd->spcont &&
thd->spcont->find_handler(thd, thd->net.last_errno,
thd->spcont->find_handler(thd, thd->main_da.sql_errno(),
MYSQL_ERROR::WARN_LEVEL_ERROR))
{
/*
We're executing a stored procedure, have an open result
set, an SQL exception conditiona and a handler for it.
set, an SQL exception condition and a handler for it.
In this situation we must abort the current statement,
silence the error and start executing the continue/exit
handler.
@ -1337,9 +1454,7 @@ void select_send::abort()
otherwise the client will hang due to the violation of the
client/server protocol.
*/
thd->net.report_error= 0;
send_eof();
thd->net.report_error= 1; // Abort SP
thd->protocol->end_partial_result_set(thd);
}
DBUG_VOID_RETURN;
}
@ -1391,12 +1506,14 @@ bool select_send::send_data(List<Item> &items)
}
}
thd->sent_row_count++;
if (!thd->vio_ok())
DBUG_RETURN(0);
if (! thd->is_error())
if (thd->is_error())
{
protocol->remove_last_row();
DBUG_RETURN(1);
}
if (thd->vio_ok())
DBUG_RETURN(protocol->write());
protocol->remove_last_row();
DBUG_RETURN(1);
DBUG_RETURN(0);
}
bool select_send::send_eof()
@ -1414,14 +1531,9 @@ bool select_send::send_eof()
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
if (! thd->is_error())
{
::send_eof(thd);
is_result_set_started= 0;
return 0;
}
else
return 1;
::send_eof(thd);
is_result_set_started= 0;
return FALSE;
}
@ -2701,7 +2813,6 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup,
{
backup->options= options;
backup->in_sub_stmt= in_sub_stmt;
backup->no_send_ok= net.no_send_ok;
backup->enable_slow_log= enable_slow_log;
backup->limit_found_rows= limit_found_rows;
backup->examined_row_count= examined_row_count;
@ -2732,9 +2843,6 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup,
cuted_fields= 0;
transaction.savepoints= 0;
first_successful_insert_id_in_cur_stmt= 0;
/* Surpress OK packets in case if we will execute statements */
net.no_send_ok= TRUE;
}
@ -2757,7 +2865,6 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup)
transaction.savepoints= backup->savepoints;
options= backup->options;
in_sub_stmt= backup->in_sub_stmt;
net.no_send_ok= backup->no_send_ok;
enable_slow_log= backup->enable_slow_log;
first_successful_insert_id_in_prev_stmt=
backup->first_successful_insert_id_in_prev_stmt;