Fix to multi-statement processing

Renamed is_mysql_comment_start to is_mysql_statement_end because it checks
whether a statement truly ends instead of just checking comment block starts.

The calculations for buffer length in readwritesplit now use the payload size
instead of the buffer size.
This commit is contained in:
Markus Makela 2016-03-03 10:44:11 +02:00
parent 8b6595aa68
commit 76f06572ed
3 changed files with 38 additions and 23 deletions

View File

@ -893,39 +893,53 @@ char* strnchr_esc_mysql(char* ptr, char c, int len)
}
/**
* Check if the start of the token is the start of a MySQL style comment block
* @param ptr String with at least two non-null characters in it
* @return True if the token starts a comment block
* @brief Check if the string is the final part of a valid SQL statement
*
* This function checks whether the string pointed by @p start contains any
* tokens that are interpreted as executable commands.
* @param start String containing the statement
* @param len Length of the string
* @return True if statement contains no executable parts
*/
bool is_mysql_comment_start(const char* start, int len)
bool is_mysql_statement_end(const char* start, int len)
{
const char *ptr = start;
bool rval = false;
while (ptr < start + len && (isspace(*ptr) || *ptr == ';'))
{
ptr++;
}
switch (*ptr)
if (ptr < start + len)
{
case '-':
if (*(ptr + 1) == '-' && isspace(*(ptr + 2)))
{
return true;
}
break;
switch (*ptr)
{
case '-':
if (ptr < start + len - 2 && *(ptr + 1) == '-' && isspace(*(ptr + 2)))
{
rval = true;
}
break;
case '#':
return true;
case '#':
rval = true;
break;
case '/':
if (*(ptr + 1) == '*')
{
return true;
}
break;
case '/':
if (ptr < start + len - 1 && *(ptr + 1) == '*')
{
rval = true;
}
break;
}
}
return false;
else
{
rval = true;
}
return rval;
}
/**

View File

@ -71,7 +71,7 @@ mxs_pcre2_result_t modutil_mysql_wildcard_match(const char* pattern, const char*
/** Character and token searching functions */
char* strnchr_esc(char* ptr, char c, int len);
char* strnchr_esc_mysql(char* ptr, char c, int len);
bool is_mysql_comment_start(const char* start, int len);
bool is_mysql_statement_end(const char* start, int len);
bool is_mysql_sp_end(const char* start, int len);
#endif

View File

@ -5362,7 +5362,8 @@ static void check_for_multi_stmt(ROUTER_CLIENT_SES* rses, GWBUF *buf,
packet_type == MYSQL_COM_QUERY && rses->forced_node != rses->rses_master_ref)
{
char *ptr, *data = GWBUF_DATA(buf) + 5;
int buflen = GWBUF_LENGTH(buf) - 5;
/** Payload size without command byte */
int buflen = gw_mysql_get_byte3((uint8_t*)GWBUF_DATA(buf)) - 1;
if ((ptr = strnchr_esc_mysql(data, ';', buflen)))
{
@ -5374,7 +5375,7 @@ static void check_for_multi_stmt(ROUTER_CLIENT_SES* rses, GWBUF *buf,
if (ptr)
{
if (ptr < data + buflen && !is_mysql_comment_start(ptr, ptr - data))
if (ptr < data + buflen && !is_mysql_statement_end(ptr, buflen - (ptr - data)))
{
rses->forced_node = rses->rses_master_ref;
MXS_INFO("Multi-statement query, routing all future queries to master.");