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:
@ -60,6 +60,71 @@ class RWBackend : public mxs::Backend
|
|||||||
RWBackend& operator=(const RWBackend&);
|
RWBackend& operator=(const RWBackend&);
|
||||||
|
|
||||||
public:
|
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);
|
static SRWBackends from_servers(SERVER_REF* servers);
|
||||||
|
|
||||||
@ -132,6 +197,16 @@ public:
|
|||||||
|
|
||||||
void process_reply(GWBUF* buffer);
|
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
|
* Check whether the response from the server is complete
|
||||||
*
|
*
|
||||||
@ -168,6 +243,7 @@ private:
|
|||||||
uint64_t m_num_coldefs = 0;
|
uint64_t m_num_coldefs = 0;
|
||||||
bool m_large_query = false;
|
bool m_large_query = false;
|
||||||
bool m_skip_next = false;
|
bool m_skip_next = false;
|
||||||
|
Error m_error;
|
||||||
|
|
||||||
inline bool is_opening_cursor() const
|
inline bool is_opening_cursor() const
|
||||||
{
|
{
|
||||||
|
@ -358,6 +358,19 @@ void RWBackend::process_packets(GWBUF* result)
|
|||||||
}
|
}
|
||||||
else if (cmd == MYSQL_REPLY_ERR)
|
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);
|
set_reply_state(REPLY_STATE_DONE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -376,8 +389,11 @@ void RWBackend::process_packets(GWBUF* result)
|
|||||||
*/
|
*/
|
||||||
void RWBackend::process_reply(GWBUF* buffer)
|
void RWBackend::process_reply(GWBUF* buffer)
|
||||||
{
|
{
|
||||||
|
m_error.clear();
|
||||||
|
|
||||||
if (current_command() == MXS_COM_STMT_FETCH)
|
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 the server responded with an error, n_eof > 0
|
||||||
if (consume_fetched_rows(buffer))
|
if (consume_fetched_rows(buffer))
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user