query_classifier.cc: query_is_parsed is now global function and can be used to check whether parsing information already exists in the buffer.

skygw_utils.cc: removed replace_str and implemented replace_literal which replaces user-provided literals in query with predefined string "?". Replacing is done one by one, so it is suboptimal ipmlementation since all literals could be passed to replacement function in one call and processed all before returning.
This commit is contained in:
VilhoRaatikka 2014-08-21 22:28:23 +03:00
parent 4a2d81e066
commit fa2189373d
6 changed files with 94 additions and 64 deletions

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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:

View File

@ -44,4 +44,6 @@
# endif
#endif
#define MAX_ERROR_MSG PATH_MAX
#endif /* SKYGW_TYPES_H */

View File

@ -24,8 +24,9 @@
#include <string.h>
#include <time.h>
#include <stddef.h>
#include <regex.h>
#include "skygw_debug.h"
#include "skygw_types.h"
#include <skygw_types.h>
#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: <string.h>, <stdlib.h> and <stddef.h>.
* @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;
}
regfree(&re);
retblock:
return newstr;
}

View File

@ -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 */