1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-31 22:22:30 +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

@@ -913,7 +913,6 @@ public:
uint in_sub_stmt;
bool enable_slow_log;
bool last_insert_id_used;
my_bool no_send_ok;
SAVEPOINT *savepoints;
};
@@ -975,6 +974,123 @@ public:
};
/**
Stores status of the currently executed statement.
Cleared at the beginning of the statement, and then
can hold either OK, ERROR, or EOF status.
Can not be assigned twice per statement.
*/
class Diagnostics_area
{
public:
enum enum_diagnostics_status
{
/** The area is cleared at start of a statement. */
DA_EMPTY= 0,
/** Set whenever one calls send_ok(). */
DA_OK,
/** Set whenever one calls send_eof(). */
DA_EOF,
/** Set whenever one calls my_error() or my_message(). */
DA_ERROR,
/** Set in case of a custom response, such as one from COM_STMT_PREPARE. */
DA_DISABLED
};
/** True if status information is sent to the client. */
bool is_sent;
/** Set to make set_error_status after set_{ok,eof}_status possible. */
bool can_overwrite_status;
void set_ok_status(THD *thd, ha_rows affected_rows_arg,
ulong last_insert_id_arg,
const char *message);
void set_eof_status(THD *thd);
void set_error_status(THD *thd, uint sql_errno_arg, const char *message_arg);
void disable_status();
void reset_diagnostics_area();
bool is_set() const { return m_status != DA_EMPTY; }
bool is_error() const { return m_status == DA_ERROR; }
bool is_eof() const { return m_status == DA_EOF; }
bool is_ok() const { return m_status == DA_OK; }
bool is_disabled() const { return m_status == DA_DISABLED; }
enum_diagnostics_status status() const { return m_status; }
const char *message() const
{ DBUG_ASSERT(m_status == DA_ERROR || m_status == DA_OK); return m_message; }
uint sql_errno() const
{ DBUG_ASSERT(m_status == DA_ERROR); return m_sql_errno; }
uint server_status() const
{
DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF);
return m_server_status;
}
ha_rows affected_rows() const
{ DBUG_ASSERT(m_status == DA_OK); return m_affected_rows; }
ulong last_insert_id() const
{ DBUG_ASSERT(m_status == DA_OK); return m_last_insert_id; }
uint total_warn_count() const
{
DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF);
return m_total_warn_count;
}
Diagnostics_area() { reset_diagnostics_area(); }
private:
/** Message buffer. Can be used by OK or ERROR status. */
char m_message[MYSQL_ERRMSG_SIZE];
/**
SQL error number. One of ER_ codes from share/errmsg.txt.
Set by set_error_status.
*/
uint m_sql_errno;
/**
Copied from thd->server_status when the diagnostics area is assigned.
We need this member as some places in the code use the following pattern:
thd->server_status|= ...
send_eof(thd);
thd->server_status&= ~...
Assigned by OK, EOF or ERROR.
*/
uint m_server_status;
/**
The number of rows affected by the last statement. This is
semantically close to thd->row_count_func, but has a different
life cycle. thd->row_count_func stores the value returned by
function ROW_COUNT() and is cleared only by statements that
update its value, such as INSERT, UPDATE, DELETE and few others.
This member is cleared at the beginning of the next statement.
We could possibly merge the two, but life cycle of thd->row_count_func
can not be changed.
*/
ha_rows m_affected_rows;
/**
Similarly to the previous member, this is a replacement of
thd->first_successful_insert_id_in_prev_stmt, which is used
to implement LAST_INSERT_ID().
*/
ulong m_last_insert_id;
/** The total number of warnings. */
uint m_total_warn_count;
enum_diagnostics_status m_status;
/**
@todo: the following THD members belong here:
- warn_list, warn_count,
*/
};
/**
@class THD
For each client connection we create a separate thread with THD serving as
@@ -1400,6 +1516,7 @@ public:
List <MYSQL_ERROR> warn_list;
uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
uint total_warn_count;
Diagnostics_area main_da;
/*
Id of current query. Statement can be reused to execute several queries
query_id is global in context of the whole MySQL server.
@@ -1714,12 +1831,18 @@ public:
CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length);
int send_explain_fields(select_result *result);
#ifndef EMBEDDED_LIBRARY
/**
Clear the current error, if any.
We do not clear is_fatal_error or is_fatal_sub_stmt_error since we
assume this is never called if the fatal error is set.
@todo: To silence an error, one should use Internal_error_handler
mechanism. In future this function will be removed.
*/
inline void clear_error()
{
DBUG_ENTER("clear_error");
net.last_error[0]= 0;
net.last_errno= 0;
net.report_error= 0;
if (main_da.is_error())
main_da.reset_diagnostics_area();
is_slave_error= 0;
DBUG_VOID_RETURN;
}
@@ -1728,10 +1851,14 @@ public:
void clear_error();
inline bool vio_ok() const { return true; }
#endif
/**
Mark the current error as fatal. Warning: this does not
set any error, it sets a property of the error, so must be
followed or prefixed with my_error().
*/
inline void fatal_error()
{
is_fatal_error= 1;
net.report_error= 1;
DBUG_PRINT("error",("Fatal error set"));
}
/**
@@ -1747,7 +1874,7 @@ public:
To raise this flag, use my_error().
*/
inline bool is_error() const { return net.report_error; }
inline bool is_error() const { return main_da.is_error(); }
inline CHARSET_INFO *charset() { return variables.character_set_client; }
void update_charset();
@@ -1971,6 +2098,24 @@ private:
};
/** A short cut for thd->main_da.set_ok_status(). */
inline void
send_ok(THD *thd, ha_rows affected_rows= 0, ulonglong id= 0,
const char *message= NULL)
{
thd->main_da.set_ok_status(thd, affected_rows, id, message);
}
/** A short cut for thd->main_da.set_eof_status(). */
inline void
send_eof(THD *thd)
{
thd->main_da.set_eof_status(thd);
}
#define tmp_disable_binlog(A) \
{ulonglong tmp_disable_binlog__save_options= (A)->options; \
(A)->options&= ~OPTION_BIN_LOG
@@ -2508,6 +2653,7 @@ public:
void send_error(uint errcode,const char *err);
int do_deletes();
bool send_eof();
virtual void abort();
};
@@ -2550,6 +2696,7 @@ public:
void send_error(uint errcode,const char *err);
int do_updates (bool from_send_error);
bool send_eof();
virtual void abort();
};
class my_var : public Sql_alloc {