diff --git a/query_classifier/query_classifier.cc b/query_classifier/query_classifier.cc index 7354d9639..9c2ab146a 100644 --- a/query_classifier/query_classifier.cc +++ b/query_classifier/query_classifier.cc @@ -84,9 +84,6 @@ static bool skygw_stmt_causes_implicit_commit( static int is_autocommit_stmt( LEX* lex); -static bool query_is_parsed( - GWBUF* buf); - static void parsing_info_set_plain_str(void* ptr, char* str); @@ -203,7 +200,7 @@ retblock: * * @return true or false */ -static bool query_is_parsed( +bool query_is_parsed( GWBUF* buf) { if (buf->gwbuf_parsing_info != NULL) @@ -873,7 +870,7 @@ char* skygw_get_canonical( } pi = (parsing_info_t*)querybuf->gwbuf_parsing_info; - if ((querystr = pi->pi_query_plain_str) == NULL || + if (pi->pi_query_plain_str == NULL || (mysql = (MYSQL *)pi->pi_handle) == NULL || (thd = (THD *)mysql->thd) == NULL || (lex = thd->lex) == NULL) @@ -885,6 +882,8 @@ char* skygw_get_canonical( goto retblock; } + querystr = strdup(pi->pi_query_plain_str); + for (item=thd->free_list; item != NULL; item=item->next) { Item::Type itype; @@ -901,14 +900,18 @@ char* skygw_get_canonical( { if (!found) { - newstr = replace_str(querystr, item->name, "?"); - found = true; + newstr = replace_literal(querystr, item->name, "?"); + if (newstr != NULL) + { + free(querystr); + found = true; + } } else { char* prevstr = newstr; - newstr = replace_str(prevstr, item->name, "?"); + newstr = replace_literal(prevstr, item->name, "?"); free(prevstr); } } diff --git a/query_classifier/query_classifier.h b/query_classifier/query_classifier.h index beef84c2c..dd5ddc5cc 100644 --- a/query_classifier/query_classifier.h +++ b/query_classifier/query_classifier.h @@ -61,6 +61,8 @@ char* skygw_get_canonical(GWBUF* querybuf); bool parse_query (GWBUF* querybuf); parsing_info_t* parsing_info_init(void (*donefun)(void *)); void parsing_info_done(void* ptr); +bool query_is_parsed(GWBUF* buf); + diff --git a/utils/makefile b/utils/makefile index a8df09a7f..0faa27144 100644 --- a/utils/makefile +++ b/utils/makefile @@ -3,6 +3,7 @@ include ../makefile.inc CC = gcc CPP = g++ +UTILS_PATH := $(ROOT_PATH)/utils makeall: clean all @@ -13,7 +14,7 @@ clean: - $(DEL) *~ all: - $(CPP) -c $(CFLAGS) \ + $(CPP) -c $(CFLAGS) -I$(UTILS_PATH) \ -fPIC skygw_utils.cc -o skygw_utils.o cleantests: diff --git a/utils/skygw_types.h b/utils/skygw_types.h index d497fbfd7..cccf55f2b 100644 --- a/utils/skygw_types.h +++ b/utils/skygw_types.h @@ -44,4 +44,6 @@ # endif #endif +#define MAX_ERROR_MSG PATH_MAX + #endif /* SKYGW_TYPES_H */ diff --git a/utils/skygw_utils.cc b/utils/skygw_utils.cc index c7175c76f..2b2204814 100644 --- a/utils/skygw_utils.cc +++ b/utils/skygw_utils.cc @@ -24,8 +24,9 @@ #include #include #include +#include #include "skygw_debug.h" -#include "skygw_types.h" +#include #include "skygw_utils.h" const char* timestamp_formatstr = "%04d %02d/%02d %02d:%02d:%02d "; @@ -1864,68 +1865,83 @@ void skygw_file_done( } } + /** - * Replaces in the string str all the occurrences of the source string old with - * the destination string new. The lengths of the strings old and new may differ. - * The string new may be of any length, but the string "old" must be of non-zero - * length - the penalty for providing an empty string for the "old" parameter is - * an infinite loop. In addition, none of the three parameters may be NULL. + * Find the given needle - user-provided literal - and replace it with + * replacement string. Separate user-provided literals from matching table names + * etc. by searching only substrings preceded by non-letter and non-number. * - * @param str String to be modified - * @param old Substring to be replaced - * @param new Replacement - * @return String with replacements in new memory area or NULL if memory - * allocation failed. - * Dependencies: For this function to compile, you will need to also #include - * the following files: , and . + * @param haystack Plain text query string, not to be freed + * @param needle Substring to be searched, not to be freed + * @param replacement Replacement text, not to be freed * - * Thanks, to Laird Shaw who implemented most of this function. - */ -char* replace_str ( - const char *str, - const char *old, - const char *replacement) + * @return newly allocated string where needle is replaced + */ +char* replace_literal( + char* haystack, + const char* needle, + const char* replacement) { - char* ret; - char* r; - const char* p; - const char* q; - size_t oldlen; - size_t count; - size_t retlen; - size_t newlen; + const char* prefix = "[ =',\\(]"; /*< ' ','=','(',''',',' are allowed before needle */ + const char* suffix = "[$^[:alnum:]]?"; /*< alpha-num chars aren't allowed after the needle */ + char* search_re; + char* newstr; + regex_t re; + regmatch_t match; + int rc; + size_t rlen = strlen(replacement); + size_t nlen = strlen(needle); + size_t hlen = strlen(haystack); - oldlen = strlen(old); - newlen = strlen(replacement); + search_re = (char *)malloc(strlen(prefix)+nlen+strlen(suffix)+1); + sprintf(search_re, "%s%s%s", prefix, needle, suffix); + /** + * +2 because there may be up to 2 extra characters which + * aren't replaced + */ + newstr = (char *)malloc(hlen-nlen+rlen); - if (oldlen != newlen) + rc = regcomp(&re, search_re, REG_EXTENDED); + ss_dassert(rc == 0); + + if (rc != 0) { - for (count = 0, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen) - { - count++; - } - /* this is undefined if p - str > PTRDIFF_MAX */ - retlen = p - str + strlen(p) + count * (newlen - oldlen); - } - else - { - retlen = strlen(str); - } - if ((ret = (char *)malloc(retlen + 1)) == NULL) - { - return NULL; + char error_message[MAX_ERROR_MSG]; + regerror (rc, &re, error_message, MAX_ERROR_MSG); + fprintf(stderr, + "Regex error compiling '%s': %s\n", + search_re, + error_message); + free(search_re); + newstr = NULL; + goto retblock; } + rc = regexec(&re, haystack, 1, &match, 0); - for (r = ret, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen) + if (rc != 0) { - /* this is undefined if q - p > PTRDIFF_MAX */ - ptrdiff_t l = q - p; - memcpy(r, p, l); - r += l; - memcpy(r, replacement, newlen); - r += newlen; + free(search_re); + newstr = NULL; + goto retblock; } - strcpy(r, p); + memcpy(newstr, haystack, match.rm_so+1); + memcpy(newstr+match.rm_so+1, replacement, rlen); + /** +1 is terminating byte */ + memcpy(newstr+match.rm_so+1+rlen, haystack+match.rm_so+1+nlen, hlen-(match.rm_so+1)-nlen+1); - return ret; -} \ No newline at end of file + regfree(&re); + +retblock: + return newstr; +} + + + + + + + + + + + diff --git a/utils/skygw_utils.h b/utils/skygw_utils.h index 854c82541..a50dd08b6 100644 --- a/utils/skygw_utils.h +++ b/utils/skygw_utils.h @@ -191,7 +191,13 @@ int skygw_rwlock_unlock(skygw_rwlock_t* rwlock); int skygw_rwlock_init(skygw_rwlock_t** rwlock); int atomic_add(int *variable, int value); -char* replace_str(const char* str, const char* old, const char* replacement); +EXTERN_C_BLOCK_BEGIN + +char* replace_literal(char* haystack, + const char* needle, + const char* replacement); + +EXTERN_C_BLOCK_END #endif /* SKYGW_UTILS_H */