MXS-1536: Fix crash in CREATE TABLE
If a CREATE TABLE statement had a quoted keyword as the name of a field, the calculated column count and actual column counts would differ. In addition to this, oneline comments before the end of the statement would truncate the SQL due to the fact that the whitespace was squashed before the comment removal was done.
This commit is contained in:
@ -553,7 +553,9 @@ strip_escape_chars(char* val)
|
|||||||
#define BUFFER_GROWTH_RATE 2.0
|
#define BUFFER_GROWTH_RATE 2.0
|
||||||
static pcre2_code* remove_comments_re = NULL;
|
static pcre2_code* remove_comments_re = NULL;
|
||||||
static const PCRE2_SPTR remove_comments_pattern = (PCRE2_SPTR)
|
static const PCRE2_SPTR remove_comments_pattern = (PCRE2_SPTR)
|
||||||
"(?:`[^`]*`\\K)|(\\/[*](?!(M?!)).*?[*]\\/)|(?:#.*|--[[:space:]].*)";
|
"(?:`[^`]*`\\K)|"
|
||||||
|
"(\\/[*](?!(M?!)).*?[*]\\/)|"
|
||||||
|
"([[:space:]](?:#.*|--[[:space:]].*(\\n|\\r\\n)))";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove SQL comments from the end of a string
|
* Remove SQL comments from the end of a string
|
||||||
|
@ -1008,13 +1008,13 @@ void handle_query_event(AVRO_INSTANCE *router, REP_HEADER *hdr, int *pending_tra
|
|||||||
memcpy(db, (char*) ptr + PHDR_OFF + vblklen, dblen);
|
memcpy(db, (char*) ptr + PHDR_OFF + vblklen, dblen);
|
||||||
db[dblen] = 0;
|
db[dblen] = 0;
|
||||||
|
|
||||||
unify_whitespace(sql, len);
|
|
||||||
size_t sqlsz = len, tmpsz = len;
|
size_t sqlsz = len, tmpsz = len;
|
||||||
char *tmp = MXS_MALLOC(len);
|
char *tmp = MXS_MALLOC(len);
|
||||||
MXS_ABORT_IF_NULL(tmp);
|
MXS_ABORT_IF_NULL(tmp);
|
||||||
remove_mysql_comments((const char**)&sql, &sqlsz, &tmp, &tmpsz);
|
remove_mysql_comments((const char**)&sql, &sqlsz, &tmp, &tmpsz);
|
||||||
sql = tmp;
|
sql = tmp;
|
||||||
len = tmpsz;
|
len = tmpsz;
|
||||||
|
unify_whitespace(sql, len);
|
||||||
|
|
||||||
if (is_create_table_statement(router, sql, len))
|
if (is_create_table_statement(router, sql, len))
|
||||||
{
|
{
|
||||||
|
@ -321,11 +321,11 @@ void save_avro_schema(const char *path, const char* schema, TABLE_MAP *map)
|
|||||||
* @return Pointer to the start of the definition of NULL if the query is
|
* @return Pointer to the start of the definition of NULL if the query is
|
||||||
* malformed.
|
* malformed.
|
||||||
*/
|
*/
|
||||||
static const char* get_table_definition(const char *sql, int* size)
|
static const char* get_table_definition(const char *sql, int len, int* size)
|
||||||
{
|
{
|
||||||
const char *rval = NULL;
|
const char *rval = NULL;
|
||||||
const char *ptr = sql;
|
const char *ptr = sql;
|
||||||
const char *end = strchr(sql, '\0');
|
const char *end = sql + len;
|
||||||
while (ptr < end && *ptr != '(')
|
while (ptr < end && *ptr != '(')
|
||||||
{
|
{
|
||||||
ptr++;
|
ptr++;
|
||||||
@ -512,13 +512,17 @@ static const char *extract_field_name(const char* ptr, char* dest, size_t size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!bt)
|
||||||
|
{
|
||||||
if (strncasecmp(ptr, "constraint", 10) == 0 || strncasecmp(ptr, "index", 5) == 0 ||
|
if (strncasecmp(ptr, "constraint", 10) == 0 || strncasecmp(ptr, "index", 5) == 0 ||
|
||||||
strncasecmp(ptr, "key", 3) == 0 || strncasecmp(ptr, "fulltext", 8) == 0 ||
|
strncasecmp(ptr, "key", 3) == 0 || strncasecmp(ptr, "fulltext", 8) == 0 ||
|
||||||
strncasecmp(ptr, "spatial", 7) == 0 || strncasecmp(ptr, "foreign", 7) == 0 ||
|
strncasecmp(ptr, "spatial", 7) == 0 || strncasecmp(ptr, "foreign", 7) == 0 ||
|
||||||
strncasecmp(ptr, "unique", 6) == 0 || strncasecmp(ptr, "primary", 7) == 0)
|
strncasecmp(ptr, "unique", 6) == 0 || strncasecmp(ptr, "primary", 7) == 0)
|
||||||
{
|
{
|
||||||
|
// Found a keyword
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char *start = ptr;
|
const char *start = ptr;
|
||||||
|
|
||||||
@ -698,31 +702,40 @@ TABLE_CREATE* table_create_alloc(const char* sql, int len, const char* event_db)
|
|||||||
{
|
{
|
||||||
/** Extract the table definition so we can get the column names from it */
|
/** Extract the table definition so we can get the column names from it */
|
||||||
int stmt_len = 0;
|
int stmt_len = 0;
|
||||||
const char* statement_sql = get_table_definition(sql, &stmt_len);
|
const char* statement_sql = get_table_definition(sql, len, &stmt_len);
|
||||||
ss_dassert(statement_sql);
|
ss_dassert(statement_sql);
|
||||||
char table[MYSQL_TABLE_MAXLEN + 1];
|
char table[MYSQL_TABLE_MAXLEN + 1];
|
||||||
char database[MYSQL_DATABASE_MAXLEN + 1];
|
char database[MYSQL_DATABASE_MAXLEN + 1];
|
||||||
const char *db = event_db;
|
const char* db = event_db;
|
||||||
|
const char* err = NULL;
|
||||||
MXS_INFO("Create table: %.*s", len, sql);
|
MXS_INFO("Create table: %.*s", len, sql);
|
||||||
|
|
||||||
if (!get_table_name(sql, table))
|
if (!statement_sql)
|
||||||
{
|
{
|
||||||
MXS_ERROR("Malformed CREATE TABLE statement, could not extract table name: %s", sql);
|
err = "table definition";
|
||||||
return NULL;
|
}
|
||||||
|
else if (!get_table_name(sql, table))
|
||||||
|
{
|
||||||
|
err = "table name";
|
||||||
|
}
|
||||||
|
/** The CREATE statement contains the database name */
|
||||||
|
else if (strlen(db) == 0)
|
||||||
|
{
|
||||||
|
if (get_database_name(sql, database))
|
||||||
|
{
|
||||||
|
db = database;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
err = "database name";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The CREATE statement contains the database name */
|
if (err)
|
||||||
if (strlen(db) == 0)
|
|
||||||
{
|
{
|
||||||
if (!get_database_name(sql, database))
|
MXS_ERROR("Malformed CREATE TABLE statement, could not extract %s: %.*s", err, len, sql);
|
||||||
{
|
|
||||||
MXS_ERROR("Malformed CREATE TABLE statement, could not extract "
|
|
||||||
"database name: %s", sql);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
db = database;
|
|
||||||
}
|
|
||||||
|
|
||||||
int* lengths = NULL;
|
int* lengths = NULL;
|
||||||
char **names = NULL;
|
char **names = NULL;
|
||||||
|
Reference in New Issue
Block a user