diff --git a/query_classifier/query_classifier.cc b/query_classifier/query_classifier.cc index 8379c1b89..009cbe94f 100644 --- a/query_classifier/query_classifier.cc +++ b/query_classifier/query_classifier.cc @@ -105,20 +105,29 @@ skygw_query_type_t query_classifier_get_type( ss_info_dassert(querybuf != NULL, ("querybuf is NULL")); /** Create parsing info for the query and store it to buffer */ - if (!query_is_parsed(querybuf)) + succp = query_is_parsed(querybuf); + + if (!succp) { succp = parse_query(querybuf); } /** Read thd pointer and resolve the query type with it. */ if (succp) { - parsing_info_t* pi = (parsing_info_t*)gwbuf_get_parsing_info(querybuf); - mysql = (MYSQL *)pi->pi_handle; - - /** Find out the query type */ - if (mysql != NULL) + parsing_info_t* pi; + + pi = (parsing_info_t*)gwbuf_get_buffer_object_data(querybuf, + GWBUF_PARSING_INFO); + + if (pi != NULL) { - qtype = resolve_query_type((THD *)mysql->thd); + mysql = (MYSQL *)pi->pi_handle; + + /** Find out the query type */ + if (mysql != NULL) + { + qtype = resolve_query_type((THD *)mysql->thd); + } } } return qtype; @@ -143,19 +152,21 @@ bool parse_query ( parsing_info_t* pi; CHK_GWBUF(querybuf); + /** Do not parse without releasing previous parse info first */ ss_dassert(!query_is_parsed(querybuf)); - if (querybuf->gwbuf_parsing_info == NULL) + if (query_is_parsed(querybuf)) { - /** Create parsing info */ - querybuf->gwbuf_parsing_info = parsing_info_init(parsing_info_done); + return false; } + /** Create parsing info */ + pi = parsing_info_init(parsing_info_done); - if (querybuf->gwbuf_parsing_info == NULL) + if (pi == NULL) { succp = false; goto retblock; - } + } /** Extract query and copy it to different buffer */ data = (uint8_t*)GWBUF_DATA(querybuf); len = MYSQL_GET_PACKET_LEN(data)-1; /*< distract 1 for packet type byte */ @@ -163,21 +174,22 @@ bool parse_query ( if (query_str == NULL) { + /** Free parsing info data */ + parsing_info_done(pi); succp = false; goto retblock; } memcpy(query_str, &data[5], len); memset(&query_str[len], 0, 1); - parsing_info_set_plain_str(querybuf->gwbuf_parsing_info, query_str); + parsing_info_set_plain_str(pi, query_str); /** Get one or create new THD object to be use in parsing */ - pi = (parsing_info_t *)querybuf->gwbuf_parsing_info; thd = get_or_create_thd_for_parsing((MYSQL *)pi->pi_handle, query_str); if (thd == NULL) { - parsing_info_done(querybuf->gwbuf_parsing_info); - querybuf->gwbuf_parsing_info = NULL; + /** Free parsing info data */ + parsing_info_done(pi); succp = false; goto retblock; } @@ -186,6 +198,12 @@ bool parse_query ( * thd and lex are readable even if creating parse tree fails. */ create_parse_tree(thd); + /** Add complete parsing info struct to the query buffer */ + gwbuf_add_buffer_object(querybuf, + GWBUF_PARSING_INFO, + (void *)pi, + parsing_info_done); + succp = true; retblock: return succp; @@ -203,11 +221,8 @@ retblock: bool query_is_parsed( GWBUF* buf) { - if (buf->gwbuf_parsing_info != NULL) - { - return true; - } - return false; + CHK_GWBUF(buf); + return GWBUF_IS_PARSED(buf); } @@ -859,23 +874,29 @@ char* skygw_get_canonical( MYSQL* mysql; THD* thd; LEX* lex; - bool found = false; Item* item; char* querystr; - if (querybuf->gwbuf_parsing_info == NULL) + if (!GWBUF_IS_PARSED(querybuf)) { querystr = NULL; goto retblock; - } - pi = (parsing_info_t*)querybuf->gwbuf_parsing_info; + } + pi = (parsing_info_t *)gwbuf_get_buffer_object_data(querybuf, + GWBUF_PARSING_INFO); + if (pi == NULL) + { + querystr = NULL; + goto retblock; + } + if (pi->pi_query_plain_str == NULL || (mysql = (MYSQL *)pi->pi_handle) == NULL || (thd = (THD *)mysql->thd) == NULL || (lex = thd->lex) == NULL) { - ss_dassert(querystr != NULL && + ss_dassert(pi->pi_query_plain_str != NULL && mysql != NULL && thd != NULL && lex != NULL); @@ -899,7 +920,14 @@ char* skygw_get_canonical( itype == Item::VARBIN_ITEM || itype == Item::NULL_ITEM)) { - querystr = replace_literal(querystr, item->name, "?"); + if (itype == Item::STRING_ITEM && strlen(item->name) == 0) + { + querystr = replace_literal(querystr, "\"\"", "\"?\""); + } + else + { + querystr = replace_literal(querystr, item->name, "?"); + } } } /*< for */ retblock: diff --git a/query_classifier/query_classifier.h b/query_classifier/query_classifier.h index dd5ddc5cc..325087910 100644 --- a/query_classifier/query_classifier.h +++ b/query_classifier/query_classifier.h @@ -47,6 +47,20 @@ typedef enum { QUERY_TYPE_EXEC_STMT = 0x1000 /*< Execute prepared statement */ } skygw_query_type_t; + +typedef struct parsing_info_st { +#if defined(SS_DEBUG) + skygw_chk_t pi_chk_top; +#endif + void* pi_handle; /*< parsing info object pointer */ + char* pi_query_plain_str; /*< query as plain string */ + void (*pi_done_fp)(void *); /*< clean-up function for parsing info */ +#if defined(SS_DEBUG) + skygw_chk_t pi_chk_tail; +#endif +} parsing_info_t; + + #define QUERY_IS_TYPE(mask,type) ((mask & type) == type) /** @@ -61,9 +75,7 @@ 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); - - +bool query_is_parsed(GWBUF* buf); EXTERN_C_BLOCK_END diff --git a/server/core/buffer.c b/server/core/buffer.c index 47e9a22eb..3b8a8c8e6 100644 --- a/server/core/buffer.c +++ b/server/core/buffer.c @@ -40,6 +40,11 @@ #include #include +static buffer_object_t* gwbuf_remove_buffer_object( + GWBUF* buf, + buffer_object_t* bufobj); + + /** * Allocate a new gateway buffer structure of size bytes. * @@ -77,13 +82,15 @@ SHARED_BUF *sbuf; free(sbuf); return NULL; } + spinlock_init(&rval->gwbuf_lock); rval->start = sbuf->data; rval->end = rval->start + size; sbuf->refcount = 1; rval->sbuf = sbuf; rval->next = NULL; rval->gwbuf_type = GWBUF_TYPE_UNDEFINED; - rval->gwbuf_parsing_info = NULL; + rval->gwbuf_info = GWBUF_INFO_NONE; + rval->gwbuf_bufobj = NULL; CHK_GWBUF(rval); return rval; } @@ -96,16 +103,19 @@ SHARED_BUF *sbuf; void gwbuf_free(GWBUF *buf) { + buffer_object_t* bo; + CHK_GWBUF(buf); if (atomic_add(&buf->sbuf->refcount, -1) == 1) { free(buf->sbuf->data); free(buf->sbuf); - } - if (buf->gwbuf_parsing_info != NULL) - { - parsing_info_t* pi = (parsing_info_t *)buf->gwbuf_parsing_info; - pi->pi_done_fp(pi); + bo = buf->gwbuf_bufobj; + + while (bo != NULL) + { + bo = gwbuf_remove_buffer_object(buf, bo); + } } free(buf); } @@ -135,8 +145,9 @@ GWBUF *rval; rval->start = buf->start; rval->end = buf->end; rval->gwbuf_type = buf->gwbuf_type; + rval->gwbuf_info = buf->gwbuf_info; + rval->gwbuf_bufobj = buf->gwbuf_bufobj; rval->next = NULL; - rval->gwbuf_parsing_info = NULL; CHK_GWBUF(rval); return rval; } @@ -162,8 +173,9 @@ GWBUF *gwbuf_clone_portion( clonebuf->start = (void *)((char*)buf->start)+start_offset; clonebuf->end = (void *)((char *)clonebuf->start)+length; clonebuf->gwbuf_type = buf->gwbuf_type; /*< clone the type for now */ + clonebuf->gwbuf_info = buf->gwbuf_info; + clonebuf->gwbuf_bufobj = buf->gwbuf_bufobj; clonebuf->next = NULL; - clonebuf->gwbuf_parsing_info = NULL; CHK_GWBUF(clonebuf); return clonebuf; @@ -343,10 +355,87 @@ void gwbuf_set_type( } } -void* gwbuf_get_parsing_info( - GWBUF* buf) +/** + * Add a buffer object to GWBUF buffer. + * + * @param buf GWBUF where object is added + * @param id Type identifier for object + * @param data Object data + * @param donefun_dp Clean-up function to be executed before buffer is freed. + */ +void gwbuf_add_buffer_object( + GWBUF* buf, + bufobj_id_t id, + void* data, + void (*donefun_fp)(void *)) { + buffer_object_t** p_b; + buffer_object_t* newb; + CHK_GWBUF(buf); - return buf->gwbuf_parsing_info; + newb = (buffer_object_t *)malloc(sizeof(buffer_object_t)); + newb->bo_id = id; + newb->bo_data = data; + newb->bo_donefun_fp = donefun_fp; + newb->bo_next = NULL; + /** Lock */ + spinlock_acquire(&buf->gwbuf_lock); + p_b = &buf->gwbuf_bufobj; + /** Search the end of the list and add there */ + while (*p_b != NULL) + { + p_b = &(*p_b)->bo_next; + } + *p_b = newb; + /** Set flag */ + buf->gwbuf_info |= GWBUF_INFO_PARSED; + /** Unlock */ + spinlock_release(&buf->gwbuf_lock); +} + +/** + * Search buffer object which matches with the id. + * + * @param buf GWBUF to be searched + * @param id Identifier for the object + * + * @return Searched buffer object or NULL if not found + */ +void* gwbuf_get_buffer_object_data( + GWBUF* buf, + bufobj_id_t id) +{ + buffer_object_t* bo; + + CHK_GWBUF(buf); + /** Lock */ + spinlock_acquire(&buf->gwbuf_lock); + bo = buf->gwbuf_bufobj; + + while (bo != NULL && bo->bo_id != id) + { + bo = bo->bo_next; + } + /** Unlock */ + spinlock_release(&buf->gwbuf_lock); + + return bo->bo_data; +} + + +/** + * @return pointer to next buffer object or NULL + */ +static buffer_object_t* gwbuf_remove_buffer_object( + GWBUF* buf, + buffer_object_t* bufobj) +{ + buffer_object_t* next; + + next = bufobj->bo_next; + /** Call corresponding clean-up function to clean buffer object's data */ + bufobj->bo_donefun_fp(bufobj->bo_data); + free(bufobj); + return next; } diff --git a/server/include/buffer.h b/server/include/buffer.h index 57e20dc2e..8f6dcf864 100644 --- a/server/include/buffer.h +++ b/server/include/buffer.h @@ -42,6 +42,8 @@ * @endverbatim */ #include +#include + EXTERN_C_BLOCK_BEGIN @@ -74,18 +76,33 @@ typedef struct { int refcount; /*< Reference count on the buffer */ } SHARED_BUF; +typedef enum +{ + GWBUF_INFO_NONE = 0x0, + GWBUF_INFO_PARSED = 0x1 +} gwbuf_info_t; -typedef struct parsing_info_st { -#if defined(SS_DEBUG) - skygw_chk_t pi_chk_top; -#endif - void* pi_handle; /*< parsing info object pointer */ - char* pi_query_plain_str; /*< query as plain string */ - void (*pi_done_fp)(void *); /*< clean-up function for parsing info */ -#if defined(SS_DEBUG) - skygw_chk_t pi_chk_tail; -#endif -} parsing_info_t; +#define GWBUF_IS_PARSED(b) (b->gwbuf_info & GWBUF_INFO_PARSED) + +/** + * A structure for cleaning up memory allocations of structures which are + * referred to by GWBUF and deallocated in gwbuf_free but GWBUF doesn't + * know what they are. + * All functions on the list are executed before freeing memory of GWBUF struct. + */ +typedef enum +{ + GWBUF_PARSING_INFO +} bufobj_id_t; + +typedef struct buffer_object_st buffer_object_t; + +struct buffer_object_st { + bufobj_id_t bo_id; + void* bo_data; + void (*bo_donefun_fp)(void *); + buffer_object_t* bo_next; +}; /** @@ -97,11 +114,13 @@ typedef struct parsing_info_st { * be copied within the gateway. */ typedef struct gwbuf { + SPINLOCK gwbuf_lock; struct gwbuf *next; /*< Next buffer in a linked chain of buffers */ void *start; /*< Start of the valid data */ void *end; /*< First byte after the valid data */ SHARED_BUF *sbuf; /*< The shared buffer with the real data */ - void *gwbuf_parsing_info; /*< parsing info object pointer */ + buffer_object_t *gwbuf_bufobj; /*< List of objects referred to by GWBUF */ + gwbuf_info_t gwbuf_info; /*< Info bits */ gwbuf_type_t gwbuf_type; /*< buffer's data type information */ } GWBUF; @@ -136,8 +155,12 @@ extern unsigned int gwbuf_length(GWBUF *head); extern GWBUF *gwbuf_clone_portion(GWBUF *head, size_t offset, size_t len); extern GWBUF *gwbuf_clone_transform(GWBUF *head, gwbuf_type_t type); extern void gwbuf_set_type(GWBUF *head, gwbuf_type_t type); -void* gwbuf_get_parsing_info(GWBUF* buf); +void gwbuf_add_buffer_object(GWBUF* buf, + bufobj_id_t id, + void* data, + void (*donefun_fp)(void *)); +void* gwbuf_get_buffer_object_data(GWBUF* buf, bufobj_id_t id); EXTERN_C_BLOCK_END diff --git a/utils/skygw_utils.cc b/utils/skygw_utils.cc index 6ffafd7c3..7bfc42949 100644 --- a/utils/skygw_utils.cc +++ b/utils/skygw_utils.cc @@ -1916,7 +1916,7 @@ char* replace_literal( goto retblock; } - rc = regcomp(&re, search_re, REG_EXTENDED); + rc = regcomp(&re, search_re, REG_EXTENDED|REG_ICASE); ss_dassert(rc == 0); if (rc != 0) @@ -1936,6 +1936,7 @@ char* replace_literal( if (rc != 0) { free(search_re); + regfree(&re); newstr = haystack; goto retblock; }