diff --git a/include/maxscale/protocol/rwbackend.hh b/include/maxscale/protocol/rwbackend.hh index 515f42a54..af610d80c 100644 --- a/include/maxscale/protocol/rwbackend.hh +++ b/include/maxscale/protocol/rwbackend.hh @@ -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 + 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 { diff --git a/server/modules/protocol/MySQL/rwbackend.cc b/server/modules/protocol/MySQL/rwbackend.cc index a4acab2d4..664213119 100644 --- a/server/modules/protocol/MySQL/rwbackend.cc +++ b/server/modules/protocol/MySQL/rwbackend.cc @@ -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)) {