From 42cb6bbff7706273fb44950cb63611ed3e5ac616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Tue, 10 Oct 2017 08:25:18 +0300 Subject: [PATCH] Fix multi-statement execution in readwritesplit A multi-statements can return multiple resultsets in one response. To accommodate for this, both the readwritesplit and modutil code must be altered. By ignoring complete resultsets in readwritesplit, the code can deduce whether a result is complete or not. --- server/core/modutil.cc | 18 ++++++++--------- .../routing/readwritesplit/readwritesplit.cc | 20 +++++++++++++++++++ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/server/core/modutil.cc b/server/core/modutil.cc index a5850ac6b..172f317aa 100644 --- a/server/core/modutil.cc +++ b/server/core/modutil.cc @@ -628,10 +628,9 @@ GWBUF* modutil_get_complete_packets(GWBUF **p_readbuf) return complete; } -int modutil_count_signal_packets(GWBUF *reply, int n_found, bool* more_dest, modutil_state* state) +int modutil_count_signal_packets(GWBUF *reply, int n_found, bool* more_out, modutil_state* state) { unsigned int len = gwbuf_length(reply); - ss_debug(int real_offset = 0); int eof = 0; int err = 0; size_t offset = 0; @@ -661,18 +660,18 @@ int modutil_count_signal_packets(GWBUF *reply, int n_found, bool* more_dest, mod if (command == MYSQL_REPLY_ERR) { - err++; + /** Any errors in the packet stream mean that the result set + * generation was aborted due to an error. No more results will + * follow after this. */ + *more_out = false; + return 2; } else if (command == MYSQL_REPLY_EOF && pktlen == MYSQL_EOF_PACKET_LEN) { eof++; } - else if (more && command == MYSQL_REPLY_OK) + else if (command == MYSQL_REPLY_OK && pktlen >= MYSQL_OK_PACKET_MIN_LEN) { - // This should not be the first packet - ss_dassert(pktlen >= MYSQL_OK_PACKET_MIN_LEN); - ss_dassert(real_offset > 0); - uint8_t data[payloadlen - 1]; gwbuf_copy_data(reply, offset + MYSQL_HEADER_LEN + 1, sizeof(data), data); @@ -693,7 +692,6 @@ int modutil_count_signal_packets(GWBUF *reply, int n_found, bool* more_dest, mod } offset += pktlen; - ss_debug(real_offset += pktlen); if (offset >= GWBUF_LENGTH(reply) && reply->next) { @@ -709,7 +707,7 @@ int modutil_count_signal_packets(GWBUF *reply, int n_found, bool* more_dest, mod state->state = skip_next; } - *more_dest = more; + *more_out = more; return total; } diff --git a/server/modules/routing/readwritesplit/readwritesplit.cc b/server/modules/routing/readwritesplit/readwritesplit.cc index 24260c7b7..e9eda014b 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.cc +++ b/server/modules/routing/readwritesplit/readwritesplit.cc @@ -537,6 +537,16 @@ bool reply_is_complete(SRWBackend& backend, GWBUF *buffer) LOG_RS(backend, REPLY_STATE_DONE); backend->set_reply_state(REPLY_STATE_DONE); } + else + { + // This is an OK packet and more results will follow + ss_dassert(mxs_mysql_is_ok_packet(buffer) && + mxs_mysql_more_results_after_ok(buffer)); + + LOG_RS(backend, REPLY_STATE_RSET_COLDEF); + backend->set_reply_state(REPLY_STATE_RSET_COLDEF); + return reply_is_complete(backend, buffer); + } } else { @@ -546,6 +556,16 @@ bool reply_is_complete(SRWBackend& backend, GWBUF *buffer) int n_eof = modutil_count_signal_packets(buffer, n_old_eof, &more, &state); backend->set_large_packet(state.state); + if (n_eof > 2) + { + /** + * We have multiple results in the buffer, we only care about + * the state of the last one. Skip the complete result sets and act + * like we're processing a single result set. + */ + n_eof = n_eof % 2 ? 1 : 2; + } + if (n_eof == 0) { /** Waiting for the EOF packet after the column definitions */