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:
@ -84,9 +84,6 @@ static bool skygw_stmt_causes_implicit_commit(
|
|||||||
static int is_autocommit_stmt(
|
static int is_autocommit_stmt(
|
||||||
LEX* lex);
|
LEX* lex);
|
||||||
|
|
||||||
static bool query_is_parsed(
|
|
||||||
GWBUF* buf);
|
|
||||||
|
|
||||||
static void parsing_info_set_plain_str(void* ptr,
|
static void parsing_info_set_plain_str(void* ptr,
|
||||||
char* str);
|
char* str);
|
||||||
|
|
||||||
@ -203,7 +200,7 @@ retblock:
|
|||||||
*
|
*
|
||||||
* @return true or false
|
* @return true or false
|
||||||
*/
|
*/
|
||||||
static bool query_is_parsed(
|
bool query_is_parsed(
|
||||||
GWBUF* buf)
|
GWBUF* buf)
|
||||||
{
|
{
|
||||||
if (buf->gwbuf_parsing_info != NULL)
|
if (buf->gwbuf_parsing_info != NULL)
|
||||||
@ -873,7 +870,7 @@ char* skygw_get_canonical(
|
|||||||
}
|
}
|
||||||
pi = (parsing_info_t*)querybuf->gwbuf_parsing_info;
|
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 ||
|
(mysql = (MYSQL *)pi->pi_handle) == NULL ||
|
||||||
(thd = (THD *)mysql->thd) == NULL ||
|
(thd = (THD *)mysql->thd) == NULL ||
|
||||||
(lex = thd->lex) == NULL)
|
(lex = thd->lex) == NULL)
|
||||||
@ -885,6 +882,8 @@ char* skygw_get_canonical(
|
|||||||
goto retblock;
|
goto retblock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
querystr = strdup(pi->pi_query_plain_str);
|
||||||
|
|
||||||
for (item=thd->free_list; item != NULL; item=item->next)
|
for (item=thd->free_list; item != NULL; item=item->next)
|
||||||
{
|
{
|
||||||
Item::Type itype;
|
Item::Type itype;
|
||||||
@ -901,14 +900,18 @@ char* skygw_get_canonical(
|
|||||||
{
|
{
|
||||||
if (!found)
|
if (!found)
|
||||||
{
|
{
|
||||||
newstr = replace_str(querystr, item->name, "?");
|
newstr = replace_literal(querystr, item->name, "?");
|
||||||
found = true;
|
if (newstr != NULL)
|
||||||
|
{
|
||||||
|
free(querystr);
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char* prevstr = newstr;
|
char* prevstr = newstr;
|
||||||
|
|
||||||
newstr = replace_str(prevstr, item->name, "?");
|
newstr = replace_literal(prevstr, item->name, "?");
|
||||||
free(prevstr);
|
free(prevstr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,6 +61,8 @@ char* skygw_get_canonical(GWBUF* querybuf);
|
|||||||
bool parse_query (GWBUF* querybuf);
|
bool parse_query (GWBUF* querybuf);
|
||||||
parsing_info_t* parsing_info_init(void (*donefun)(void *));
|
parsing_info_t* parsing_info_init(void (*donefun)(void *));
|
||||||
void parsing_info_done(void* ptr);
|
void parsing_info_done(void* ptr);
|
||||||
|
bool query_is_parsed(GWBUF* buf);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ include ../makefile.inc
|
|||||||
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
CPP = g++
|
CPP = g++
|
||||||
|
UTILS_PATH := $(ROOT_PATH)/utils
|
||||||
|
|
||||||
makeall: clean all
|
makeall: clean all
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ clean:
|
|||||||
- $(DEL) *~
|
- $(DEL) *~
|
||||||
|
|
||||||
all:
|
all:
|
||||||
$(CPP) -c $(CFLAGS) \
|
$(CPP) -c $(CFLAGS) -I$(UTILS_PATH) \
|
||||||
-fPIC skygw_utils.cc -o skygw_utils.o
|
-fPIC skygw_utils.cc -o skygw_utils.o
|
||||||
|
|
||||||
cleantests:
|
cleantests:
|
||||||
|
|||||||
@ -44,4 +44,6 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MAX_ERROR_MSG PATH_MAX
|
||||||
|
|
||||||
#endif /* SKYGW_TYPES_H */
|
#endif /* SKYGW_TYPES_H */
|
||||||
|
|||||||
@ -24,8 +24,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <regex.h>
|
||||||
#include "skygw_debug.h"
|
#include "skygw_debug.h"
|
||||||
#include "skygw_types.h"
|
#include <skygw_types.h>
|
||||||
#include "skygw_utils.h"
|
#include "skygw_utils.h"
|
||||||
|
|
||||||
const char* timestamp_formatstr = "%04d %02d/%02d %02d:%02d:%02d ";
|
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
|
* Find the given needle - user-provided literal - and replace it with
|
||||||
* the destination string new. The lengths of the strings old and new may differ.
|
* replacement string. Separate user-provided literals from matching table names
|
||||||
* The string new may be of any length, but the string "old" must be of non-zero
|
* etc. by searching only substrings preceded by non-letter and non-number.
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
* @param str String to be modified
|
* @param haystack Plain text query string, not to be freed
|
||||||
* @param old Substring to be replaced
|
* @param needle Substring to be searched, not to be freed
|
||||||
* @param new Replacement
|
* @param replacement Replacement text, not to be freed
|
||||||
* @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>.
|
|
||||||
*
|
*
|
||||||
* Thanks, to Laird Shaw who implemented most of this function.
|
* @return newly allocated string where needle is replaced
|
||||||
*/
|
*/
|
||||||
char* replace_str (
|
char* replace_literal(
|
||||||
const char *str,
|
char* haystack,
|
||||||
const char *old,
|
const char* needle,
|
||||||
const char *replacement)
|
const char* replacement)
|
||||||
{
|
{
|
||||||
char* ret;
|
const char* prefix = "[ =',\\(]"; /*< ' ','=','(',''',',' are allowed before needle */
|
||||||
char* r;
|
const char* suffix = "[$^[:alnum:]]?"; /*< alpha-num chars aren't allowed after the needle */
|
||||||
const char* p;
|
char* search_re;
|
||||||
const char* q;
|
char* newstr;
|
||||||
size_t oldlen;
|
regex_t re;
|
||||||
size_t count;
|
regmatch_t match;
|
||||||
size_t retlen;
|
int rc;
|
||||||
size_t newlen;
|
size_t rlen = strlen(replacement);
|
||||||
|
size_t nlen = strlen(needle);
|
||||||
|
size_t hlen = strlen(haystack);
|
||||||
|
|
||||||
oldlen = strlen(old);
|
search_re = (char *)malloc(strlen(prefix)+nlen+strlen(suffix)+1);
|
||||||
newlen = strlen(replacement);
|
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)
|
char error_message[MAX_ERROR_MSG];
|
||||||
{
|
regerror (rc, &re, error_message, MAX_ERROR_MSG);
|
||||||
count++;
|
fprintf(stderr,
|
||||||
}
|
"Regex error compiling '%s': %s\n",
|
||||||
/* this is undefined if p - str > PTRDIFF_MAX */
|
search_re,
|
||||||
retlen = p - str + strlen(p) + count * (newlen - oldlen);
|
error_message);
|
||||||
}
|
free(search_re);
|
||||||
else
|
newstr = NULL;
|
||||||
{
|
goto retblock;
|
||||||
retlen = strlen(str);
|
|
||||||
}
|
|
||||||
if ((ret = (char *)malloc(retlen + 1)) == NULL)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
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 */
|
free(search_re);
|
||||||
ptrdiff_t l = q - p;
|
newstr = NULL;
|
||||||
memcpy(r, p, l);
|
goto retblock;
|
||||||
r += l;
|
|
||||||
memcpy(r, replacement, newlen);
|
|
||||||
r += newlen;
|
|
||||||
}
|
}
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -191,7 +191,13 @@ int skygw_rwlock_unlock(skygw_rwlock_t* rwlock);
|
|||||||
int skygw_rwlock_init(skygw_rwlock_t** rwlock);
|
int skygw_rwlock_init(skygw_rwlock_t** rwlock);
|
||||||
|
|
||||||
int atomic_add(int *variable, int value);
|
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 */
|
#endif /* SKYGW_UTILS_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user