From 842e8440d4557b6f3d5c206dbc38c39d6df10688 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Tue, 17 Jan 2017 10:41:51 +0200 Subject: [PATCH] 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. --- .../qc_mysqlembedded/qc_mysqlembedded.cc | 60 +++++++------------ 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc b/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc index cf7405368..047e6d873 100644 --- a/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc +++ b/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc @@ -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;