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.
This commit is contained in:
Markus Mäkelä
2017-10-10 08:25:18 +03:00
parent d9922ac895
commit 42cb6bbff7
2 changed files with 28 additions and 10 deletions

View File

@ -628,10 +628,9 @@ GWBUF* modutil_get_complete_packets(GWBUF **p_readbuf)
return complete; 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); unsigned int len = gwbuf_length(reply);
ss_debug(int real_offset = 0);
int eof = 0; int eof = 0;
int err = 0; int err = 0;
size_t offset = 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) 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) else if (command == MYSQL_REPLY_EOF && pktlen == MYSQL_EOF_PACKET_LEN)
{ {
eof++; 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]; uint8_t data[payloadlen - 1];
gwbuf_copy_data(reply, offset + MYSQL_HEADER_LEN + 1, sizeof(data), data); 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; offset += pktlen;
ss_debug(real_offset += pktlen);
if (offset >= GWBUF_LENGTH(reply) && reply->next) 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; state->state = skip_next;
} }
*more_dest = more; *more_out = more;
return total; return total;
} }

View File

@ -537,6 +537,16 @@ bool reply_is_complete(SRWBackend& backend, GWBUF *buffer)
LOG_RS(backend, REPLY_STATE_DONE); LOG_RS(backend, REPLY_STATE_DONE);
backend->set_reply_state(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 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); int n_eof = modutil_count_signal_packets(buffer, n_old_eof, &more, &state);
backend->set_large_packet(state.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) if (n_eof == 0)
{ {
/** Waiting for the EOF packet after the column definitions */ /** Waiting for the EOF packet after the column definitions */