diff --git a/server/modules/routing/readwritesplit/readwritesplit.hh b/server/modules/routing/readwritesplit/readwritesplit.hh index b2941da65..637a471ca 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.hh +++ b/server/modules/routing/readwritesplit/readwritesplit.hh @@ -423,6 +423,44 @@ std::pair get_slave_counts(mxs::PRWBackends& backends, mxs::RWBackend* */ void close_all_connections(mxs::PRWBackends& backends); +/** + * Extract the SQL state from an error packet. + * + * @param pBuffer Pointer to an error packet. + * @param ppState On return will point to the state in @c pBuffer. + * @param pnState On return the pointed to value will be 6. + */ +inline void extract_error_state(uint8_t* pBuffer, uint8_t** ppState, uint16_t* pnState) +{ + mxb_assert(MYSQL_IS_ERROR_PACKET(pBuffer)); + + // The payload starts with a one byte command followed by a two byte error code, + // followed by a 1 byte sql state marker and 5 bytes of sql state. In this context + // the marker and the state itself are combined. + *ppState = pBuffer + MYSQL_HEADER_LEN + 1 + 2; + *pnState = 6; +} + +/** + * Extract the message from an error packet. + * + * @param pBuffer Pointer to an error packet. + * @param ppMessage On return will point to the start of the message in @c pBuffer. + * @param pnMessage On return the pointed to value will be the length of the message. + */ +inline void extract_error_message(uint8_t* pBuffer, uint8_t** ppMessage, uint16_t* pnMessage) +{ + mxb_assert(MYSQL_IS_ERROR_PACKET(pBuffer)); + + int packet_len = MYSQL_HEADER_LEN + MYSQL_GET_PAYLOAD_LEN(pBuffer); + + // The payload starts with a one byte command followed by a two byte error code, + // followed by a 1 byte sql state marker and 5 bytes of sql state, followed by + // a message until the end of the packet. + *ppMessage = pBuffer + MYSQL_HEADER_LEN + 1 + 2 + 1 + 5; + *pnMessage = packet_len - MYSQL_HEADER_LEN - 1 - 2 - 1 - 5; +} + /** * Utility function for extracting error messages from buffers * diff --git a/server/modules/routing/readwritesplit/rwsplit_session_cmd.cc b/server/modules/routing/readwritesplit/rwsplit_session_cmd.cc index 35d9deda0..f959530fe 100644 --- a/server/modules/routing/readwritesplit/rwsplit_session_cmd.cc +++ b/server/modules/routing/readwritesplit/rwsplit_session_cmd.cc @@ -28,7 +28,6 @@ using namespace maxscale; * Functions for session command handling */ - std::string extract_error(GWBUF* buffer) { std::string rval; @@ -36,17 +35,20 @@ std::string extract_error(GWBUF* buffer) if (MYSQL_IS_ERROR_PACKET(((uint8_t*)GWBUF_DATA(buffer)))) { size_t replylen = MYSQL_GET_PAYLOAD_LEN(GWBUF_DATA(buffer)) + MYSQL_HEADER_LEN; - char replybuf[replylen]; - gwbuf_copy_data(buffer, 0, sizeof(replybuf), (uint8_t*)replybuf); - std::string err; - std::string msg; + uint8_t replybuf[replylen]; + gwbuf_copy_data(buffer, 0, sizeof(replybuf), replybuf); + + uint8_t* pState; + uint16_t nState; + extract_error_state(replybuf, &pState, &nState); + + uint8_t* pMessage; + uint16_t nMessage; + extract_error_message(replybuf, &pMessage, &nMessage); + + std::string err(reinterpret_cast(pState), nState); + std::string msg(reinterpret_cast(pMessage), nMessage); - /** - * The payload starts with a one byte command followed by a two byte error code, a six byte state and - * a human-readable string that spans the rest of the packet. - */ - err.append(replybuf + MYSQL_HEADER_LEN + 3, 6); - msg.append(replybuf + MYSQL_HEADER_LEN + 3 + 6, replylen - MYSQL_HEADER_LEN - 3 - 6); rval = err + ": " + msg; }