From 4188d2009cc9141b2ecb6b28fc362ab2b779fe99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Canna=C3=B2?= Date: Sat, 17 Jun 2017 18:18:18 +0200 Subject: [PATCH] mysql_query_rules.OK_msg #1045 Extending mysql_query_rules with a new field: OK_msg If OK_msg is not NULL, an OK packet is sent to the client with an optional message as specified in OK_msg itself. If OK_msg is an not NULL empty string, an OK packet is sent to the client without any message. If both error_msg and OK_msg are present, error_msg is returned. This commit includes also few minor bugs, mostly related to typo that would prevent online upgrade of mysql_query_rules from early release of 1.4.0 . --- include/query_processor.h | 11 ++++-- lib/MySQL_Session.cpp | 11 ++++++ lib/ProxySQL_Admin.cpp | 75 +++++++++++++++++++++++++++------------ lib/Query_Processor.cpp | 28 ++++++++++----- 4 files changed, 91 insertions(+), 34 deletions(-) diff --git a/include/query_processor.h b/include/query_processor.h index a78b995b48..1abedd8290 100644 --- a/include/query_processor.h +++ b/include/query_processor.h @@ -33,6 +33,7 @@ struct _Query_Processor_rule_t { int mirror_hostgroup; int mirror_flagOUT; char *error_msg; + char *OK_msg; int sticky_conn; int multiplex; int log; @@ -59,7 +60,8 @@ class Query_Processor_Output { int timeout; int retries; int delay; - char *error_msg; + char *error_msg; + char *OK_msg; int sticky_conn; int multiplex; int log; @@ -94,6 +96,7 @@ class Query_Processor_Output { log=-1; new_query=NULL; error_msg=NULL; + OK_msg=NULL; comment=NULL; // #643 } void destroy() { @@ -101,6 +104,10 @@ class Query_Processor_Output { free(error_msg); error_msg=NULL; } + if (OK_msg) { + free(OK_msg); + OK_msg=NULL; + } if (comment) { // #643 free(comment); } @@ -187,7 +194,7 @@ class Query_Processor { void wrlock(); // explicit write lock, to be used in multi-isert void wrunlock(); // explicit write unlock bool insert(QP_rule_t *qr, bool lock=true); // insert a new rule. Uses a generic void pointer to a structure that may vary depending from the Query Processor - QP_rule_t * new_query_rule(int rule_id, bool active, char *username, char *schemaname, int flagIN, char *client_addr, char *proxy_addr, int proxy_port, char *digest, char *match_digest, char *match_pattern, bool negate_match_pattern, char *re_modifiers, int flagOUT, char *replace_pattern, int destination_hostgroup, int cache_ttl, int reconnect, int timeout, int retries, int delay, int next_query_flagIN, int mirror_hostgroup, int mirror_flagOUT, char *error_msg, int sticky_conn, int multiplex, int log, bool apply, char *comment); // to use a generic query rule struct, this is generated by this function and returned as generic void pointer + QP_rule_t * new_query_rule(int rule_id, bool active, char *username, char *schemaname, int flagIN, char *client_addr, char *proxy_addr, int proxy_port, char *digest, char *match_digest, char *match_pattern, bool negate_match_pattern, char *re_modifiers, int flagOUT, char *replace_pattern, int destination_hostgroup, int cache_ttl, int reconnect, int timeout, int retries, int delay, int next_query_flagIN, int mirror_hostgroup, int mirror_flagOUT, char *error_msg, char *OK_msg, int sticky_conn, int multiplex, int log, bool apply, char *comment); // to use a generic query rule struct, this is generated by this function and returned as generic void pointer void delete_query_rule(QP_rule_t *qr); // destructor 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); diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index a6fbb7bd6b..a71b450dde 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -3292,6 +3292,17 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C return true; } + if (qpo->OK_msg) { + client_myds->DSS=STATE_QUERY_SENT_NET; + unsigned int nTrx=NumActiveTransactions(); + uint16_t setStatus = (nTrx ? SERVER_STATUS_IN_TRANS : 0 ); + if (autocommit) setStatus += SERVER_STATUS_AUTOCOMMIT; + client_myds->myprot.generate_pkt_OK(true,NULL,NULL,client_myds->pkt_sid+1,0,0,setStatus,0,qpo->OK_msg); + l_free(pkt->size,pkt->ptr); + RequestEnd(NULL); + return true; + } + if (qpo->error_msg) { client_myds->DSS=STATE_QUERY_SENT_NET; client_myds->myprot.generate_pkt_ERR(true,NULL,NULL,client_myds->pkt_sid+1,1148,(char *)"42000",qpo->error_msg); diff --git a/lib/ProxySQL_Admin.cpp b/lib/ProxySQL_Admin.cpp index 2b77b098e1..6938bad2ac 100644 --- a/lib/ProxySQL_Admin.cpp +++ b/lib/ProxySQL_Admin.cpp @@ -188,7 +188,10 @@ pthread_mutex_t users_mutex = PTHREAD_MUTEX_INITIALIZER; #define ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_V1_4_0b "CREATE TABLE mysql_query_rules (rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0 , username VARCHAR , schemaname VARCHAR , flagIN INT NOT NULL DEFAULT 0 , client_addr VARCHAR , proxy_addr VARCHAR , proxy_port INT , digest VARCHAR , match_digest VARCHAR , match_pattern VARCHAR , negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0 , re_modifiers VARCHAR DEFAULT 'CASELESS' , flagOUT INT , replace_pattern VARCHAR , destination_hostgroup INT DEFAULT NULL , cache_ttl INT CHECK(cache_ttl > 0) , reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL , timeout INT UNSIGNED , retries INT CHECK (retries>=0 AND retries <=1000) , delay INT UNSIGNED , next_query_flagIN INT UNSIGNED , mirror_flagOUT INT UNSIGNED , mirror_hostgroup INT UNSIGNED , error_msg VARCHAR , sticky_conn INT CHECK (sticky_conn IN (0,1)) , multiplex INT CHECK (multiplex IN (0,1,2)) , log INT CHECK (log IN (0,1)) , apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0 , comment VARCHAR)" -#define ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_V1_4_0b +#define ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_V1_4_1 "CREATE TABLE mysql_query_rules (rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0 , username VARCHAR , schemaname VARCHAR , flagIN INT NOT NULL DEFAULT 0 , client_addr VARCHAR , proxy_addr VARCHAR , proxy_port INT , digest VARCHAR , match_digest VARCHAR , match_pattern VARCHAR , negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0 , re_modifiers VARCHAR DEFAULT 'CASELESS' , flagOUT INT , replace_pattern VARCHAR , destination_hostgroup INT DEFAULT NULL , cache_ttl INT CHECK(cache_ttl > 0) , reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL , timeout INT UNSIGNED , retries INT CHECK (retries>=0 AND retries <=1000) , delay INT UNSIGNED , next_query_flagIN INT UNSIGNED , mirror_flagOUT INT UNSIGNED , mirror_hostgroup INT UNSIGNED , error_msg VARCHAR , OK_msg VARCHAR , sticky_conn INT CHECK (sticky_conn IN (0,1)) , multiplex INT CHECK (multiplex IN (0,1,2)) , log INT CHECK (log IN (0,1)) , apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0 , comment VARCHAR)" + +#define ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_V1_4_1 +//#define ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_V1_4_0b #define ADMIN_SQLITE_TABLE_GLOBAL_VARIABLES "CREATE TABLE global_variables (variable_name VARCHAR NOT NULL PRIMARY KEY , variable_value VARCHAR NOT NULL)" @@ -218,7 +221,7 @@ pthread_mutex_t users_mutex = PTHREAD_MUTEX_INITIALIZER; #define ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_REPLICATION_HOSTGROUPS "CREATE TABLE runtime_mysql_replication_hostgroups (writer_hostgroup INT CHECK (writer_hostgroup>=0) NOT NULL PRIMARY KEY , reader_hostgroup INT NOT NULL CHECK (reader_hostgroup<>writer_hostgroup AND reader_hostgroup>0) , comment VARCHAR , UNIQUE (reader_hostgroup))" -#define ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_QUERY_RULES "CREATE TABLE runtime_mysql_query_rules (rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0 , username VARCHAR , schemaname VARCHAR , flagIN INT NOT NULL DEFAULT 0 , client_addr VARCHAR , proxy_addr VARCHAR , proxy_port INT , digest VARCHAR , match_digest VARCHAR , match_pattern VARCHAR , negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0 , re_modifiers VARCHAR , flagOUT INT , replace_pattern VARCHAR , destination_hostgroup INT DEFAULT NULL , cache_ttl INT CHECK(cache_ttl > 0) , reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL , timeout INT UNSIGNED , retries INT CHECK (retries>=0 AND retries <=1000) , delay INT UNSIGNED , next_query_flagIN INT UNSIGNED , mirror_flagOUT INT UNSIGNED , mirror_hostgroup INT UNSIGNED , error_msg VARCHAR , sticky_conn INT CHECK (sticky_conn IN (0,1)) , multiplex INT CHECK (multiplex IN (0,1)) , log INT CHECK (log IN (0,1)) , apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0 , comment VARCHAR)" +#define ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_QUERY_RULES "CREATE TABLE runtime_mysql_query_rules (rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0 , username VARCHAR , schemaname VARCHAR , flagIN INT NOT NULL DEFAULT 0 , client_addr VARCHAR , proxy_addr VARCHAR , proxy_port INT , digest VARCHAR , match_digest VARCHAR , match_pattern VARCHAR , negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0 , re_modifiers VARCHAR , flagOUT INT , replace_pattern VARCHAR , destination_hostgroup INT DEFAULT NULL , cache_ttl INT CHECK(cache_ttl > 0) , reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL , timeout INT UNSIGNED , retries INT CHECK (retries>=0 AND retries <=1000) , delay INT UNSIGNED , next_query_flagIN INT UNSIGNED , mirror_flagOUT INT UNSIGNED , mirror_hostgroup INT UNSIGNED , error_msg VARCHAR , OK_msg VARCHAR , sticky_conn INT CHECK (sticky_conn IN (0,1)) , multiplex INT CHECK (multiplex IN (0,1)) , log INT CHECK (log IN (0,1)) , apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0 , comment VARCHAR)" #define ADMIN_SQLITE_TABLE_RUNTIME_SCHEDULER "CREATE TABLE runtime_scheduler (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1 , interval_ms INTEGER CHECK (interval_ms>=100 AND interval_ms<=100000000) NOT NULL , filename VARCHAR NOT NULL , arg1 VARCHAR , arg2 VARCHAR , arg3 VARCHAR , arg4 VARCHAR , arg5 VARCHAR , comment VARCHAR NOT NULL DEFAULT '')" @@ -3711,15 +3714,15 @@ void ProxySQL_Admin::save_mysql_query_rules_from_runtime(bool _runtime) { //char *a=(char *)"INSERT INTO mysql_query_rules VALUES (\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\")"; char *a=NULL; if (_runtime) { - a=(char *)"INSERT INTO runtime_mysql_query_rules (rule_id, active, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, sticky_conn, multiplex, log, apply, comment) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"; + a=(char *)"INSERT INTO runtime_mysql_query_rules (rule_id, active, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, OK_msg, sticky_conn, multiplex, log, apply, comment) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"; } else { - a=(char *)"INSERT INTO mysql_query_rules (rule_id, active, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, sticky_conn, multiplex, log, apply, comment) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"; + a=(char *)"INSERT INTO mysql_query_rules (rule_id, active, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, OK_msg, sticky_conn, multiplex, log, apply, comment) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"; } for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; int arg_len=0; - char *buffs[30]; - for (int i=0; i<30; i++) { + char *buffs[31]; // number of fields + for (int i=0; i<31; i++) { if (r->fields[i]) { char *o=escape_string_single_quotes(r->fields[i],false); int l=strlen(o)+4; @@ -3764,15 +3767,16 @@ void ProxySQL_Admin::save_mysql_query_rules_from_runtime(bool _runtime) { ( strcmp(r->fields[22],"-1")==0 ? "NULL" : r->fields[22] ), // mirror_flagOUT ( strcmp(r->fields[23],"-1")==0 ? "NULL" : r->fields[23] ), // mirror_hostgroup buffs[24], // error_msg - ( strcmp(r->fields[25],"-1")==0 ? "NULL" : r->fields[25] ), // sticky_conn - ( strcmp(r->fields[26],"-1")==0 ? "NULL" : r->fields[26] ), // multiplex - ( strcmp(r->fields[27],"-1")==0 ? "NULL" : r->fields[27] ), // log - ( strcmp(r->fields[28],"-1")==0 ? "NULL" : r->fields[28] ), // apply - buffs[29] // comment + buffs[25], // OK_msg + ( strcmp(r->fields[26],"-1")==0 ? "NULL" : r->fields[26] ), // sticky_conn + ( strcmp(r->fields[27],"-1")==0 ? "NULL" : r->fields[27] ), // multiplex + ( strcmp(r->fields[28],"-1")==0 ? "NULL" : r->fields[28] ), // log + ( strcmp(r->fields[29],"-1")==0 ? "NULL" : r->fields[29] ), // apply + buffs[30] // comment ); //fprintf(stderr,"%s\n",query); admindb->execute(query); - for (int i=0; i<29; i++) { + for (int i=0; i<31; i++) { free(buffs[i]); } free(query); @@ -4698,7 +4702,7 @@ char * ProxySQL_Admin::load_mysql_query_rules_to_runtime() { int affected_rows=0; if (GloQPro==NULL) return (char *)"Global Query Processor not started: command impossible to run"; SQLite3_result *resultset=NULL; - char *query=(char *)"SELECT rule_id, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, sticky_conn, multiplex, log, apply, comment FROM main.mysql_query_rules WHERE active=1"; + char *query=(char *)"SELECT rule_id, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, ok_msg, sticky_conn, multiplex, log, apply, comment FROM main.mysql_query_rules WHERE active=1"; admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); if (error) { proxy_error("Error on %s : %s\n", query, error); @@ -4734,11 +4738,12 @@ char * ProxySQL_Admin::load_mysql_query_rules_to_runtime() { (r->fields[21]==NULL ? -1 : atol(r->fields[21])), // mirror_flagOUT (r->fields[22]==NULL ? -1 : atol(r->fields[22])), // mirror_hostgroup r->fields[23], // error_msg - (r->fields[24]==NULL ? -1 : atol(r->fields[24])), // sticky_conn - (r->fields[25]==NULL ? -1 : atol(r->fields[25])), // multiplex - (r->fields[26]==NULL ? -1 : atol(r->fields[26])), // log - (atoi(r->fields[27])==1 ? true : false), - r->fields[28] // comment + r->fields[24], // OK_msg + (r->fields[25]==NULL ? -1 : atol(r->fields[25])), // sticky_conn + (r->fields[26]==NULL ? -1 : atol(r->fields[26])), // multiplex + (r->fields[27]==NULL ? -1 : atol(r->fields[27])), // log + (atoi(r->fields[28])==1 ? true : false), + r->fields[29] // comment ); GloQPro->insert(nqpr, false); } @@ -4941,7 +4946,7 @@ int ProxySQL_Admin::Read_MySQL_Query_Rules_from_configfile() { int i; int rows=0; admindb->execute("PRAGMA foreign_keys = OFF"); - char *q=(char *)"INSERT OR REPLACE INTO mysql_query_rules (rule_id, active, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, sticky_conn, multiplex, log, apply, comment) VALUES (%d, %d, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d, %s)"; + char *q=(char *)"INSERT OR REPLACE INTO mysql_query_rules (rule_id, active, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, ok_msg, sticky_conn, multiplex, log, apply, comment) VALUES (%d, %d, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d, %s)"; for (i=0; i< count; i++) { const Setting &rule = mysql_query_rules[i]; int rule_id; @@ -4991,6 +4996,8 @@ int ProxySQL_Admin::Read_MySQL_Query_Rules_from_configfile() { int delay=-1; bool error_msg_exists=false; std::string error_msg; + bool OK_msg_exists=false; + std::string OK_msg; int sticky_conn=-1; int multiplex=-1; @@ -5033,7 +5040,9 @@ int ProxySQL_Admin::Read_MySQL_Query_Rules_from_configfile() { rule.lookupValue("timeout", timeout); rule.lookupValue("retries", retries); rule.lookupValue("delay", delay); - if (rule.lookupValue("error_msg", username)) error_msg_exists=true; + + if (rule.lookupValue("error_msg", error_msg)) error_msg_exists=true; + if (rule.lookupValue("OK_msg", OK_msg)) OK_msg_exists=true; rule.lookupValue("sticky_conn", sticky_conn); rule.lookupValue("multiplex", multiplex); @@ -5041,8 +5050,8 @@ int ProxySQL_Admin::Read_MySQL_Query_Rules_from_configfile() { rule.lookupValue("log", log); rule.lookupValue("apply", apply); + if (rule.lookupValue("comment", comment)) comment_exists=true; - if (rule.lookupValue("error_msg", username)) error_msg_exists=true; //if (user.lookupValue("default_schema", default_schema)==false) default_schema=""; int query_len=0; @@ -5073,6 +5082,7 @@ int ProxySQL_Admin::Read_MySQL_Query_Rules_from_configfile() { strlen(std::to_string(retries).c_str()) + 4 + strlen(std::to_string(delay).c_str()) + 4 + ( error_msg_exists ? strlen(error_msg.c_str()) : 0 ) + 4 + + ( OK_msg_exists ? strlen(OK_msg.c_str()) : 0 ) + 4 + strlen(std::to_string(sticky_conn).c_str()) + 4 + strlen(std::to_string(multiplex).c_str()) + 4 + strlen(std::to_string(log).c_str()) + 4 + @@ -5118,6 +5128,10 @@ int ProxySQL_Admin::Read_MySQL_Query_Rules_from_configfile() { error_msg="\"" + error_msg + "\""; else error_msg = "NULL"; + if (OK_msg_exists) + OK_msg="\"" + OK_msg + "\""; + else + OK_msg = "NULL"; if (re_modifiers_exists) re_modifiers="\"" + re_modifiers + "\""; else @@ -5153,6 +5167,7 @@ int ProxySQL_Admin::Read_MySQL_Query_Rules_from_configfile() { ( mirror_flagOUT >= 0 ? std::to_string(mirror_flagOUT).c_str() : "NULL") , ( mirror_hostgroup >= 0 ? std::to_string(mirror_hostgroup).c_str() : "NULL") , error_msg.c_str(), + OK_msg.c_str(), ( sticky_conn >= 0 ? std::to_string(sticky_conn).c_str() : "NULL") , ( multiplex >= 0 ? std::to_string(multiplex).c_str() : "NULL") , ( log >= 0 ? std::to_string(log).c_str() : "NULL") , @@ -5375,13 +5390,27 @@ void ProxySQL_Admin::disk_upgrade_mysql_query_rules() { // drop any existing table with suffix _v140a configdb->execute("DROP TABLE IF EXISTS mysql_query_rules_v140a"); // rename current table to add suffix _v140a - configdb->execute("ALTER TABLE mysql_query_rules RENAME TO mysql_query_rules_v40b"); + configdb->execute("ALTER TABLE mysql_query_rules RENAME TO mysql_query_rules_v40a"); // create new table configdb->build_table((char *)"mysql_query_rules",(char *)ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES,false); // copy fields from old table - configdb->execute("INSERT INTO mysql_query_rules (rule_id,active,username,schemaname,flagIN,client_addr,proxy_addr,proxy_port,digest,match_digest,match_pattern,negate_match_pattern,re_modifiers,flagOUT,replace_pattern,destination_hostgroup,cache_ttl,reconnect,timeout,retries,delay,mirror_flagOUT,mirror_hostgroup,error_msg,sticky_conn,multiplex,log,apply,comment) SELECT rule_id,active,username,schemaname,flagIN,client_addr,proxy_addr,proxy_port,digest,match_digest,match_pattern,negate_match_pattern,re_modifiersmflagOUT,replace_pattern,destination_hostgroup,cache_ttl,reconnect,timeout,retries,delay,mirror_flagOUT,mirror_hostgroup,error_msg,sticky_conn,multiplex,log,apply,comment FROM mysql_query_rules_v140a"); + configdb->execute("INSERT INTO mysql_query_rules (rule_id,active,username,schemaname,flagIN,client_addr,proxy_addr,proxy_port,digest,match_digest,match_pattern,negate_match_pattern,re_modifiers,flagOUT,replace_pattern,destination_hostgroup,cache_ttl,reconnect,timeout,retries,delay,mirror_flagOUT,mirror_hostgroup,error_msg,sticky_conn,multiplex,log,apply,comment) SELECT rule_id,active,username,schemaname,flagIN,client_addr,proxy_addr,proxy_port,digest,match_digest,match_pattern,negate_match_pattern,re_modifiers,flagOUT,replace_pattern,destination_hostgroup,cache_ttl,reconnect,timeout,retries,delay,mirror_flagOUT,mirror_hostgroup,error_msg,sticky_conn,multiplex,log,apply,comment FROM mysql_query_rules_v140a"); } + rci=configdb->check_table_structure((char *)"mysql_query_rules",(char *)ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_V1_4_0b); + if (rci) { // note: upgrade from V1_4_0a or V1_4_0b is the same + // upgrade is required + proxy_warning("Detected version v1.4.0b of table mysql_query_rules\n"); + proxy_warning("ONLINE UPGRADE of table mysql_query_rules in progress\n"); + // drop any existing table with suffix _v140a + configdb->execute("DROP TABLE IF EXISTS mysql_query_rules_v140b"); + // rename current table to add suffix _v140a + configdb->execute("ALTER TABLE mysql_query_rules RENAME TO mysql_query_rules_v140b"); + // create new table + configdb->build_table((char *)"mysql_query_rules",(char *)ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES,false); + // copy fields from old table + configdb->execute("INSERT INTO mysql_query_rules (rule_id,active,username,schemaname,flagIN,client_addr,proxy_addr,proxy_port,digest,match_digest,match_pattern,negate_match_pattern,re_modifiers,flagOUT,replace_pattern,destination_hostgroup,cache_ttl,reconnect,timeout,retries,delay,mirror_flagOUT,mirror_hostgroup,error_msg,sticky_conn,multiplex,log,apply,comment) SELECT rule_id,active,username,schemaname,flagIN,client_addr,proxy_addr,proxy_port,digest,match_digest,match_pattern,negate_match_pattern,re_modifiers,flagOUT,replace_pattern,destination_hostgroup,cache_ttl,reconnect,timeout,retries,delay,mirror_flagOUT,mirror_hostgroup,error_msg,sticky_conn,multiplex,log,apply,comment FROM mysql_query_rules_v140b"); + } configdb->execute("PRAGMA foreign_keys = ON"); } diff --git a/lib/Query_Processor.cpp b/lib/Query_Processor.cpp index 2e961424d6..d0207395a6 100644 --- a/lib/Query_Processor.cpp +++ b/lib/Query_Processor.cpp @@ -42,7 +42,7 @@ class QP_rule_text { char **pta; int num_fields; QP_rule_text(QP_rule_t *QPr) { - num_fields=31; + num_fields=32; // this count the number of fields pta=NULL; pta=(char **)malloc(sizeof(char *)*num_fields); itostr(pta[0], (long long)QPr->rule_id); @@ -88,12 +88,13 @@ class QP_rule_text { itostr(pta[22], (long long)QPr->mirror_flagOUT); itostr(pta[23], (long long)QPr->mirror_hostgroup); pta[24]=strdup_null(QPr->error_msg); - itostr(pta[25], (long long)QPr->sticky_conn); - itostr(pta[26], (long long)QPr->multiplex); - itostr(pta[27], (long long)QPr->log); - itostr(pta[28], (long long)QPr->apply); - pta[29]=strdup_null(QPr->comment); // issue #643 - itostr(pta[30], (long long)QPr->hits); + pta[25]=strdup_null(QPr->OK_msg); + itostr(pta[26], (long long)QPr->sticky_conn); + itostr(pta[27], (long long)QPr->multiplex); + itostr(pta[28], (long long)QPr->log); + itostr(pta[29], (long long)QPr->apply); + pta[30]=strdup_null(QPr->comment); // issue #643 + itostr(pta[31], (long long)QPr->hits); } ~QP_rule_text() { for(int i=0; ireplace_pattern); if (qr->error_msg) free(qr->error_msg); + if (qr->OK_msg) + free(qr->OK_msg); if (qr->regex_engine1) { re2_t *r=(re2_t *)qr->regex_engine1; if (r->opt1) { delete r->opt1; r->opt1=NULL; } @@ -420,7 +423,7 @@ void Query_Processor::wrunlock() { #endif }; -QP_rule_t * Query_Processor::new_query_rule(int rule_id, bool active, char *username, char *schemaname, int flagIN, char *client_addr, char *proxy_addr, int proxy_port, char *digest, char *match_digest, char *match_pattern, bool negate_match_pattern, char *re_modifiers, int flagOUT, char *replace_pattern, int destination_hostgroup, int cache_ttl, int reconnect, int timeout, int retries, int delay, int next_query_flagIN, int mirror_flagOUT, int mirror_hostgroup, char *error_msg, int sticky_conn, int multiplex, int log, bool apply, char *comment) { +QP_rule_t * Query_Processor::new_query_rule(int rule_id, bool active, char *username, char *schemaname, int flagIN, char *client_addr, char *proxy_addr, int proxy_port, char *digest, char *match_digest, char *match_pattern, bool negate_match_pattern, char *re_modifiers, int flagOUT, char *replace_pattern, int destination_hostgroup, int cache_ttl, int reconnect, int timeout, int retries, int delay, int next_query_flagIN, int mirror_flagOUT, int mirror_hostgroup, char *error_msg, char *OK_msg, int sticky_conn, int multiplex, int log, bool apply, char *comment) { QP_rule_t * newQR=(QP_rule_t *)malloc(sizeof(QP_rule_t)); newQR->rule_id=rule_id; newQR->active=active; @@ -456,6 +459,7 @@ QP_rule_t * Query_Processor::new_query_rule(int rule_id, bool active, char *user newQR->mirror_flagOUT=mirror_flagOUT; newQR->mirror_hostgroup=mirror_hostgroup; newQR->error_msg=(error_msg ? strdup(error_msg) : NULL); + newQR->OK_msg=(OK_msg ? strdup(OK_msg) : NULL); newQR->sticky_conn=sticky_conn; newQR->multiplex=multiplex; newQR->apply=apply; @@ -641,6 +645,7 @@ SQLite3_result * Query_Processor::get_current_query_rules() { result->add_column_definition(SQLITE_TEXT,"mirror_flagOUT"); result->add_column_definition(SQLITE_TEXT,"mirror_hostgroup"); result->add_column_definition(SQLITE_TEXT,"error_msg"); + result->add_column_definition(SQLITE_TEXT,"OK_msg"); result->add_column_definition(SQLITE_TEXT,"sticky_conn"); result->add_column_definition(SQLITE_TEXT,"multiplex"); result->add_column_definition(SQLITE_TEXT,"log"); @@ -785,7 +790,7 @@ Query_Processor_Output * Query_Processor::process_mysql_query(MySQL_Session *ses qr1->match_digest, qr1->match_pattern, qr1->negate_match_pattern, (char *)re_mod.c_str(), qr1->flagOUT, qr1->replace_pattern, qr1->destination_hostgroup, qr1->cache_ttl, qr1->reconnect, qr1->timeout, qr1->retries, qr1->delay, qr1->next_query_flagIN, qr1->mirror_flagOUT, qr1->mirror_hostgroup, - qr1->error_msg, qr1->sticky_conn, qr1->multiplex, qr1->log, qr1->apply, + qr1->error_msg, qr1->OK_msg, qr1->sticky_conn, qr1->multiplex, qr1->log, qr1->apply, qr1->comment); qr2->parent=qr1; // pointer to parent to speed up parent update (hits) if (qr2->match_digest) { @@ -977,6 +982,11 @@ Query_Processor_Output * Query_Processor::process_mysql_query(MySQL_Session *ses //proxy_warning("User \"%s\" has issued query that has been filtered: %s \n " , sess->client_myds->myconn->userinfo->username, query); ret->error_msg=strdup(qr->error_msg); } + if (qr->OK_msg) { + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "query rule %d has set error_msg: %s\n", qr->rule_id, qr->OK_msg); + //proxy_warning("User \"%s\" has issued query that has been filtered: %s \n " , sess->client_myds->myconn->userinfo->username, query); + ret->OK_msg=strdup(qr->OK_msg); + } if (qr->cache_ttl >= 0) { // Note: negative TTL means this rule doesn't change proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "query rule %d has set cache_ttl: %d. Query will%s hit the cache\n", qr->rule_id, qr->cache_ttl, (qr->cache_ttl == 0 ? " NOT" : "" ));