qc_mysqlembedded: Replace '?':s with '0':s

The embedded parser is not capable of parsing preparable statements
containing ?:s as ordinary statements, so they have to be replaced
with something else. Replacing them with a dummy variable cannot be
done as that will affect the type of the statement. Replacing with
0 seems to be a good compromise.
This commit is contained in:
Johan Wikman 2017-01-17 10:41:51 +02:00
parent a40692d81d
commit 842e8440d4

View File

@ -1790,56 +1790,38 @@ int32_t qc_mysql_get_preparable_stmt(GWBUF* stmt, GWBUF** preparable_stmt)
if (!pi->preparable_stmt)
{
// This is terriby inefficient, but as qc_mysqlembedded is not used
// for anything else but comparisons it is ok.
const char* preparable_str = lex->prepared_stmt_code.str;
size_t preparable_str_len = lex->prepared_stmt_code.length;
// MySQL does not parse e.g. "select * from x where ?=5". To work
// around that we'll replace all "?":s with "@a":s. We might replace
// something unnecessarily, but that won't hurt the classification.
size_t n_questions = 0;
const char* p = preparable_str;
while (p < preparable_str + preparable_str_len)
{
if (*p == '?')
{
++n_questions;
}
++p;
}
size_t preparable_stmt_len = preparable_str_len + n_questions * 2;
const char* preparable_stmt = lex->prepared_stmt_code.str;
size_t preparable_stmt_len = lex->prepared_stmt_code.length;
size_t payload_len = preparable_stmt_len + 1;
size_t packet_len = MYSQL_HEADER_LEN + payload_len;
GWBUF* preperable_stmt = gwbuf_alloc(packet_len);
GWBUF* preperable_packet = gwbuf_alloc(packet_len);
if (preperable_stmt)
if (preperable_packet)
{
// Encode the length of the payload in the 3 first bytes.
*((unsigned char*)GWBUF_DATA(preperable_stmt) + 0) = payload_len;
*((unsigned char*)GWBUF_DATA(preperable_stmt) + 1) = (payload_len >> 8);
*((unsigned char*)GWBUF_DATA(preperable_stmt) + 2) = (payload_len >> 16);
*((unsigned char*)GWBUF_DATA(preperable_packet) + 0) = payload_len;
*((unsigned char*)GWBUF_DATA(preperable_packet) + 1) = (payload_len >> 8);
*((unsigned char*)GWBUF_DATA(preperable_packet) + 2) = (payload_len >> 16);
// Sequence id
*((unsigned char*)GWBUF_DATA(preperable_stmt) + 3) = 0x00;
*((unsigned char*)GWBUF_DATA(preperable_packet) + 3) = 0x00;
// Payload, starts with command.
*((unsigned char*)GWBUF_DATA(preperable_stmt) + 4) = COM_QUERY;
*((unsigned char*)GWBUF_DATA(preperable_packet) + 4) = COM_QUERY;
// Is followed by the statement.
char *s = (char*)GWBUF_DATA(preperable_stmt) + 5;
p = preparable_str;
char *s = (char*)GWBUF_DATA(preperable_packet) + 5;
while (p < preparable_str + preparable_str_len)
// We copy the statment, blindly replacing all '?':s with '0':s as
// otherwise the parsing of the preparable statement as a regular
// statement will not always succeed.
const char* p = preparable_stmt;
while (p < preparable_stmt + preparable_stmt_len)
{
switch (*p)
if (*p == '?')
{
*s = '0';
}
else
{
case '?':
*s++ = '@';
*s = 'a';
break;
default:
*s = *p;
}
@ -1848,7 +1830,7 @@ int32_t qc_mysql_get_preparable_stmt(GWBUF* stmt, GWBUF** preparable_stmt)
}
}
pi->preparable_stmt = preperable_stmt;
pi->preparable_stmt = preperable_packet;
}
*preparable_stmt = pi->preparable_stmt;