MXS-2512 Store received error during backend processing

If a server returns an error, it will be retained inside RWBackend
so that it later is accessible without having to parse the GWBUF
again.
This commit is contained in:
Johan Wikman 2019-06-06 12:10:01 +03:00
parent b50193a868
commit aa9b6cb8c5
2 changed files with 92 additions and 0 deletions

View File

@ -60,6 +60,71 @@ class RWBackend : public mxs::Backend
RWBackend& operator=(const RWBackend&);
public:
class Error
{
public:
Error() = default;
explicit operator bool() const
{
return m_code != 0;
}
bool is_rollback() const
{
bool rv = false;
if (m_code != 0)
{
mxb_assert(m_sql_state.length() == 5);
// The 'sql_state' of all transaction rollbacks is "40XXX".
if (m_sql_state[0] == '4' && m_sql_state[1] == '0')
{
rv = true;
}
}
return rv;
}
uint32_t code() const
{
return m_code;
}
const std::string& sql_state() const
{
return m_sql_state;
}
const std::string& message() const
{
return m_message;
}
template<class InputIterator>
void set(uint32_t code,
InputIterator sql_state_begin, InputIterator sql_state_end,
InputIterator message_begin, InputIterator message_end)
{
mxb_assert(std::distance(sql_state_begin, sql_state_end) == 5);
m_code = code;
m_sql_state.assign(sql_state_begin, sql_state_end);
m_message.assign(message_begin, message_end);
}
void clear()
{
m_code = 0;
m_sql_state.clear();
m_message.clear();
}
private:
uint16_t m_code { 0 };
std::string m_sql_state;
std::string m_message;
};
static SRWBackends from_servers(SERVER_REF* servers);
@ -132,6 +197,16 @@ public:
void process_reply(GWBUF* buffer);
/**
* Updated during the call to @c process_reply().
*
* @return The current error state.
*/
const Error& error() const
{
return m_error;
}
/**
* Check whether the response from the server is complete
*
@ -168,6 +243,7 @@ private:
uint64_t m_num_coldefs = 0;
bool m_large_query = false;
bool m_skip_next = false;
Error m_error;
inline bool is_opening_cursor() const
{

View File

@ -358,6 +358,19 @@ void RWBackend::process_packets(GWBUF* result)
}
else if (cmd == MYSQL_REPLY_ERR)
{
++it;
uint16_t code = 0;
code |= (*it++);
code |= (*it++) << 8;
++it;
auto sql_state_begin = it;
it.advance(5);
auto sql_state_end = it;
auto message_begin = it;
it.advance(len - (1 + 2 + 1 + 5));
auto message_end = it;
m_error.set(code, sql_state_begin, sql_state_end, message_begin, message_end);
set_reply_state(REPLY_STATE_DONE);
}
break;
@ -376,8 +389,11 @@ void RWBackend::process_packets(GWBUF* result)
*/
void RWBackend::process_reply(GWBUF* buffer)
{
m_error.clear();
if (current_command() == MXS_COM_STMT_FETCH)
{
// TODO: m_error is not updated here.
// If the server responded with an error, n_eof > 0
if (consume_fetched_rows(buffer))
{