diff --git a/include/proxysql_admin.h b/include/proxysql_admin.h index b838d4005..840d65124 100644 --- a/include/proxysql_admin.h +++ b/include/proxysql_admin.h @@ -9,7 +9,7 @@ #include "ProxySQL_RESTAPI_Server.hpp" typedef struct { uint32_t hash; uint32_t key; } t_symstruct; - +class ProxySQL_Config; class Scheduler_Row { public: @@ -269,20 +269,7 @@ class ProxySQL_Admin { void stats___mysql_prepared_statements_info(); void stats___mysql_gtid_executed(); - int Read_Global_Variables_from_configfile(const char *prefix); - int Read_MySQL_Users_from_configfile(); - int Read_MySQL_Query_Rules_from_configfile(); - int Read_MySQL_Servers_from_configfile(); - int Read_Scheduler_from_configfile(); - int Read_ProxySQL_Servers_from_configfile(); - - void addField(std::string& data, const char* name, const char* value, const char* dq="\""); - int Write_Global_Variables_to_configfile(std::string& data); - int Write_MySQL_Users_to_configfile(std::string& data); - int Write_MySQL_Query_Rules_to_configfile(std::string& data); - int Write_MySQL_Servers_to_configfile(std::string& data); - int Write_Scheduler_to_configfile(std::string& data); - int Write_ProxySQL_Servers_to_configfile(std::string& data); + ProxySQL_Config& proxysql_config(); void flush_error_log(); bool GenericRefreshStatistics(const char *query_no_space, unsigned int query_no_space_length, bool admin); diff --git a/include/proxysql_config.h b/include/proxysql_config.h new file mode 100644 index 000000000..1c88f9144 --- /dev/null +++ b/include/proxysql_config.h @@ -0,0 +1,30 @@ +#ifndef __PROXYSQL_CONFIG_H__ +#define __PROXYSQL_CONFIG_H__ + +#include + +class SQLite3DB; + +class ProxySQL_Config { + SQLite3DB* admindb; +public: + ProxySQL_Config(SQLite3DB* db); + virtual ~ProxySQL_Config(); + + int Read_Global_Variables_from_configfile(const char *prefix); + int Read_MySQL_Users_from_configfile(); + int Read_MySQL_Query_Rules_from_configfile(); + int Read_MySQL_Servers_from_configfile(); + int Read_Scheduler_from_configfile(); + int Read_ProxySQL_Servers_from_configfile(); + + void addField(std::string& data, const char* name, const char* value, const char* dq="\""); + int Write_Global_Variables_to_configfile(std::string& data); + int Write_MySQL_Users_to_configfile(std::string& data); + int Write_MySQL_Query_Rules_to_configfile(std::string& data); + int Write_MySQL_Servers_to_configfile(std::string& data); + int Write_Scheduler_to_configfile(std::string& data); + int Write_ProxySQL_Servers_to_configfile(std::string& data); +}; + +#endif diff --git a/lib/Makefile b/lib/Makefile index fd38ed041..2159404d5 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -95,7 +95,7 @@ default: libproxysql.a _OBJ = c_tokenizer.o OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ)) -_OBJ_CXX = ProxySQL_GloVars.oo network.oo debug.oo configfile.oo Query_Cache.oo SpookyV2.oo MySQL_Authentication.oo gen_utils.oo sqlite3db.oo mysql_connection.oo MySQL_HostGroups_Manager.oo mysql_data_stream.oo MySQL_Thread.oo MySQL_Session.oo MySQL_Protocol.oo mysql_backend.oo Query_Processor.oo ProxySQL_Admin.oo MySQL_Monitor.oo MySQL_Logger.oo thread.oo MySQL_PreparedStatement.oo ProxySQL_Cluster.oo SQLite3_Server.oo ClickHouse_Authentication.oo ClickHouse_Server.oo ProxySQL_Statistics.oo Chart_bundle_js.oo ProxySQL_HTTP_Server.oo ProxySQL_RESTAPI_Server.oo font-awesome.min.css.oo main-bundle.min.css.oo set_parser.oo +_OBJ_CXX = ProxySQL_GloVars.oo network.oo debug.oo configfile.oo Query_Cache.oo SpookyV2.oo MySQL_Authentication.oo gen_utils.oo sqlite3db.oo mysql_connection.oo MySQL_HostGroups_Manager.oo mysql_data_stream.oo MySQL_Thread.oo MySQL_Session.oo MySQL_Protocol.oo mysql_backend.oo Query_Processor.oo ProxySQL_Admin.oo ProxySQL_Config.oo MySQL_Monitor.oo MySQL_Logger.oo thread.oo MySQL_PreparedStatement.oo ProxySQL_Cluster.oo SQLite3_Server.oo ClickHouse_Authentication.oo ClickHouse_Server.oo ProxySQL_Statistics.oo Chart_bundle_js.oo ProxySQL_HTTP_Server.oo ProxySQL_RESTAPI_Server.oo font-awesome.min.css.oo main-bundle.min.css.oo set_parser.oo OBJ_CXX = $(patsubst %,$(ODIR)/%,$(_OBJ_CXX)) HEADERS = ../include/*.h ../include/*.hpp diff --git a/lib/ProxySQL_Admin.cpp b/lib/ProxySQL_Admin.cpp index f687abd6e..1b962e42f 100644 --- a/lib/ProxySQL_Admin.cpp +++ b/lib/ProxySQL_Admin.cpp @@ -5,6 +5,7 @@ #include "re2/re2.h" #include "re2/regexp.h" #include "proxysql.h" +#include "proxysql_config.h" #include "cpp.h" #include "MySQL_Data_Stream.h" @@ -583,6 +584,11 @@ int ProxySQL_Test___GetDigestTable(bool reset, bool use_swap) { return r; } +ProxySQL_Config& ProxySQL_Admin::proxysql_config() { + static ProxySQL_Config instance = ProxySQL_Config(admindb); + return instance; +} + int ProxySQL_Admin::FlushDigestTableToDisk(SQLite3DB *_db) { int r = 0; if (!GloQPro) return 0; @@ -1373,7 +1379,7 @@ bool admin_handler_command_load_or_save(char *query_no_space, unsigned int query if (GloVars.confFile->OpenFile(NULL)==true) { ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; int rows=0; - rows=SPA->Read_Scheduler_from_configfile(); + rows=SPA->proxysql_config().Read_Scheduler_from_configfile(); proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded scheduler from CONFIG\n"); SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL, rows); GloVars.confFile->CloseFile(); @@ -1592,7 +1598,7 @@ bool admin_handler_command_load_or_save(char *query_no_space, unsigned int query if (GloVars.confFile->OpenFile(NULL)==true) { ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; int rows=0; - rows=SPA->Read_MySQL_Users_from_configfile(); + rows=SPA->proxysql_config().Read_MySQL_Users_from_configfile(); proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded mysql users from CONFIG\n"); SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL, rows); GloVars.confFile->CloseFile(); @@ -1970,7 +1976,7 @@ bool admin_handler_command_load_or_save(char *query_no_space, unsigned int query if (GloVars.confFile->OpenFile(NULL)==true) { int rows=0; ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; - rows=SPA->Read_Global_Variables_from_configfile("mysql"); + rows=SPA->proxysql_config().Read_Global_Variables_from_configfile("mysql"); proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded mysql variables from CONFIG\n"); SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL, rows); GloVars.confFile->CloseFile(); @@ -2068,7 +2074,7 @@ bool admin_handler_command_load_or_save(char *query_no_space, unsigned int query if (GloVars.confFile->OpenFile(NULL)==true) { ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; int rows=0; - rows=SPA->Read_MySQL_Servers_from_configfile(); + rows=SPA->proxysql_config().Read_MySQL_Servers_from_configfile(); proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded mysql servers from CONFIG\n"); SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL, rows); GloVars.confFile->CloseFile(); @@ -2184,7 +2190,7 @@ bool admin_handler_command_load_or_save(char *query_no_space, unsigned int query if (GloVars.confFile->OpenFile(NULL)==true) { ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; int rows=0; - rows=SPA->Read_ProxySQL_Servers_from_configfile(); + rows=SPA->proxysql_config().Read_ProxySQL_Servers_from_configfile(); proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded ProxySQL servers from CONFIG\n"); SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL, rows); GloVars.confFile->CloseFile(); @@ -2331,7 +2337,7 @@ bool admin_handler_command_load_or_save(char *query_no_space, unsigned int query if (GloVars.confFile->OpenFile(NULL)==true) { ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; int rows=0; - rows=SPA->Read_MySQL_Query_Rules_from_configfile(); + rows=SPA->proxysql_config().Read_MySQL_Query_Rules_from_configfile(); proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded mysql query rules from CONFIG\n"); SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL, rows); GloVars.confFile->CloseFile(); @@ -2461,7 +2467,7 @@ bool admin_handler_command_load_or_save(char *query_no_space, unsigned int query if (GloVars.confFile->OpenFile(NULL)==true) { int rows=0; ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; - rows=SPA->Read_Global_Variables_from_configfile("admin"); + rows=SPA->proxysql_config().Read_Global_Variables_from_configfile("admin"); proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded admin variables from CONFIG\n"); SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL, rows); GloVars.confFile->CloseFile(); @@ -3820,12 +3826,12 @@ void admin_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *pkt) { std::string data; data.reserve(100000); data += config_header; - int rc = pa->Write_Global_Variables_to_configfile(data); - rc = pa->Write_MySQL_Users_to_configfile(data); - rc = pa->Write_MySQL_Query_Rules_to_configfile(data); - rc = pa->Write_MySQL_Servers_to_configfile(data); - rc = pa->Write_Scheduler_to_configfile(data); - rc = pa->Write_ProxySQL_Servers_to_configfile(data); + int rc = pa->proxysql_config().Write_Global_Variables_to_configfile(data); + rc = pa->proxysql_config().Write_MySQL_Users_to_configfile(data); + rc = pa->proxysql_config().Write_MySQL_Query_Rules_to_configfile(data); + rc = pa->proxysql_config().Write_MySQL_Servers_to_configfile(data); + rc = pa->proxysql_config().Write_Scheduler_to_configfile(data); + rc = pa->proxysql_config().Write_ProxySQL_Servers_to_configfile(data); if (rc) { std::stringstream ss; ss << "ProxySQL Admin Error: Cannot extract configuration"; @@ -3859,12 +3865,12 @@ void admin_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *pkt) { std::string data; data.reserve(100000); data += config_header; - int rc = pa->Write_Global_Variables_to_configfile(data); - rc = pa->Write_MySQL_Users_to_configfile(data); - rc = pa->Write_MySQL_Query_Rules_to_configfile(data); - rc = pa->Write_MySQL_Servers_to_configfile(data); - rc = pa->Write_Scheduler_to_configfile(data); - rc = pa->Write_ProxySQL_Servers_to_configfile(data); + int rc = pa->proxysql_config().Write_Global_Variables_to_configfile(data); + rc = pa->proxysql_config().Write_MySQL_Users_to_configfile(data); + rc = pa->proxysql_config().Write_MySQL_Query_Rules_to_configfile(data); + rc = pa->proxysql_config().Write_MySQL_Servers_to_configfile(data); + rc = pa->proxysql_config().Write_Scheduler_to_configfile(data); + rc = pa->proxysql_config().Write_ProxySQL_Servers_to_configfile(data); if (rc) { std::stringstream ss; ss << "ProxySQL Admin Error: Cannot write proxysql.cnf"; @@ -4899,13 +4905,13 @@ bool ProxySQL_Admin::init() { if (GloVars.__cmd_proxysql_reload || GloVars.__cmd_proxysql_initial || admindb_file_exists==false) { // see #617 if (GloVars.configfile_open) { - Read_MySQL_Servers_from_configfile(); - Read_MySQL_Users_from_configfile(); - Read_MySQL_Query_Rules_from_configfile(); - Read_Global_Variables_from_configfile("admin"); - Read_Global_Variables_from_configfile("mysql"); - Read_Scheduler_from_configfile(); - Read_ProxySQL_Servers_from_configfile(); + proxysql_config().Read_MySQL_Servers_from_configfile(); + proxysql_config().Read_MySQL_Users_from_configfile(); + proxysql_config().Read_MySQL_Query_Rules_from_configfile(); + proxysql_config().Read_Global_Variables_from_configfile("admin"); + proxysql_config().Read_Global_Variables_from_configfile("mysql"); + proxysql_config().Read_Scheduler_from_configfile(); + proxysql_config().Read_ProxySQL_Servers_from_configfile(); __insert_or_replace_disktable_select_maintable(); } } @@ -9771,1196 +9777,6 @@ char * ProxySQL_Admin::load_mysql_query_rules_to_runtime() { return NULL; } -void ProxySQL_Admin::addField(std::string& data, const char* name, const char* value, const char* dq) { - std::stringstream ss; - if (!value || !strlen(value)) return; - ss << "\t\t" << name << "=" << dq << value << dq << "\n"; - data += ss.str(); -} - -int ProxySQL_Admin::Write_Global_Variables_to_configfile(std::string& data) { - char* error = NULL; - int cols = 0; - int affected_rows = 0; - SQLite3_result* sqlite_resultset = NULL; - - char *query=(char *)"SELECT variable_name, variable_value FROM global_variables ORDER BY variable_name"; - admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); - if (error) { - proxy_error("Error on read from global_variables : %s\n", error); - return -1; - } else { - if (sqlite_resultset) { - std::string prefix; - - for (auto r : sqlite_resultset->rows) { - std::string input(r->fields[0]); - std::string p1 = input.substr(0, input.find("-")); - if (prefix.empty()) { - prefix = input.substr(0, input.find("-")); - data += prefix + "_variables =\n{\n"; - } else { - if (p1.compare(prefix)) { - prefix = p1; - data += "}\n\n" + prefix + "_variables = \n{\n"; - } - } - if (r->fields[1] && strlen(r->fields[1])) { - std::stringstream ss; - ss << "\t" << r->fields[0] + p1.size() + 1 << "=\"" << r->fields[1] << "\"\n"; - data += ss.str(); - } - } - - if (!prefix.empty()) - data += "}\n"; - } - } - - if (sqlite_resultset) - delete sqlite_resultset; - - return 0; -} - -int ProxySQL_Admin::Read_Global_Variables_from_configfile(const char *prefix) { - const Setting& root = GloVars.confFile->cfg.getRoot(); - char *groupname=(char *)malloc(strlen(prefix)+strlen((char *)"_variables")+1); - sprintf(groupname,"%s%s",prefix,"_variables"); - if (root.exists(groupname)==false) { - free(groupname); - return 0; - } - const Setting &group = root[(const char *)groupname]; - int count = group.getLength(); - //fprintf(stderr, "Found %d %s_variables\n",count, prefix); - int i; - admindb->execute("PRAGMA foreign_keys = OFF"); - char *q=(char *)"INSERT OR REPLACE INTO global_variables VALUES (\"%s-%s\", \"%s\")"; - for (i=0; i< count; i++) { - const Setting &sett = group[i]; - const char *n=sett.getName(); - bool value_bool; - int value_int; - std::string value_string=""; - if (group.lookupValue(n, value_bool)) { - value_string = (value_bool ? "true" : "false"); - } else { - if (group.lookupValue(n, value_int)) { - value_string = std::to_string(value_int); - } else { - group.lookupValue(n, value_string); - } - } - //fprintf(stderr,"%s = %s\n", n, value_string.c_str()); - char *query=(char *)malloc(strlen(q)+strlen(prefix)+strlen(n)+strlen(value_string.c_str())); - sprintf(query,q, prefix, n, value_string.c_str()); - //fprintf(stderr, "%s\n", query); - admindb->execute(query); - free(query); - } - admindb->execute("PRAGMA foreign_keys = ON"); - free(groupname); - return i; -} - -int ProxySQL_Admin::Write_MySQL_Users_to_configfile(std::string& data) { - char* error = NULL; - int cols = 0; - int affected_rows = 0; - SQLite3_result* sqlite_resultset = NULL; - - char *query=(char *)"SELECT * FROM mysql_users"; - admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); - if (error) { - proxy_error("Error on read from mysql_users: %s\n", error); - return -1; - } else { - if (sqlite_resultset) { - data += "mysql_users:\n(\n"; - bool isNext = false; - for (auto r : sqlite_resultset->rows) { - if (isNext) - data += ",\n"; - data += "\t{\n"; - addField(data, "username", r->fields[0]); - addField(data, "password", r->fields[1]); - addField(data, "active", r->fields[2], ""); - addField(data, "use_ssl", r->fields[3], ""); - addField(data, "default_hostgroup", r->fields[4], ""); - addField(data, "default_schema", r->fields[5]); - addField(data, "schema_locked", r->fields[6], ""); - addField(data, "transaction_persistent", r->fields[7], ""); - addField(data, "fast_forward", r->fields[8], ""); - addField(data, "backend", r->fields[9], ""); - addField(data, "frontend", r->fields[10], ""); - addField(data, "max_connections", r->fields[11], ""); - addField(data, "comment", r->fields[12]); - data += "\t}"; - isNext = true; - } - data += "\n)\n"; - } - } - - if (sqlite_resultset) - delete sqlite_resultset; - - return 0; -} - -int ProxySQL_Admin::Read_MySQL_Users_from_configfile() { - const Setting& root = GloVars.confFile->cfg.getRoot(); - if (root.exists("mysql_users")==false) return 0; - const Setting &mysql_users = root["mysql_users"]; - int count = mysql_users.getLength(); - //fprintf(stderr, "Found %d users\n",count); - int i; - int rows=0; - admindb->execute("PRAGMA foreign_keys = OFF"); - char *q=(char *)"INSERT OR REPLACE INTO mysql_users (username, password, active, use_ssl, default_hostgroup, default_schema, schema_locked, transaction_persistent, fast_forward, max_connections, comment) VALUES ('%s', '%s', %d, %d, %d, '%s', %d, %d, %d, %d, '%s')"; - for (i=0; i< count; i++) { - const Setting &user = mysql_users[i]; - std::string username; - std::string password=""; - int active=1; - int use_ssl=0; - int default_hostgroup=0; - std::string default_schema=""; - int schema_locked=0; - int transaction_persistent=1; - int fast_forward=0; - int max_connections=10000; - std::string comment=""; - if (user.lookupValue("username", username)==false) { - proxy_error("Admin: detected a mysql_users in config file without a mandatory username\n"); - continue; - } - user.lookupValue("password", password); - user.lookupValue("default_hostgroup", default_hostgroup); - user.lookupValue("active", active); - user.lookupValue("use_ssl", use_ssl); - //if (user.lookupValue("default_schema", default_schema)==false) default_schema=""; - user.lookupValue("default_schema", default_schema); - user.lookupValue("schema_locked", schema_locked); - user.lookupValue("transaction_persistent", transaction_persistent); - user.lookupValue("fast_forward", fast_forward); - user.lookupValue("max_connections", max_connections); - user.lookupValue("comment", comment); - char *o1=strdup(comment.c_str()); - char *o=escape_string_single_quotes(o1, false); - char *query=(char *)malloc(strlen(q)+strlen(username.c_str())+strlen(password.c_str())+strlen(o)+128); - sprintf(query,q, username.c_str(), password.c_str(), active, use_ssl, default_hostgroup, default_schema.c_str(), schema_locked, transaction_persistent, fast_forward, max_connections, o); - admindb->execute(query); - if (o!=o1) free(o); - free(o1); - free(query); - rows++; - } - admindb->execute("PRAGMA foreign_keys = ON"); - return rows; -} - -int ProxySQL_Admin::Write_Scheduler_to_configfile(std::string& data) { - char* error = NULL; - int cols = 0; - int affected_rows = 0; - SQLite3_result* sqlite_resultset = NULL; - - char *query=(char *)"SELECT * FROM scheduler"; - admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); - if (error) { - proxy_error("Error on read from scheduler: %s\n", error); - return -1; - } else { - if (sqlite_resultset) { - data += "scheduler:\n(\n"; - bool isNext = false; - for (auto r : sqlite_resultset->rows) { - if (isNext) - data += ",\n"; - data += "\t{\n"; - addField(data, "id", r->fields[0], ""); - addField(data, "active", r->fields[1], ""); - addField(data, "interval_ms", r->fields[2], ""); - addField(data, "filename", r->fields[3]); - addField(data, "arg1", r->fields[4]); - addField(data, "arg2", r->fields[5]); - addField(data, "arg3", r->fields[6]); - addField(data, "arg4", r->fields[7]); - addField(data, "arg5", r->fields[8]); - addField(data, "comment", r->fields[9]); - - data += "\t}"; - isNext = true; - } - data += "\n)\n"; - } - } - - if (sqlite_resultset) - delete sqlite_resultset; - - return 0; -} - -int ProxySQL_Admin::Read_Scheduler_from_configfile() { - const Setting& root = GloVars.confFile->cfg.getRoot(); - if (root.exists("scheduler")==false) return 0; - const Setting &schedulers = root["scheduler"]; - int count = schedulers.getLength(); - //fprintf(stderr, "Found %d users\n",count); - int i; - int rows=0; - admindb->execute("PRAGMA foreign_keys = OFF"); - char *q=(char *)"INSERT OR REPLACE INTO scheduler (id, active, interval_ms, filename, arg1, arg2, arg3, arg4, arg5, comment) VALUES (%d, %d, %d, '%s', %s, %s, %s, %s, %s, '%s')"; - for (i=0; i< count; i++) { - const Setting &sched = schedulers[i]; - int id; - int active=1; - - std::string filename; - - bool arg1_exists=false; - std::string arg1; - bool arg2_exists=false; - std::string arg2; - bool arg3_exists=false; - std::string arg3; - bool arg4_exists=false; - std::string arg4; - bool arg5_exists=false; - std::string arg5; - - // variable for parsing interval_ms - int interval_ms=0; - - std::string comment=""; - - // validate arguments - if (sched.lookupValue("id", id)==false) { - proxy_error("Admin: detected a scheduler in config file without a mandatory id\n"); - continue; - } - sched.lookupValue("active", active); - sched.lookupValue("interval_ms", interval_ms); - if (sched.lookupValue("filename", filename)==false) { - proxy_error("Admin: detected a scheduler in config file without a mandatory filename\n"); - continue; - } - if (sched.lookupValue("arg1", arg1)) arg1_exists=true; - if (sched.lookupValue("arg2", arg2)) arg2_exists=true; - if (sched.lookupValue("arg3", arg3)) arg3_exists=true; - if (sched.lookupValue("arg4", arg4)) arg4_exists=true; - if (sched.lookupValue("arg5", arg5)) arg5_exists=true; - sched.lookupValue("comment", comment); - - - int query_len=0; - query_len+=strlen(q) + - strlen(std::to_string(id).c_str()) + - strlen(std::to_string(active).c_str()) + - strlen(std::to_string(interval_ms).c_str()) + - strlen(filename.c_str()) + - ( arg1_exists ? strlen(arg1.c_str()) : 0 ) + 4 + - ( arg2_exists ? strlen(arg2.c_str()) : 0 ) + 4 + - ( arg3_exists ? strlen(arg3.c_str()) : 0 ) + 4 + - ( arg4_exists ? strlen(arg4.c_str()) : 0 ) + 4 + - ( arg5_exists ? strlen(arg5.c_str()) : 0 ) + 4 + - strlen(comment.c_str()) + - 40; - char *query=(char *)malloc(query_len); - if (arg1_exists) - arg1="\'" + arg1 + "\'"; - else - arg1 = "NULL"; - if (arg2_exists) - arg2="\'" + arg2 + "\'"; - else - arg2 = "NULL"; - if (arg3_exists) - arg3="\'" + arg3 + "\'"; - else - arg3 = "NULL"; - if (arg4_exists) - arg4="\'" + arg4 + "\'"; - else - arg4 = "NULL"; - if (arg5_exists) - arg5="\'" + arg5 + "\'"; - else - arg5 = "NULL"; - - sprintf(query, q, - id, active, - interval_ms, - filename.c_str(), - arg1.c_str(), - arg2.c_str(), - arg3.c_str(), - arg4.c_str(), - arg5.c_str(), - comment.c_str() - ); - admindb->execute(query); - free(query); - rows++; - } - admindb->execute("PRAGMA foreign_keys = ON"); - return rows; -} - -int ProxySQL_Admin::Write_MySQL_Query_Rules_to_configfile(std::string& data) { - char* error = NULL; - int cols = 0; - int affected_rows = 0; - SQLite3_result* sqlite_resultset = NULL; - - char *query=(char *)"SELECT * FROM mysql_query_rules"; - admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); - if (error) { - proxy_error("Error on read from mysql_query_rules : %s\n", error); - return -1; - } else { - if (sqlite_resultset) { - std::string prefix; - data += "mysql_query_rules:\n(\n"; - bool isNext = false; - for (auto r : sqlite_resultset->rows) { - if (isNext) - data += ",\n"; - data += "\t{\n"; - addField(data, "rule_id", r->fields[0], ""); - addField(data, "active", r->fields[1], ""); - addField(data, "username", r->fields[2]); - addField(data, "schemaname", r->fields[3]); - addField(data, "flagIN", r->fields[4], ""); - addField(data, "client_addr", r->fields[5]); - addField(data, "proxy_addr", r->fields[6]); - addField(data, "proxy_port", r->fields[7], ""); - addField(data, "digest", r->fields[8]); - addField(data, "match_digest", r->fields[9]); - addField(data, "match_pattern", r->fields[10]); - addField(data, "negate_match_pattern", r->fields[11], ""); - addField(data, "re_modifiers", r->fields[12]); - addField(data, "flagOUT", r->fields[13], ""); - addField(data, "replace_pattern", r->fields[14]); - addField(data, "destination_hostgroup", r->fields[15], ""); - addField(data, "cache_ttl", r->fields[16], ""); - addField(data, "cache_empty_result", r->fields[17], ""); - addField(data, "cache_timeout", r->fields[18], ""); - addField(data, "reconnect", r->fields[19], ""); - addField(data, "timeout", r->fields[20], ""); - addField(data, "retries", r->fields[21], ""); - addField(data, "delay", r->fields[22], ""); - addField(data, "next_query_flagIN", r->fields[23], ""); - addField(data, "mirror_flagOUT", r->fields[24], ""); - addField(data, "mirror_hostgroup", r->fields[25], ""); - addField(data, "error_msg", r->fields[26]); - addField(data, "OK_msg", r->fields[27]); - addField(data, "sticky_conn", r->fields[28], ""); - addField(data, "multiplex", r->fields[29], ""); - addField(data, "gtid_from_hostgroup", r->fields[30], ""); - addField(data, "log", r->fields[31], ""); - addField(data, "apply", r->fields[32], ""); - addField(data, "comment", r->fields[33]); - - data += "\t}"; - isNext = true; - } - data += "\n)\n"; - } - } - - if (sqlite_resultset) - delete sqlite_resultset; - - return 0; -} - -int ProxySQL_Admin::Read_MySQL_Query_Rules_from_configfile() { - const Setting& root = GloVars.confFile->cfg.getRoot(); - if (root.exists("mysql_query_rules")==false) return 0; - const Setting &mysql_query_rules = root["mysql_query_rules"]; - int count = mysql_query_rules.getLength(); - //fprintf(stderr, "Found %d users\n",count); - 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, cache_empty_result, cache_timeout, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, ok_msg, sticky_conn, multiplex, gtid_from_hostgroup, 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, %s, %s, %s, %s, %d, %s)"; - for (i=0; i< count; i++) { - const Setting &rule = mysql_query_rules[i]; - int rule_id; - int active=1; - bool username_exists=false; - std::string username; - bool schemaname_exists=false; - std::string schemaname; - int flagIN=0; - - // variables for parsing client_addr - bool client_addr_exists=false; - std::string client_addr; - - // variables for parsing proxy_addr - bool proxy_addr_exists=false; - std::string proxy_addr; - - // variable for parsing proxy_port - int proxy_port=-1; - - // variables for parsing digest - bool digest_exists=false; - std::string digest; - - - bool match_digest_exists=false; - std::string match_digest; - bool match_pattern_exists=false; - std::string match_pattern; - int negate_match_pattern=0; - - bool re_modifiers_exists=false; - std::string re_modifiers; - - int flagOUT=-1; - bool replace_pattern_exists=false; - std::string replace_pattern; - int destination_hostgroup=-1; - int next_query_flagIN=-1; - int mirror_flagOUT=-1; - int mirror_hostgroup=-1; - int cache_ttl=-1; - int cache_empty_result=-1; - int cache_timeout=-1; - int reconnect=-1; - int timeout=-1; - int retries=-1; - 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; - int gtid_from_hostgroup = -1; - - // variable for parsing log - int log=-1; - - int apply=0; - - bool comment_exists=false; - std::string comment; - - // validate arguments - if (rule.lookupValue("rule_id", rule_id)==false) { - proxy_error("Admin: detected a mysql_query_rules in config file without a mandatory rule_id\n"); - continue; - } - rule.lookupValue("active", active); - if (rule.lookupValue("username", username)) username_exists=true; - if (rule.lookupValue("schemaname", schemaname)) schemaname_exists=true; - rule.lookupValue("flagIN", flagIN); - - if (rule.lookupValue("client_addr", client_addr)) client_addr_exists=true; - if (rule.lookupValue("proxy_addr", proxy_addr)) proxy_addr_exists=true; - rule.lookupValue("proxy_port", proxy_port); - if (rule.lookupValue("digest", digest)) digest_exists=true; - - if (rule.lookupValue("match_digest", match_digest)) match_digest_exists=true; - if (rule.lookupValue("match_pattern", match_pattern)) match_pattern_exists=true; - rule.lookupValue("negate_match_pattern", negate_match_pattern); - if (rule.lookupValue("re_modifiers", re_modifiers)) { - } else { - re_modifiers = "CASELESS"; - } - re_modifiers_exists=true; - rule.lookupValue("flagOUT", flagOUT); - if (rule.lookupValue("replace_pattern", replace_pattern)) replace_pattern_exists=true; - rule.lookupValue("destination_hostgroup", destination_hostgroup); - rule.lookupValue("next_query_flagIN", next_query_flagIN); - rule.lookupValue("mirror_flagOUT", mirror_flagOUT); - rule.lookupValue("mirror_hostgroup", mirror_hostgroup); - rule.lookupValue("cache_ttl", cache_ttl); - rule.lookupValue("cache_empty_result", cache_empty_result); - rule.lookupValue("cache_timeout", cache_timeout); - rule.lookupValue("reconnect", reconnect); - rule.lookupValue("timeout", timeout); - rule.lookupValue("retries", retries); - rule.lookupValue("delay", delay); - - 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); - rule.lookupValue("gtid_from_hostgroup", gtid_from_hostgroup); - - rule.lookupValue("log", log); - - rule.lookupValue("apply", apply); - if (rule.lookupValue("comment", comment)) comment_exists=true; - - - //if (user.lookupValue("default_schema", default_schema)==false) default_schema=""; - int query_len=0; - query_len+=strlen(q) + - strlen(std::to_string(rule_id).c_str()) + - strlen(std::to_string(active).c_str()) + - ( username_exists ? strlen(username.c_str()) : 0 ) + 4 + - ( schemaname_exists ? strlen(schemaname.c_str()) : 0 ) + 4 + - strlen(std::to_string(flagIN).c_str()) + 4 + - - ( client_addr_exists ? strlen(client_addr.c_str()) : 0 ) + 4 + - ( proxy_addr_exists ? strlen(proxy_addr.c_str()) : 0 ) + 4 + - strlen(std::to_string(proxy_port).c_str()) + 4 + - - ( match_digest_exists ? strlen(match_digest.c_str()) : 0 ) + 4 + - ( match_pattern_exists ? strlen(match_pattern.c_str()) : 0 ) + 4 + - strlen(std::to_string(negate_match_pattern).c_str()) + 4 + - ( re_modifiers_exists ? strlen(re_modifiers.c_str()) : 0 ) + 4 + - strlen(std::to_string(flagOUT).c_str()) + 4 + - ( replace_pattern_exists ? strlen(replace_pattern.c_str()) : 0 ) + 4 + - strlen(std::to_string(destination_hostgroup).c_str()) + 4 + - strlen(std::to_string(cache_ttl).c_str()) + 4 + - strlen(std::to_string(cache_empty_result).c_str()) + 4 + - strlen(std::to_string(cache_timeout).c_str()) + 4 + - strlen(std::to_string(reconnect).c_str()) + 4 + - strlen(std::to_string(timeout).c_str()) + 4 + - strlen(std::to_string(next_query_flagIN).c_str()) + 4 + - strlen(std::to_string(mirror_flagOUT).c_str()) + 4 + - strlen(std::to_string(mirror_hostgroup).c_str()) + 4 + - 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(gtid_from_hostgroup).c_str()) + 4 + - strlen(std::to_string(log).c_str()) + 4 + - strlen(std::to_string(apply).c_str()) + 4 + - ( comment_exists ? strlen(comment.c_str()) : 0 ) + 4 + - 64; - char *query=(char *)malloc(query_len); - if (username_exists) - username="\"" + username + "\""; - else - username = "NULL"; - if (schemaname_exists) - schemaname="\"" + schemaname + "\""; - else - schemaname = "NULL"; - - if (client_addr_exists) - client_addr="\"" + client_addr + "\""; - else - client_addr = "NULL"; - if (proxy_addr_exists) - proxy_addr="\"" + proxy_addr + "\""; - else - proxy_addr = "NULL"; - if (digest_exists) - digest="\"" + digest + "\""; - else - digest = "NULL"; - - if (match_digest_exists) - match_digest="\"" + match_digest + "\""; - else - match_digest = "NULL"; - if (match_pattern_exists) - match_pattern="\"" + match_pattern + "\""; - else - match_pattern = "NULL"; - if (replace_pattern_exists) - replace_pattern="\"" + replace_pattern + "\""; - else - replace_pattern = "NULL"; - if (error_msg_exists) - 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 - re_modifiers = "NULL"; - if (comment_exists) - comment="\"" + comment + "\""; - else - comment = "NULL"; - - - sprintf(query, q, - rule_id, active, - username.c_str(), - schemaname.c_str(), - ( flagIN >= 0 ? std::to_string(flagIN).c_str() : "NULL") , - client_addr.c_str(), - proxy_addr.c_str(), - ( proxy_port >= 0 ? std::to_string(proxy_port).c_str() : "NULL") , - digest.c_str(), - match_digest.c_str(), - match_pattern.c_str(), - ( negate_match_pattern == 0 ? 0 : 1) , - re_modifiers.c_str(), - ( flagOUT >= 0 ? std::to_string(flagOUT).c_str() : "NULL") , - replace_pattern.c_str(), - ( destination_hostgroup >= 0 ? std::to_string(destination_hostgroup).c_str() : "NULL") , - ( cache_ttl >= 0 ? std::to_string(cache_ttl).c_str() : "NULL") , - ( cache_empty_result >= 0 ? std::to_string(cache_empty_result).c_str() : "NULL") , - ( cache_timeout >= 0 ? std::to_string(cache_timeout).c_str() : "NULL") , - ( reconnect >= 0 ? std::to_string(reconnect).c_str() : "NULL") , - ( timeout >= 0 ? std::to_string(timeout).c_str() : "NULL") , - ( retries >= 0 ? std::to_string(retries).c_str() : "NULL") , - ( delay >= 0 ? std::to_string(delay).c_str() : "NULL") , - ( next_query_flagIN >= 0 ? std::to_string(next_query_flagIN).c_str() : "NULL") , - ( 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") , - ( gtid_from_hostgroup >= 0 ? std::to_string(gtid_from_hostgroup).c_str() : "NULL") , - ( log >= 0 ? std::to_string(log).c_str() : "NULL") , - ( apply == 0 ? 0 : 1) , - comment.c_str() - ); - //fprintf(stderr, "%s\n", query); - admindb->execute(query); - free(query); - rows++; - } - admindb->execute("PRAGMA foreign_keys = ON"); - return rows; -} - -int ProxySQL_Admin::Write_MySQL_Servers_to_configfile(std::string& data) { - char* error = NULL; - int cols = 0; - int affected_rows = 0; - SQLite3_result* sqlite_resultset = NULL; - - char *query=(char *)"SELECT * FROM mysql_servers"; - admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); - if (error) { - proxy_error("Error on read from mysql_query_rules : %s\n", error); - return -1; - } else { - if (sqlite_resultset) { - data += "mysql_servers:\n(\n"; - bool isNext = false; - for (auto r : sqlite_resultset->rows) { - if (isNext) - data += ",\n"; - data += "\t{\n"; - addField(data, "hostgroup_id", r->fields[0], ""); - addField(data, "hostname", r->fields[1]); - addField(data, "port", r->fields[2], ""); - addField(data, "gtid_port", r->fields[3], ""); - addField(data, "status", r->fields[4]); - addField(data, "weight", r->fields[5], ""); - addField(data, "compression", r->fields[6], ""); - addField(data, "max_connections", r->fields[7], ""); - addField(data, "max_replication_lag", r->fields[8], ""); - addField(data, "use_ssl", r->fields[9], ""); - addField(data, "max_latency_ms", r->fields[10], ""); - addField(data, "comment", r->fields[11]); - - data += "\t}"; - isNext = true; - } - data += "\n)\n"; - } - } - - if (sqlite_resultset) - delete sqlite_resultset; - - query=(char *)"SELECT * FROM mysql_replication_hostgroups"; - admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); - if (error) { - proxy_error("Error on read from mysql_replication_hostgroups : %s\n", error); - return -1; - } else { - if (sqlite_resultset) { - data += "mysql_replication_hostgroups:\n(\n"; - bool isNext = false; - for (auto r : sqlite_resultset->rows) { - if (isNext) - data += ",\n"; - data += "\t{\n"; - addField(data, "writer_hostgroup", r->fields[0], ""); - addField(data, "reader_hostgroup", r->fields[1], ""); - addField(data, "check_type", r->fields[2]); - addField(data, "comment", r->fields[3]); - - data += "\t}"; - isNext = true; - } - data += "\n)\n"; - } - } - - if (sqlite_resultset) - delete sqlite_resultset; - - query=(char *)"SELECT * FROM mysql_group_replication_hostgroups"; - admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); - if (error) { - proxy_error("Error on read from mysql_group_replication_hostgroups : %s\n", error); - return -1; - } else { - if (sqlite_resultset) { - data += "mysql_group_replication_hostgroups:\n(\n"; - bool isNext = false; - for (auto r : sqlite_resultset->rows) { - if (isNext) - data += ",\n"; - data += "\t{\n"; - addField(data, "writer_hostgroup", r->fields[0], ""); - addField(data, "backup_writer_hostgroup", r->fields[1], ""); - addField(data, "reader_hostgroup", r->fields[2], ""); - addField(data, "offline_hostgroup", r->fields[3], ""); - addField(data, "active", r->fields[4], ""); - addField(data, "max_writers", r->fields[5], ""); - addField(data, "writer_is_also_reader", r->fields[6], ""); - addField(data, "max_transactions_behind", r->fields[7], ""); - addField(data, "comment", r->fields[8]); - - data += "\t}"; - isNext = true; - } - data += "\n)\n"; - } - } - - if (sqlite_resultset) - delete sqlite_resultset; - - query=(char *)"SELECT * FROM mysql_galera_hostgroups"; - admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); - if (error) { - proxy_error("Error on read from mysql_galera_hostgroups: %s\n", error); - return -1; - } else { - if (sqlite_resultset) { - data += "mysql_galera_hostgroups:\n(\n"; - bool isNext = false; - for (auto r : sqlite_resultset->rows) { - if (isNext) - data += ",\n"; - data += "\t{\n"; - addField(data, "writer_hostgroup", r->fields[0], ""); - addField(data, "backup_writer_hostgroup", r->fields[1], ""); - addField(data, "reader_hostgroup", r->fields[2], ""); - addField(data, "offline_hostgroup", r->fields[3], ""); - addField(data, "active", r->fields[4], ""); - addField(data, "max_writers", r->fields[5], ""); - addField(data, "writer_is_also_reader", r->fields[6], ""); - addField(data, "max_transactions_behind", r->fields[7], ""); - addField(data, "comment", r->fields[8]); - - data += "\t}"; - isNext = true; - } - data += "\n)\n"; - } - } - - if (sqlite_resultset) - delete sqlite_resultset; - - query=(char *)"SELECT * FROM mysql_aws_aurora_hostgroups"; - admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); - if (error) { - proxy_error("Error on read from mysql_aws_aurora_hostgroups: %s\n", error); - return -1; - } else { - if (sqlite_resultset) { - data += "mysql_aws_aurora_hostgroups:\n(\n"; - bool isNext = false; - for (auto r : sqlite_resultset->rows) { - if (isNext) - data += ",\n"; - data += "\t{\n"; - addField(data, "writer_hostgroup", r->fields[0], ""); - addField(data, "reader_hostgroup", r->fields[1], ""); - addField(data, "active", r->fields[2], ""); - addField(data, "aurora_port", r->fields[3], ""); - addField(data, "domain_name", r->fields[4]); - addField(data, "max_lag_ms", r->fields[5], ""); - addField(data, "check_interval_ms", r->fields[6], ""); - addField(data, "check_timeout_ms", r->fields[7], ""); - addField(data, "writer_is_also_reader", r->fields[8], ""); - addField(data, "new_reader_weight", r->fields[9], ""); - addField(data, "add_lag_ms", r->fields[10], ""); - addField(data, "min_lag_ms", r->fields[11], ""); - addField(data, "lag_num_checks", r->fields[12], ""); - addField(data, "comment", r->fields[13]); - - data += "\t}"; - isNext = true; - } - data += "\n)\n"; - } - } - - if (sqlite_resultset) - delete sqlite_resultset; - - return 0; -} - -int ProxySQL_Admin::Read_MySQL_Servers_from_configfile() { - const Setting& root = GloVars.confFile->cfg.getRoot(); - int i; - int rows=0; - admindb->execute("PRAGMA foreign_keys = OFF"); - if (root.exists("mysql_servers")==true) { - const Setting &mysql_servers = root["mysql_servers"]; - int count = mysql_servers.getLength(); - //fprintf(stderr, "Found %d servers\n",count); - char *q=(char *)"INSERT OR REPLACE INTO mysql_servers (hostname, port, gtid_port, hostgroup_id, compression, weight, status, max_connections, max_replication_lag, use_ssl, max_latency_ms, comment) VALUES (\"%s\", %d, %d, %d, %d, %d, \"%s\", %d, %d, %d, %d, '%s')"; - for (i=0; i< count; i++) { - const Setting &server = mysql_servers[i]; - std::string address; - std::string status="ONLINE"; - int port=3306; - int gtid_port=0; - int hostgroup; - int weight=1; - int compression=0; - int max_connections=1000; // default - int max_replication_lag=0; // default - int use_ssl=0; - int max_latency_ms=0; - std::string comment=""; - if (server.lookupValue("address", address)==false) { - if (server.lookupValue("hostname", address)==false) { - proxy_error("Admin: detected a mysql_servers in config file without a mandatory hostname\n"); - continue; - } - } - server.lookupValue("port", port); - server.lookupValue("gtid_port", gtid_port); - if (server.lookupValue("hostgroup", hostgroup)==false) { - if (server.lookupValue("hostgroup_id", hostgroup)==false) { - proxy_error("Admin: detected a mysql_servers in config file without a mandatory hostgroup_id\n"); - continue; - } - } - server.lookupValue("status", status); - if ( - (strcasecmp(status.c_str(),(char *)"ONLINE")) - && (strcasecmp(status.c_str(),(char *)"SHUNNED")) - && (strcasecmp(status.c_str(),(char *)"OFFLINE_SOFT")) - && (strcasecmp(status.c_str(),(char *)"OFFLINE_HARD")) - ) { - status="ONLINE"; - } - server.lookupValue("compression", compression); - server.lookupValue("weight", weight); - server.lookupValue("max_connections", max_connections); - server.lookupValue("max_replication_lag", max_replication_lag); - server.lookupValue("use_ssl", use_ssl); - server.lookupValue("max_latency_ms", max_latency_ms); - server.lookupValue("comment", comment); - char *o1=strdup(comment.c_str()); - char *o=escape_string_single_quotes(o1, false); - char *query=(char *)malloc(strlen(q)+strlen(status.c_str())+strlen(address.c_str())+strlen(o)+128); - sprintf(query,q, address.c_str(), port, gtid_port, hostgroup, compression, weight, status.c_str(), max_connections, max_replication_lag, use_ssl, max_latency_ms, o); - //fprintf(stderr, "%s\n", query); - admindb->execute(query); - if (o!=o1) free(o); - free(o1); - free(query); - rows++; - } - } - if (root.exists("mysql_replication_hostgroups")==true) { - const Setting &mysql_replication_hostgroups = root["mysql_replication_hostgroups"]; - int count = mysql_replication_hostgroups.getLength(); - char *q=(char *)"INSERT OR REPLACE INTO mysql_replication_hostgroups (writer_hostgroup, reader_hostgroup, comment, check_type) VALUES (%d, %d, '%s', '%s')"; - for (i=0; i< count; i++) { - const Setting &line = mysql_replication_hostgroups[i]; - int writer_hostgroup; - int reader_hostgroup; - std::string comment=""; - std::string check_type=""; - if (line.lookupValue("writer_hostgroup", writer_hostgroup)==false) { - proxy_error("Admin: detected a mysql_replication_hostgroups in config file without a mandatory writer_hostgroup\n"); - continue; - } - if (line.lookupValue("reader_hostgroup", reader_hostgroup)==false) { - proxy_error("Admin: detected a mysql_replication_hostgroups in config file without a mandatory reader_hostgroup\n"); - continue; - } - line.lookupValue("comment", comment); - char *o1=strdup(comment.c_str()); - char *o=escape_string_single_quotes(o1, false); - line.lookupValue("check_type", check_type); - if ( - (strcasecmp(check_type.c_str(),(char *)"read_only")) - && (strcasecmp(check_type.c_str(),(char *)"innodb_read_only")) - && (strcasecmp(check_type.c_str(),(char *)"super_read_only")) - ) { - check_type="read_only"; - } - char *t1=strdup(check_type.c_str()); - char *t=escape_string_single_quotes(t1, false); - char *query=(char *)malloc(strlen(q)+strlen(o)+strlen(t)+32); - sprintf(query,q, writer_hostgroup, reader_hostgroup, o, t); - //fprintf(stderr, "%s\n", query); - admindb->execute(query); - if (o!=o1) free(o); - free(o1); - if (t!=t1) free(t); - free(t1); - free(query); - rows++; - } - } - if (root.exists("mysql_group_replication_hostgroups")==true) { - const Setting &mysql_group_replication_hostgroups = root["mysql_group_replication_hostgroups"]; - int count = mysql_group_replication_hostgroups.getLength(); - char *q=(char *)"INSERT OR REPLACE INTO mysql_group_replication_hostgroups (writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, active, max_writers, writer_is_also_reader, max_transactions_behind, comment) VALUES (%d, %d, %d, %d, %d, %d, %d, %d, '%s')"; - for (i=0; i< count; i++) { - const Setting &line = mysql_group_replication_hostgroups[i]; - int writer_hostgroup; - int backup_writer_hostgroup; - int reader_hostgroup; - int offline_hostgroup; - int active=1; // default - int max_writers; - int writer_is_also_reader; - int max_transactions_behind; - std::string comment=""; - if (line.lookupValue("writer_hostgroup", writer_hostgroup)==false) { - proxy_error("Admin: detected a mysql_group_replication_hostgroups in config file without a mandatory writer_hostgroup\n"); - continue; - } - if (line.lookupValue("backup_writer_hostgroup", backup_writer_hostgroup)==false) { - proxy_error("Admin: detected a mysql_group_replication_hostgroups in config file without a mandatory backup_writer_hostgroup\n"); - continue; - } - if (line.lookupValue("reader_hostgroup", reader_hostgroup)==false) { - proxy_error("Admin: detected a mysql_group_replication_hostgroups in config file without a mandatory reader_hostgroup\n"); - continue; - } - if (line.lookupValue("offline_hostgroup", offline_hostgroup)==false) { - proxy_error("Admin: detected a mysql_group_replication_hostgroups in config file without a mandatory offline_hostgroup\n"); - continue; - } - if (line.lookupValue("max_writers", max_writers)==false) max_writers=1; - if (line.lookupValue("writer_is_also_reader", writer_is_also_reader)==false) writer_is_also_reader=0; - if (line.lookupValue("max_transactions_behind", max_transactions_behind)==false) max_transactions_behind=0; - line.lookupValue("comment", comment); - char *o1=strdup(comment.c_str()); - char *o=escape_string_single_quotes(o1, false); - char *query=(char *)malloc(strlen(q)+strlen(o)+128); // 128 vs sizeof(int)*8 - sprintf(query,q, writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, active, max_writers, writer_is_also_reader, max_transactions_behind, o); - //fprintf(stderr, "%s\n", query); - admindb->execute(query); - if (o!=o1) free(o); - free(o1); - free(query); - rows++; - } - } - if (root.exists("mysql_galera_hostgroups")==true) { - const Setting &mysql_galera_hostgroups = root["mysql_galera_hostgroups"]; - int count = mysql_galera_hostgroups.getLength(); - char *q=(char *)"INSERT OR REPLACE INTO mysql_galera_hostgroups (writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, active, max_writers, writer_is_also_reader, max_transactions_behind, comment) VALUES (%d, %d, %d, %d, %d, %d, %d, %d, '%s')"; - for (i=0; i< count; i++) { - const Setting &line = mysql_galera_hostgroups[i]; - int writer_hostgroup; - int backup_writer_hostgroup; - int reader_hostgroup; - int offline_hostgroup; - int active=1; // default - int max_writers; - int writer_is_also_reader; - int max_transactions_behind; - std::string comment=""; - if (line.lookupValue("writer_hostgroup", writer_hostgroup)==false) { - proxy_error("Admin: detected a mysql_galera_hostgroups in config file without a mandatory writer_hostgroup\n"); - continue; - } - if (line.lookupValue("backup_writer_hostgroup", backup_writer_hostgroup)==false) { - proxy_error("Admin: detected a mysql_galera_hostgroups in config file without a mandatory backup_writer_hostgroup\n"); - continue; - } - if (line.lookupValue("reader_hostgroup", reader_hostgroup)==false) { - proxy_error("Admin: detected a mysql_galera_hostgroups in config file without a mandatory reader_hostgroup\n"); - continue; - } - if (line.lookupValue("offline_hostgroup", offline_hostgroup)==false) { - proxy_error("Admin: detected a mysql_galera_hostgroups in config file without a mandatory offline_hostgroup\n"); - continue; - } - if (line.lookupValue("max_writers", max_writers)==false) max_writers=1; - if (line.lookupValue("writer_is_also_reader", writer_is_also_reader)==false) writer_is_also_reader=0; - if (line.lookupValue("max_transactions_behind", max_transactions_behind)==false) max_transactions_behind=0; - line.lookupValue("comment", comment); - char *o1=strdup(comment.c_str()); - char *o=escape_string_single_quotes(o1, false); - char *query=(char *)malloc(strlen(q)+strlen(o)+128); // 128 vs sizeof(int)*8 - sprintf(query,q, writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, active, max_writers, writer_is_also_reader, max_transactions_behind, o); - //fprintf(stderr, "%s\n", query); - admindb->execute(query); - if (o!=o1) free(o); - free(o1); - free(query); - rows++; - } - } - if (root.exists("mysql_aws_aurora_hostgroups")==true) { - const Setting &mysql_aws_aurora_hostgroups = root["mysql_aws_aurora_hostgroups"]; - int count = mysql_aws_aurora_hostgroups.getLength(); - char *q=(char *)"INSERT OR REPLACE INTO mysql_aws_aurora_hostgroups (writer_hostgroup, reader_hostgroup, active, aurora_port, domain_name, max_lag_ms, check_interval_ms, check_timeout_ms, writer_is_also_reader, new_reader_weight, add_lag_ms, min_lag_ms, lag_num_checks, comment ) VALUES (%d, %d, %d, %d, '%s', %d, %d, %d, %d, %d, %d, %d, %d, '%s')"; - for (i=0; i< count; i++) { - const Setting &line = mysql_aws_aurora_hostgroups[i]; - int writer_hostgroup; - int reader_hostgroup; - int active=1; // default - int aurora_port; - int max_lag_ms; - int add_lag_ms; - int min_lag_ms; - int lag_num_checks; - int check_interval_ms; - int check_timeout_ms; - int writer_is_also_reader; - int new_reader_weight; - std::string comment=""; - std::string domain_name=""; - if (line.lookupValue("writer_hostgroup", writer_hostgroup)==false) { - proxy_error("Admin: detected a mysql_aws_aurora_hostgroups in config file without a mandatory writer_hostgroup\n"); - continue; - } - if (line.lookupValue("reader_hostgroup", reader_hostgroup)==false) { - proxy_error("Admin: detected a mysql_aws_aurora_hostgroups in config file without a mandatory reader_hostgroup\n"); - continue; - } - if (line.lookupValue("aurora_port", aurora_port)==false) aurora_port=3306; - if (line.lookupValue("max_lag_ms", max_lag_ms)==false) max_lag_ms=600000; - if (line.lookupValue("check_interval_ms", check_interval_ms)==false) check_interval_ms=1000; - if (line.lookupValue("check_timeout_ms", check_timeout_ms)==false) check_timeout_ms=1000; - if (line.lookupValue("writer_is_also_reader", writer_is_also_reader)==false) writer_is_also_reader=0; - if (line.lookupValue("new_reader_weight", new_reader_weight)==false) new_reader_weight=1; - if (line.lookupValue("add_lag_ms", add_lag_ms)==false) add_lag_ms=30; - if (line.lookupValue("min_lag_ms", min_lag_ms)==false) min_lag_ms=30; - if (line.lookupValue("lag_num_checks", lag_num_checks)==false) lag_num_checks=1; - line.lookupValue("comment", comment); - line.lookupValue("domain_name", domain_name); - char *o1=strdup(comment.c_str()); - char *o=escape_string_single_quotes(o1, false); - char *p1=strdup(domain_name.c_str()); - char *p=escape_string_single_quotes(p1, false); - char *query=(char *)malloc(strlen(q)+strlen(o)+strlen(p)+256); // 128 vs sizeof(int)*8 - sprintf(query,q, writer_hostgroup, reader_hostgroup, active, aurora_port, p, max_lag_ms, check_interval_ms, check_timeout_ms, writer_is_also_reader, new_reader_weight, add_lag_ms, min_lag_ms, lag_num_checks, o); - //fprintf(stderr, "%s\n", query); - admindb->execute(query); - if (o!=o1) free(o); - free(o1); - if (p!=p1) free(p); - free(p1); - free(query); - rows++; - } - } - admindb->execute("PRAGMA foreign_keys = ON"); - return rows; -} - -int ProxySQL_Admin::Write_ProxySQL_Servers_to_configfile(std::string& data) { - char* error = NULL; - int cols = 0; - int affected_rows = 0; - SQLite3_result* sqlite_resultset = NULL; - - char *query=(char *)"SELECT * FROM proxysql_servers"; - admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); - if (error) { - proxy_error("Error on read from proxysql_servers: %s\n", error); - return -1; - } else { - if (sqlite_resultset) { - data += "proxysql_servers:\n(\n"; - bool isNext = false; - for (auto r : sqlite_resultset->rows) { - if (isNext) - data += ",\n"; - data += "\t{\n"; - addField(data, "hostname", r->fields[0]); - addField(data, "port", r->fields[1], ""); - addField(data, "weight", r->fields[2], ""); - addField(data, "comment", r->fields[3]); - - data += "\t}"; - isNext = true; - } - data += "\n)\n"; - } - } - - if (sqlite_resultset) - delete sqlite_resultset; - - return 0; -} - -int ProxySQL_Admin::Read_ProxySQL_Servers_from_configfile() { - const Setting& root = GloVars.confFile->cfg.getRoot(); - int i; - int rows=0; - admindb->execute("PRAGMA foreign_keys = OFF"); - if (root.exists("proxysql_servers")==true) { - const Setting &mysql_servers = root["proxysql_servers"]; - int count = mysql_servers.getLength(); - //fprintf(stderr, "Found %d servers\n",count); - char *q=(char *)"INSERT OR REPLACE INTO proxysql_servers (hostname, port, weight, comment) VALUES (\"%s\", %d, %d, '%s')"; - for (i=0; i< count; i++) { - const Setting &server = mysql_servers[i]; - std::string address; - int port; - int weight=0; - std::string comment=""; - if (server.lookupValue("address", address)==false) { - if (server.lookupValue("hostname", address)==false) { - proxy_error("Admin: detected a proxysql_servers in config file without a mandatory hostname\n"); - continue; - } - } - if (server.lookupValue("port", port)==false) { - proxy_error("Admin: detected a proxysql_servers in config file without a mandatory port\n"); - continue; - } - server.lookupValue("weight", weight); - server.lookupValue("comment", comment); - char *o1=strdup(comment.c_str()); - char *o=escape_string_single_quotes(o1, false); - char *query=(char *)malloc(strlen(q)+strlen(address.c_str())+strlen(o)+128); - sprintf(query, q, address.c_str(), port, weight, o); - proxy_info("Cluster: Adding ProxySQL Servers %s:%d from config file\n", address.c_str(), port); - //fprintf(stderr, "%s\n", query); - admindb->execute(query); - if (o!=o1) free(o); - free(o1); - free(query); - rows++; - } - } - admindb->execute("PRAGMA foreign_keys = ON"); - return rows; -} - extern "C" ProxySQL_Admin * create_ProxySQL_Admin_func() { return new ProxySQL_Admin(); } diff --git a/lib/ProxySQL_Config.cpp b/lib/ProxySQL_Config.cpp new file mode 100644 index 000000000..62b1828ca --- /dev/null +++ b/lib/ProxySQL_Config.cpp @@ -0,0 +1,1204 @@ +#include "proxysql_config.h" +#include "proxysql.h" +#include "cpp.h" + +#include + +ProxySQL_Config::ProxySQL_Config(SQLite3DB* db) { + assert(db); + + admindb = db; +} + +ProxySQL_Config:: ~ProxySQL_Config() { +} + +void ProxySQL_Config::addField(std::string& data, const char* name, const char* value, const char* dq) { + std::stringstream ss; + if (!value || !strlen(value)) return; + ss << "\t\t" << name << "=" << dq << value << dq << "\n"; + data += ss.str(); +} + +int ProxySQL_Config::Read_Global_Variables_from_configfile(const char *prefix) { + const Setting& root = GloVars.confFile->cfg.getRoot(); + char *groupname=(char *)malloc(strlen(prefix)+strlen((char *)"_variables")+1); + sprintf(groupname,"%s%s",prefix,"_variables"); + if (root.exists(groupname)==false) { + free(groupname); + return 0; + } + const Setting &group = root[(const char *)groupname]; + int count = group.getLength(); + //fprintf(stderr, "Found %d %s_variables\n",count, prefix); + int i; + admindb->execute("PRAGMA foreign_keys = OFF"); + char *q=(char *)"INSERT OR REPLACE INTO global_variables VALUES (\"%s-%s\", \"%s\")"; + for (i=0; i< count; i++) { + const Setting &sett = group[i]; + const char *n=sett.getName(); + bool value_bool; + int value_int; + std::string value_string=""; + if (group.lookupValue(n, value_bool)) { + value_string = (value_bool ? "true" : "false"); + } else { + if (group.lookupValue(n, value_int)) { + value_string = std::to_string(value_int); + } else { + group.lookupValue(n, value_string); + } + } + //fprintf(stderr,"%s = %s\n", n, value_string.c_str()); + char *query=(char *)malloc(strlen(q)+strlen(prefix)+strlen(n)+strlen(value_string.c_str())); + sprintf(query,q, prefix, n, value_string.c_str()); + //fprintf(stderr, "%s\n", query); + admindb->execute(query); + free(query); + } + admindb->execute("PRAGMA foreign_keys = ON"); + free(groupname); + return i; +} + +int ProxySQL_Config::Write_MySQL_Users_to_configfile(std::string& data) { + char* error = NULL; + int cols = 0; + int affected_rows = 0; + SQLite3_result* sqlite_resultset = NULL; + + char *query=(char *)"SELECT * FROM mysql_users"; + admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); + if (error) { + proxy_error("Error on read from mysql_users: %s\n", error); + return -1; + } else { + if (sqlite_resultset) { + data += "mysql_users:\n(\n"; + bool isNext = false; + for (auto r : sqlite_resultset->rows) { + if (isNext) + data += ",\n"; + data += "\t{\n"; + addField(data, "username", r->fields[0]); + addField(data, "password", r->fields[1]); + addField(data, "active", r->fields[2], ""); + addField(data, "use_ssl", r->fields[3], ""); + addField(data, "default_hostgroup", r->fields[4], ""); + addField(data, "default_schema", r->fields[5]); + addField(data, "schema_locked", r->fields[6], ""); + addField(data, "transaction_persistent", r->fields[7], ""); + addField(data, "fast_forward", r->fields[8], ""); + addField(data, "backend", r->fields[9], ""); + addField(data, "frontend", r->fields[10], ""); + addField(data, "max_connections", r->fields[11], ""); + addField(data, "comment", r->fields[12]); + data += "\t}"; + isNext = true; + } + data += "\n)\n"; + } + } + + if (sqlite_resultset) + delete sqlite_resultset; + + return 0; +} + +int ProxySQL_Config::Read_MySQL_Users_from_configfile() { + const Setting& root = GloVars.confFile->cfg.getRoot(); + if (root.exists("mysql_users")==false) return 0; + const Setting &mysql_users = root["mysql_users"]; + int count = mysql_users.getLength(); + //fprintf(stderr, "Found %d users\n",count); + int i; + int rows=0; + admindb->execute("PRAGMA foreign_keys = OFF"); + char *q=(char *)"INSERT OR REPLACE INTO mysql_users (username, password, active, use_ssl, default_hostgroup, default_schema, schema_locked, transaction_persistent, fast_forward, max_connections, comment) VALUES ('%s', '%s', %d, %d, %d, '%s', %d, %d, %d, %d, '%s')"; + for (i=0; i< count; i++) { + const Setting &user = mysql_users[i]; + std::string username; + std::string password=""; + int active=1; + int use_ssl=0; + int default_hostgroup=0; + std::string default_schema=""; + int schema_locked=0; + int transaction_persistent=1; + int fast_forward=0; + int max_connections=10000; + std::string comment=""; + if (user.lookupValue("username", username)==false) { + proxy_error("Admin: detected a mysql_users in config file without a mandatory username\n"); + continue; + } + user.lookupValue("password", password); + user.lookupValue("default_hostgroup", default_hostgroup); + user.lookupValue("active", active); + user.lookupValue("use_ssl", use_ssl); + //if (user.lookupValue("default_schema", default_schema)==false) default_schema=""; + user.lookupValue("default_schema", default_schema); + user.lookupValue("schema_locked", schema_locked); + user.lookupValue("transaction_persistent", transaction_persistent); + user.lookupValue("fast_forward", fast_forward); + user.lookupValue("max_connections", max_connections); + user.lookupValue("comment", comment); + char *o1=strdup(comment.c_str()); + char *o=escape_string_single_quotes(o1, false); + char *query=(char *)malloc(strlen(q)+strlen(username.c_str())+strlen(password.c_str())+strlen(o)+128); + sprintf(query,q, username.c_str(), password.c_str(), active, use_ssl, default_hostgroup, default_schema.c_str(), schema_locked, transaction_persistent, fast_forward, max_connections, o); + admindb->execute(query); + if (o!=o1) free(o); + free(o1); + free(query); + rows++; + } + admindb->execute("PRAGMA foreign_keys = ON"); + return rows; +} + +int ProxySQL_Config::Write_Scheduler_to_configfile(std::string& data) { + char* error = NULL; + int cols = 0; + int affected_rows = 0; + SQLite3_result* sqlite_resultset = NULL; + + char *query=(char *)"SELECT * FROM scheduler"; + admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); + if (error) { + proxy_error("Error on read from scheduler: %s\n", error); + return -1; + } else { + if (sqlite_resultset) { + data += "scheduler:\n(\n"; + bool isNext = false; + for (auto r : sqlite_resultset->rows) { + if (isNext) + data += ",\n"; + data += "\t{\n"; + addField(data, "id", r->fields[0], ""); + addField(data, "active", r->fields[1], ""); + addField(data, "interval_ms", r->fields[2], ""); + addField(data, "filename", r->fields[3]); + addField(data, "arg1", r->fields[4]); + addField(data, "arg2", r->fields[5]); + addField(data, "arg3", r->fields[6]); + addField(data, "arg4", r->fields[7]); + addField(data, "arg5", r->fields[8]); + addField(data, "comment", r->fields[9]); + + data += "\t}"; + isNext = true; + } + data += "\n)\n"; + } + } + + if (sqlite_resultset) + delete sqlite_resultset; + + return 0; +} + +int ProxySQL_Config::Read_Scheduler_from_configfile() { + const Setting& root = GloVars.confFile->cfg.getRoot(); + if (root.exists("scheduler")==false) return 0; + const Setting &schedulers = root["scheduler"]; + int count = schedulers.getLength(); + //fprintf(stderr, "Found %d users\n",count); + int i; + int rows=0; + admindb->execute("PRAGMA foreign_keys = OFF"); + char *q=(char *)"INSERT OR REPLACE INTO scheduler (id, active, interval_ms, filename, arg1, arg2, arg3, arg4, arg5, comment) VALUES (%d, %d, %d, '%s', %s, %s, %s, %s, %s, '%s')"; + for (i=0; i< count; i++) { + const Setting &sched = schedulers[i]; + int id; + int active=1; + + std::string filename; + + bool arg1_exists=false; + std::string arg1; + bool arg2_exists=false; + std::string arg2; + bool arg3_exists=false; + std::string arg3; + bool arg4_exists=false; + std::string arg4; + bool arg5_exists=false; + std::string arg5; + + // variable for parsing interval_ms + int interval_ms=0; + + std::string comment=""; + + // validate arguments + if (sched.lookupValue("id", id)==false) { + proxy_error("Admin: detected a scheduler in config file without a mandatory id\n"); + continue; + } + sched.lookupValue("active", active); + sched.lookupValue("interval_ms", interval_ms); + if (sched.lookupValue("filename", filename)==false) { + proxy_error("Admin: detected a scheduler in config file without a mandatory filename\n"); + continue; + } + if (sched.lookupValue("arg1", arg1)) arg1_exists=true; + if (sched.lookupValue("arg2", arg2)) arg2_exists=true; + if (sched.lookupValue("arg3", arg3)) arg3_exists=true; + if (sched.lookupValue("arg4", arg4)) arg4_exists=true; + if (sched.lookupValue("arg5", arg5)) arg5_exists=true; + sched.lookupValue("comment", comment); + + + int query_len=0; + query_len+=strlen(q) + + strlen(std::to_string(id).c_str()) + + strlen(std::to_string(active).c_str()) + + strlen(std::to_string(interval_ms).c_str()) + + strlen(filename.c_str()) + + ( arg1_exists ? strlen(arg1.c_str()) : 0 ) + 4 + + ( arg2_exists ? strlen(arg2.c_str()) : 0 ) + 4 + + ( arg3_exists ? strlen(arg3.c_str()) : 0 ) + 4 + + ( arg4_exists ? strlen(arg4.c_str()) : 0 ) + 4 + + ( arg5_exists ? strlen(arg5.c_str()) : 0 ) + 4 + + strlen(comment.c_str()) + + 40; + char *query=(char *)malloc(query_len); + if (arg1_exists) + arg1="\'" + arg1 + "\'"; + else + arg1 = "NULL"; + if (arg2_exists) + arg2="\'" + arg2 + "\'"; + else + arg2 = "NULL"; + if (arg3_exists) + arg3="\'" + arg3 + "\'"; + else + arg3 = "NULL"; + if (arg4_exists) + arg4="\'" + arg4 + "\'"; + else + arg4 = "NULL"; + if (arg5_exists) + arg5="\'" + arg5 + "\'"; + else + arg5 = "NULL"; + + sprintf(query, q, + id, active, + interval_ms, + filename.c_str(), + arg1.c_str(), + arg2.c_str(), + arg3.c_str(), + arg4.c_str(), + arg5.c_str(), + comment.c_str() + ); + admindb->execute(query); + free(query); + rows++; + } + admindb->execute("PRAGMA foreign_keys = ON"); + return rows; +} + +int ProxySQL_Config::Write_MySQL_Query_Rules_to_configfile(std::string& data) { + char* error = NULL; + int cols = 0; + int affected_rows = 0; + SQLite3_result* sqlite_resultset = NULL; + + char *query=(char *)"SELECT * FROM mysql_query_rules"; + admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); + if (error) { + proxy_error("Error on read from mysql_query_rules : %s\n", error); + return -1; + } else { + if (sqlite_resultset) { + std::string prefix; + data += "mysql_query_rules:\n(\n"; + bool isNext = false; + for (auto r : sqlite_resultset->rows) { + if (isNext) + data += ",\n"; + data += "\t{\n"; + addField(data, "rule_id", r->fields[0], ""); + addField(data, "active", r->fields[1], ""); + addField(data, "username", r->fields[2]); + addField(data, "schemaname", r->fields[3]); + addField(data, "flagIN", r->fields[4], ""); + addField(data, "client_addr", r->fields[5]); + addField(data, "proxy_addr", r->fields[6]); + addField(data, "proxy_port", r->fields[7], ""); + addField(data, "digest", r->fields[8]); + addField(data, "match_digest", r->fields[9]); + addField(data, "match_pattern", r->fields[10]); + addField(data, "negate_match_pattern", r->fields[11], ""); + addField(data, "re_modifiers", r->fields[12]); + addField(data, "flagOUT", r->fields[13], ""); + addField(data, "replace_pattern", r->fields[14]); + addField(data, "destination_hostgroup", r->fields[15], ""); + addField(data, "cache_ttl", r->fields[16], ""); + addField(data, "cache_empty_result", r->fields[17], ""); + addField(data, "cache_timeout", r->fields[18], ""); + addField(data, "reconnect", r->fields[19], ""); + addField(data, "timeout", r->fields[20], ""); + addField(data, "retries", r->fields[21], ""); + addField(data, "delay", r->fields[22], ""); + addField(data, "next_query_flagIN", r->fields[23], ""); + addField(data, "mirror_flagOUT", r->fields[24], ""); + addField(data, "mirror_hostgroup", r->fields[25], ""); + addField(data, "error_msg", r->fields[26]); + addField(data, "OK_msg", r->fields[27]); + addField(data, "sticky_conn", r->fields[28], ""); + addField(data, "multiplex", r->fields[29], ""); + addField(data, "gtid_from_hostgroup", r->fields[30], ""); + addField(data, "log", r->fields[31], ""); + addField(data, "apply", r->fields[32], ""); + addField(data, "comment", r->fields[33]); + + data += "\t}"; + isNext = true; + } + data += "\n)\n"; + } + } + + if (sqlite_resultset) + delete sqlite_resultset; + + return 0; +} + +int ProxySQL_Config::Read_MySQL_Query_Rules_from_configfile() { + const Setting& root = GloVars.confFile->cfg.getRoot(); + if (root.exists("mysql_query_rules")==false) return 0; + const Setting &mysql_query_rules = root["mysql_query_rules"]; + int count = mysql_query_rules.getLength(); + //fprintf(stderr, "Found %d users\n",count); + 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, cache_empty_result, cache_timeout, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, ok_msg, sticky_conn, multiplex, gtid_from_hostgroup, 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, %s, %s, %s, %s, %d, %s)"; + for (i=0; i< count; i++) { + const Setting &rule = mysql_query_rules[i]; + int rule_id; + int active=1; + bool username_exists=false; + std::string username; + bool schemaname_exists=false; + std::string schemaname; + int flagIN=0; + + // variables for parsing client_addr + bool client_addr_exists=false; + std::string client_addr; + + // variables for parsing proxy_addr + bool proxy_addr_exists=false; + std::string proxy_addr; + + // variable for parsing proxy_port + int proxy_port=-1; + + // variables for parsing digest + bool digest_exists=false; + std::string digest; + + + bool match_digest_exists=false; + std::string match_digest; + bool match_pattern_exists=false; + std::string match_pattern; + int negate_match_pattern=0; + + bool re_modifiers_exists=false; + std::string re_modifiers; + + int flagOUT=-1; + bool replace_pattern_exists=false; + std::string replace_pattern; + int destination_hostgroup=-1; + int next_query_flagIN=-1; + int mirror_flagOUT=-1; + int mirror_hostgroup=-1; + int cache_ttl=-1; + int cache_empty_result=-1; + int cache_timeout=-1; + int reconnect=-1; + int timeout=-1; + int retries=-1; + 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; + int gtid_from_hostgroup = -1; + + // variable for parsing log + int log=-1; + + int apply=0; + + bool comment_exists=false; + std::string comment; + + // validate arguments + if (rule.lookupValue("rule_id", rule_id)==false) { + proxy_error("Admin: detected a mysql_query_rules in config file without a mandatory rule_id\n"); + continue; + } + rule.lookupValue("active", active); + if (rule.lookupValue("username", username)) username_exists=true; + if (rule.lookupValue("schemaname", schemaname)) schemaname_exists=true; + rule.lookupValue("flagIN", flagIN); + + if (rule.lookupValue("client_addr", client_addr)) client_addr_exists=true; + if (rule.lookupValue("proxy_addr", proxy_addr)) proxy_addr_exists=true; + rule.lookupValue("proxy_port", proxy_port); + if (rule.lookupValue("digest", digest)) digest_exists=true; + + if (rule.lookupValue("match_digest", match_digest)) match_digest_exists=true; + if (rule.lookupValue("match_pattern", match_pattern)) match_pattern_exists=true; + rule.lookupValue("negate_match_pattern", negate_match_pattern); + if (rule.lookupValue("re_modifiers", re_modifiers)) { + } else { + re_modifiers = "CASELESS"; + } + re_modifiers_exists=true; + rule.lookupValue("flagOUT", flagOUT); + if (rule.lookupValue("replace_pattern", replace_pattern)) replace_pattern_exists=true; + rule.lookupValue("destination_hostgroup", destination_hostgroup); + rule.lookupValue("next_query_flagIN", next_query_flagIN); + rule.lookupValue("mirror_flagOUT", mirror_flagOUT); + rule.lookupValue("mirror_hostgroup", mirror_hostgroup); + rule.lookupValue("cache_ttl", cache_ttl); + rule.lookupValue("cache_empty_result", cache_empty_result); + rule.lookupValue("cache_timeout", cache_timeout); + rule.lookupValue("reconnect", reconnect); + rule.lookupValue("timeout", timeout); + rule.lookupValue("retries", retries); + rule.lookupValue("delay", delay); + + 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); + rule.lookupValue("gtid_from_hostgroup", gtid_from_hostgroup); + + rule.lookupValue("log", log); + + rule.lookupValue("apply", apply); + if (rule.lookupValue("comment", comment)) comment_exists=true; + + + //if (user.lookupValue("default_schema", default_schema)==false) default_schema=""; + int query_len=0; + query_len+=strlen(q) + + strlen(std::to_string(rule_id).c_str()) + + strlen(std::to_string(active).c_str()) + + ( username_exists ? strlen(username.c_str()) : 0 ) + 4 + + ( schemaname_exists ? strlen(schemaname.c_str()) : 0 ) + 4 + + strlen(std::to_string(flagIN).c_str()) + 4 + + + ( client_addr_exists ? strlen(client_addr.c_str()) : 0 ) + 4 + + ( proxy_addr_exists ? strlen(proxy_addr.c_str()) : 0 ) + 4 + + strlen(std::to_string(proxy_port).c_str()) + 4 + + + ( match_digest_exists ? strlen(match_digest.c_str()) : 0 ) + 4 + + ( match_pattern_exists ? strlen(match_pattern.c_str()) : 0 ) + 4 + + strlen(std::to_string(negate_match_pattern).c_str()) + 4 + + ( re_modifiers_exists ? strlen(re_modifiers.c_str()) : 0 ) + 4 + + strlen(std::to_string(flagOUT).c_str()) + 4 + + ( replace_pattern_exists ? strlen(replace_pattern.c_str()) : 0 ) + 4 + + strlen(std::to_string(destination_hostgroup).c_str()) + 4 + + strlen(std::to_string(cache_ttl).c_str()) + 4 + + strlen(std::to_string(cache_empty_result).c_str()) + 4 + + strlen(std::to_string(cache_timeout).c_str()) + 4 + + strlen(std::to_string(reconnect).c_str()) + 4 + + strlen(std::to_string(timeout).c_str()) + 4 + + strlen(std::to_string(next_query_flagIN).c_str()) + 4 + + strlen(std::to_string(mirror_flagOUT).c_str()) + 4 + + strlen(std::to_string(mirror_hostgroup).c_str()) + 4 + + 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(gtid_from_hostgroup).c_str()) + 4 + + strlen(std::to_string(log).c_str()) + 4 + + strlen(std::to_string(apply).c_str()) + 4 + + ( comment_exists ? strlen(comment.c_str()) : 0 ) + 4 + + 64; + char *query=(char *)malloc(query_len); + if (username_exists) + username="\"" + username + "\""; + else + username = "NULL"; + if (schemaname_exists) + schemaname="\"" + schemaname + "\""; + else + schemaname = "NULL"; + + if (client_addr_exists) + client_addr="\"" + client_addr + "\""; + else + client_addr = "NULL"; + if (proxy_addr_exists) + proxy_addr="\"" + proxy_addr + "\""; + else + proxy_addr = "NULL"; + if (digest_exists) + digest="\"" + digest + "\""; + else + digest = "NULL"; + + if (match_digest_exists) + match_digest="\"" + match_digest + "\""; + else + match_digest = "NULL"; + if (match_pattern_exists) + match_pattern="\"" + match_pattern + "\""; + else + match_pattern = "NULL"; + if (replace_pattern_exists) + replace_pattern="\"" + replace_pattern + "\""; + else + replace_pattern = "NULL"; + if (error_msg_exists) + 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 + re_modifiers = "NULL"; + if (comment_exists) + comment="\"" + comment + "\""; + else + comment = "NULL"; + + + sprintf(query, q, + rule_id, active, + username.c_str(), + schemaname.c_str(), + ( flagIN >= 0 ? std::to_string(flagIN).c_str() : "NULL") , + client_addr.c_str(), + proxy_addr.c_str(), + ( proxy_port >= 0 ? std::to_string(proxy_port).c_str() : "NULL") , + digest.c_str(), + match_digest.c_str(), + match_pattern.c_str(), + ( negate_match_pattern == 0 ? 0 : 1) , + re_modifiers.c_str(), + ( flagOUT >= 0 ? std::to_string(flagOUT).c_str() : "NULL") , + replace_pattern.c_str(), + ( destination_hostgroup >= 0 ? std::to_string(destination_hostgroup).c_str() : "NULL") , + ( cache_ttl >= 0 ? std::to_string(cache_ttl).c_str() : "NULL") , + ( cache_empty_result >= 0 ? std::to_string(cache_empty_result).c_str() : "NULL") , + ( cache_timeout >= 0 ? std::to_string(cache_timeout).c_str() : "NULL") , + ( reconnect >= 0 ? std::to_string(reconnect).c_str() : "NULL") , + ( timeout >= 0 ? std::to_string(timeout).c_str() : "NULL") , + ( retries >= 0 ? std::to_string(retries).c_str() : "NULL") , + ( delay >= 0 ? std::to_string(delay).c_str() : "NULL") , + ( next_query_flagIN >= 0 ? std::to_string(next_query_flagIN).c_str() : "NULL") , + ( 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") , + ( gtid_from_hostgroup >= 0 ? std::to_string(gtid_from_hostgroup).c_str() : "NULL") , + ( log >= 0 ? std::to_string(log).c_str() : "NULL") , + ( apply == 0 ? 0 : 1) , + comment.c_str() + ); + //fprintf(stderr, "%s\n", query); + admindb->execute(query); + free(query); + rows++; + } + admindb->execute("PRAGMA foreign_keys = ON"); + return rows; +} + +int ProxySQL_Config::Write_MySQL_Servers_to_configfile(std::string& data) { + char* error = NULL; + int cols = 0; + int affected_rows = 0; + SQLite3_result* sqlite_resultset = NULL; + + char *query=(char *)"SELECT * FROM mysql_servers"; + admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); + if (error) { + proxy_error("Error on read from mysql_query_rules : %s\n", error); + return -1; + } else { + if (sqlite_resultset) { + data += "mysql_servers:\n(\n"; + bool isNext = false; + for (auto r : sqlite_resultset->rows) { + if (isNext) + data += ",\n"; + data += "\t{\n"; + addField(data, "hostgroup_id", r->fields[0], ""); + addField(data, "hostname", r->fields[1]); + addField(data, "port", r->fields[2], ""); + addField(data, "gtid_port", r->fields[3], ""); + addField(data, "status", r->fields[4]); + addField(data, "weight", r->fields[5], ""); + addField(data, "compression", r->fields[6], ""); + addField(data, "max_connections", r->fields[7], ""); + addField(data, "max_replication_lag", r->fields[8], ""); + addField(data, "use_ssl", r->fields[9], ""); + addField(data, "max_latency_ms", r->fields[10], ""); + addField(data, "comment", r->fields[11]); + + data += "\t}"; + isNext = true; + } + data += "\n)\n"; + } + } + + if (sqlite_resultset) + delete sqlite_resultset; + + query=(char *)"SELECT * FROM mysql_replication_hostgroups"; + admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); + if (error) { + proxy_error("Error on read from mysql_replication_hostgroups : %s\n", error); + return -1; + } else { + if (sqlite_resultset) { + data += "mysql_replication_hostgroups:\n(\n"; + bool isNext = false; + for (auto r : sqlite_resultset->rows) { + if (isNext) + data += ",\n"; + data += "\t{\n"; + addField(data, "writer_hostgroup", r->fields[0], ""); + addField(data, "reader_hostgroup", r->fields[1], ""); + addField(data, "check_type", r->fields[2]); + addField(data, "comment", r->fields[3]); + + data += "\t}"; + isNext = true; + } + data += "\n)\n"; + } + } + + if (sqlite_resultset) + delete sqlite_resultset; + + query=(char *)"SELECT * FROM mysql_group_replication_hostgroups"; + admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); + if (error) { + proxy_error("Error on read from mysql_group_replication_hostgroups : %s\n", error); + return -1; + } else { + if (sqlite_resultset) { + data += "mysql_group_replication_hostgroups:\n(\n"; + bool isNext = false; + for (auto r : sqlite_resultset->rows) { + if (isNext) + data += ",\n"; + data += "\t{\n"; + addField(data, "writer_hostgroup", r->fields[0], ""); + addField(data, "backup_writer_hostgroup", r->fields[1], ""); + addField(data, "reader_hostgroup", r->fields[2], ""); + addField(data, "offline_hostgroup", r->fields[3], ""); + addField(data, "active", r->fields[4], ""); + addField(data, "max_writers", r->fields[5], ""); + addField(data, "writer_is_also_reader", r->fields[6], ""); + addField(data, "max_transactions_behind", r->fields[7], ""); + addField(data, "comment", r->fields[8]); + + data += "\t}"; + isNext = true; + } + data += "\n)\n"; + } + } + + if (sqlite_resultset) + delete sqlite_resultset; + + query=(char *)"SELECT * FROM mysql_galera_hostgroups"; + admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); + if (error) { + proxy_error("Error on read from mysql_galera_hostgroups: %s\n", error); + return -1; + } else { + if (sqlite_resultset) { + data += "mysql_galera_hostgroups:\n(\n"; + bool isNext = false; + for (auto r : sqlite_resultset->rows) { + if (isNext) + data += ",\n"; + data += "\t{\n"; + addField(data, "writer_hostgroup", r->fields[0], ""); + addField(data, "backup_writer_hostgroup", r->fields[1], ""); + addField(data, "reader_hostgroup", r->fields[2], ""); + addField(data, "offline_hostgroup", r->fields[3], ""); + addField(data, "active", r->fields[4], ""); + addField(data, "max_writers", r->fields[5], ""); + addField(data, "writer_is_also_reader", r->fields[6], ""); + addField(data, "max_transactions_behind", r->fields[7], ""); + addField(data, "comment", r->fields[8]); + + data += "\t}"; + isNext = true; + } + data += "\n)\n"; + } + } + + if (sqlite_resultset) + delete sqlite_resultset; + + query=(char *)"SELECT * FROM mysql_aws_aurora_hostgroups"; + admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); + if (error) { + proxy_error("Error on read from mysql_aws_aurora_hostgroups: %s\n", error); + return -1; + } else { + if (sqlite_resultset) { + data += "mysql_aws_aurora_hostgroups:\n(\n"; + bool isNext = false; + for (auto r : sqlite_resultset->rows) { + if (isNext) + data += ",\n"; + data += "\t{\n"; + addField(data, "writer_hostgroup", r->fields[0], ""); + addField(data, "reader_hostgroup", r->fields[1], ""); + addField(data, "active", r->fields[2], ""); + addField(data, "aurora_port", r->fields[3], ""); + addField(data, "domain_name", r->fields[4]); + addField(data, "max_lag_ms", r->fields[5], ""); + addField(data, "check_interval_ms", r->fields[6], ""); + addField(data, "check_timeout_ms", r->fields[7], ""); + addField(data, "writer_is_also_reader", r->fields[8], ""); + addField(data, "new_reader_weight", r->fields[9], ""); + addField(data, "add_lag_ms", r->fields[10], ""); + addField(data, "min_lag_ms", r->fields[11], ""); + addField(data, "lag_num_checks", r->fields[12], ""); + addField(data, "comment", r->fields[13]); + + data += "\t}"; + isNext = true; + } + data += "\n)\n"; + } + } + + if (sqlite_resultset) + delete sqlite_resultset; + + return 0; +} + +int ProxySQL_Config::Read_MySQL_Servers_from_configfile() { + const Setting& root = GloVars.confFile->cfg.getRoot(); + int i; + int rows=0; + admindb->execute("PRAGMA foreign_keys = OFF"); + if (root.exists("mysql_servers")==true) { + const Setting &mysql_servers = root["mysql_servers"]; + int count = mysql_servers.getLength(); + //fprintf(stderr, "Found %d servers\n",count); + char *q=(char *)"INSERT OR REPLACE INTO mysql_servers (hostname, port, gtid_port, hostgroup_id, compression, weight, status, max_connections, max_replication_lag, use_ssl, max_latency_ms, comment) VALUES (\"%s\", %d, %d, %d, %d, %d, \"%s\", %d, %d, %d, %d, '%s')"; + for (i=0; i< count; i++) { + const Setting &server = mysql_servers[i]; + std::string address; + std::string status="ONLINE"; + int port=3306; + int gtid_port=0; + int hostgroup; + int weight=1; + int compression=0; + int max_connections=1000; // default + int max_replication_lag=0; // default + int use_ssl=0; + int max_latency_ms=0; + std::string comment=""; + if (server.lookupValue("address", address)==false) { + if (server.lookupValue("hostname", address)==false) { + proxy_error("Admin: detected a mysql_servers in config file without a mandatory hostname\n"); + continue; + } + } + server.lookupValue("port", port); + server.lookupValue("gtid_port", gtid_port); + if (server.lookupValue("hostgroup", hostgroup)==false) { + if (server.lookupValue("hostgroup_id", hostgroup)==false) { + proxy_error("Admin: detected a mysql_servers in config file without a mandatory hostgroup_id\n"); + continue; + } + } + server.lookupValue("status", status); + if ( + (strcasecmp(status.c_str(),(char *)"ONLINE")) + && (strcasecmp(status.c_str(),(char *)"SHUNNED")) + && (strcasecmp(status.c_str(),(char *)"OFFLINE_SOFT")) + && (strcasecmp(status.c_str(),(char *)"OFFLINE_HARD")) + ) { + status="ONLINE"; + } + server.lookupValue("compression", compression); + server.lookupValue("weight", weight); + server.lookupValue("max_connections", max_connections); + server.lookupValue("max_replication_lag", max_replication_lag); + server.lookupValue("use_ssl", use_ssl); + server.lookupValue("max_latency_ms", max_latency_ms); + server.lookupValue("comment", comment); + char *o1=strdup(comment.c_str()); + char *o=escape_string_single_quotes(o1, false); + char *query=(char *)malloc(strlen(q)+strlen(status.c_str())+strlen(address.c_str())+strlen(o)+128); + sprintf(query,q, address.c_str(), port, gtid_port, hostgroup, compression, weight, status.c_str(), max_connections, max_replication_lag, use_ssl, max_latency_ms, o); + //fprintf(stderr, "%s\n", query); + admindb->execute(query); + if (o!=o1) free(o); + free(o1); + free(query); + rows++; + } + } + if (root.exists("mysql_replication_hostgroups")==true) { + const Setting &mysql_replication_hostgroups = root["mysql_replication_hostgroups"]; + int count = mysql_replication_hostgroups.getLength(); + char *q=(char *)"INSERT OR REPLACE INTO mysql_replication_hostgroups (writer_hostgroup, reader_hostgroup, comment, check_type) VALUES (%d, %d, '%s', '%s')"; + for (i=0; i< count; i++) { + const Setting &line = mysql_replication_hostgroups[i]; + int writer_hostgroup; + int reader_hostgroup; + std::string comment=""; + std::string check_type=""; + if (line.lookupValue("writer_hostgroup", writer_hostgroup)==false) { + proxy_error("Admin: detected a mysql_replication_hostgroups in config file without a mandatory writer_hostgroup\n"); + continue; + } + if (line.lookupValue("reader_hostgroup", reader_hostgroup)==false) { + proxy_error("Admin: detected a mysql_replication_hostgroups in config file without a mandatory reader_hostgroup\n"); + continue; + } + line.lookupValue("comment", comment); + char *o1=strdup(comment.c_str()); + char *o=escape_string_single_quotes(o1, false); + line.lookupValue("check_type", check_type); + if ( + (strcasecmp(check_type.c_str(),(char *)"read_only")) + && (strcasecmp(check_type.c_str(),(char *)"innodb_read_only")) + && (strcasecmp(check_type.c_str(),(char *)"super_read_only")) + ) { + check_type="read_only"; + } + char *t1=strdup(check_type.c_str()); + char *t=escape_string_single_quotes(t1, false); + char *query=(char *)malloc(strlen(q)+strlen(o)+strlen(t)+32); + sprintf(query,q, writer_hostgroup, reader_hostgroup, o, t); + //fprintf(stderr, "%s\n", query); + admindb->execute(query); + if (o!=o1) free(o); + free(o1); + if (t!=t1) free(t); + free(t1); + free(query); + rows++; + } + } + if (root.exists("mysql_group_replication_hostgroups")==true) { + const Setting &mysql_group_replication_hostgroups = root["mysql_group_replication_hostgroups"]; + int count = mysql_group_replication_hostgroups.getLength(); + char *q=(char *)"INSERT OR REPLACE INTO mysql_group_replication_hostgroups (writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, active, max_writers, writer_is_also_reader, max_transactions_behind, comment) VALUES (%d, %d, %d, %d, %d, %d, %d, %d, '%s')"; + for (i=0; i< count; i++) { + const Setting &line = mysql_group_replication_hostgroups[i]; + int writer_hostgroup; + int backup_writer_hostgroup; + int reader_hostgroup; + int offline_hostgroup; + int active=1; // default + int max_writers; + int writer_is_also_reader; + int max_transactions_behind; + std::string comment=""; + if (line.lookupValue("writer_hostgroup", writer_hostgroup)==false) { + proxy_error("Admin: detected a mysql_group_replication_hostgroups in config file without a mandatory writer_hostgroup\n"); + continue; + } + if (line.lookupValue("backup_writer_hostgroup", backup_writer_hostgroup)==false) { + proxy_error("Admin: detected a mysql_group_replication_hostgroups in config file without a mandatory backup_writer_hostgroup\n"); + continue; + } + if (line.lookupValue("reader_hostgroup", reader_hostgroup)==false) { + proxy_error("Admin: detected a mysql_group_replication_hostgroups in config file without a mandatory reader_hostgroup\n"); + continue; + } + if (line.lookupValue("offline_hostgroup", offline_hostgroup)==false) { + proxy_error("Admin: detected a mysql_group_replication_hostgroups in config file without a mandatory offline_hostgroup\n"); + continue; + } + if (line.lookupValue("max_writers", max_writers)==false) max_writers=1; + if (line.lookupValue("writer_is_also_reader", writer_is_also_reader)==false) writer_is_also_reader=0; + if (line.lookupValue("max_transactions_behind", max_transactions_behind)==false) max_transactions_behind=0; + line.lookupValue("comment", comment); + char *o1=strdup(comment.c_str()); + char *o=escape_string_single_quotes(o1, false); + char *query=(char *)malloc(strlen(q)+strlen(o)+128); // 128 vs sizeof(int)*8 + sprintf(query,q, writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, active, max_writers, writer_is_also_reader, max_transactions_behind, o); + //fprintf(stderr, "%s\n", query); + admindb->execute(query); + if (o!=o1) free(o); + free(o1); + free(query); + rows++; + } + } + if (root.exists("mysql_galera_hostgroups")==true) { + const Setting &mysql_galera_hostgroups = root["mysql_galera_hostgroups"]; + int count = mysql_galera_hostgroups.getLength(); + char *q=(char *)"INSERT OR REPLACE INTO mysql_galera_hostgroups (writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, active, max_writers, writer_is_also_reader, max_transactions_behind, comment) VALUES (%d, %d, %d, %d, %d, %d, %d, %d, '%s')"; + for (i=0; i< count; i++) { + const Setting &line = mysql_galera_hostgroups[i]; + int writer_hostgroup; + int backup_writer_hostgroup; + int reader_hostgroup; + int offline_hostgroup; + int active=1; // default + int max_writers; + int writer_is_also_reader; + int max_transactions_behind; + std::string comment=""; + if (line.lookupValue("writer_hostgroup", writer_hostgroup)==false) { + proxy_error("Admin: detected a mysql_galera_hostgroups in config file without a mandatory writer_hostgroup\n"); + continue; + } + if (line.lookupValue("backup_writer_hostgroup", backup_writer_hostgroup)==false) { + proxy_error("Admin: detected a mysql_galera_hostgroups in config file without a mandatory backup_writer_hostgroup\n"); + continue; + } + if (line.lookupValue("reader_hostgroup", reader_hostgroup)==false) { + proxy_error("Admin: detected a mysql_galera_hostgroups in config file without a mandatory reader_hostgroup\n"); + continue; + } + if (line.lookupValue("offline_hostgroup", offline_hostgroup)==false) { + proxy_error("Admin: detected a mysql_galera_hostgroups in config file without a mandatory offline_hostgroup\n"); + continue; + } + if (line.lookupValue("max_writers", max_writers)==false) max_writers=1; + if (line.lookupValue("writer_is_also_reader", writer_is_also_reader)==false) writer_is_also_reader=0; + if (line.lookupValue("max_transactions_behind", max_transactions_behind)==false) max_transactions_behind=0; + line.lookupValue("comment", comment); + char *o1=strdup(comment.c_str()); + char *o=escape_string_single_quotes(o1, false); + char *query=(char *)malloc(strlen(q)+strlen(o)+128); // 128 vs sizeof(int)*8 + sprintf(query,q, writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, active, max_writers, writer_is_also_reader, max_transactions_behind, o); + //fprintf(stderr, "%s\n", query); + admindb->execute(query); + if (o!=o1) free(o); + free(o1); + free(query); + rows++; + } + } + if (root.exists("mysql_aws_aurora_hostgroups")==true) { + const Setting &mysql_aws_aurora_hostgroups = root["mysql_aws_aurora_hostgroups"]; + int count = mysql_aws_aurora_hostgroups.getLength(); + char *q=(char *)"INSERT OR REPLACE INTO mysql_aws_aurora_hostgroups (writer_hostgroup, reader_hostgroup, active, aurora_port, domain_name, max_lag_ms, check_interval_ms, check_timeout_ms, writer_is_also_reader, new_reader_weight, add_lag_ms, min_lag_ms, lag_num_checks, comment ) VALUES (%d, %d, %d, %d, '%s', %d, %d, %d, %d, %d, %d, %d, %d, '%s')"; + for (i=0; i< count; i++) { + const Setting &line = mysql_aws_aurora_hostgroups[i]; + int writer_hostgroup; + int reader_hostgroup; + int active=1; // default + int aurora_port; + int max_lag_ms; + int add_lag_ms; + int min_lag_ms; + int lag_num_checks; + int check_interval_ms; + int check_timeout_ms; + int writer_is_also_reader; + int new_reader_weight; + std::string comment=""; + std::string domain_name=""; + if (line.lookupValue("writer_hostgroup", writer_hostgroup)==false) { + proxy_error("Admin: detected a mysql_aws_aurora_hostgroups in config file without a mandatory writer_hostgroup\n"); + continue; + } + if (line.lookupValue("reader_hostgroup", reader_hostgroup)==false) { + proxy_error("Admin: detected a mysql_aws_aurora_hostgroups in config file without a mandatory reader_hostgroup\n"); + continue; + } + if (line.lookupValue("aurora_port", aurora_port)==false) aurora_port=3306; + if (line.lookupValue("max_lag_ms", max_lag_ms)==false) max_lag_ms=600000; + if (line.lookupValue("check_interval_ms", check_interval_ms)==false) check_interval_ms=1000; + if (line.lookupValue("check_timeout_ms", check_timeout_ms)==false) check_timeout_ms=1000; + if (line.lookupValue("writer_is_also_reader", writer_is_also_reader)==false) writer_is_also_reader=0; + if (line.lookupValue("new_reader_weight", new_reader_weight)==false) new_reader_weight=1; + if (line.lookupValue("add_lag_ms", add_lag_ms)==false) add_lag_ms=30; + if (line.lookupValue("min_lag_ms", min_lag_ms)==false) min_lag_ms=30; + if (line.lookupValue("lag_num_checks", lag_num_checks)==false) lag_num_checks=1; + line.lookupValue("comment", comment); + line.lookupValue("domain_name", domain_name); + char *o1=strdup(comment.c_str()); + char *o=escape_string_single_quotes(o1, false); + char *p1=strdup(domain_name.c_str()); + char *p=escape_string_single_quotes(p1, false); + char *query=(char *)malloc(strlen(q)+strlen(o)+strlen(p)+256); // 128 vs sizeof(int)*8 + sprintf(query,q, writer_hostgroup, reader_hostgroup, active, aurora_port, p, max_lag_ms, check_interval_ms, check_timeout_ms, writer_is_also_reader, new_reader_weight, add_lag_ms, min_lag_ms, lag_num_checks, o); + //fprintf(stderr, "%s\n", query); + admindb->execute(query); + if (o!=o1) free(o); + free(o1); + if (p!=p1) free(p); + free(p1); + free(query); + rows++; + } + } + admindb->execute("PRAGMA foreign_keys = ON"); + return rows; +} + +int ProxySQL_Config::Write_ProxySQL_Servers_to_configfile(std::string& data) { + char* error = NULL; + int cols = 0; + int affected_rows = 0; + SQLite3_result* sqlite_resultset = NULL; + + char *query=(char *)"SELECT * FROM proxysql_servers"; + admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); + if (error) { + proxy_error("Error on read from proxysql_servers: %s\n", error); + return -1; + } else { + if (sqlite_resultset) { + data += "proxysql_servers:\n(\n"; + bool isNext = false; + for (auto r : sqlite_resultset->rows) { + if (isNext) + data += ",\n"; + data += "\t{\n"; + addField(data, "hostname", r->fields[0]); + addField(data, "port", r->fields[1], ""); + addField(data, "weight", r->fields[2], ""); + addField(data, "comment", r->fields[3]); + + data += "\t}"; + isNext = true; + } + data += "\n)\n"; + } + } + + if (sqlite_resultset) + delete sqlite_resultset; + + return 0; +} + +int ProxySQL_Config::Read_ProxySQL_Servers_from_configfile() { + const Setting& root = GloVars.confFile->cfg.getRoot(); + int i; + int rows=0; + admindb->execute("PRAGMA foreign_keys = OFF"); + if (root.exists("proxysql_servers")==true) { + const Setting &mysql_servers = root["proxysql_servers"]; + int count = mysql_servers.getLength(); + //fprintf(stderr, "Found %d servers\n",count); + char *q=(char *)"INSERT OR REPLACE INTO proxysql_servers (hostname, port, weight, comment) VALUES (\"%s\", %d, %d, '%s')"; + for (i=0; i< count; i++) { + const Setting &server = mysql_servers[i]; + std::string address; + int port; + int weight=0; + std::string comment=""; + if (server.lookupValue("address", address)==false) { + if (server.lookupValue("hostname", address)==false) { + proxy_error("Admin: detected a proxysql_servers in config file without a mandatory hostname\n"); + continue; + } + } + if (server.lookupValue("port", port)==false) { + proxy_error("Admin: detected a proxysql_servers in config file without a mandatory port\n"); + continue; + } + server.lookupValue("weight", weight); + server.lookupValue("comment", comment); + char *o1=strdup(comment.c_str()); + char *o=escape_string_single_quotes(o1, false); + char *query=(char *)malloc(strlen(q)+strlen(address.c_str())+strlen(o)+128); + sprintf(query, q, address.c_str(), port, weight, o); + proxy_info("Cluster: Adding ProxySQL Servers %s:%d from config file\n", address.c_str(), port); + //fprintf(stderr, "%s\n", query); + admindb->execute(query); + if (o!=o1) free(o); + free(o1); + free(query); + rows++; + } + } + admindb->execute("PRAGMA foreign_keys = ON"); + return rows; +} + +int ProxySQL_Config::Write_Global_Variables_to_configfile(std::string& data) { + char* error = NULL; + int cols = 0; + int affected_rows = 0; + SQLite3_result* sqlite_resultset = NULL; + + char *query=(char *)"SELECT variable_name, variable_value FROM global_variables ORDER BY variable_name"; + admindb->execute_statement(query, &error, &cols, &affected_rows, &sqlite_resultset); + if (error) { + proxy_error("Error on read from global_variables : %s\n", error); + return -1; + } else { + if (sqlite_resultset) { + std::string prefix; + + for (auto r : sqlite_resultset->rows) { + std::string input(r->fields[0]); + std::string p1 = input.substr(0, input.find("-")); + if (prefix.empty()) { + prefix = input.substr(0, input.find("-")); + data += prefix + "_variables =\n{\n"; + } else { + if (p1.compare(prefix)) { + prefix = p1; + data += "}\n\n" + prefix + "_variables = \n{\n"; + } + } + if (r->fields[1] && strlen(r->fields[1])) { + std::stringstream ss; + ss << "\t" << r->fields[0] + p1.size() + 1 << "=\"" << r->fields[1] << "\"\n"; + data += ss.str(); + } + } + + if (!prefix.empty()) + data += "}\n"; + } + } + + if (sqlite_resultset) + delete sqlite_resultset; + + return 0; +}