diff --git a/server/modules/routing/avrorouter/avro_file.c b/server/modules/routing/avrorouter/avro_file.c index dffb375d4..ee9fd04f2 100644 --- a/server/modules/routing/avrorouter/avro_file.c +++ b/server/modules/routing/avrorouter/avro_file.c @@ -1021,6 +1021,40 @@ void unify_whitespace(char *sql, int len) } } +/** + * A very simple function for stripping auto-generated executable comments + * + * Note that the string will not strip the trailing part of the comment, making + * the SQL invalid. + * + * @param sql String to modify + * @param len Pointer to current length of string, updated to new length if + * @c sql is modified + */ +static void strip_executable_comments(char *sql, int* len) +{ + if (strncmp(sql, "/*!", 3) == 0 || strncmp(sql, "/*M!", 4) == 0) + { + // Executable comment, remove it + char* p = sql + 3; + if (*p == '!') + { + p++; + } + + // Skip the versioning part + while (*p && isdigit(*p)) + { + p++; + } + + int n_extra = p - sql; + int new_len = *len - n_extra; + memmove(sql, sql + n_extra, new_len); + *len = new_len; + } +} + /** * @brief Handling of query events * @@ -1046,6 +1080,7 @@ void handle_query_event(AVRO_INSTANCE *router, REP_HEADER *hdr, int *pending_tra sql = tmp; len = tmpsz; unify_whitespace(sql, len); + strip_executable_comments(sql, &len); sql[len] = '\0'; static bool warn_not_row_format = true; @@ -1107,7 +1142,7 @@ void handle_query_event(AVRO_INSTANCE *router, REP_HEADER *hdr, int *pending_tra } else { - MXS_ERROR("Alter statement to a table with no create statement."); + MXS_ERROR("Alter statement to table '%s' has no preceding create statement.", ident); } } /* A transaction starts with this event */ diff --git a/server/modules/routing/avrorouter/avro_rbr.c b/server/modules/routing/avrorouter/avro_rbr.c index 4c506f284..4b9f5d177 100644 --- a/server/modules/routing/avrorouter/avro_rbr.c +++ b/server/modules/routing/avrorouter/avro_rbr.c @@ -337,9 +337,9 @@ bool handle_row_event(AVRO_INSTANCE *router, REP_HEADER *hdr, uint8_t *ptr) } else if (ncolumns == map->columns && create->columns != map->columns) { - MXS_ERROR("Table map event has a different column " - "count for table %s.%s than the CREATE TABLE statement.", - map->database, map->table); + MXS_ERROR("Table map event has a different column count for table " + "%s.%s than the CREATE TABLE statement. Possible " + "unsupported DDL detected.", map->database, map->table); } else { diff --git a/server/modules/routing/avrorouter/avro_schema.c b/server/modules/routing/avrorouter/avro_schema.c index efc1bb832..aaacc4a32 100644 --- a/server/modules/routing/avrorouter/avro_schema.c +++ b/server/modules/routing/avrorouter/avro_schema.c @@ -1392,6 +1392,14 @@ int get_column_index(TABLE_CREATE *create, const char *tok, int len) char safe_tok[len + 2]; memcpy(safe_tok, tok, len); safe_tok[len] = '\0'; + + if (*safe_tok == '`') + { + int toklen = strlen(safe_tok) - 2; // Token length without backticks + memmove(safe_tok, safe_tok + 1, toklen); // Overwrite first backtick + safe_tok[toklen] = '\0'; // Null-terminate the string before the second backtick + } + fix_reserved_word(safe_tok); for (int x = 0; x < create->columns; x++) @@ -1406,6 +1414,35 @@ int get_column_index(TABLE_CREATE *create, const char *tok, int len) return idx; } +static bool not_column_operation(const char* tok, int len) +{ + const char* keywords[] = + { + "PRIMARY", + "UNIQUE", + "FULLTEXT", + "SPATIAL", + "PERIOD", + "PRIMARY", + "KEY", + "KEYS", + "INDEX", + "FOREIGN", + "CONSTRAINT", + NULL + }; + + for (int i = 0; keywords[i]; i++) + { + if (tok_eq(tok, keywords[i], strlen(keywords[i]))) + { + return true; + } + } + + return false; +} + bool table_create_alter(TABLE_CREATE *create, const char *sql, const char *end) { const char *tbl = strcasestr(sql, "table"), *def; @@ -1431,7 +1468,12 @@ bool table_create_alter(TABLE_CREATE *create, const char *sql, const char *end) if (tok) { - if (tok_eq(tok, "column", len)) + if (not_column_operation(tok, len)) + { + MXS_INFO("Statement doesn't affect columns, not processing: %s", sql); + return true; + } + else if (tok_eq(tok, "column", len)) { // Skip the optional COLUMN keyword tok = get_tok(tok + len, &len, end);