diff --git a/include/proxysql_structs.h b/include/proxysql_structs.h index 835157ec2..dddde86da 100644 --- a/include/proxysql_structs.h +++ b/include/proxysql_structs.h @@ -260,6 +260,7 @@ class PtrArray; class PtrSizeArray; class StatCounters; class ProxySQL_ConfigFile; +class Query_Info; //class MySQL_Server; class SQLite3_result; //class MySQL_Servers; diff --git a/include/query_processor.h b/include/query_processor.h index 8744fef65..ee2cc2550 100644 --- a/include/query_processor.h +++ b/include/query_processor.h @@ -199,7 +199,7 @@ class Query_Processor { void delete_query_rule(QP_rule_t *qr); // destructor //virtual bool remove(int rule_id, bool lock=true) {return false;}; // FIXME: not implemented yet, should be implemented at all ? // virtual bool remove_locked(int rule_id) {return false;}; // call this instead of remove() in case lock was already acquired via wrlock() - Query_Processor_Output * process_mysql_query(MySQL_Session *sess, void *ptr, unsigned int size, bool delete_original); + Query_Processor_Output * process_mysql_query(MySQL_Session *sess, void *ptr, unsigned int size, Query_Info *qi); void delete_QP_out(Query_Processor_Output *o); void sort(bool lock=true); @@ -214,7 +214,7 @@ class Query_Processor { void * query_parser_init(char *query, int query_length, int flags); enum MYSQL_COM_QUERY_command query_parser_command_type(void *args); - char * query_parser_first_comment(void *args); + bool query_parser_first_comment(Query_Processor_Output *qpo, char *fc); void query_parser_free(void *args); void update_query_digest(void *p, MySQL_Connection_userinfo *ui, unsigned long long t, unsigned long long n); diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index 1f4ccdc68..16905b1c5 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -462,7 +462,7 @@ __get_pkts_from_client: if (rc_break==true) { break; } - qpo=GloQPro->process_mysql_query(this,pkt.ptr,pkt.size,false); + qpo=GloQPro->process_mysql_query(this,pkt.ptr,pkt.size,&CurrentQuery); if (qpo) { rc_break=handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_qpo(&pkt); if (rc_break==true) { break; } diff --git a/lib/Query_Processor.cpp b/lib/Query_Processor.cpp index bf65d696c..d824e96aa 100644 --- a/lib/Query_Processor.cpp +++ b/lib/Query_Processor.cpp @@ -592,9 +592,13 @@ SQLite3_result * Query_Processor::get_query_digests_reset() { -Query_Processor_Output * Query_Processor::process_mysql_query(MySQL_Session *sess, void *ptr, unsigned int size, bool delete_original) { +Query_Processor_Output * Query_Processor::process_mysql_query(MySQL_Session *sess, void *ptr, unsigned int size, Query_Info *qi) { Query_Processor_Output *ret=NULL; ret=new Query_Processor_Output(); + SQP_par_t *qp=NULL; + if (qi && qi->QueryParserArgs) { + qp=(SQP_par_t *)qi->QueryParserArgs; + } unsigned int len=size-sizeof(mysql_hdr)-1; char *query=(char *)l_alloc(len+1); memcpy(query,(char *)ptr+sizeof(mysql_hdr)+1,len); @@ -733,6 +737,10 @@ Query_Processor_Output * Query_Processor::process_mysql_query(MySQL_Session *ses __exit_process_mysql_query: // FIXME : there is too much data being copied around l_free(len+1,query); + if (qp && qp->first_comment[0]) { + // we have a comment to parse + query_parser_first_comment(ret, qp->first_comment); + } return ret; }; @@ -783,6 +791,7 @@ void * Query_Processor::query_parser_init(char *query, int query_length, int fla qp->digest_text=NULL; qp->first_comment=NULL; qp->first_comment=(char *)l_alloc(FIRST_COMMENT_MAX_LENGTH); + qp->first_comment[0]=0; // initialize it to 0 . Useful to determine if there is any string or not if (mysql_thread___query_digests) { qp->digest_text=mysql_query_digest_and_first_comment(query, query_length, qp->first_comment); qp->digest=SpookyHash::Hash64(qp->digest_text,strlen(qp->digest_text),0); @@ -958,7 +967,39 @@ enum MYSQL_COM_QUERY_command Query_Processor::__query_parser_command_type(void * return MYSQL_COM_QUERY_UNKNOWN; } -char * Query_Processor::query_parser_first_comment(void *args) { return NULL; } +bool Query_Processor::query_parser_first_comment(Query_Processor_Output *qpo, char *fc) { + bool ret=false; + tokenizer_t tok = tokenizer( fc, ";", TOKENIZER_NO_EMPTIES ); + const char* token; + for ( token = tokenize( &tok ) ; token ; token = tokenize( &tok ) ) { + char *key=NULL; + char *value=NULL; + c_split_2(token, "=", &key, &value); + remove_spaces(key); + remove_spaces(value); + if (strlen(key)) { + char c=value[0]; + if (!strcasecmp(key,"query_timeout")) { + if (c >= '0' && c <= '9') { // it is a digit + int t=atoi(value); + qpo->timeout=t; + } + } + if (!strcasecmp(key,"hostgroup")) { + if (c >= '0' && c <= '9') { // it is a digit + int t=atoi(value); + qpo->destination_hostgroup=t; + } + } + } + free(key); + free(value); + fprintf(stderr,"%s , key=%s , value=%s\n", token, key, value); + } + free_tokenizer( &tok ); + return ret; +} + void Query_Processor::query_parser_free(void *args) { SQP_par_t *qp=(SQP_par_t *)args; diff --git a/lib/c_tokenizer.c b/lib/c_tokenizer.c index 9707454e8..9c742ac71 100644 --- a/lib/c_tokenizer.c +++ b/lib/c_tokenizer.c @@ -72,6 +72,7 @@ void c_split_2(const char *in, const char *del, char **out1, char **out2) { *out1=NULL; *out2=NULL; const char *t; + //tokenizer_t tok = tokenizer( in, del, TOKENIZER_NO_EMPTIES ); tokenizer_t tok = tokenizer( in, del, TOKENIZER_NO_EMPTIES ); for ( t=tokenize(&tok); t; t=tokenize(&tok)) { if (*out1==NULL) { *out1=strdup(t); continue; } diff --git a/lib/gen_utils.cpp b/lib/gen_utils.cpp index 969e7b7f5..f9a0bfb74 100644 --- a/lib/gen_utils.cpp +++ b/lib/gen_utils.cpp @@ -5,18 +5,27 @@ int remove_spaces(const char *s) { char *inp = (char *)s, *outp = (char *)s; bool prev_space = false; + bool fns = false; while (*inp) { if (isspace(*inp)) { - if (!prev_space) { - *outp++ = ' '; - prev_space = true; + if (fns) { + if (!prev_space) { + *outp++ = ' '; + prev_space = true; + } } } else { *outp++ = *inp; - prev_space = 0; + prev_space = false; + if (!fns) fns=true; } ++inp; } + if (outp>s) { + if (prev_space) { + outp--; + } + } *outp = '\0'; return strlen(s); }