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:
parent
b50193a868
commit
aa9b6cb8c5
@ -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
|
||||
{
|
||||
|
@ -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))
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user