diff --git a/include/maxscale/queryclassifier.hh b/include/maxscale/queryclassifier.hh index df0a4f63b..c07f211b0 100644 --- a/include/maxscale/queryclassifier.hh +++ b/include/maxscale/queryclassifier.hh @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -156,6 +157,23 @@ public: void ps_erase(std::string id); void ps_erase(uint32_t id); + /** + * @brief Get the internal ID for the given binary prepared statement + * + * @param buffer Buffer containing a binary protocol statement other than COM_STMT_PREPARE + * + * @return The internal ID of the prepared statement that the buffer contents refer to + */ + uint32_t ps_id_internal_get(GWBUF* pBuffer); + + /** + * @brief Store a mapping from an external id to the corresponding internal id + * + * @param external_id The external id as seen by the client. + * @param internal_id The corresponding internal id. + */ + void ps_id_internal_put(uint32_t external_id, uint32_t internal_id); + uint32_t get_route_target(uint8_t command, uint32_t qtype); MXS_SESSION* session() const @@ -167,6 +185,8 @@ private: class PSManager; typedef std::shared_ptr SPSManager; + typedef std::tr1::unordered_map HandleMap; + private: MXS_SESSION* m_pSession; mxs_target_t m_use_sql_variables_in; @@ -177,6 +197,7 @@ private: bool m_large_query; /**< Set to true when processing payloads >= 2^24 bytes */ bool m_multi_statements_allowed; /**< Are multi-statements allowed */ SPSManager m_sPs_manager; + HandleMap m_ps_handles; /** External ID to internal ID */ }; } diff --git a/server/core/queryclassifier.cc b/server/core/queryclassifier.cc index 49cbe116d..b62512596 100644 --- a/server/core/queryclassifier.cc +++ b/server/core/queryclassifier.cc @@ -364,5 +364,52 @@ uint32_t QueryClassifier::get_route_target(uint8_t command, uint32_t qtype) return target; } +namespace +{ + +// Copy of mxs_mysql_extract_ps_id() in modules/protocol/MySQL/mysql_common.cc, +// but we do not want to create a dependency from maxscale-common to that. + +uint32_t mysql_extract_ps_id(GWBUF* buffer) +{ + uint32_t rval = 0; + uint8_t id[MYSQL_PS_ID_SIZE]; + + if (gwbuf_copy_data(buffer, MYSQL_PS_ID_OFFSET, sizeof(id), id) == sizeof(id)) + { + rval = gw_mysql_get_byte4(id); + } + + return rval; +} + +} + +uint32_t QueryClassifier::ps_id_internal_get(GWBUF* pBuffer) +{ + uint32_t internal_id = 0; + + // All COM_STMT type statements store the ID in the same place + uint32_t external_id = mysql_extract_ps_id(pBuffer); + auto it = m_ps_handles.find(external_id); + + if (it != m_ps_handles.end()) + { + internal_id = it->second; + } + else + { + MXS_WARNING("Client requests unknown prepared statement ID '%u' that " + "does not map to an internal ID", external_id); + } + + return internal_id; +} + +void QueryClassifier::ps_id_internal_put(uint32_t external_id, uint32_t internal_id) +{ + m_ps_handles[external_id] = internal_id; +} + } diff --git a/server/modules/routing/readwritesplit/routeinfo.cc b/server/modules/routing/readwritesplit/routeinfo.cc index b0c0e5fbf..b9d7181a2 100644 --- a/server/modules/routing/readwritesplit/routeinfo.cc +++ b/server/modules/routing/readwritesplit/routeinfo.cc @@ -613,7 +613,7 @@ route_target_t get_target_type(RWSplitSession *rses, GWBUF *buffer, } else if (mxs_mysql_is_ps_command(*command)) { - *stmt_id = get_internal_ps_id(rses, buffer); + *stmt_id = rses->qc().ps_id_internal_get(buffer); *type = rses->qc().ps_get_type(*stmt_id); } diff --git a/server/modules/routing/readwritesplit/rwsplit_session_cmd.cc b/server/modules/routing/readwritesplit/rwsplit_session_cmd.cc index 9b6b574ed..88531c180 100644 --- a/server/modules/routing/readwritesplit/rwsplit_session_cmd.cc +++ b/server/modules/routing/readwritesplit/rwsplit_session_cmd.cc @@ -111,7 +111,7 @@ void RWSplitSession::process_sescmd_response(SRWBackend& backend, GWBUF** ppPack { /** Map the returned response to the internal ID */ MXS_INFO("PS ID %u maps to internal ID %lu", resp.id, id); - m_ps_handles[resp.id] = id; + m_qc.ps_id_internal_put(resp.id, id); } // Discard any slave connections that did not return the same result diff --git a/server/modules/routing/readwritesplit/rwsplitsession.cc b/server/modules/routing/readwritesplit/rwsplitsession.cc index 1655ceeee..2d15f4a85 100644 --- a/server/modules/routing/readwritesplit/rwsplitsession.cc +++ b/server/modules/routing/readwritesplit/rwsplitsession.cc @@ -737,24 +737,3 @@ void RWSplitSession::handle_error_reply_client(DCB *backend_dcb, GWBUF *errmsg) m_client->func.write(m_client, gwbuf_clone(errmsg)); } } - -uint32_t get_internal_ps_id(RWSplitSession* rses, GWBUF* buffer) -{ - uint32_t rval = 0; - - // All COM_STMT type statements store the ID in the same place - uint32_t id = mxs_mysql_extract_ps_id(buffer); - ClientHandleMap::iterator it = rses->m_ps_handles.find(id); - - if (it != rses->m_ps_handles.end()) - { - rval = it->second; - } - else - { - MXS_WARNING("Client requests unknown prepared statement ID '%u' that " - "does not map to an internal ID", id); - } - - return rval; -}