Implement qc_get_preparable_stmt

Now returns the preparable statement as a GWBUF on which the
other qc-functions can be used.
This commit is contained in:
Johan Wikman
2017-01-16 20:12:00 +02:00
parent 8a95a0f045
commit cc6a3e629e
3 changed files with 163 additions and 61 deletions

View File

@ -88,6 +88,7 @@ typedef struct parsing_info_st
QC_FUNCTION_INFO* function_infos;
size_t function_infos_len;
size_t function_infos_capacity;
GWBUF* preparable_stmt;
#if defined(SS_DEBUG)
skygw_chk_t pi_chk_tail;
#endif
@ -1547,6 +1548,8 @@ static void parsing_info_done(void* ptr)
}
free(pi->function_infos);
gwbuf_free(pi->preparable_stmt);
free(pi);
}
}
@ -1775,10 +1778,84 @@ int32_t qc_mysql_get_prepare_name(GWBUF* stmt, char** namep)
int32_t qc_mysql_get_preparable_stmt(GWBUF* stmt, GWBUF** preparable_stmt)
{
*preparable_stmt = NULL;
if (stmt)
{
if (ensure_query_is_parsed(stmt))
{
LEX* lex = get_lex(stmt);
if (lex->sql_command == SQLCOM_PREPARE)
{
parsing_info_t* pi = get_pinfo(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;
size_t payload_len = preparable_stmt_len + 1;
size_t packet_len = MYSQL_HEADER_LEN + payload_len;
GWBUF* preperable_stmt = gwbuf_alloc(packet_len);
if (preperable_stmt)
{
// 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);
// Sequence id
*((unsigned char*)GWBUF_DATA(preperable_stmt) + 3) = 0x00;
// Payload, starts with command.
*((unsigned char*)GWBUF_DATA(preperable_stmt) + 4) = COM_QUERY;
// Is followed by the statement.
char *s = (char*)GWBUF_DATA(preperable_stmt) + 5;
p = preparable_str;
while (p < preparable_str + preparable_str_len)
{
switch (*p)
{
case '?':
*s++ = '@';
*s = 'a';
break;
default:
*s = *p;
}
++p;
++s;
}
}
pi->preparable_stmt = preperable_stmt;
}
*preparable_stmt = pi->preparable_stmt;
}
}
}
// TODO: Extract preparable stmt.
ss_dassert(!true);
return QC_RESULT_OK;
}