diff --git a/include/maxscale/protocol/mysql.h b/include/maxscale/protocol/mysql.h index 64df4b912..7b1ca1e73 100644 --- a/include/maxscale/protocol/mysql.h +++ b/include/maxscale/protocol/mysql.h @@ -536,4 +536,13 @@ uint8_t mxs_mysql_get_command(GWBUF* buffer); */ bool mxs_mysql_extract_ps_response(GWBUF* buffer, MXS_PS_RESPONSE* out); +/** + * @brief Extract the ID of a COM_STMT_EXECUTE + * + * @param buffer Buffer containing a COM_STMT_EXECUTE packet + * + * @return The ID of the prepared statement being executed or 0 on failure + */ +uint32_t mxs_mysql_extract_execute(GWBUF* buffer); + MXS_END_DECLS diff --git a/server/modules/protocol/MySQL/mysql_common.c b/server/modules/protocol/MySQL/mysql_common.c index bd3758599..e39e1f948 100644 --- a/server/modules/protocol/MySQL/mysql_common.c +++ b/server/modules/protocol/MySQL/mysql_common.c @@ -1636,3 +1636,16 @@ bool mxs_mysql_extract_ps_response(GWBUF* buffer, MXS_PS_RESPONSE* out) return rval; } + +uint32_t mxs_mysql_extract_execute(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; +} diff --git a/server/modules/routing/readwritesplit/readwritesplit.hh b/server/modules/routing/readwritesplit/readwritesplit.hh index 1cfe551f4..5dea83441 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.hh +++ b/server/modules/routing/readwritesplit/readwritesplit.hh @@ -154,7 +154,8 @@ struct rwsplit_config_t * been idle for too long */ }; -typedef std::map HandleMap; +typedef std::map BackendHandleMap; +typedef std::map ClientHandleMap; class RWBackend: public mxs::Backend { @@ -213,8 +214,8 @@ public: } private: - reply_state_t m_reply_state; - HandleMap m_ps_handles; + reply_state_t m_reply_state; + BackendHandleMap m_ps_handles; /**< Internal ID to backend PS handle mapping */ }; /** Prepared statement ID to type maps for text protocols */ @@ -295,7 +296,8 @@ struct ROUTER_CLIENT_SES ResponseMap sescmd_responses; /**< Response to each session command */ uint64_t sent_sescmd; /**< ID of the last sent session command*/ uint64_t recv_sescmd; /**< ID of the most recently completed session command */ - PSManager ps_manager; /**< Prepared statement manager*/ + PSManager ps_manager; /**< Prepared statement manager*/ + ClientHandleMap ps_handles; /**< Client PS handle to internal ID mapping */ skygw_chk_t rses_chk_tail; }; diff --git a/server/modules/routing/readwritesplit/rwsplit_ps.cc b/server/modules/routing/readwritesplit/rwsplit_ps.cc index c30a18be8..de30536f7 100644 --- a/server/modules/routing/readwritesplit/rwsplit_ps.cc +++ b/server/modules/routing/readwritesplit/rwsplit_ps.cc @@ -126,6 +126,7 @@ uint32_t PSManager::get_type(uint64_t id) const MXS_WARNING("Using unknown prepared statement with ID %lu", id); } + ss_dassert(rval != QUERY_TYPE_UNKNOWN); return rval; } diff --git a/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc b/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc index 813422ee0..05d80b91a 100644 --- a/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc +++ b/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc @@ -148,6 +148,18 @@ bool route_single_stmt(ROUTER_INSTANCE *inst, ROUTER_CLIENT_SES *rses, std::string id = extract_text_ps_id(querybuf); qtype = rses->ps_manager.get_type(id); } + else if (command == MYSQL_COM_STMT_EXECUTE) + { + uint32_t id = mxs_mysql_extract_execute(querybuf); + ClientHandleMap::iterator it = rses->ps_handles.find(id); + + if (it != rses->ps_handles.end()) + { + char *qtypestr = qc_typemask_to_string(rses->ps_manager.get_type(it->second)); + MXS_INFO("Client handle %u maps to %lu of type %s", id, it->second, qtypestr); + MXS_FREE(qtypestr); + } + } route_target = get_route_target(rses, qtype, querybuf->hint); } diff --git a/server/modules/routing/readwritesplit/rwsplit_session_cmd.cc b/server/modules/routing/readwritesplit/rwsplit_session_cmd.cc index 84992e2a5..185634fdc 100644 --- a/server/modules/routing/readwritesplit/rwsplit_session_cmd.cc +++ b/server/modules/routing/readwritesplit/rwsplit_session_cmd.cc @@ -38,15 +38,14 @@ void process_sescmd_response(ROUTER_CLIENT_SES* rses, SRWBackend& backend, gwbuf_copy_data(*ppPacket, MYSQL_HEADER_LEN, 1, &cmd); uint8_t command = backend->next_session_command()->get_command(); uint64_t id = backend->complete_session_command(); + MXS_PS_RESPONSE resp = {}; if (command == MYSQL_COM_STMT_PREPARE) { - MXS_PS_RESPONSE resp; - - if (mxs_mysql_extract_ps_response(*ppPacket, &resp)) - { - backend->add_ps_handle(id, resp.id); - } + // This should never fail or the backend protocol is broken + ss_debug(bool b = )mxs_mysql_extract_ps_response(*ppPacket, &resp); + ss_dassert(b); + backend->add_ps_handle(id, resp.id); } if (rses->recv_sescmd < rses->sent_sescmd && @@ -60,6 +59,12 @@ void process_sescmd_response(ROUTER_CLIENT_SES* rses, SRWBackend& backend, /** Store the master's response so that the slave responses can * be compared to it */ rses->sescmd_responses[id] = cmd; + + if (command == MYSQL_COM_STMT_PREPARE) + { + /** Map the returned response to the internal ID */ + rses->ps_handles[resp.id] = id; + } } else {