From cf7ed16461122dea3b8d878eb3b003f1b6edcbc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Canna=C3=B2?= Date: Sun, 25 Jun 2017 21:40:04 +0200 Subject: [PATCH] Added skelethon for SQLite3_Server --- include/SQLite3_Server.h | 219 +++ include/cpp.h | 1 + lib/Makefile | 2 +- lib/SQLite3_Server.cpp | 3464 ++++++++++++++++++++++++++++++++++++++ src/main.cpp | 16 + 5 files changed, 3701 insertions(+), 1 deletion(-) create mode 100644 include/SQLite3_Server.h create mode 100644 lib/SQLite3_Server.cpp diff --git a/include/SQLite3_Server.h b/include/SQLite3_Server.h new file mode 100644 index 000000000..597404007 --- /dev/null +++ b/include/SQLite3_Server.h @@ -0,0 +1,219 @@ +#ifndef CLASS_PROXYSQL_SQLITE3_SERVER_H +#define CLASS_PROXYSQL_SQLITE3_SERVER_H + +#include "proxy_defines.h" +#include "proxysql.h" +#include "cpp.h" +#include + +/* +typedef struct { uint32_t hash; uint32_t key; } t_symstruct; + + +class Scheduler_Row { + public: + unsigned int id; + bool is_active; + unsigned int interval_ms; + unsigned long long last; + unsigned long long next; + char *filename; + char **args; + char *comment; + Scheduler_Row(unsigned int _id, bool _is_active, unsigned int _in, char *_f, char *a1, char *a2, char *a3, char *a4, char *a5, char *_comment); + ~Scheduler_Row(); +}; + +class ProxySQL_External_Scheduler { + private: + unsigned long long next_run; + public: + unsigned int last_version; + unsigned int version; +#ifdef PA_PTHREAD_MUTEX + pthread_rwlock_t rwlock; +#else + rwlock_t rwlock; +#endif + std::vector Scheduler_Rows; + ProxySQL_External_Scheduler(); + ~ProxySQL_External_Scheduler(); + unsigned long long run_once(); + void update_table(SQLite3_result *result); +}; +*/ + +class SQLite3_Server { + private: + volatile int main_shutdown; +/* + std::vector *tables_defs_admin; + std::vector *tables_defs_stats; + std::vector *tables_defs_config; + + pthread_t admin_thr; +*/ + int main_poll_nfds; + struct pollfd *main_poll_fds; + int *main_callback_func; + + pthread_rwlock_t rwlock; + + + + + void wrlock(); + void wrunlock(); + + struct { + char *admin_credentials; + char *stats_credentials; + int refresh_interval; + char *mysql_ifaces; + char *telnet_admin_ifaces; + char *telnet_stats_ifaces; + bool admin_read_only; + bool hash_passwords; + char * admin_version; +#ifdef DEBUG + bool debug; +#endif // DEBUG + } variables; +/* + + ProxySQL_External_Scheduler *scheduler; + + void dump_mysql_collations(); + void insert_into_tables_defs(std::vector *, const char *table_name, const char *table_def); + void drop_tables_defs(std::vector *tables_defs); + void check_and_build_standard_tables(SQLite3DB *db, std::vector *tables_defs); + +#ifdef DEBUG + void flush_debug_levels_runtime_to_database(SQLite3DB *db, bool replace); + int flush_debug_levels_database_to_runtime(SQLite3DB *db); +#endif // DEBUG + + void __insert_or_ignore_maintable_select_disktable(); + void __insert_or_replace_maintable_select_disktable(); + void __delete_disktable(); + void __insert_or_replace_disktable_select_maintable(); + void __attach_db(SQLite3DB *db1, SQLite3DB *db2, char *alias); + + void __add_active_users(enum cred_username_type usertype, char *user=NULL); + void __delete_inactive_users(enum cred_username_type usertype); + void add_admin_users(); + void __refresh_users(); + + void flush_mysql_variables___runtime_to_database(SQLite3DB *db, bool replace, bool del, bool onlyifempty, bool runtime=false); + void flush_mysql_variables___database_to_runtime(SQLite3DB *db, bool replace); + + char **get_variables_list(); + char *get_variable(char *name); + bool set_variable(char *name, char *value); + void flush_admin_variables___database_to_runtime(SQLite3DB *db, bool replace); + void flush_admin_variables___runtime_to_database(SQLite3DB *db, bool replace, bool del, bool onlyifempty, bool runtime=false); + void disk_upgrade_mysql_query_rules(); + void disk_upgrade_mysql_servers(); + void disk_upgrade_mysql_users(); + void disk_upgrade_scheduler(); + +#ifdef DEBUG + void add_credentials(char *type, char *credentials, int hostgroup_id); + void delete_credentials(char *type, char *credentials); +#else + void add_credentials(char *credentials, int hostgroup_id); + void delete_credentials(char *credentials); +#endif // DEBUG +*/ + public: + SQLite3_Server(); + ~SQLite3_Server(); +/* + struct { + void *opt; + void **re; + } match_regexes; + void public_add_active_users(enum cred_username_type usertype, char *user=NULL) { + __add_active_users(usertype, user); + } + ProxySQL_Admin(); + ~ProxySQL_Admin(); + SQLite3DB *admindb; // in memory + SQLite3DB *statsdb; // in memory + SQLite3DB *configdb; // on disk + SQLite3DB *monitordb; // in memory + int pipefd[2]; +*/ + void print_version(); + bool init(); +/* + bool get_read_only() { return variables.admin_read_only; } + bool set_read_only(bool ro) { variables.admin_read_only=ro; return variables.admin_read_only; } + bool has_variable(const char *name); + void init_users(); + void init_mysql_servers(); + void init_mysql_query_rules(); + void save_mysql_users_runtime_to_database(bool _runtime); + void save_mysql_servers_runtime_to_database(bool); + void admin_shutdown(); + bool is_command(std::string); +*/ + void send_MySQL_OK(MySQL_Protocol *myprot, char *msg, int rows=0); + void send_MySQL_ERR(MySQL_Protocol *myprot, char *msg); +/* +#ifdef DEBUG + int load_debug_to_runtime() { return flush_debug_levels_database_to_runtime(admindb); } + void save_debug_from_runtime() { return flush_debug_levels_runtime_to_database(admindb, true); } +#endif // DEBUG + void flush_mysql_users__from_memory_to_disk(); + void flush_mysql_users__from_disk_to_memory(); + void flush_mysql_servers__from_memory_to_disk(); + void flush_mysql_servers__from_disk_to_memory(); + void flush_mysql_query_rules__from_memory_to_disk(); + void flush_mysql_query_rules__from_disk_to_memory(); + void load_mysql_servers_to_runtime(); + void save_mysql_servers_from_runtime(); + char * load_mysql_query_rules_to_runtime(); + void save_mysql_query_rules_from_runtime(bool); + + void load_scheduler_to_runtime(); + void save_scheduler_runtime_to_database(bool); + void flush_scheduler__from_memory_to_disk(); + void flush_scheduler__from_disk_to_memory(); + + void load_admin_variables_to_runtime() { flush_admin_variables___database_to_runtime(admindb, true); } + void save_admin_variables_from_runtime() { flush_admin_variables___runtime_to_database(admindb, true, true, false); } + + void load_mysql_variables_to_runtime() { flush_mysql_variables___database_to_runtime(admindb, true); } + void save_mysql_variables_from_runtime() { flush_mysql_variables___runtime_to_database(admindb, true, true, false); } + + void stats___mysql_query_rules(); + void stats___mysql_query_digests(bool reset); + //void stats___mysql_query_digests_reset(); + void stats___mysql_commands_counters(); + void stats___mysql_processlist(); + void stats___mysql_connection_pool(bool _reset); + void stats___mysql_global(); + void stats___mysql_users(); + + 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(); + + void flush_error_log(); + void GenericRefreshStatistics(const char *query_no_space, unsigned int query_no_space_length, bool admin); + SQLite3_result * generate_show_table_status(const char *, char **err); + SQLite3_result * generate_show_fields_from(const char *tablename, char **err); + + void mysql_servers_wrlock(); + void mysql_servers_wrunlock(); + + // wrapper to call a private function + unsigned long long scheduler_run_once() { return scheduler->run_once(); } + + void flush_configdb(); // 923 +*/ +}; +#endif // CLASS_PROXYSQL_SQLITE3_SERVER_H diff --git a/include/cpp.h b/include/cpp.h index 649fcef66..a495a27d2 100644 --- a/include/cpp.h +++ b/include/cpp.h @@ -14,6 +14,7 @@ #include "configfile.hpp" #include "query_processor.h" #include "proxysql_admin.h" +#include "SQLite3_Server.h" #include "MySQL_HostGroups_Manager.h" #include "MySQL_Logger.hpp" #include "MySQL_PreparedStatement.h" diff --git a/lib/Makefile b/lib/Makefile index 81b9367f0..8991b3d97 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -61,7 +61,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 +_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 OBJ_CXX = $(patsubst %,$(ODIR)/%,$(_OBJ_CXX)) %.ko: %.cpp diff --git a/lib/SQLite3_Server.cpp b/lib/SQLite3_Server.cpp new file mode 100644 index 000000000..3203d987b --- /dev/null +++ b/lib/SQLite3_Server.cpp @@ -0,0 +1,3464 @@ +#include // std::cout +#include // std::sort +#include // std::vector +#include "re2/re2.h" +#include "re2/regexp.h" +#include "proxysql.h" +#include "cpp.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "SpookyV2.h" + +#include +#include + +#define SELECT_VERSION_COMMENT "select @@version_comment limit 1" +#define SELECT_VERSION_COMMENT_LEN 32 +#define SELECT_DB_USER "select DATABASE(), USER() limit 1" +#define SELECT_DB_USER_LEN 33 +#define SELECT_CHARSET_VARIOUS "select @@character_set_client, @@character_set_connection, @@character_set_server, @@character_set_database limit 1" +#define SELECT_CHARSET_VARIOUS_LEN 115 + +#define READ_ONLY_OFF "\x01\x00\x00\x01\x02\x23\x00\x00\x02\x03\x64\x65\x66\x00\x00\x00\x0d\x56\x61\x72\x69\x61\x62\x6c\x65\x5f\x6e\x61\x6d\x65\x00\x0c\x21\x00\x0f\x00\x00\x00\xfd\x01\x00\x1f\x00\x00\x1b\x00\x00\x03\x03\x64\x65\x66\x00\x00\x00\x05\x56\x61\x6c\x75\x65\x00\x0c\x21\x00\x0f\x00\x00\x00\xfd\x01\x00\x1f\x00\x00\x05\x00\x00\x04\xfe\x00\x00\x02\x00\x0e\x00\x00\x05\x09\x72\x65\x61\x64\x5f\x6f\x6e\x6c\x79\x03\x4f\x46\x46\x05\x00\x00\x06\xfe\x00\x00\x02\x00" +#define READ_ONLY_ON "\x01\x00\x00\x01\x02\x23\x00\x00\x02\x03\x64\x65\x66\x00\x00\x00\x0d\x56\x61\x72\x69\x61\x62\x6c\x65\x5f\x6e\x61\x6d\x65\x00\x0c\x21\x00\x0f\x00\x00\x00\xfd\x01\x00\x1f\x00\x00\x1b\x00\x00\x03\x03\x64\x65\x66\x00\x00\x00\x05\x56\x61\x6c\x75\x65\x00\x0c\x21\x00\x0f\x00\x00\x00\xfd\x01\x00\x1f\x00\x00\x05\x00\x00\x04\xfe\x00\x00\x02\x00\x0d\x00\x00\x05\x09\x72\x65\x61\x64\x5f\x6f\x6e\x6c\x79\x02\x4f\x4e\x05\x00\x00\x06\xfe\x00\x00\x02\x00" + + +#ifdef __APPLE__ +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif // MSG_NOSIGNAL +#endif // __APPLE__ + +#define SAFE_SQLITE3_STEP(_stmt) do {\ + do {\ + rc=sqlite3_step(_stmt);\ + if (rc!=SQLITE_DONE) {\ + assert(rc==SQLITE_LOCKED);\ + usleep(100);\ + }\ + } while (rc!=SQLITE_DONE);\ +} while (0) + +static void StringToHex(unsigned char *string, unsigned char *hexstring, size_t l) { + unsigned char ch; + size_t i, j; + + for (i=0, j=0; i> 4; + if (ch <= 9) { + hexstring[j]= '0' + ch; + } else { + hexstring[j]= 'A' + ch - 10; + } + ch = string[i]; + ch = ch & 0x0F; + if (ch <= 9) { + hexstring[j+1]= '0' + ch; + } else { + hexstring[j+1]= 'A' + ch - 10; + } + } +} + +struct cpu_timer +{ + cpu_timer() { + begin = monotonic_time(); + } + ~cpu_timer() + { + unsigned long long end = monotonic_time(); +#ifdef DEBUG + std::cerr << double( end - begin ) / 1000000 << " secs.\n" ; +#endif + begin=end-begin; // make the compiler happy + }; + unsigned long long begin; +}; + +static char *s_strdup(char *s) { + char *ret=NULL; + if (s) { + ret=strdup(s); + } + return ret; +} + + +static char *sha1_pass_hex(char *sha1_pass) { // copied from MySQL_Protocol.cpp + if (sha1_pass==NULL) return NULL; + // previous code is commented. Uncomment all to perform validation +// char *buff=(char *)malloc(SHA_DIGEST_LENGTH*2+2); +// buff[0]='*'; +// buff[SHA_DIGEST_LENGTH*2+1]='\0'; +// int i; +// uint8_t a; +// for (i=0;i= 0) NOT NULL DEFAULT 1 , compression INT CHECK (compression >=0 AND compression <= 102400) NOT NULL DEFAULT 0 , max_connections INT CHECK (max_connections >=0) NOT NULL DEFAULT 1000 , max_replication_lag INT CHECK (max_replication_lag >= 0 AND max_replication_lag <= 126144000) NOT NULL DEFAULT 0 , use_ssl INT CHECK (use_ssl IN(0,1)) NOT NULL DEFAULT 0 , max_latency_ms INT UNSIGNED CHECK (max_latency_ms>=0) NOT NULL DEFAULT 0 , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostgroup_id, hostname, port) )" + +// mysql_servers in v1.1.0 +#define ADMIN_SQLITE_TABLE_MYSQL_SERVERS_V1_1_0 "CREATE TABLE mysql_servers (hostgroup_id INT NOT NULL DEFAULT 0 , hostname VARCHAR NOT NULL , port INT NOT NULL DEFAULT 3306 , status VARCHAR CHECK (UPPER(status) IN ('ONLINE','SHUNNED','OFFLINE_SOFT', 'OFFLINE_HARD')) NOT NULL DEFAULT 'ONLINE' , weight INT CHECK (weight >= 0) NOT NULL DEFAULT 1 , compression INT CHECK (compression >=0 AND compression <= 102400) NOT NULL DEFAULT 0 , max_connections INT CHECK (max_connections >=0) NOT NULL DEFAULT 1000 , max_replication_lag INT CHECK (max_replication_lag >= 0 AND max_replication_lag <= 126144000) NOT NULL DEFAULT 0 , PRIMARY KEY (hostgroup_id, hostname, port) )" + +// mysql_servers in v1.2.0e +#define ADMIN_SQLITE_TABLE_MYSQL_SERVERS_V1_2_0e "CREATE TABLE mysql_servers (hostgroup_id INT NOT NULL DEFAULT 0 , hostname VARCHAR NOT NULL , port INT NOT NULL DEFAULT 3306 , status VARCHAR CHECK (UPPER(status) IN ('ONLINE','SHUNNED','OFFLINE_SOFT', 'OFFLINE_HARD')) NOT NULL DEFAULT 'ONLINE' , weight INT CHECK (weight >= 0) NOT NULL DEFAULT 1 , compression INT CHECK (compression >=0 AND compression <= 102400) NOT NULL DEFAULT 0 , max_connections INT CHECK (max_connections >=0) NOT NULL DEFAULT 1000 , max_replication_lag INT CHECK (max_replication_lag >= 0 AND max_replication_lag <= 126144000) NOT NULL DEFAULT 0 , use_ssl INT CHECK (use_ssl IN(0,1)) NOT NULL DEFAULT 0 , max_latency_ms INT UNSIGNED CHECK (max_latency_ms>=0) NOT NULL DEFAULT 0 , PRIMARY KEY (hostgroup_id, hostname, port) )" + +#define ADMIN_SQLITE_TABLE_MYSQL_SERVERS_V1_2_2 "CREATE TABLE mysql_servers (hostgroup_id INT NOT NULL DEFAULT 0 , hostname VARCHAR NOT NULL , port INT NOT NULL DEFAULT 3306 , status VARCHAR CHECK (UPPER(status) IN ('ONLINE','SHUNNED','OFFLINE_SOFT', 'OFFLINE_HARD')) NOT NULL DEFAULT 'ONLINE' , weight INT CHECK (weight >= 0) NOT NULL DEFAULT 1 , compression INT CHECK (compression >=0 AND compression <= 102400) NOT NULL DEFAULT 0 , max_connections INT CHECK (max_connections >=0) NOT NULL DEFAULT 1000 , max_replication_lag INT CHECK (max_replication_lag >= 0 AND max_replication_lag <= 126144000) NOT NULL DEFAULT 0 , use_ssl INT CHECK (use_ssl IN(0,1)) NOT NULL DEFAULT 0 , max_latency_ms INT UNSIGNED CHECK (max_latency_ms>=0) NOT NULL DEFAULT 0 , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostgroup_id, hostname, port) )" + +#define ADMIN_SQLITE_TABLE_MYSQL_USERS_V1_3_0 "CREATE TABLE mysql_users (username VARCHAR NOT NULL , password VARCHAR , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1 , use_ssl INT CHECK (use_ssl IN (0,1)) NOT NULL DEFAULT 0 , default_hostgroup INT NOT NULL DEFAULT 0 , default_schema VARCHAR , schema_locked INT CHECK (schema_locked IN (0,1)) NOT NULL DEFAULT 0 , transaction_persistent INT CHECK (transaction_persistent IN (0,1)) NOT NULL DEFAULT 0 , fast_forward INT CHECK (fast_forward IN (0,1)) NOT NULL DEFAULT 0 , backend INT CHECK (backend IN (0,1)) NOT NULL DEFAULT 1 , frontend INT CHECK (frontend IN (0,1)) NOT NULL DEFAULT 1 , max_connections INT CHECK (max_connections >=0) NOT NULL DEFAULT 10000 , PRIMARY KEY (username, backend) , UNIQUE (username, frontend))" +#define ADMIN_SQLITE_TABLE_MYSQL_USERS_V1_4_0 "CREATE TABLE mysql_users (username VARCHAR NOT NULL , password VARCHAR , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1 , use_ssl INT CHECK (use_ssl IN (0,1)) NOT NULL DEFAULT 0 , default_hostgroup INT NOT NULL DEFAULT 0 , default_schema VARCHAR , schema_locked INT CHECK (schema_locked IN (0,1)) NOT NULL DEFAULT 0 , transaction_persistent INT CHECK (transaction_persistent IN (0,1)) NOT NULL DEFAULT 1 , fast_forward INT CHECK (fast_forward IN (0,1)) NOT NULL DEFAULT 0 , backend INT CHECK (backend IN (0,1)) NOT NULL DEFAULT 1 , frontend INT CHECK (frontend IN (0,1)) NOT NULL DEFAULT 1 , max_connections INT CHECK (max_connections >=0) NOT NULL DEFAULT 10000 , PRIMARY KEY (username, backend) , UNIQUE (username, frontend))" +#define ADMIN_SQLITE_TABLE_MYSQL_USERS ADMIN_SQLITE_TABLE_MYSQL_USERS_V1_4_0 + + +#define ADMIN_SQLITE_RUNTIME_MYSQL_USERS "CREATE TABLE runtime_mysql_users (username VARCHAR NOT NULL , password VARCHAR , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1 , use_ssl INT CHECK (use_ssl IN (0,1)) NOT NULL DEFAULT 0 , default_hostgroup INT NOT NULL DEFAULT 0 , default_schema VARCHAR , schema_locked INT CHECK (schema_locked IN (0,1)) NOT NULL DEFAULT 0 , transaction_persistent INT CHECK (transaction_persistent IN (0,1)) NOT NULL DEFAULT 1 , fast_forward INT CHECK (fast_forward IN (0,1)) NOT NULL DEFAULT 0 , backend INT CHECK (backend IN (0,1)) NOT NULL DEFAULT 1 , frontend INT CHECK (frontend IN (0,1)) NOT NULL DEFAULT 1 , max_connections INT CHECK (max_connections >=0) NOT NULL DEFAULT 10000 , PRIMARY KEY (username, backend) , UNIQUE (username, frontend))" + +// mysql_query_rules in v1.1.0 +#define ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_V1_1_0 "CREATE TABLE mysql_query_rules (rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0 , username VARCHAR , schemaname VARCHAR , flagIN INT NOT NULL DEFAULT 0 , match_digest VARCHAR , match_pattern VARCHAR , negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0 , flagOUT INT , replace_pattern VARCHAR , destination_hostgroup INT DEFAULT NULL , cache_ttl INT CHECK(cache_ttl > 0) , reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL , timeout INT UNSIGNED , delay INT UNSIGNED , error_msg VARCHAR , apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0)" + +// mysql_query_rules in v1.2.0a +#define ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_V1_2_0a "CREATE TABLE mysql_query_rules (rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0 , username VARCHAR , schemaname VARCHAR , flagIN INT NOT NULL DEFAULT 0 , match_digest VARCHAR , match_pattern VARCHAR , negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0 , flagOUT INT , replace_pattern VARCHAR , destination_hostgroup INT DEFAULT NULL , cache_ttl INT CHECK(cache_ttl > 0) , reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL , timeout INT UNSIGNED , delay INT UNSIGNED , mirror_flagOUT INT UNSIGNED , mirror_hostgroup INT UNSIGNED , error_msg VARCHAR , apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0)" + +// mysql_query_rules in v1.2.0g +#define ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_V1_2_0g "CREATE TABLE mysql_query_rules (rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0 , username VARCHAR , schemaname VARCHAR , flagIN INT NOT NULL DEFAULT 0 , client_addr VARCHAR , proxy_addr VARCHAR , proxy_port INT , digest VARCHAR , match_digest VARCHAR , match_pattern VARCHAR , negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0 , flagOUT INT , replace_pattern VARCHAR , destination_hostgroup INT DEFAULT NULL , cache_ttl INT CHECK(cache_ttl > 0) , reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL , timeout INT UNSIGNED , retries INT CHECK (retries>=0 AND retries <=1000) , delay INT UNSIGNED , mirror_flagOUT INT UNSIGNED , mirror_hostgroup INT UNSIGNED , error_msg VARCHAR , log INT CHECK (log IN (0,1)) , apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0)" + +// mysql_query_rules in v1.2.2 +#define ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_V1_2_2 "CREATE TABLE mysql_query_rules (rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0 , username VARCHAR , schemaname VARCHAR , flagIN INT NOT NULL DEFAULT 0 , client_addr VARCHAR , proxy_addr VARCHAR , proxy_port INT , digest VARCHAR , match_digest VARCHAR , match_pattern VARCHAR , negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0 , flagOUT INT , replace_pattern VARCHAR , destination_hostgroup INT DEFAULT NULL , cache_ttl INT CHECK(cache_ttl > 0) , reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL , timeout INT UNSIGNED , retries INT CHECK (retries>=0 AND retries <=1000) , delay INT UNSIGNED , mirror_flagOUT INT UNSIGNED , mirror_hostgroup INT UNSIGNED , error_msg VARCHAR , log INT CHECK (log IN (0,1)) , apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0 , comment VARCHAR)" + +// mysql_query_rules in v1.3.1 +#define ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_V1_3_1 "CREATE TABLE mysql_query_rules (rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0 , username VARCHAR , schemaname VARCHAR , flagIN INT NOT NULL DEFAULT 0 , client_addr VARCHAR , proxy_addr VARCHAR , proxy_port INT , digest VARCHAR , match_digest VARCHAR , match_pattern VARCHAR , negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0 , flagOUT INT , replace_pattern VARCHAR , destination_hostgroup INT DEFAULT NULL , cache_ttl INT CHECK(cache_ttl > 0) , reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL , timeout INT UNSIGNED , retries INT CHECK (retries>=0 AND retries <=1000) , delay INT UNSIGNED , mirror_flagOUT INT UNSIGNED , mirror_hostgroup INT UNSIGNED , error_msg VARCHAR , sticky_conn INT CHECK (sticky_conn IN (0,1)) , multiplex INT CHECK (multiplex IN (0,1)) , log INT CHECK (log IN (0,1)) , apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0 , comment VARCHAR)" + +//mysql_query_rules in v1.4.0 + next_query_flagIN +#define ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_V1_4_0a "CREATE TABLE mysql_query_rules (rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0 , username VARCHAR , schemaname VARCHAR , flagIN INT NOT NULL DEFAULT 0 , client_addr VARCHAR , proxy_addr VARCHAR , proxy_port INT , digest VARCHAR , match_digest VARCHAR , match_pattern VARCHAR , negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0 , re_modifiers VARCHAR DEFAULT 'CASELESS' , flagOUT INT , replace_pattern VARCHAR , destination_hostgroup INT DEFAULT NULL , cache_ttl INT CHECK(cache_ttl > 0) , reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL , timeout INT UNSIGNED , retries INT CHECK (retries>=0 AND retries <=1000) , delay INT UNSIGNED , next_query_flagIN INT UNSIGNED , mirror_flagOUT INT UNSIGNED , mirror_hostgroup INT UNSIGNED , error_msg VARCHAR , sticky_conn INT CHECK (sticky_conn IN (0,1)) , multiplex INT CHECK (multiplex IN (0,1)) , log INT CHECK (log IN (0,1)) , apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0 , comment VARCHAR)" + +#define ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_V1_4_0b "CREATE TABLE mysql_query_rules (rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0 , username VARCHAR , schemaname VARCHAR , flagIN INT NOT NULL DEFAULT 0 , client_addr VARCHAR , proxy_addr VARCHAR , proxy_port INT , digest VARCHAR , match_digest VARCHAR , match_pattern VARCHAR , negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0 , re_modifiers VARCHAR DEFAULT 'CASELESS' , flagOUT INT , replace_pattern VARCHAR , destination_hostgroup INT DEFAULT NULL , cache_ttl INT CHECK(cache_ttl > 0) , reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL , timeout INT UNSIGNED , retries INT CHECK (retries>=0 AND retries <=1000) , delay INT UNSIGNED , next_query_flagIN INT UNSIGNED , mirror_flagOUT INT UNSIGNED , mirror_hostgroup INT UNSIGNED , error_msg VARCHAR , sticky_conn INT CHECK (sticky_conn IN (0,1)) , multiplex INT CHECK (multiplex IN (0,1,2)) , log INT CHECK (log IN (0,1)) , apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0 , comment VARCHAR)" + +#define ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_V1_4_1 "CREATE TABLE mysql_query_rules (rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0 , username VARCHAR , schemaname VARCHAR , flagIN INT NOT NULL DEFAULT 0 , client_addr VARCHAR , proxy_addr VARCHAR , proxy_port INT , digest VARCHAR , match_digest VARCHAR , match_pattern VARCHAR , negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0 , re_modifiers VARCHAR DEFAULT 'CASELESS' , flagOUT INT , replace_pattern VARCHAR , destination_hostgroup INT DEFAULT NULL , cache_ttl INT CHECK(cache_ttl > 0) , reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL , timeout INT UNSIGNED , retries INT CHECK (retries>=0 AND retries <=1000) , delay INT UNSIGNED , next_query_flagIN INT UNSIGNED , mirror_flagOUT INT UNSIGNED , mirror_hostgroup INT UNSIGNED , error_msg VARCHAR , OK_msg VARCHAR , sticky_conn INT CHECK (sticky_conn IN (0,1)) , multiplex INT CHECK (multiplex IN (0,1,2)) , log INT CHECK (log IN (0,1)) , apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0 , comment VARCHAR)" + +#define ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_V1_4_1 +//#define ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES_V1_4_0b + +#define ADMIN_SQLITE_TABLE_GLOBAL_VARIABLES "CREATE TABLE global_variables (variable_name VARCHAR NOT NULL PRIMARY KEY , variable_value VARCHAR NOT NULL)" + +#define ADMIN_SQLITE_RUNTIME_GLOBAL_VARIABLES "CREATE TABLE runtime_global_variables (variable_name VARCHAR NOT NULL PRIMARY KEY , variable_value VARCHAR NOT NULL)" + +#define ADMIN_SQLITE_TABLE_MYSQL_REPLICATION_HOSTGROUPS "CREATE TABLE mysql_replication_hostgroups (writer_hostgroup INT CHECK (writer_hostgroup>=0) NOT NULL PRIMARY KEY , reader_hostgroup INT NOT NULL CHECK (reader_hostgroup<>writer_hostgroup AND reader_hostgroup>0) , comment VARCHAR , UNIQUE (reader_hostgroup))" + +// mysql_replication_hostgroups in v1.0 +#define ADMIN_SQLITE_TABLE_MYSQL_REPLICATION_HOSTGROUPS_V1_0 "CREATE TABLE mysql_replication_hostgroups (writer_hostgroup INT CHECK (writer_hostgroup>=0) NOT NULL PRIMARY KEY , reader_hostgroup INT NOT NULL CHECK (reader_hostgroup<>writer_hostgroup AND reader_hostgroup>0) , UNIQUE (reader_hostgroup))" + +// mysql_replication_hostgroups in v1.2.2 +#define ADMIN_SQLITE_TABLE_MYSQL_REPLICATION_HOSTGROUPS_V1_2_2 "CREATE TABLE mysql_replication_hostgroups (writer_hostgroup INT CHECK (writer_hostgroup>=0) NOT NULL PRIMARY KEY , reader_hostgroup INT NOT NULL CHECK (reader_hostgroup<>writer_hostgroup AND reader_hostgroup>0) , comment VARCHAR , UNIQUE (reader_hostgroup))" + +#define ADMIN_SQLITE_TABLE_MYSQL_COLLATIONS "CREATE TABLE mysql_collations (Id INTEGER NOT NULL PRIMARY KEY , Collation VARCHAR NOT NULL , Charset VARCHAR NOT NULL , `Default` VARCHAR NOT NULL)" + +#define ADMIN_SQLITE_TABLE_SCHEDULER "CREATE TABLE scheduler (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1 , interval_ms INTEGER CHECK (interval_ms>=100 AND interval_ms<=100000000) NOT NULL , filename VARCHAR NOT NULL , arg1 VARCHAR , arg2 VARCHAR , arg3 VARCHAR , arg4 VARCHAR , arg5 VARCHAR , comment VARCHAR NOT NULL DEFAULT '')" + +#define ADMIN_SQLITE_TABLE_SCHEDULER_V1_2_0 "CREATE TABLE scheduler (id INTEGER NOT NULL , interval_ms INTEGER CHECK (interval_ms>=100 AND interval_ms<=100000000) NOT NULL , filename VARCHAR NOT NULL , arg1 VARCHAR , arg2 VARCHAR , arg3 VARCHAR , arg4 VARCHAR , arg5 VARCHAR , PRIMARY KEY(id))" + +#define ADMIN_SQLITE_TABLE_SCHEDULER_V1_2_2a "CREATE TABLE scheduler (id INTEGER NOT NULL , interval_ms INTEGER CHECK (interval_ms>=100 AND interval_ms<=100000000) NOT NULL , filename VARCHAR NOT NULL , arg1 VARCHAR , arg2 VARCHAR , arg3 VARCHAR , arg4 VARCHAR , arg5 VARCHAR , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY(id))" + +#define ADMIN_SQLITE_TABLE_SCHEDULER_V1_2_2b "CREATE TABLE scheduler (id INTEGER NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1 , interval_ms INTEGER CHECK (interval_ms>=100 AND interval_ms<=100000000) NOT NULL , filename VARCHAR NOT NULL , arg1 VARCHAR , arg2 VARCHAR , arg3 VARCHAR , arg4 VARCHAR , arg5 VARCHAR , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY(id))" + +#define ADMIN_SQLITE_TABLE_SCHEDULER_V1_2_2c "CREATE TABLE scheduler (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1 , interval_ms INTEGER CHECK (interval_ms>=100 AND interval_ms<=100000000) NOT NULL , filename VARCHAR NOT NULL , arg1 VARCHAR , arg2 VARCHAR , arg3 VARCHAR , arg4 VARCHAR , arg5 VARCHAR , comment VARCHAR NOT NULL DEFAULT '')" + +#define ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_SERVERS "CREATE TABLE runtime_mysql_servers (hostgroup_id INT NOT NULL DEFAULT 0 , hostname VARCHAR NOT NULL , port INT NOT NULL DEFAULT 3306 , status VARCHAR CHECK (UPPER(status) IN ('ONLINE','SHUNNED','OFFLINE_SOFT', 'OFFLINE_HARD')) NOT NULL DEFAULT 'ONLINE' , weight INT CHECK (weight >= 0) NOT NULL DEFAULT 1 , compression INT CHECK (compression >=0 AND compression <= 102400) NOT NULL DEFAULT 0 , max_connections INT CHECK (max_connections >=0) NOT NULL DEFAULT 1000 , max_replication_lag INT CHECK (max_replication_lag >= 0 AND max_replication_lag <= 126144000) NOT NULL DEFAULT 0 , use_ssl INT CHECK (use_ssl IN(0,1)) NOT NULL DEFAULT 0 , max_latency_ms INT UNSIGNED CHECK (max_latency_ms>=0) NOT NULL DEFAULT 0 , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostgroup_id, hostname, port) )" + +#define ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_REPLICATION_HOSTGROUPS "CREATE TABLE runtime_mysql_replication_hostgroups (writer_hostgroup INT CHECK (writer_hostgroup>=0) NOT NULL PRIMARY KEY , reader_hostgroup INT NOT NULL CHECK (reader_hostgroup<>writer_hostgroup AND reader_hostgroup>0) , comment VARCHAR , UNIQUE (reader_hostgroup))" + +#define ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_QUERY_RULES "CREATE TABLE runtime_mysql_query_rules (rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0 , username VARCHAR , schemaname VARCHAR , flagIN INT NOT NULL DEFAULT 0 , client_addr VARCHAR , proxy_addr VARCHAR , proxy_port INT , digest VARCHAR , match_digest VARCHAR , match_pattern VARCHAR , negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0 , re_modifiers VARCHAR , flagOUT INT , replace_pattern VARCHAR , destination_hostgroup INT DEFAULT NULL , cache_ttl INT CHECK(cache_ttl > 0) , reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL , timeout INT UNSIGNED , retries INT CHECK (retries>=0 AND retries <=1000) , delay INT UNSIGNED , next_query_flagIN INT UNSIGNED , mirror_flagOUT INT UNSIGNED , mirror_hostgroup INT UNSIGNED , error_msg VARCHAR , OK_msg VARCHAR , sticky_conn INT CHECK (sticky_conn IN (0,1)) , multiplex INT CHECK (multiplex IN (0,1)) , log INT CHECK (log IN (0,1)) , apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0 , comment VARCHAR)" + +#define ADMIN_SQLITE_TABLE_RUNTIME_SCHEDULER "CREATE TABLE runtime_scheduler (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1 , interval_ms INTEGER CHECK (interval_ms>=100 AND interval_ms<=100000000) NOT NULL , filename VARCHAR NOT NULL , arg1 VARCHAR , arg2 VARCHAR , arg3 VARCHAR , arg4 VARCHAR , arg5 VARCHAR , comment VARCHAR NOT NULL DEFAULT '')" + +#define STATS_SQLITE_TABLE_MYSQL_QUERY_RULES "CREATE TABLE stats_mysql_query_rules (rule_id INTEGER PRIMARY KEY , hits INT NOT NULL)" +#define STATS_SQLITE_TABLE_MYSQL_USERS "CREATE TABLE stats_mysql_users (username VARCHAR PRIMARY KEY , frontend_connections INT NOT NULL , frontend_max_connections INT NOT NULL)" +#define STATS_SQLITE_TABLE_MYSQL_COMMANDS_COUNTERS "CREATE TABLE stats_mysql_commands_counters (Command VARCHAR NOT NULL PRIMARY KEY , Total_Time_us INT NOT NULL , Total_cnt INT NOT NULL , cnt_100us INT NOT NULL , cnt_500us INT NOT NULL , cnt_1ms INT NOT NULL , cnt_5ms INT NOT NULL , cnt_10ms INT NOT NULL , cnt_50ms INT NOT NULL , cnt_100ms INT NOT NULL , cnt_500ms INT NOT NULL , cnt_1s INT NOT NULL , cnt_5s INT NOT NULL , cnt_10s INT NOT NULL , cnt_INFs)" +#define STATS_SQLITE_TABLE_MYSQL_PROCESSLIST "CREATE TABLE stats_mysql_processlist (ThreadID INT NOT NULL , SessionID INTEGER PRIMARY KEY , user VARCHAR , db VARCHAR , cli_host VARCHAR , cli_port VARCHAR , hostgroup VARCHAR , l_srv_host VARCHAR , l_srv_port VARCHAR , srv_host VARCHAR , srv_port VARCHAR , command VARCHAR , time_ms INT NOT NULL , info VARCHAR)" +#define STATS_SQLITE_TABLE_MYSQL_CONNECTION_POOL "CREATE TABLE stats_mysql_connection_pool (hostgroup VARCHAR , srv_host VARCHAR , srv_port VARCHAR , status VARCHAR , ConnUsed INT , ConnFree INT , ConnOK INT , ConnERR INT , Queries INT , Bytes_data_sent INT , Bytes_data_recv INT , Latency_us INT)" + +#define STATS_SQLITE_TABLE_MYSQL_CONNECTION_POOL_RESET "CREATE TABLE stats_mysql_connection_pool_reset (hostgroup VARCHAR , srv_host VARCHAR , srv_port VARCHAR , status VARCHAR , ConnUsed INT , ConnFree INT , ConnOK INT , ConnERR INT , Queries INT , Bytes_data_sent INT , Bytes_data_recv INT , Latency_us INT)" + +#define STATS_SQLITE_TABLE_MYSQL_QUERY_DIGEST "CREATE TABLE stats_mysql_query_digest (hostgroup INT , schemaname VARCHAR NOT NULL , username VARCHAR NOT NULL , digest VARCHAR NOT NULL , digest_text VARCHAR NOT NULL , count_star INTEGER NOT NULL , first_seen INTEGER NOT NULL , last_seen INTEGER NOT NULL , sum_time INTEGER NOT NULL , min_time INTEGER NOT NULL , max_time INTEGER NOT NULL , PRIMARY KEY(hostgroup, schemaname, username, digest))" + +#define STATS_SQLITE_TABLE_MYSQL_QUERY_DIGEST_RESET "CREATE TABLE stats_mysql_query_digest_reset (hostgroup INT , schemaname VARCHAR NOT NULL , username VARCHAR NOT NULL , digest VARCHAR NOT NULL , digest_text VARCHAR NOT NULL , count_star INTEGER NOT NULL , first_seen INTEGER NOT NULL , last_seen INTEGER NOT NULL , sum_time INTEGER NOT NULL , min_time INTEGER NOT NULL , max_time INTEGER NOT NULL , PRIMARY KEY(hostgroup, schemaname, username, digest))" + +#define STATS_SQLITE_TABLE_MYSQL_GLOBAL "CREATE TABLE stats_mysql_global (Variable_Name VARCHAR NOT NULL PRIMARY KEY , Variable_Value VARCHAR NOT NULL)" + +#ifdef DEBUG +#define ADMIN_SQLITE_TABLE_DEBUG_LEVELS "CREATE TABLE debug_levels (module VARCHAR NOT NULL PRIMARY KEY , verbosity INT NOT NULL DEFAULT 0)" +#endif // DEBUG + +#define ADMIN_SQLITE_TABLE_MYSQL_GROUP_REPLICATION_HOSTGROUPS "CREATE TABLE mysql_group_replication_hostgroups (writer_hostgroup INT CHECK (writer_hostgroup>=0) NOT NULL PRIMARY KEY , backup_writer_hostgroup INT CHECK (backup_writer_hostgroup>=0 AND backup_writer_hostgroup<>writer_hostgroup) NOT NULL , reader_hostgroup INT NOT NULL CHECK (reader_hostgroup<>writer_hostgroup AND backup_writer_hostgroup<>reader_hostgroup AND reader_hostgroup>0) , offline_hostgroup INT NOT NULL CHECK (offline_hostgroup<>writer_hostgroup AND offline_hostgroup<>reader_hostgroup AND backup_writer_hostgroup<>offline_hostgroup AND offline_hostgroup>=0) , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1 , max_writers INT NOT NULL CHECK (max_writers >= 0) DEFAULT 1 , writer_is_also_reader INT CHECK (writer_is_also_reader IN (0,1)) NOT NULL DEFAULT 0 , max_transactions_behind INT CHECK (max_transactions_behind>=0) NOT NULL DEFAULT 0 , comment VARCHAR , UNIQUE (reader_hostgroup) , UNIQUE (offline_hostgroup) , UNIQUE (backup_writer_hostgroup))" + +#define ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_GROUP_REPLICATION_HOSTGROUPS "CREATE TABLE runtime_mysql_group_replication_hostgroups (writer_hostgroup INT CHECK (writer_hostgroup>=0) NOT NULL PRIMARY KEY , backup_writer_hostgroup INT CHECK (backup_writer_hostgroup>=0 AND backup_writer_hostgroup<>writer_hostgroup) NOT NULL , reader_hostgroup INT NOT NULL CHECK (reader_hostgroup<>writer_hostgroup AND backup_writer_hostgroup<>reader_hostgroup AND reader_hostgroup>0) , offline_hostgroup INT NOT NULL CHECK (offline_hostgroup<>writer_hostgroup AND offline_hostgroup<>reader_hostgroup AND backup_writer_hostgroup<>offline_hostgroup AND offline_hostgroup>=0) , active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1 , max_writers INT NOT NULL CHECK (max_writers >= 0) DEFAULT 1 , writer_is_also_reader INT CHECK (writer_is_also_reader IN (0,1)) NOT NULL DEFAULT 0 , max_transactions_behind INT CHECK (max_transactions_behind>=0) NOT NULL DEFAULT 0 , comment VARCHAR , UNIQUE (reader_hostgroup) , UNIQUE (offline_hostgroup) , UNIQUE (backup_writer_hostgroup))" +*/ +/* +static char * admin_variables_names[]= { + (char *)"admin_credentials", + (char *)"stats_credentials", + (char *)"mysql_ifaces", + (char *)"telnet_admin_ifaces", + (char *)"telnet_stats_ifaces", + (char *)"refresh_interval", + (char *)"read_only", + (char *)"hash_passwords", + (char *)"version", +#ifdef DEBUG + (char *)"debug", +#endif // DEBUG + NULL +}; +*/ + +static char * SQLite3_Server_variables_names[] = { + (char *)"mysql_ifaces", + (char *)"read_only", + (char *)"version", +#ifdef DEBUG + (char *)"debug", +#endif // DEBUG + NULL +}; + +/* +static ProxySQL_Admin *SPA=NULL; +*/ +static void * (*child_func[1]) (void *arg); + +typedef struct _main_args { + int nfds; + struct pollfd *fds; + int *callback_func; + volatile int *shutdown; +} main_args; + +typedef struct _ifaces_desc_t { + char **mysql_ifaces; +// char **telnet_admin_ifaces; +// char **telnet_stats_ifaces; +} ifaces_desc_t; +/* +#define MAX_IFACES 8 +#define MAX_ADMIN_LISTENERS 16 +*/ + +#define MAX_IFACES 8 +#define MAX_SQLITE3SERVER_LISTENERS 16 + +class ifaces_desc { + public: + PtrArray *ifaces; + ifaces_desc() { + ifaces=new PtrArray(); + } + bool add(const char *iface) { + for (unsigned int i=0; ilen; i++) { + if (strcmp((const char *)ifaces->index(i),iface)==0) { + return false; + } + } + ifaces->add(strdup(iface)); + return true; + } + ~ifaces_desc() { + while(ifaces->len) { + char *d=(char *)ifaces->remove_index_fast(0); + free(d); + } + delete ifaces; + } +}; + +class sqlite3server_main_loop_listeners { + private: + int version; + pthread_rwlock_t rwlock; + + char ** reset_ifaces(char **ifaces) { + int i; + if (ifaces) { + for (i=0; iadd(token); + i++; + } + free_tokenizer( &tok ); + version++; + wrunlock(); + } + + + bool update_ifaces(char *list, char ***_ifaces) { + wrlock(); + int i; + char **ifaces=*_ifaces; + tokenizer_t tok = tokenizer( list, ";", TOKENIZER_NO_EMPTIES ); + const char* token; + ifaces=reset_ifaces(ifaces); + i=0; + for ( token = tokenize( &tok ) ; token && i < MAX_IFACES ; token = tokenize( &tok ) ) { + ifaces[i]=(char *)malloc(strlen(token)+1); + strcpy(ifaces[i],token); + i++; + } + free_tokenizer( &tok ); + version++; + wrunlock(); + return true; + } +}; + +static sqlite3server_main_loop_listeners S_amll; + + + +/* +bool admin_handler_command_kill_connection(char *query_no_space, unsigned int query_no_space_length, MySQL_Session *sess, ProxySQL_Admin *pa) { + uint32_t id=atoi(query_no_space+16); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Trying to kill session %u\n", id); + bool rc=GloMTH->kill_session(id); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + if (rc) { + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + } else { + char buf[1024]; + sprintf(buf,"Unknown thread id: %u", id); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, buf); + } + return false; +} +*/ +/* + * returns false if the command is a valid one and is processed + * return true if the command is not a valid one and needs to be executed by SQLite (that will return an error) + */ +/* +bool admin_handler_command_proxysql(char *query_no_space, unsigned int query_no_space_length, MySQL_Session *sess, ProxySQL_Admin *pa) { + if (query_no_space_length==strlen("PROXYSQL READONLY") && !strncasecmp("PROXYSQL READONLY",query_no_space, query_no_space_length)) { + // this command enables admin_read_only , so the admin module is in read_only mode + proxy_info("Received PROXYSQL READONLY command\n"); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->set_read_only(true); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + if (query_no_space_length==strlen("PROXYSQL READWRITE") && !strncasecmp("PROXYSQL READWRITE",query_no_space, query_no_space_length)) { + // this command disables admin_read_only , so the admin module won't be in read_only mode + proxy_info("Received PROXYSQL WRITE command\n"); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->set_read_only(false); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + if (query_no_space_length==strlen("PROXYSQL START") && !strncasecmp("PROXYSQL START",query_no_space, query_no_space_length)) { + proxy_info("Received PROXYSQL START command\n"); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + bool rc=false; + if (nostart_) { + rc=__sync_bool_compare_and_swap(&GloVars.global.nostart,1,0); + } + if (rc) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Starting ProxySQL following PROXYSQL START command\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + } else { + proxy_warning("ProxySQL was already started when received PROXYSQL START command\n"); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, (char *)"ProxySQL already started"); + } + return false; + } + + if (query_no_space_length==strlen("PROXYSQL RESTART") && !strncasecmp("PROXYSQL RESTART",query_no_space, query_no_space_length)) { + proxy_info("Received PROXYSQL RESTART command\n"); + __sync_bool_compare_and_swap(&glovars.shutdown,0,1); + glovars.reload=1; + return false; + } + + if (query_no_space_length==strlen("PROXYSQL STOP") && !strncasecmp("PROXYSQL STOP",query_no_space, query_no_space_length)) { + proxy_info("Received PROXYSQL STOP command\n"); + // to speed up this process we first change wait_timeout to 0 + // MySQL_thread will call poll() with a maximum timeout of 100ms + old_wait_timeout=GloMTH->get_variable_int((char *)"wait_timeout"); + GloMTH->set_variable((char *)"wait_timeout",(char *)"0"); + GloMTH->commit(); + GloMTH->signal_all_threads(0); + GloMTH->stop_listeners(); + char buf[32]; + sprintf(buf,"%d",old_wait_timeout); + GloMTH->set_variable((char *)"wait_timeout",buf); + GloMTH->commit(); + glovars.reload=2; + __sync_bool_compare_and_swap(&glovars.shutdown,0,1); + return false; + } + + if (query_no_space_length==strlen("PROXYSQL PAUSE") && !strncasecmp("PROXYSQL PAUSE",query_no_space, query_no_space_length)) { + proxy_info("Received PROXYSQL PAUSE command\n"); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + if (nostart_) { + if (__sync_fetch_and_add((uint8_t *)(&GloVars.global.nostart),0)) { + SPA->send_MySQL_ERR(&sess->client_myds->myprot, (char *)"ProxySQL MySQL module not running, impossible to pause"); + return false; + } + } + if (proxysql_mysql_paused==false) { + // to speed up this process we first change poll_timeout to 10 + // MySQL_thread will call poll() with a maximum timeout of 10ms + old_wait_timeout=GloMTH->get_variable_int((char *)"poll_timeout"); + GloMTH->set_variable((char *)"poll_timeout",(char *)"10"); + GloMTH->commit(); + GloMTH->signal_all_threads(0); + GloMTH->stop_listeners(); + proxysql_mysql_paused=true; + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + // we now rollback poll_timeout + char buf[32]; + sprintf(buf,"%d",old_wait_timeout); + GloMTH->set_variable((char *)"poll_timeout",buf); + GloMTH->commit(); + } else { + SPA->send_MySQL_ERR(&sess->client_myds->myprot, (char *)"ProxySQL MySQL module is already paused, impossible to pause"); + } + return false; + } + + if (query_no_space_length==strlen("PROXYSQL RESUME") && !strncasecmp("PROXYSQL RESUME",query_no_space, query_no_space_length)) { + proxy_info("Received PROXYSQL RESUME command\n"); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + if (nostart_) { + if (__sync_fetch_and_add((uint8_t *)(&GloVars.global.nostart),0)) { + SPA->send_MySQL_ERR(&sess->client_myds->myprot, (char *)"ProxySQL MySQL module not running, impossible to resume"); + return false; + } + } + if (proxysql_mysql_paused==true) { + // to speed up this process we first change poll_timeout to 10 + // MySQL_thread will call poll() with a maximum timeout of 10ms + old_wait_timeout=GloMTH->get_variable_int((char *)"poll_timeout"); + GloMTH->set_variable((char *)"poll_timeout",(char *)"10"); + GloMTH->commit(); + GloMTH->signal_all_threads(0); + GloMTH->start_listeners(); + //char buf[32]; + //sprintf(buf,"%d",old_wait_timeout); + //GloMTH->set_variable((char *)"poll_timeout",buf); + //GloMTH->commit(); + proxysql_mysql_paused=false; + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + // we now rollback poll_timeout + char buf[32]; + sprintf(buf,"%d",old_wait_timeout); + GloMTH->set_variable((char *)"poll_timeout",buf); + GloMTH->commit(); + } else { + SPA->send_MySQL_ERR(&sess->client_myds->myprot, (char *)"ProxySQL MySQL module is not paused, impossible to resume"); + } + return false; + } + + if (query_no_space_length==strlen("PROXYSQL SHUTDOWN") && !strncasecmp("PROXYSQL SHUTDOWN",query_no_space, query_no_space_length)) { + proxy_info("Received PROXYSQL SHUTDOWN command\n"); + __sync_bool_compare_and_swap(&glovars.shutdown,0,1); + glovars.reload=0; + return false; + } + + if (query_no_space_length==strlen("PROXYSQL FLUSH LOGS") && !strncasecmp("PROXYSQL FLUSH LOGS",query_no_space, query_no_space_length)) { + proxy_info("Received PROXYSQL FLUSH LOGS command\n"); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + if (GloMyLogger) { + GloMyLogger->flush_log(); + } + SPA->flush_error_log(); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + if ( + (query_no_space_length==strlen("PROXYSQL FLUSH CONFIGDB") && !strncasecmp("PROXYSQL FLUSH CONFIGDB",query_no_space, query_no_space_length)) // see #923 + ) { + proxy_info("Received %s command\n", query_no_space); + proxy_warning("A misconfigured configdb will cause undefined behaviors\n"); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->flush_configdb(); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + +#ifndef NOJEM + if (query_no_space_length==strlen("PROXYSQL MEMPROFILE START") && !strncasecmp("PROXYSQL MEMPROFILE START",query_no_space, query_no_space_length)) { + bool en=true; + mallctl("prof.active", NULL, NULL, &en, sizeof(bool)); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + if (query_no_space_length==strlen("PROXYSQL MEMPROFILE STOP") && !strncasecmp("PROXYSQL MEMPROFILE STOP",query_no_space, query_no_space_length)) { + bool en=false; + mallctl("prof.active", NULL, NULL, &en, sizeof(bool)); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } +#endif + + if (query_no_space_length==strlen("PROXYSQL KILL") && !strncasecmp("PROXYSQL KILL",query_no_space, query_no_space_length)) { + proxy_info("Received PROXYSQL KILL command\n"); + exit(EXIT_SUCCESS); + } + + return true; +} +*/ +/* +// Returns true if the given name is either a know mysql or admin global variable. +bool is_valid_global_variable(const char *var_name) { + if (strlen(var_name) > 6 && !strncmp(var_name, "mysql-", 6) && GloMTH->has_variable(var_name + 6)) { + return true; + } else if (strlen(var_name) > 6 && !strncmp(var_name, "admin-", 6) && SPA->has_variable(var_name + 6)) { + return true; + } else { + return false; + } +} + +// This method translates a 'SET variable=value' command into an equivalent UPDATE. It doesn't yes support setting +// multiple variables at once. +// +// It modifies the original query. +bool admin_handler_command_set(char *query_no_space, unsigned int query_no_space_length, MySQL_Session *sess, ProxySQL_Admin *pa, char **q, unsigned int *ql) { + if (!strstr(query_no_space,(char *)"password")) { // issue #599 + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Received command %s\n", query_no_space); + if (strcmp(query_no_space,(char *)"set autocommit=0")) { + proxy_info("Received command %s\n", query_no_space); + } + } + // Get a pointer to the beginnig of var=value entry and split to get var name and value + char *set_entry = query_no_space + strlen("SET "); + char *untrimmed_var_name=NULL; + char *var_value=NULL; + c_split_2(set_entry, "=", &untrimmed_var_name, &var_value); + + // Trim spaces from var name to allow writing like 'var = value' + char *var_name = trim_spaces_in_place(untrimmed_var_name); + + + bool run_query = false; + // Check if the command tries to set a non-existing variable. + if (strcmp(var_name,"mysql-init_connect")==0) { + char *err_msg_fmt = (char *) "ERROR: Global variable '%s' is not configurable using SET command. You must run UPDATE global_variables"; + size_t buff_len = strlen(err_msg_fmt) + strlen(var_name) + 1; + char *buff = (char *) malloc(buff_len); + snprintf(buff, buff_len, err_msg_fmt, var_name); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, buff); + free(buff); + run_query = false; + } else { + if (!is_valid_global_variable(var_name)) { + char *err_msg_fmt = (char *) "ERROR: Unknown global variable: '%s'."; + size_t buff_len = strlen(err_msg_fmt) + strlen(var_name) + 1; + char *buff = (char *) malloc(buff_len); + snprintf(buff, buff_len, err_msg_fmt, var_name); + SPA->send_MySQL_OK(&sess->client_myds->myprot, buff); + free(buff); + run_query = false; + } else { + const char *update_format = (char *)"UPDATE global_variables SET variable_value=%s WHERE variable_name='%s'"; + // Computed length is more than needed since it also counts the format modifiers (%s). + size_t query_len = strlen(update_format) + strlen(var_name) + strlen(var_value) + 1; + char *query = (char *)l_alloc(query_len); + snprintf(query, query_len, update_format, var_value, var_name); + + run_query = true; + l_free(*ql,*q); + *q = query; + *ql = strlen(*q) + 1; + } + } + free(untrimmed_var_name); + free(var_value); + return run_query; +} +*/ +/* Note: + * This function can modify the original query + */ +/* +bool admin_handler_command_load_or_save(char *query_no_space, unsigned int query_no_space_length, MySQL_Session *sess, ProxySQL_Admin *pa, char **q, unsigned int *ql) { + proxy_debug(PROXY_DEBUG_ADMIN, 5, "Received command %s\n", query_no_space); + +#ifdef DEBUG + if ((query_no_space_length>11) && ( (!strncasecmp("SAVE DEBUG ", query_no_space, 11)) || (!strncasecmp("LOAD DEBUG ", query_no_space, 11))) ) { + if ( + (query_no_space_length==strlen("LOAD DEBUG TO MEMORY") && !strncasecmp("LOAD DEBUG TO MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD DEBUG TO MEM") && !strncasecmp("LOAD DEBUG TO MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD DEBUG FROM DISK") && !strncasecmp("LOAD DEBUG FROM DISK",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + l_free(*ql,*q); + *q=l_strdup("INSERT OR REPLACE INTO main.debug_levels SELECT * FROM disk.debug_levels"); + *ql=strlen(*q)+1; + return true; + } + + if ( + (query_no_space_length==strlen("SAVE DEBUG FROM MEMORY") && !strncasecmp("SAVE DEBUG FROM MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE DEBUG FROM MEM") && !strncasecmp("SAVE DEBUG FROM MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE DEBUG TO DISK") && !strncasecmp("SAVE DEBUG TO DISK",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + l_free(*ql,*q); + *q=l_strdup("INSERT OR REPLACE INTO disk.debug_levels SELECT * FROM main.debug_levels"); + *ql=strlen(*q)+1; + return true; + } + + if ( + (query_no_space_length==strlen("LOAD DEBUG FROM MEMORY") && !strncasecmp("LOAD DEBUG FROM MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD DEBUG FROM MEM") && !strncasecmp("LOAD DEBUG FROM MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD DEBUG TO RUNTIME") && !strncasecmp("LOAD DEBUG TO RUNTIME",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD DEBUG TO RUN") && !strncasecmp("LOAD DEBUG TO RUN",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + int rc=SPA->load_debug_to_runtime(); + if (rc) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded debug levels to RUNTIME\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + } else { + proxy_debug(PROXY_DEBUG_ADMIN, 1, "Error while loading debug levels to RUNTIME\n"); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, (char *)"Error while loading debug levels to RUNTIME"); + } + return false; + } + + if ( + (query_no_space_length==strlen("SAVE DEBUG TO MEMORY") && !strncasecmp("SAVE DEBUG TO MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE DEBUG TO MEM") && !strncasecmp("SAVE DEBUG TO MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE DEBUG FROM RUNTIME") && !strncasecmp("SAVE DEBUG FROM RUNTIME",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE DEBUG FROM RUN") && !strncasecmp("SAVE DEBUG FROM RUN",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->save_debug_from_runtime(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Saved debug levels from RUNTIME\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + } +#endif // DEBUG + + if ((query_no_space_length>15) && ( (!strncasecmp("SAVE SCHEDULER ", query_no_space, 15)) || (!strncasecmp("LOAD SCHEDULER ", query_no_space, 15))) ) { + + if ( + (query_no_space_length==strlen("LOAD SCHEDULER TO MEMORY") && !strncasecmp("LOAD SCHEDULER TO MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD SCHEDULER TO MEM") && !strncasecmp("LOAD SCHEDULER TO MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD SCHEDULER FROM DISK") && !strncasecmp("LOAD SCHEDULER FROM DISK",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->flush_scheduler__from_disk_to_memory(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loading scheduler to to MEMORY\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + if ( + (query_no_space_length==strlen("SAVE SCHEDULER FROM MEMORY") && !strncasecmp("SAVE SCHEDULER FROM MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE SCHEDULER FROM MEM") && !strncasecmp("SAVE SCHEDULER FROM MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE SCHEDULER TO DISK") && !strncasecmp("SAVE SCHEDULER TO DISK",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->flush_scheduler__from_memory_to_disk(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Saving scheduler to DISK\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + if ( + (query_no_space_length==strlen("LOAD SCHEDULER FROM MEMORY") && !strncasecmp("LOAD SCHEDULER FROM MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD SCHEDULER FROM MEM") && !strncasecmp("LOAD SCHEDULER FROM MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD SCHEDULER TO RUNTIME") && !strncasecmp("LOAD SCHEDULER TO RUNTIME",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD SCHEDULER TO RUN") && !strncasecmp("LOAD SCHEDULER TO RUN",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->load_scheduler_to_runtime(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded scheduler to RUNTIME\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + if ( + (query_no_space_length==strlen("LOAD SCHEDULER FROM CONFIG") && !strncasecmp("LOAD SCHEDULER FROM CONFIG",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + if (GloVars.configfile_open) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loading from file %s\n", GloVars.config_file); + if (GloVars.confFile->OpenFile(NULL)==true) { + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + int rows=0; + rows=SPA->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(); + } else { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Unable to open or parse config file %s\n", GloVars.config_file); + char *s=(char *)"Unable to open or parse config file %s"; + char *m=(char *)malloc(strlen(s)+strlen(GloVars.config_file)+1); + sprintf(m,s,GloVars.config_file); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, m); + free(m); + } + } else { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Unknown config file\n"); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, (char *)"Config file unknown"); + } + return false; + } + + if ( + (query_no_space_length==strlen("SAVE SCHEDULER TO MEMORY") && !strncasecmp("SAVE SCHEDULER TO MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE SCHEDULER TO MEM") && !strncasecmp("SAVE SCHEDULER TO MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE SCHEDULER FROM RUNTIME") && !strncasecmp("SAVE SCHEDULER FROM RUNTIME",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE SCHEDULER FROM RUN") && !strncasecmp("SAVE SCHEDULER FROM RUN",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->save_scheduler_runtime_to_database(false); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Saved scheduler from RUNTIME\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + } + if ((query_no_space_length>16) && (!strncasecmp("LOAD MYSQL USER ", query_no_space, 16)) ) { + if (query_no_space_length>27) { + if (!strncasecmp(" TO RUNTIME", query_no_space+query_no_space_length-11, 11)) { + char *name=(char *)malloc(query_no_space_length-27+1); + strncpy(name,query_no_space+16,query_no_space_length-27); + name[query_no_space_length-27]=0; + int i=0; + int s=strlen(name); + bool legitname=true; + for (i=0; i= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + ( (c == '-') || (c == '+') || (c == '_')) + ) { + v=true; + } + if (v==false) { + legitname=false; + } + } + if (legitname) { + proxy_info("Loading user %s\n", name); + pthread_mutex_lock(&users_mutex); + SPA->public_add_active_users(USERNAME_BACKEND, name); + SPA->public_add_active_users(USERNAME_FRONTEND, name); + pthread_mutex_unlock(&users_mutex); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + } else { + proxy_info("Tried to load invalid user %s\n", name); + char *s=(char *)"Invalid name %s"; + char *m=(char *)malloc(strlen(s)+strlen(name)+1); + sprintf(m,s,name); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, m); + } + free(name); + return false; + } + } + } + if ((query_no_space_length>17) && ( (!strncasecmp("SAVE MYSQL USERS ", query_no_space, 17)) || (!strncasecmp("LOAD MYSQL USERS ", query_no_space, 17))) ) { + + if ( + (query_no_space_length==strlen("LOAD MYSQL USERS TO MEMORY") && !strncasecmp("LOAD MYSQL USERS TO MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL USERS TO MEM") && !strncasecmp("LOAD MYSQL USERS TO MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL USERS FROM DISK") && !strncasecmp("LOAD MYSQL USERS FROM DISK",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->flush_mysql_users__from_disk_to_memory(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loading mysql users to MEMORY\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + if ( + (query_no_space_length==strlen("SAVE MYSQL USERS FROM MEMORY") && !strncasecmp("SAVE MYSQL USERS FROM MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL USERS FROM MEM") && !strncasecmp("SAVE MYSQL USERS FROM MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL USERS TO DISK") && !strncasecmp("SAVE MYSQL USERS TO DISK",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->flush_mysql_users__from_memory_to_disk(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Saving mysql users to DISK\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + if ( + (query_no_space_length==strlen("LOAD MYSQL USERS FROM MEMORY") && !strncasecmp("LOAD MYSQL USERS FROM MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL USERS FROM MEM") && !strncasecmp("LOAD MYSQL USERS FROM MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL USERS TO RUNTIME") && !strncasecmp("LOAD MYSQL USERS TO RUNTIME",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL USERS TO RUN") && !strncasecmp("LOAD MYSQL USERS TO RUN",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->init_users(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded mysql users to RUNTIME\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + if ( + (query_no_space_length==strlen("LOAD MYSQL USERS FROM CONFIG") && !strncasecmp("LOAD MYSQL USERS FROM CONFIG",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + if (GloVars.configfile_open) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loading from file %s\n", GloVars.config_file); + if (GloVars.confFile->OpenFile(NULL)==true) { + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + int rows=0; + rows=SPA->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(); + } else { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Unable to open or parse config file %s\n", GloVars.config_file); + char *s=(char *)"Unable to open or parse config file %s"; + char *m=(char *)malloc(strlen(s)+strlen(GloVars.config_file)+1); + sprintf(m,s,GloVars.config_file); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, m); + free(m); + } + } else { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Unknown config file\n"); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, (char *)"Config file unknown"); + } + return false; + } + + if ( + (query_no_space_length==strlen("SAVE MYSQL USERS TO MEMORY") && !strncasecmp("SAVE MYSQL USERS TO MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL USERS TO MEM") && !strncasecmp("SAVE MYSQL USERS TO MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL USERS FROM RUNTIME") && !strncasecmp("SAVE MYSQL USERS FROM RUNTIME",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL USERS FROM RUN") && !strncasecmp("SAVE MYSQL USERS FROM RUN",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->save_mysql_users_runtime_to_database(false); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Saved mysql users from RUNTIME\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + } + if ((query_no_space_length>21) && ( (!strncasecmp("SAVE MYSQL VARIABLES ", query_no_space, 21)) || (!strncasecmp("LOAD MYSQL VARIABLES ", query_no_space, 21))) ) { + + if ( + (query_no_space_length==strlen("LOAD MYSQL VARIABLES TO MEMORY") && !strncasecmp("LOAD MYSQL VARIABLES TO MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL VARIABLES TO MEM") && !strncasecmp("LOAD MYSQL VARIABLES TO MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL VARIABLES FROM DISK") && !strncasecmp("LOAD MYSQL VARIABLES FROM DISK",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + l_free(*ql,*q); + *q=l_strdup("INSERT OR REPLACE INTO main.global_variables SELECT * FROM disk.global_variables WHERE variable_name LIKE 'mysql-%'"); + *ql=strlen(*q)+1; + return true; + } + + if ( + (query_no_space_length==strlen("SAVE MYSQL VARIABLES FROM MEMORY") && !strncasecmp("SAVE MYSQL VARIABLES FROM MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL VARIABLES FROM MEM") && !strncasecmp("SAVE MYSQL VARIABLES FROM MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL VARIABLES TO DISK") && !strncasecmp("SAVE MYSQL VARIABLES TO DISK",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + l_free(*ql,*q); + *q=l_strdup("INSERT OR REPLACE INTO disk.global_variables SELECT * FROM main.global_variables WHERE variable_name LIKE 'mysql-%'"); + *ql=strlen(*q)+1; + return true; + } + + if ( + (query_no_space_length==strlen("LOAD MYSQL VARIABLES FROM MEMORY") && !strncasecmp("LOAD MYSQL VARIABLES FROM MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL VARIABLES FROM MEM") && !strncasecmp("LOAD MYSQL VARIABLES FROM MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL VARIABLES TO RUNTIME") && !strncasecmp("LOAD MYSQL VARIABLES TO RUNTIME",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL VARIABLES TO RUN") && !strncasecmp("LOAD MYSQL VARIABLES TO RUN",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->load_mysql_variables_to_runtime(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded mysql variables to RUNTIME\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + if ( + (query_no_space_length==strlen("LOAD MYSQL VARIABLES FROM CONFIG") && !strncasecmp("LOAD MYSQL VARIABLES FROM CONFIG",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + if (GloVars.configfile_open) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loading from file %s\n", GloVars.config_file); + if (GloVars.confFile->OpenFile(NULL)==true) { + int rows=0; + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + rows=SPA->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(); + } else { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Unable to open or parse config file %s\n", GloVars.config_file); + char *s=(char *)"Unable to open or parse config file %s"; + char *m=(char *)malloc(strlen(s)+strlen(GloVars.config_file)+1); + sprintf(m,s,GloVars.config_file); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, m); + free(m); + } + } else { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Unknown config file\n"); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, (char *)"Config file unknown"); + } + return false; + } + + if ( + (query_no_space_length==strlen("SAVE MYSQL VARIABLES TO MEMORY") && !strncasecmp("SAVE MYSQL VARIABLES TO MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL VARIABLES TO MEM") && !strncasecmp("SAVE MYSQL VARIABLES TO MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL VARIABLES FROM RUNTIME") && !strncasecmp("SAVE MYSQL VARIABLES FROM RUNTIME",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL VARIABLES FROM RUN") && !strncasecmp("SAVE MYSQL VARIABLES FROM RUN",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->save_mysql_variables_from_runtime(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Saved mysql variables from RUNTIME\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + } + + if ((query_no_space_length>19) && ( (!strncasecmp("SAVE MYSQL SERVERS ", query_no_space, 19)) || (!strncasecmp("LOAD MYSQL SERVERS ", query_no_space, 19))) ) { + + if ( + (query_no_space_length==strlen("LOAD MYSQL SERVERS TO MEMORY") && !strncasecmp("LOAD MYSQL SERVERS TO MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL SERVERS TO MEM") && !strncasecmp("LOAD MYSQL SERVERS TO MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL SERVERS FROM DISK") && !strncasecmp("LOAD MYSQL SERVERS FROM DISK",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->flush_mysql_servers__from_disk_to_memory(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded mysql servers to MEMORY\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + if ( + (query_no_space_length==strlen("SAVE MYSQL SERVERS FROM MEMORY") && !strncasecmp("SAVE MYSQL SERVERS FROM MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL SERVERS FROM MEM") && !strncasecmp("SAVE MYSQL SERVERS FROM MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL SERVERS TO DISK") && !strncasecmp("SAVE MYSQL SERVERS TO DISK",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->flush_mysql_servers__from_memory_to_disk(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Saved mysql servers to DISK\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + if ( + (query_no_space_length==strlen("LOAD MYSQL SERVERS FROM MEMORY") && !strncasecmp("LOAD MYSQL SERVERS FROM MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL SERVERS FROM MEM") && !strncasecmp("LOAD MYSQL SERVERS FROM MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL SERVERS TO RUNTIME") && !strncasecmp("LOAD MYSQL SERVERS TO RUNTIME",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL SERVERS TO RUN") && !strncasecmp("LOAD MYSQL SERVERS TO RUN",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->mysql_servers_wrlock(); + SPA->load_mysql_servers_to_runtime(); + SPA->mysql_servers_wrunlock(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded mysql servers to RUNTIME\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + if ( + (query_no_space_length==strlen("LOAD MYSQL SERVERS FROM CONFIG") && !strncasecmp("LOAD MYSQL SERVERS FROM CONFIG",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + if (GloVars.configfile_open) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loading from file %s\n", GloVars.config_file); + if (GloVars.confFile->OpenFile(NULL)==true) { + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + int rows=0; + rows=SPA->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(); + } else { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Unable to open or parse config file %s\n", GloVars.config_file); + char *s=(char *)"Unable to open or parse config file %s"; + char *m=(char *)malloc(strlen(s)+strlen(GloVars.config_file)+1); + sprintf(m,s,GloVars.config_file); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, m); + free(m); + } + } else { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Unknown config file\n"); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, (char *)"Config file unknown"); + } + return false; + } + + if ( + (query_no_space_length==strlen("SAVE MYSQL SERVERS TO MEMORY") && !strncasecmp("SAVE MYSQL SERVERS TO MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL SERVERS TO MEM") && !strncasecmp("SAVE MYSQL SERVERS TO MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL SERVERS FROM RUNTIME") && !strncasecmp("SAVE MYSQL SERVERS FROM RUNTIME",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL SERVERS FROM RUN") && !strncasecmp("SAVE MYSQL SERVERS FROM RUN",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->mysql_servers_wrlock(); + SPA->save_mysql_servers_runtime_to_database(false); + SPA->mysql_servers_wrunlock(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Saved mysql servers from RUNTIME\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + } + + if ((query_no_space_length>23) && ( (!strncasecmp("SAVE MYSQL QUERY RULES ", query_no_space, 23)) || (!strncasecmp("LOAD MYSQL QUERY RULES ", query_no_space, 23))) ) { + + if ( + (query_no_space_length==strlen("LOAD MYSQL QUERY RULES TO MEMORY") && !strncasecmp("LOAD MYSQL QUERY RULES TO MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL QUERY RULES TO MEM") && !strncasecmp("LOAD MYSQL QUERY RULES TO MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL QUERY RULES FROM DISK") && !strncasecmp("LOAD MYSQL QUERY RULES FROM DISK",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->flush_mysql_query_rules__from_disk_to_memory(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded mysql query rules to MEMORY\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + if ( + (query_no_space_length==strlen("LOAD MYSQL QUERY RULES FROM CONFIG") && !strncasecmp("LOAD MYSQL QUERY RULES FROM CONFIG",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + if (GloVars.configfile_open) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loading from file %s\n", GloVars.config_file); + if (GloVars.confFile->OpenFile(NULL)==true) { + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + int rows=0; + rows=SPA->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(); + } else { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Unable to open or parse config file %s\n", GloVars.config_file); + char *s=(char *)"Unable to open or parse config file %s"; + char *m=(char *)malloc(strlen(s)+strlen(GloVars.config_file)+1); + sprintf(m,s,GloVars.config_file); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, m); + free(m); + } + } else { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Unknown config file\n"); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, (char *)"Config file unknown"); + } + return false; + } + + if ( + (query_no_space_length==strlen("SAVE MYSQL QUERY RULES FROM MEMORY") && !strncasecmp("SAVE MYSQL QUERY RULES FROM MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL QUERY RULES FROM MEM") && !strncasecmp("SAVE MYSQL QUERY RULES FROM MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL QUERY RULES TO DISK") && !strncasecmp("SAVE MYSQL QUERY RULES TO DISK",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->flush_mysql_query_rules__from_memory_to_disk(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Saved mysql query rules to DISK\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + if ( + (query_no_space_length==strlen("LOAD MYSQL QUERY RULES FROM MEMORY") && !strncasecmp("LOAD MYSQL QUERY RULES FROM MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL QUERY RULES FROM MEM") && !strncasecmp("LOAD MYSQL QUERY RULES FROM MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL QUERY RULES TO RUNTIME") && !strncasecmp("LOAD MYSQL QUERY RULES TO RUNTIME",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD MYSQL QUERY RULES TO RUN") && !strncasecmp("LOAD MYSQL QUERY RULES TO RUN",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + char *err=SPA->load_mysql_query_rules_to_runtime(); + if (err==NULL) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded mysql query rules to RUNTIME\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + } else { + SPA->send_MySQL_ERR(&sess->client_myds->myprot, err); + } + return false; + } + + if ( + (query_no_space_length==strlen("SAVE MYSQL QUERY RULES TO MEMORY") && !strncasecmp("SAVE MYSQL QUERY RULES TO MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL QUERY RULES TO MEM") && !strncasecmp("SAVE MYSQL QUERY RULES TO MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL QUERY RULES FROM RUNTIME") && !strncasecmp("SAVE MYSQL QUERY RULES FROM RUNTIME",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE MYSQL QUERY RULES FROM RUN") && !strncasecmp("SAVE MYSQL QUERY RULES FROM RUN",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->save_mysql_query_rules_from_runtime(false); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Saved mysql query rules from RUNTIME\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + } + + if ((query_no_space_length>21) && ( (!strncasecmp("SAVE ADMIN VARIABLES ", query_no_space, 21)) || (!strncasecmp("LOAD ADMIN VARIABLES ", query_no_space, 21))) ) { + + if ( + (query_no_space_length==strlen("LOAD ADMIN VARIABLES TO MEMORY") && !strncasecmp("LOAD ADMIN VARIABLES TO MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD ADMIN VARIABLES TO MEM") && !strncasecmp("LOAD ADMIN VARIABLES TO MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD ADMIN VARIABLES FROM DISK") && !strncasecmp("LOAD ADMIN VARIABLES FROM DISK",query_no_space, query_no_space_length)) + ) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Received %s command\n", query_no_space); + l_free(*ql,*q); + *q=l_strdup("INSERT OR REPLACE INTO main.global_variables SELECT * FROM disk.global_variables WHERE variable_name LIKE 'admin-%'"); + *ql=strlen(*q)+1; + return true; + } + + if ( + (query_no_space_length==strlen("SAVE ADMIN VARIABLES FROM MEMORY") && !strncasecmp("SAVE ADMIN VARIABLES FROM MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE ADMIN VARIABLES FROM MEM") && !strncasecmp("SAVE ADMIN VARIABLES FROM MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE ADMIN VARIABLES TO DISK") && !strncasecmp("SAVE ADMIN VARIABLES TO DISK",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + l_free(*ql,*q); + *q=l_strdup("INSERT OR REPLACE INTO disk.global_variables SELECT * FROM main.global_variables WHERE variable_name LIKE 'admin-%'"); + *ql=strlen(*q)+1; + return true; + } + + if ( + (query_no_space_length==strlen("LOAD ADMIN VARIABLES FROM MEMORY") && !strncasecmp("LOAD ADMIN VARIABLES FROM MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD ADMIN VARIABLES FROM MEM") && !strncasecmp("LOAD ADMIN VARIABLES FROM MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD ADMIN VARIABLES TO RUNTIME") && !strncasecmp("LOAD ADMIN VARIABLES TO RUNTIME",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("LOAD ADMIN VARIABLES TO RUN") && !strncasecmp("LOAD ADMIN VARIABLES TO RUN",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->load_admin_variables_to_runtime(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded admin variables to RUNTIME\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + if ( + (query_no_space_length==strlen("SAVE ADMIN VARIABLES TO MEMORY") && !strncasecmp("SAVE ADMIN VARIABLES TO MEMORY",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE ADMIN VARIABLES TO MEM") && !strncasecmp("SAVE ADMIN VARIABLES TO MEM",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE ADMIN VARIABLES FROM RUNTIME") && !strncasecmp("SAVE ADMIN VARIABLES FROM RUNTIME",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SAVE ADMIN VARIABLES FROM RUN") && !strncasecmp("SAVE ADMIN VARIABLES FROM RUN",query_no_space, query_no_space_length)) + ) { + proxy_info("Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->save_admin_variables_from_runtime(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Saved admin variables from RUNTIME\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + return false; + } + + } + + return true; +} +*/ +/* +void ProxySQL_Admin::flush_configdb() { // see #923 + wrlock(); + admindb->execute((char *)"DETACH DATABASE disk"); + delete configdb; + configdb=new SQLite3DB(); + configdb->open((char *)GloVars.admindb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX); + __attach_db(admindb, configdb, (char *)"disk"); + // Fully synchronous is not required. See to #1055 + // https://sqlite.org/pragma.html#pragma_synchronous + configdb->execute("PRAGMA disk.synchronous=0"); + wrunlock(); +} + +void ProxySQL_Admin::GenericRefreshStatistics(const char *query_no_space, unsigned int query_no_space_length, bool admin) { + bool refresh=false; + bool stats_mysql_processlist=false; + bool stats_mysql_connection_pool=false; + bool stats_mysql_connection_pool_reset=false; + bool stats_mysql_query_digest=false; + bool stats_mysql_query_digest_reset=false; + bool stats_mysql_global=false; + bool stats_mysql_commands_counters=false; + bool stats_mysql_query_rules=false; + bool stats_mysql_users=false; + bool dump_global_variables=false; + + bool runtime_scheduler=false; + bool runtime_mysql_users=false; + bool runtime_mysql_servers=false; + bool runtime_mysql_query_rules=false; + + bool monitor_mysql_server_group_replication_log=false; + + if (strcasestr(query_no_space,"processlist")) + // This will match the following usecases: + // SHOW PROCESSLIST + // SHOW FULL PROCESSLIST + // SELECT * FROM stats_mysql_processlist + { stats_mysql_processlist=true; refresh=true; } + if (strstr(query_no_space,"stats_mysql_query_digest")) + { stats_mysql_query_digest=true; refresh=true; } + if (strstr(query_no_space,"stats_mysql_query_digest_reset")) + { stats_mysql_query_digest_reset=true; refresh=true; } + if (strstr(query_no_space,"stats_mysql_global")) + { stats_mysql_global=true; refresh=true; } + if (strstr(query_no_space,"stats_mysql_connection_pool_reset")) + { + stats_mysql_connection_pool_reset=true; refresh=true; + } else { + if (strstr(query_no_space,"stats_mysql_connection_pool")) + { stats_mysql_connection_pool=true; refresh=true; } + } + if (strstr(query_no_space,"stats_mysql_commands_counters")) + { stats_mysql_commands_counters=true; refresh=true; } + if (strstr(query_no_space,"stats_mysql_query_rules")) + { stats_mysql_query_rules=true; refresh=true; } + if (strstr(query_no_space,"stats_mysql_users")) + { stats_mysql_users=true; refresh=true; } + if (admin) { + if (strstr(query_no_space,"global_variables")) + { dump_global_variables=true; refresh=true; } + if (strstr(query_no_space,"runtime_")) { + if ( + strstr(query_no_space,"runtime_mysql_servers") + || + strstr(query_no_space,"runtime_mysql_replication_hostgroups") + || + strstr(query_no_space,"runtime_mysql_group_replication_hostgroups") + ) { + runtime_mysql_servers=true; refresh=true; + } + if (strstr(query_no_space,"runtime_mysql_users")) { + runtime_mysql_users=true; refresh=true; + } + if (strstr(query_no_space,"runtime_mysql_query_rules")) { + runtime_mysql_query_rules=true; refresh=true; + } + if (strstr(query_no_space,"runtime_scheduler")) { + runtime_scheduler=true; refresh=true; + } + } + } + if (strstr(query_no_space,"mysql_server_group_replication_log")) { + monitor_mysql_server_group_replication_log=true; refresh=true; + } +// if (stats_mysql_processlist || stats_mysql_connection_pool || stats_mysql_query_digest || stats_mysql_query_digest_reset) { + if (refresh==true) { + pthread_mutex_lock(&admin_mutex); + //ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + if (stats_mysql_processlist) + stats___mysql_processlist(); + if (stats_mysql_query_digest) + stats___mysql_query_digests(false); + if (stats_mysql_query_digest_reset) + stats___mysql_query_digests(true); + if (stats_mysql_connection_pool_reset) { + stats___mysql_connection_pool(true); + } else { + if (stats_mysql_connection_pool) + stats___mysql_connection_pool(false); + } + if (stats_mysql_global) + stats___mysql_global(); + if (stats_mysql_query_rules) + stats___mysql_query_rules(); + if (stats_mysql_commands_counters) + stats___mysql_commands_counters(); + if (stats_mysql_users) + stats___mysql_users(); + if (admin) { + if (dump_global_variables) { + admindb->execute("DELETE FROM runtime_global_variables"); // extra + flush_admin_variables___runtime_to_database(admindb, false, false, false, true); + flush_mysql_variables___runtime_to_database(admindb, false, false, false, true); + } + if (runtime_mysql_servers) { + mysql_servers_wrlock(); + save_mysql_servers_runtime_to_database(true); + mysql_servers_wrunlock(); + } + if (runtime_mysql_users) { + save_mysql_users_runtime_to_database(true); + } + if (runtime_mysql_query_rules) { + save_mysql_query_rules_from_runtime(true); + } + if (runtime_scheduler) { + save_scheduler_runtime_to_database(true); + } + } + if (monitor_mysql_server_group_replication_log) { + if (GloMyMon) { + GloMyMon->populate_monitor_mysql_server_group_replication_log(); + } + } + pthread_mutex_unlock(&admin_mutex); + } +} +*/ + +/* +SQLite3_result * ProxySQL_Admin::generate_show_fields_from(const char *tablename, char **err) { + char *tn=NULL; // tablename + // note that tablename is passed with a trailing ' + tn=(char *)malloc(strlen(tablename)); + unsigned int i=0, j=0; + while (iexecute_statement(q2, &error , &cols , &affected_rows , &resultset); + if (error) { + proxy_error("Error on %s : %s\n", q2, error); + free(q2); + *err=strdup(error); + free(error); + if (resultset) delete resultset; + free(tn); + return NULL; + } + + if (resultset==NULL) { + free(tn); + return NULL; + } + + if (resultset->rows_count==0) { + free(tn); + delete resultset; + *err=strdup((char *)"Table does not exist"); + return NULL; + } + + SQLite3_result *result=new SQLite3_result(6); + result->add_column_definition(SQLITE_TEXT,"Field"); + result->add_column_definition(SQLITE_TEXT,"Type"); + result->add_column_definition(SQLITE_TEXT,"Null"); + result->add_column_definition(SQLITE_TEXT,"Key"); + result->add_column_definition(SQLITE_TEXT,"Default"); + result->add_column_definition(SQLITE_TEXT,"Extra"); + char *pta[6]; + pta[1]=(char *)"varchar(255)"; + pta[2]=(char *)"NO"; + pta[3]=(char *)""; + pta[4]=(char *)""; + pta[5]=(char *)""; + free(q2); + for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { + SQLite3_row *r=*it; + pta[0]=r->fields[0]; + result->add_row(pta); + } + delete resultset; + free(tn); + return result; +} + +SQLite3_result * ProxySQL_Admin::generate_show_table_status(const char *tablename, char **err) { + char *pta[18]; + pta[0]=NULL; + char *tn=NULL; // tablename + // note that tablename is passed with a trailing ' + tn=(char *)malloc(strlen(tablename)); + unsigned int i=0, j=0; + while (iexecute_statement(q2, &error , &cols , &affected_rows , &resultset); + if (error) { + proxy_error("Error on %s : %s\n", q2, error); + free(q2); + *err=strdup(error); + free(error); + if (resultset) delete resultset; + free(tn); + return NULL; + } + + if (resultset==NULL) { + free(tn); + return NULL; + } + + if (resultset->rows_count==0) { + free(tn); + delete resultset; + *err=strdup((char *)"Table does not exist"); + return NULL; + } + SQLite3_result *result=new SQLite3_result(18); + result->add_column_definition(SQLITE_TEXT,"Name"); + result->add_column_definition(SQLITE_TEXT,"Engine"); + result->add_column_definition(SQLITE_TEXT,"Version"); + result->add_column_definition(SQLITE_TEXT,"Row_format"); + result->add_column_definition(SQLITE_TEXT,"Rows"); + result->add_column_definition(SQLITE_TEXT,"Avg_row_length"); + result->add_column_definition(SQLITE_TEXT,"Data_length"); + result->add_column_definition(SQLITE_TEXT,"Max_data_length"); + result->add_column_definition(SQLITE_TEXT,"Index_length"); + result->add_column_definition(SQLITE_TEXT,"Data_free"); + result->add_column_definition(SQLITE_TEXT,"Auto_increment"); + result->add_column_definition(SQLITE_TEXT,"Create_time"); + result->add_column_definition(SQLITE_TEXT,"Update_time"); + result->add_column_definition(SQLITE_TEXT,"Check_time"); + result->add_column_definition(SQLITE_TEXT,"Collation"); + result->add_column_definition(SQLITE_TEXT,"Checksum"); + result->add_column_definition(SQLITE_TEXT,"Create_options"); + result->add_column_definition(SQLITE_TEXT,"Comment"); + pta[0]=tn; + pta[1]=(char *)"SQLite"; + pta[2]=(char *)"10"; + pta[3]=(char *)"Dynamic"; + pta[4]=(char *)"10"; + pta[5]=(char *)"0"; + pta[6]=(char *)"0"; + pta[7]=(char *)"0"; + pta[8]=(char *)"0"; + pta[9]=(char *)"0"; + pta[10]=(char *)"NULL"; + pta[11]=(char *)"0000-00-00 00:00:00"; + pta[12]=(char *)"0000-00-00 00:00:00"; + pta[13]=(char *)"0000-00-00 00:00:00"; + pta[14]=(char *)"utf8_bin"; + pta[15]=(char *)"NULL"; + pta[16]=(char *)""; + pta[17]=(char *)""; + result->add_row(pta); + free(tn); + return result; +} + +*/ +void SQLite3_Server_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *pkt) { + + SQLite3_Server *s3s=(SQLite3_Server *)_pa; + char *error=NULL; + int cols; + int affected_rows; + bool run_query=true; + SQLite3_result *resultset=NULL; + char *strA=NULL; + char *strB=NULL; + int strAl, strBl; + char *query=NULL; + unsigned int query_length=pkt->size-sizeof(mysql_hdr); + query=(char *)l_alloc(query_length); + memcpy(query,(char *)pkt->ptr+sizeof(mysql_hdr)+1,query_length-1); + query[query_length-1]=0; + + char *query_no_space=(char *)l_alloc(query_length); + memcpy(query_no_space,query,query_length); + + unsigned int query_no_space_length=remove_spaces(query_no_space); + //fprintf(stderr,"%s----\n",query_no_space); + + // fix bug #925 + while (query_no_space[query_no_space_length-1]==';' || query_no_space[query_no_space_length-1]==' ') { + query_no_space_length--; + query_no_space[query_no_space_length]=0; + } + +/* + if (!strncasecmp("SHOW GLOBAL VARIABLES LIKE 'read_only'", query_no_space, strlen("SHOW GLOBAL VARIABLES LIKE 'read_only'"))) { + l_free(query_length,query); + char *q=(char *)"SELECT 'read_only' Variable_name, '%s' Value FROM global_variables WHERE Variable_name='admin-read_only'"; + query_length=strlen(q)+5; + query=(char *)l_alloc(query_length); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + bool ro=SPA->get_read_only(); + //sprintf(query,q,( ro ? "ON" : "OFF")); + PtrSize_t pkt_2; + if (ro) { + pkt_2.size=110; + pkt_2.ptr=l_alloc(pkt_2.size); + memcpy(pkt_2.ptr,READ_ONLY_ON,pkt_2.size); + } else { + pkt_2.size=111; + pkt_2.ptr=l_alloc(pkt_2.size); + memcpy(pkt_2.ptr,READ_ONLY_OFF,pkt_2.size); + } + sess->status=WAITING_CLIENT_DATA; + sess->client_myds->DSS=STATE_SLEEP; + sess->client_myds->PSarrayOUT->add(pkt_2.ptr,pkt_2.size); + run_query=false; + goto __run_query; + } + + if (sess->session_type == PROXYSQL_SESSION_ADMIN) { // no stats + if ((query_no_space_length>8) && (!strncasecmp("PROXYSQL ", query_no_space, 8))) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Received PROXYSQL command\n"); + pthread_mutex_lock(&admin_mutex); + run_query=admin_handler_command_proxysql(query_no_space, query_no_space_length, sess, pa); + pthread_mutex_unlock(&admin_mutex); + goto __run_query; + } + if ((query_no_space_length>5) && ( (!strncasecmp("SAVE ", query_no_space, 5)) || (!strncasecmp("LOAD ", query_no_space, 5))) ) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Received LOAD or SAVE command\n"); + run_query=admin_handler_command_load_or_save(query_no_space, query_no_space_length, sess, pa, &query, &query_length); + goto __run_query; + } + if ((query_no_space_length>16) && ( (!strncasecmp("KILL CONNECTION ", query_no_space, 16)) || (!strncasecmp("KILL CONNECTION ", query_no_space, 16))) ) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Received KILL CONNECTION command\n"); + run_query=admin_handler_command_kill_connection(query_no_space, query_no_space_length, sess, pa); + goto __run_query; + } + + + // queries generated by mysqldump + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + if ( +*/ +// !strncmp("/*!40014 SET ", query_no_space, 13) || +// !strncmp("/*!40101 SET ", query_no_space, 13) || +// !strncmp("/*!40103 SET ", query_no_space, 13) || +// !strncmp("/*!40111 SET ", query_no_space, 13) || +// !strncmp("/*!40000 ALTER TABLE", query_no_space, strlen("/*!40000 ALTER TABLE")) +// || +// !strncmp("/*!40100 SET @@SQL_MODE='' */", query_no_space, strlen("/*!40100 SET @@SQL_MODE='' */")) +// || +// !strncmp("/*!40103 SET TIME_ZONE=", query_no_space, strlen("/*!40103 SET TIME_ZONE=")) +// || +// !strncmp("LOCK TABLES", query_no_space, strlen("LOCK TABLES")) +// || +// !strncmp("UNLOCK TABLES", query_no_space, strlen("UNLOCK TABLES")) +// || +// !strncmp("SET SQL_QUOTE_SHOW_CREATE=1", query_no_space, strlen("SET SQL_QUOTE_SHOW_CREATE=1")) +// || +// !strncmp("SET SESSION character_set_results", query_no_space, strlen("SET SESSION character_set_results")) +// || +/* + !strncasecmp("USE ", query_no_space, strlen("USE ")) // this applies to all clients, not only mysqldump + ) { + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + run_query=false; + goto __run_query; + } + if (!strncmp("SHOW VARIABLES LIKE 'gtid\\_mode'", query_no_space, strlen("SHOW VARIABLES LIKE 'gtid\\_mode'"))) { + l_free(query_length,query); + query=l_strdup("SELECT variable_name Variable_name, Variable_value Value FROM global_variables WHERE Variable_name='gtid_mode'"); + query_length=strlen(query)+1; + goto __run_query; + } + if (!strncmp("select @@collation_database", query_no_space, strlen("select @@collation_database"))) { + l_free(query_length,query); + query=l_strdup("SELECT Collation '@@collation_database' FROM mysql_collations WHERE Collation='utf8_general_ci' LIMIT 1"); + query_length=strlen(query)+1; + goto __run_query; + } + if (!strncmp("SHOW VARIABLES LIKE 'ndbinfo\\_version'", query_no_space, strlen("SHOW VARIABLES LIKE 'ndbinfo\\_version'"))) { + l_free(query_length,query); + query=l_strdup("SELECT variable_name Variable_name, Variable_value Value FROM global_variables WHERE Variable_name='ndbinfo_version'"); + query_length=strlen(query)+1; + goto __run_query; + } + if (!strncmp("show table status like '", query_no_space, strlen("show table status like '"))) { + char *strA=query_no_space+24; + int strAl=strlen(strA); + if (strAl<2) { // error + goto __run_query; + } + char *err=NULL; + SQLite3_result *resultset=SPA->generate_show_table_status(strA, &err); + sess->SQLite3_to_MySQL(resultset, err, 0, &sess->client_myds->myprot); + if (resultset) delete resultset; + if (err) free(err); + run_query=false; + goto __run_query; + } + if (!strncmp("show fields from `", query_no_space, strlen("show fields from `"))) { + char *strA=query_no_space+18; + int strAl=strlen(strA); + if (strAl<2) { // error + goto __run_query; + } + char *err=NULL; + SQLite3_result *resultset=SPA->generate_show_fields_from(strA, &err); + sess->SQLite3_to_MySQL(resultset, err, 0, &sess->client_myds->myprot); + if (resultset) delete resultset; + if (err) free(err); + run_query=false; + goto __run_query; + } + } + + // FIXME: this should be removed, it is just a POC for issue #253 . What is important is the call to GloMTH->signal_all_threads(); + if (!strncasecmp("SIGNAL MYSQL THREADS", query_no_space, strlen("SIGNAL MYSQL THREADS"))) { + GloMTH->signal_all_threads(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Received %s command\n", query_no_space); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SPA->save_admin_variables_from_runtime(); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Sent signal to all mysql threads\n"); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + run_query=false; + goto __run_query; + } + + // fix bug #442 + if (!strncmp("SET SQL_SAFE_UPDATES=1", query_no_space, strlen("SET SQL_SAFE_UPDATES=1"))) { + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + run_query=false; + goto __run_query; + } + + if (query_no_space_length==SELECT_VERSION_COMMENT_LEN) { + if (!strncasecmp(SELECT_VERSION_COMMENT, query_no_space, query_no_space_length)) { + l_free(query_length,query); + query=l_strdup("SELECT '(ProxySQL Admin Module)'"); + query_length=strlen(query)+1; + goto __run_query; + } + } + + if (query_no_space_length==SELECT_DB_USER_LEN) { + if (!strncasecmp(SELECT_DB_USER, query_no_space, query_no_space_length)) { + l_free(query_length,query); + char *query1=(char *)"SELECT \"admin\" AS 'DATABASE()', \"%s\" AS 'USER()'"; + char *query2=(char *)malloc(strlen(query1)+strlen(sess->client_myds->myconn->userinfo->username)+10); + sprintf(query2,query1,sess->client_myds->myconn->userinfo->username); + query=l_strdup(query2); + query_length=strlen(query2)+1; + free(query2); + goto __run_query; + } + } + + if (query_no_space_length==SELECT_CHARSET_VARIOUS_LEN) { + if (!strncasecmp(SELECT_CHARSET_VARIOUS, query_no_space, query_no_space_length)) { + l_free(query_length,query); + char *query1=(char *)"select 'utf8' as '@@character_set_client', 'utf8' as '@@character_set_connection', 'utf8' as '@@character_set_server', 'utf8' as '@@character_set_database' limit 1"; + query=l_strdup(query1); + query_length=strlen(query1)+1; + goto __run_query; + } + } + + if (!strncasecmp("SELECT @@version", query_no_space, strlen("SELECT @@version"))) { + l_free(query_length,query); + char *q=(char *)"SELECT '%s' AS '@@version'"; + query_length=strlen(q)+20; + query=(char *)l_alloc(query_length); + sprintf(query,q,PROXYSQL_VERSION); + goto __run_query; + } + + if (!strncasecmp("SELECT version()", query_no_space, strlen("SELECT version()"))) { + l_free(query_length,query); + char *q=(char *)"SELECT '%s' AS 'version()'"; + query_length=strlen(q)+20; + query=(char *)l_alloc(query_length); + sprintf(query,q,PROXYSQL_VERSION); + goto __run_query; + } + + if (!strncasecmp("SHOW VARIABLES WHERE Variable_name in ('max_allowed_packet','system_time_zone','time_zone','sql_mode')", query_no_space, strlen("SHOW VARIABLES WHERE Variable_name in ('max_allowed_packet','system_time_zone','time_zone','sql_mode')"))) { + l_free(query_length,query); + char *q=(char *)"SELECT 'max_allowed_packet' Variable_name,'4194304' Value UNION ALL SELECT 'sql_mode', 'STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION' UNION ALL SELECT 'system_time_zone', 'UTC' UNION ALL SELECT 'time_zone','SYSTEM'"; + query_length=strlen(q)+20; + query=(char *)l_alloc(query_length); + sprintf(query,q,PROXYSQL_VERSION); + goto __run_query; + } + + { + bool rc; + rc=RE2::PartialMatch(query_no_space,*(RE2 *)(pa->match_regexes.re[0])); + if (rc) { + string *new_query=new std::string(query_no_space); + RE2::Replace(new_query,(char *)"^(\\w+)\\s+@@(\\w+)\\s*",(char *)"SELECT variable_value AS '@@max_allowed_packet' FROM global_variables WHERE variable_name='mysql-max_allowed_packet'"); + free(query); + query_length=new_query->length()+1; + query=(char *)malloc(query_length); + memcpy(query,new_query->c_str(),query_length-1); + query[query_length-1]='\0'; + goto __run_query; + } + } + { + bool rc; + rc=RE2::PartialMatch(query_no_space,*(RE2 *)(pa->match_regexes.re[1])); + if (rc) { + string *new_query=new std::string(query_no_space); + RE2::Replace(new_query,(char *)"^(\\w+) *@@([0-9A-Za-z_-]+) *",(char *)"SELECT variable_value AS '@@\\2' FROM global_variables WHERE variable_name='\\2'"); + free(query); + query_length=new_query->length()+1; + query=(char *)malloc(query_length); + memcpy(query,new_query->c_str(),query_length-1); + query[query_length-1]='\0'; + goto __run_query; + } + } + { + bool rc; + rc=RE2::PartialMatch(query_no_space,*(RE2 *)(pa->match_regexes.re[2])); + if (rc) { + string *new_query=new std::string(query_no_space); + RE2::Replace(new_query,(char *)"([Ss][Hh][Oo][Ww]\\s+[Vv][Aa][Rr][Ii][Aa][Bb][Ll][Ee][Ss]\\s+[Ww][Hh][Ee][Rr][Ee])",(char *)"SELECT variable_name AS Variable_name, variable_value AS Value FROM global_variables WHERE"); + free(query); + query_length=new_query->length()+1; + query=(char *)malloc(query_length); + memcpy(query,new_query->c_str(),query_length-1); + query[query_length-1]='\0'; + goto __run_query; + } + } + { + bool rc; + rc=RE2::PartialMatch(query_no_space,*(RE2 *)(pa->match_regexes.re[3])); + if (rc) { + string *new_query=new std::string(query_no_space); + RE2::Replace(new_query,(char *)"([Ss][Hh][Oo][Ww]\\s+[Vv][Aa][Rr][Ii][Aa][Bb][Ll][Ee][Ss]\\s+[Ll][Ii][Kk][Ee])",(char *)"SELECT variable_name AS Variable_name, variable_value AS Value FROM global_variables WHERE variable_name LIKE"); + free(query); + query_length=new_query->length()+1; + query=(char *)malloc(query_length); + memcpy(query,new_query->c_str(),query_length-1); + query[query_length-1]='\0'; + goto __run_query; + } + } + + if (!strncasecmp("SET ", query_no_space, 4)) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Received SET\n"); + run_query = admin_handler_command_set(query_no_space, query_no_space_length, sess, pa, &query, &query_length); + goto __run_query; + } + + if(!strncasecmp("CHECKSUM ", query_no_space, 9)){ + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Received CHECKSUM command\n"); + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + SQLite3_result *resultset=NULL; + char *tablename=NULL; + char *error=NULL; + int affected_rows=0; + int cols=0; + if (strlen(query_no_space)==strlen("CHECKSUM DISK MYSQL SERVERS") && !strncasecmp("CHECKSUM DISK MYSQL SERVERS", query_no_space, strlen(query_no_space))){ + char *q=(char *)"SELECT * FROM mysql_servers ORDER BY hostgroup_id, hostname, port"; + tablename=(char *)"MYSQL SERVERS"; + SPA->configdb->execute_statement(q, &error, &cols, &affected_rows, &resultset); + } + + if (strlen(query_no_space)==strlen("CHECKSUM DISK MYSQL USERS") && !strncasecmp("CHECKSUM DISK MYSQL USERS", query_no_space, strlen(query_no_space))){ + char *q=(char *)"SELECT * FROM mysql_users ORDER BY username"; + tablename=(char *)"MYSQL USERS"; + SPA->configdb->execute_statement(q, &error, &cols, &affected_rows, &resultset); + } + + if (strlen(query_no_space)==strlen("CHECKSUM DISK MYSQL QUERY RULES") && !strncasecmp("CHECKSUM DISK MYSQL QUERY RULES", query_no_space, strlen(query_no_space))){ + char *q=(char *)"SELECT * FROM mysql_query_rules ORDER BY rule_id"; + tablename=(char *)"MYSQL QUERY RULES"; + SPA->configdb->execute_statement(q, &error, &cols, &affected_rows, &resultset); + } + + if (strlen(query_no_space)==strlen("CHECKSUM DISK MYSQL VARIABLES") && !strncasecmp("CHECKSUM DISK MYSQL VARIABLES", query_no_space, strlen(query_no_space))){ + char *q=(char *)"SELECT * FROM global_variables WHERE variable_name LIKE 'mysql-%' ORDER BY variable_name"; + tablename=(char *)"MYSQL VARIABLES"; + SPA->configdb->execute_statement(q, &error, &cols, &affected_rows, &resultset); + } + + if (strlen(query_no_space)==strlen("CHECKSUM DISK MYSQL REPLICATION HOSTGROUPS") && !strncasecmp("CHECKSUM DISK MYSQL REPLICATION HOSTGROUPS", query_no_space, strlen(query_no_space))){ + char *q=(char *)"SELECT * FROM mysql_replication_hostgroups ORDER BY writer_hostgroup"; + tablename=(char *)"MYSQL REPLICATION HOSTGROUPS"; + SPA->configdb->execute_statement(q, &error, &cols, &affected_rows, &resultset); + } + + if ((strlen(query_no_space)==strlen("CHECKSUM MEMORY MYSQL SERVERS") && !strncasecmp("CHECKSUM MEMORY MYSQL SERVERS", query_no_space, strlen(query_no_space))) + || + (strlen(query_no_space)==strlen("CHECKSUM MEM MYSQL SERVERS") && !strncasecmp("CHECKSUM MEM MYSQL SERVERS", query_no_space, strlen(query_no_space))) + || + (strlen(query_no_space)==strlen("CHECKSUM MYSQL SERVERS") && !strncasecmp("CHECKSUM MYSQL SERVERS", query_no_space, strlen(query_no_space)))){ + char *q=(char *)"SELECT * FROM mysql_servers ORDER BY hostgroup_id, hostname, port"; + tablename=(char *)"MYSQL SERVERS"; + SPA->admindb->execute_statement(q, &error, &cols, &affected_rows, &resultset); + } + + if ((strlen(query_no_space)==strlen("CHECKSUM MEMORY MYSQL USERS") && !strncasecmp("CHECKSUM MEMORY MYSQL USERS", query_no_space, strlen(query_no_space))) + || + (strlen(query_no_space)==strlen("CHECKSUM MEM MYSQL USERS") && !strncasecmp("CHECKSUM MEM MYSQL USERS", query_no_space, strlen(query_no_space))) + || + (strlen(query_no_space)==strlen("CHECKSUM MYSQL USERS") && !strncasecmp("CHECKSUM MYSQL USERS", query_no_space, strlen(query_no_space)))){ + char *q=(char *)"SELECT * FROM mysql_users ORDER BY username"; + tablename=(char *)"MYSQL USERS"; + SPA->admindb->execute_statement(q, &error, &cols, &affected_rows, &resultset); + } + + if ((strlen(query_no_space)==strlen("CHECKSUM MEMORY MYSQL QUERY RULES") && !strncasecmp("CHECKSUM MEMORY MYSQL QUERY RULES", query_no_space, strlen(query_no_space))) + || + (strlen(query_no_space)==strlen("CHECKSUM MEM MYSQL QUERY RULES") && !strncasecmp("CHECKSUM MEM MYSQL QUERY RULES", query_no_space, strlen(query_no_space))) + || + (strlen(query_no_space)==strlen("CHECKSUM MYSQL QUERY RULES") && !strncasecmp("CHECKSUM MYSQL QUERY RULES", query_no_space, strlen(query_no_space)))){ + char *q=(char *)"SELECT * FROM mysql_query_rules ORDER BY rule_id"; + tablename=(char *)"MYSQL QUERY RULES"; + SPA->admindb->execute_statement(q, &error, &cols, &affected_rows, &resultset); + } + + if ((strlen(query_no_space)==strlen("CHECKSUM MEMORY MYSQL VARIABLES") && !strncasecmp("CHECKSUM MEMORY MYSQL VARIABLES", query_no_space, strlen(query_no_space))) + || + (strlen(query_no_space)==strlen("CHECKSUM MEM MYSQL VARIABLES") && !strncasecmp("CHECKSUM MEM MYSQL VARIABLES", query_no_space, strlen(query_no_space))) + || + (strlen(query_no_space)==strlen("CHECKSUM MYSQL VARIABLES") && !strncasecmp("CHECKSUM MYSQL VARIABLES", query_no_space, strlen(query_no_space)))){ + char *q=(char *)"SELECT * FROM global_variables WHERE variable_name LIKE 'mysql-%' ORDER BY variable_name"; + tablename=(char *)"MYSQL VARIABLES"; + SPA->admindb->execute_statement(q, &error, &cols, &affected_rows, &resultset); + } + + if ((strlen(query_no_space)==strlen("CHECKSUM MEMORY MYSQL REPLICATION HOSTGROUPS") && !strncasecmp("CHECKSUM MEMORY MYSQL REPLICATION HOSTGROUPS", query_no_space, strlen(query_no_space))) + || + (strlen(query_no_space)==strlen("CHECKSUM MEM MYSQL REPLICATION HOSTGROUPS") && !strncasecmp("CHECKSUM MEM MYSQL REPLICATION HOSTGROUPS", query_no_space, strlen(query_no_space))) + || + (strlen(query_no_space)==strlen("CHECKSUM MYSQL REPLICATION HOSTGROUPS") && !strncasecmp("CHECKSUM MYSQL REPLICATION HOSTGROUPS", query_no_space, strlen(query_no_space)))){ + char *q=(char *)"SELECT * FROM mysql_replication_hostgroups ORDER BY writer_hostgroup"; + tablename=(char *)"MYSQL REPLICATION HOSTGROUPS"; + SPA->admindb->execute_statement(q, &error, &cols, &affected_rows, &resultset); + } + + if ((strlen(query_no_space)==strlen("CHECKSUM MEMORY MYSQL GROUP REPLICATION HOSTGROUPS") && !strncasecmp("CHECKSUM MEMORY GROUP MYSQL REPLICATION HOSTGROUPS", query_no_space, strlen(query_no_space))) + || + (strlen(query_no_space)==strlen("CHECKSUM MEM MYSQL GROUP REPLICATION HOSTGROUPS") && !strncasecmp("CHECKSUM MEM MYSQL GROUP REPLICATION HOSTGROUPS", query_no_space, strlen(query_no_space))) + || + (strlen(query_no_space)==strlen("CHECKSUM MYSQL GROUP REPLICATION HOSTGROUPS") && !strncasecmp("CHECKSUM MYSQL GROUP REPLICATION HOSTGROUPS", query_no_space, strlen(query_no_space)))){ + char *q=(char *)"SELECT * FROM mysql_group_replication_hostgroups ORDER BY writer_hostgroup"; + tablename=(char *)"MYSQL GROUP REPLICATION HOSTGROUPS"; + SPA->admindb->execute_statement(q, &error, &cols, &affected_rows, &resultset); + } + + if (error) { + proxy_error("Error: %s\n", error); + char buf[1024]; + sprintf(buf,"%s", error); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, buf); + run_query=false; + } else if (resultset) { + char *q=(char *)"SELECT '%s' AS 'table', '%s' AS 'checksum'"; + char *checksum=(char *)resultset->checksum(); + query=(char *)malloc(strlen(q)+strlen(tablename)+strlen(checksum)+1); + sprintf(query,q,tablename,checksum); + free(checksum); + } + goto __run_query; + } + + if (strncasecmp("SHOW ", query_no_space, 5)) { + goto __end_show_commands; // in the next block there are only SHOW commands + } + + + if (!strncasecmp("SHOW GLOBAL VARIABLES LIKE 'version'", query_no_space, strlen("SHOW GLOBAL VARIABLES LIKE 'version'"))) { + l_free(query_length,query); + char *q=(char *)"SELECT 'version' Variable_name, '%s' Value FROM global_variables WHERE Variable_name='admin-version'"; + query_length=strlen(q)+20; + query=(char *)l_alloc(query_length); + sprintf(query,q,PROXYSQL_VERSION); + goto __run_query; + } + + + if (query_no_space_length==strlen("SHOW TABLES") && !strncasecmp("SHOW TABLES",query_no_space, query_no_space_length)) { + l_free(query_length,query); + query=l_strdup("SELECT name AS tables FROM sqlite_master WHERE type='table' AND name NOT IN ('sqlite_sequence') ORDER BY name"); + query_length=strlen(query)+1; + goto __run_query; + } + + if (query_no_space_length==strlen("SHOW CHARSET") && !strncasecmp("SHOW CHARSET",query_no_space, query_no_space_length)) { + l_free(query_length,query); + query=l_strdup("SELECT Charset, Collation AS 'Default collation' FROM mysql_collations WHERE `Default`='Yes'"); + query_length=strlen(query)+1; + goto __run_query; + } + + if (query_no_space_length==strlen("SHOW COLLATION") && !strncasecmp("SHOW COLLATION",query_no_space, query_no_space_length)) { + l_free(query_length,query); + query=l_strdup("SELECT * FROM mysql_collations"); + query_length=strlen(query)+1; + goto __run_query; + } + + if ((query_no_space_length>17) && (!strncasecmp("SHOW TABLES FROM ", query_no_space, 17))) { + strA=query_no_space+17; + strAl=strlen(strA); + strB=(char *)"SELECT name AS tables FROM %s.sqlite_master WHERE type='table' AND name NOT IN ('sqlite_sequence') ORDER BY name"; + strBl=strlen(strB); + int l=strBl+strAl-2; + char *b=(char *)l_alloc(l+1); + snprintf(b,l+1,strB,strA); + b[l]=0; + l_free(query_length,query); + query=b; + query_length=l+1; + goto __run_query; + } + + if ((query_no_space_length>17) && (!strncasecmp("SHOW TABLES LIKE ", query_no_space, 17))) { + strA=query_no_space+17; + strAl=strlen(strA); + strB=(char *)"SELECT name AS tables FROM sqlite_master WHERE type='table' AND name LIKE '%s'"; + strBl=strlen(strB); + char *tn=NULL; // tablename + tn=(char *)malloc(strlen(strA)); + unsigned int i=0, j=0; + while (istats___mysql_global(); + goto __run_query; + } + + strA=(char *)"SHOW CREATE TABLE "; + strB=(char *)"SELECT name AS 'table' , REPLACE(REPLACE(sql,' , ', X'2C0A20202020'),'CREATE TABLE %s (','CREATE TABLE %s ('||X'0A20202020') AS 'Create Table' FROM %s.sqlite_master WHERE type='table' AND name='%s'"; + strAl=strlen(strA); + if (strncasecmp("SHOW CREATE TABLE ", query_no_space, strAl)==0) { + strBl=strlen(strB); + char *dbh=NULL; + char *tbh=NULL; + c_split_2(query_no_space+strAl,".",&dbh,&tbh); + + if (strlen(tbh)==0) { + free(tbh); + tbh=dbh; + dbh=strdup("main"); + } + if (strlen(tbh)>=3 && tbh[0]=='`' && tbh[strlen(tbh)-1]=='`') { // tablename is quoted + char *tbh_tmp=(char *)malloc(strlen(tbh)-1); + strncpy(tbh_tmp,tbh+1,strlen(tbh)-2); + tbh_tmp[strlen(tbh)-2]=0; + free(tbh); + tbh=tbh_tmp; + } + int l=strBl+strlen(tbh)*3+strlen(dbh)-8; + char *buff=(char *)l_alloc(l+1); + snprintf(buff,l+1,strB,tbh,tbh,dbh,tbh); + buff[l]=0; + free(tbh); + free(dbh); + l_free(query_length,query); + query=buff; + query_length=l+1; + goto __run_query; + } + + if ( + (query_no_space_length==strlen("SHOW DATABASES") && !strncasecmp("SHOW DATABASES",query_no_space, query_no_space_length)) + || + (query_no_space_length==strlen("SHOW SCHEMAS") && !strncasecmp("SHOW SCHEMAS",query_no_space, query_no_space_length)) + ) { + l_free(query_length,query); + query=l_strdup("PRAGMA DATABASE_LIST"); + query_length=strlen(query)+1; + goto __run_query; + } + + if (query_no_space_length==strlen("SHOW FULL PROCESSLIST") && !strncasecmp("SHOW FULL PROCESSLIST",query_no_space, query_no_space_length)) { + l_free(query_length,query); + query=l_strdup("SELECT * FROM stats_mysql_processlist"); + query_length=strlen(query)+1; + goto __run_query; + } + + if (query_no_space_length==strlen("SHOW PROCESSLIST") && !strncasecmp("SHOW PROCESSLIST",query_no_space, query_no_space_length)) { + l_free(query_length,query); + query=l_strdup("SELECT SessionID, user, db, hostgroup, command, time_ms, SUBSTR(info,0,100) info FROM stats_mysql_processlist"); + query_length=strlen(query)+1; + goto __run_query; + } + +__end_show_commands: + + if (query_no_space_length==strlen("SELECT DATABASE()") && !strncasecmp("SELECT DATABASE()",query_no_space, query_no_space_length)) { + l_free(query_length,query); + if (sess->session_type == PROXYSQL_SESSION_ADMIN) { // no stats + query=l_strdup("SELECT \"admin\" AS 'DATABASE()'"); + } else { + query=l_strdup("SELECT \"stats\" AS 'DATABASE()'"); + } + query_length=strlen(query)+1; + goto __run_query; + } + + // see issue #1022 + if (query_no_space_length==strlen("SELECT DATABASE() AS name") && !strncasecmp("SELECT DATABASE() AS name",query_no_space, query_no_space_length)) { + l_free(query_length,query); + if (sess->session_type == PROXYSQL_SESSION_ADMIN) { // no stats + query=l_strdup("SELECT \"admin\" AS 'name'"); + } else { + query=l_strdup("SELECT \"stats\" AS 'name'"); + } + query_length=strlen(query)+1; + goto __run_query; + } + + if (sess->session_type == PROXYSQL_SESSION_STATS) { // no admin + if ( + (strncasecmp("PRAGMA",query_no_space,6)==0) + || + (strncasecmp("ATTACH",query_no_space,6)==0) + ) { + proxy_error("[WARNING]: Commands executed from stats interface in Admin Module: \"%s\"\n", query_no_space); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, (char *)"Command not allowed"); + run_query=false; + } + } + +*/ +/* +__run_query: + if (run_query) { + ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa; + if (sess->session_type == PROXYSQL_SESSION_ADMIN) { // no stats + if (SPA->get_read_only()) { // disable writes if the admin interface is in read_only mode + SPA->admindb->execute("PRAGMA query_only = ON"); + SPA->admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); + SPA->admindb->execute("PRAGMA query_only = OFF"); + } else { + SPA->admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); + } + } else { + SPA->statsdb->execute("PRAGMA query_only = ON"); + SPA->statsdb->execute_statement(query, &error , &cols , &affected_rows , &resultset); + SPA->statsdb->execute("PRAGMA query_only = OFF"); + } + sess->SQLite3_to_MySQL(resultset, error, affected_rows, &sess->client_myds->myprot); + delete resultset; + } + l_free(pkt->size-sizeof(mysql_hdr),query_no_space); // it is always freed here + l_free(query_length,query); +*/ +} + + +static void *child_mysql(void *arg) { + + int client = *(int *)arg; + + GloMTH->wrlock(); + { + char *s=GloMTH->get_variable((char *)"server_capabilities"); + mysql_thread___server_capabilities=atoi(s); + free(s); + } + GloMTH->wrunlock(); + + struct pollfd fds[1]; + nfds_t nfds=1; + int rc; + pthread_mutex_unlock(&sock_mutex); + MySQL_Thread *mysql_thr=new MySQL_Thread(); + mysql_thr->curtime=monotonic_time(); + GloQPro->init_thread(); + mysql_thr->refresh_variables(); + MySQL_Session *sess=mysql_thr->create_new_session_and_client_data_stream(client); + sess->thread=mysql_thr; + sess->session_type = PROXYSQL_SESSION_SQLITE; + sess->handler_function=SQLite3_Server_session_handler; + MySQL_Data_Stream *myds=sess->client_myds; + + fds[0].fd=client; + fds[0].revents=0; + fds[0].events=POLLIN|POLLOUT; + free(arg); + sess->client_myds->myprot.generate_pkt_initial_handshake(true,NULL,NULL, &sess->thread_session_id); + + while (__sync_fetch_and_add(&glovars.shutdown,0)==0) { + if (myds->available_data_out()) { + fds[0].events=POLLIN|POLLOUT; + } else { + fds[0].events=POLLIN; + } + fds[0].revents=0; + rc=poll(fds,nfds,__sync_fetch_and_add(&__SQLite3_Server_refresh_interval,0)); + if (rc == -1) { + if (errno == EINTR) { + continue; + } else { + goto __exit_child_mysql; + } + } + myds->revents=fds[0].revents; + myds->read_from_net(); + if (myds->net_failure) goto __exit_child_mysql; + myds->read_pkts(); + sess->to_process=1; + int rc=sess->handler(); + if (rc==-1) goto __exit_child_mysql; + } + +__exit_child_mysql: + delete mysql_thr; + return NULL; +} + + +/* +void* child_telnet(void* arg) +{ + int bytes_read; + char line[LINESIZE+1]; + int client = *(int *)arg; + free(arg); + pthread_mutex_unlock(&sock_mutex); + memset(line,0,LINESIZE+1); + while ((strncmp(line, "quit", 4) != 0) && glovars.shutdown==0) { + bytes_read = recv(client, line, LINESIZE, 0); + if (bytes_read==-1) { + break; + } + char *eow = strchr(line, '\n'); + if (eow) *eow=0; + //SPA->is_command(line); + if (strncmp(line,"shutdown",8)==0) glovars.shutdown=1; + if (send(client, line, strlen(line), MSG_NOSIGNAL)==-1) break; + if (send(client, "\nOK\n", 4, MSG_NOSIGNAL)==-1) break; + } + shutdown(client,SHUT_RDWR); + close(client); + return arg; +} + +void* child_telnet_also(void* arg) +{ + int bytes_read; + char line[LINESIZE+1]; + int client = *(int *)arg; + free(arg); + pthread_mutex_unlock(&sock_mutex); + memset(line,0,LINESIZE+1); + while ((strncmp(line, "quit", 4) != 0) && glovars.shutdown==0) { + bytes_read = recv(client, line, LINESIZE, 0); + if (bytes_read==-1) { + break; + } + char *eow = strchr(line, '\n'); + if (eow) *eow=0; + if (strncmp(line,"shutdown",8)==0) glovars.shutdown=1; + if (send(client, line, strlen(line), MSG_NOSIGNAL)==-1) break; + if (send(client, "\nNOT OK\n", 8, MSG_NOSIGNAL)==-1) break; + } + shutdown(client,SHUT_RDWR); + close(client); + return arg; +} +*/ +static void * sqlite3server_main_loop(void *arg) +{ + int i; + int version=0; + struct sockaddr_in addr; + struct pollfd *fds=((struct _main_args *)arg)->fds; + int nfds=((struct _main_args *)arg)->nfds; + int *callback_func=((struct _main_args *)arg)->callback_func; + volatile int *shutdown=((struct _main_args *)arg)->shutdown; + char *socket_names[MAX_SQLITE3SERVER_LISTENERS]; + for (i=0;ischeduler_run_once(); + unsigned long long poll_wait=500000; + if (next_run < curtime + 500000) { + poll_wait=next_run-curtime; + } + if (poll_wait > 500000) { + poll_wait=500000; + } + poll_wait=poll_wait/1000; // conversion to millisecond + rc=poll(fds,nfds,poll_wait); + //if ((nostart_ && __sync_val_compare_and_swap(&GloVars.global.nostart,0,1)==0) || __sync_fetch_and_add(&glovars.shutdown,0)==1) { + // nostart_=false; + // pthread_mutex_unlock(&GloVars.global.start_mutex); + //} + if ((rc == -1 && errno == EINTR) || rc==0) { + // poll() timeout, try again + goto __end_while_pool; + } + for (i=1;ipipefd[0]; + fds[nfds].events=POLLIN; + fds[nfds].revents=0; + nfds++; + unsigned int j; + i=0; j=0; + for (j=0; jifaces->len; j++) { + char *add=NULL; char *port=NULL; char *sn=(char *)S_amll.ifaces_mysql->ifaces->index(j); + + char *h = NULL; + if (*sn == '[') { + char *p = strchr(sn, ']'); + if (p == NULL) + proxy_error("Invalid IPv6 address: %s\n", sn); + + h = ++sn; // remove first '[' + *p = '\0'; + sn = p++; // remove last ']' + add = h; + port = ++p; // remove ':' + } else { + c_split_2(sn, ":" , &add, &port); + } + + int s = ( atoi(port) ? listen_on_port(add, atoi(port), 128) : listen_on_unix(add, 128)); + if (s>0) { fds[nfds].fd=s; fds[nfds].events=POLLIN; fds[nfds].revents=0; callback_func[nfds]=0; socket_names[nfds]=strdup(sn); nfds++; } + if (add) free(add); + if (port) free(port); + } + S_amll.wrunlock(); + } + + } + //if (__sync_add_and_fetch(shutdown,0)==0) __sync_add_and_fetch(shutdown,1); + for (i=0; iset_case_sensitive(false); + match_regexes.re=(void **)malloc(sizeof(void *)*10); + match_regexes.re[0]=(RE2 *)new RE2("^SELECT\\s+@@max_allowed_packet\\s*", *opt2); + match_regexes.re[1]=(RE2 *)new RE2("^SELECT\\s+@@[0-9A-Za-z_-]+\\s*", *opt2); + match_regexes.re[2]=(RE2 *)new RE2("SHOW\\s+VARIABLES\\s+WHERE", *opt2); + match_regexes.re[3]=(RE2 *)new RE2("SHOW\\s+VARIABLES\\s+LIKE", *opt2); +*/ +}; + +void SQLite3_Server::wrlock() { + pthread_rwlock_wrlock(&rwlock); +}; + +void SQLite3_Server::wrunlock() { + pthread_rwlock_unlock(&rwlock); +}; + + +void SQLite3_Server::print_version() { + fprintf(stderr,"Standard ProxySQL SQLite3 Server rev. %s -- %s -- %s\n", PROXYSQL_SQLITE3_SERVER_VERSION, __FILE__, __TIMESTAMP__); +}; + +bool SQLite3_Server::init() { + cpu_timer cpt; + + child_func[0]=child_mysql; +// child_func[1]=child_telnet; +// child_func[2]=child_telnet_also; + main_shutdown=0; + main_poll_nfds=0; + main_poll_fds=NULL; + main_callback_func=NULL; + +/* + { + int rc=pipe(pipefd); + if (rc) { + perror("Call to pipe() failed"); + exit(EXIT_FAILURE); + } + } +*/ + main_callback_func=(int *)malloc(sizeof(int)*MAX_SQLITE3SERVER_LISTENERS); + main_poll_fds=(struct pollfd *)malloc(sizeof(struct pollfd)*MAX_SQLITE3SERVER_LISTENERS); + main_poll_nfds=0; + +/* + pthread_attr_t attr; + pthread_attr_init(&attr); + //pthread_attr_setstacksize (&attr, mystacksize); + + admindb=new SQLite3DB(); + admindb->open((char *)"file:mem_admindb?mode=memory&cache=shared", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX); + statsdb=new SQLite3DB(); + statsdb->open((char *)"file:mem_statsdb?mode=memory&cache=shared", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX); + + // check if file exists , see #617 + bool admindb_file_exists=Proxy_file_exists(GloVars.admindb); + + configdb=new SQLite3DB(); + configdb->open((char *)GloVars.admindb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX); + // Fully synchronous is not required. See to #1055 + // https://sqlite.org/pragma.html#pragma_synchronous + configdb->execute("PRAGMA synchronous=0"); + + monitordb = new SQLite3DB(); + monitordb->open((char *)"file:mem_monitordb?mode=memory&cache=shared", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX); + + tables_defs_admin=new std::vector; + tables_defs_stats=new std::vector; + tables_defs_config=new std::vector; + + insert_into_tables_defs(tables_defs_admin,"mysql_servers", ADMIN_SQLITE_TABLE_MYSQL_SERVERS); + insert_into_tables_defs(tables_defs_admin,"runtime_mysql_servers", ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_SERVERS); + insert_into_tables_defs(tables_defs_admin,"mysql_users", ADMIN_SQLITE_TABLE_MYSQL_USERS); + insert_into_tables_defs(tables_defs_admin,"runtime_mysql_users", ADMIN_SQLITE_RUNTIME_MYSQL_USERS); + insert_into_tables_defs(tables_defs_admin,"runtime_mysql_replication_hostgroups", ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_REPLICATION_HOSTGROUPS); + insert_into_tables_defs(tables_defs_admin,"mysql_replication_hostgroups", ADMIN_SQLITE_TABLE_MYSQL_REPLICATION_HOSTGROUPS); + insert_into_tables_defs(tables_defs_admin,"mysql_group_replication_hostgroups", ADMIN_SQLITE_TABLE_MYSQL_GROUP_REPLICATION_HOSTGROUPS); + insert_into_tables_defs(tables_defs_admin,"runtime_mysql_group_replication_hostgroups", ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_GROUP_REPLICATION_HOSTGROUPS); + insert_into_tables_defs(tables_defs_admin,"mysql_query_rules", ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES); + insert_into_tables_defs(tables_defs_admin,"runtime_mysql_query_rules", ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_QUERY_RULES); + insert_into_tables_defs(tables_defs_admin,"global_variables", ADMIN_SQLITE_TABLE_GLOBAL_VARIABLES); + insert_into_tables_defs(tables_defs_admin,"runtime_global_variables", ADMIN_SQLITE_RUNTIME_GLOBAL_VARIABLES); + insert_into_tables_defs(tables_defs_admin,"mysql_collations", ADMIN_SQLITE_TABLE_MYSQL_COLLATIONS); + insert_into_tables_defs(tables_defs_admin,"scheduler", ADMIN_SQLITE_TABLE_SCHEDULER); + insert_into_tables_defs(tables_defs_admin,"runtime_scheduler", ADMIN_SQLITE_TABLE_RUNTIME_SCHEDULER); +#ifdef DEBUG + insert_into_tables_defs(tables_defs_admin,"debug_levels", ADMIN_SQLITE_TABLE_DEBUG_LEVELS); +#endif // DEBUG + + insert_into_tables_defs(tables_defs_config,"mysql_servers", ADMIN_SQLITE_TABLE_MYSQL_SERVERS); + insert_into_tables_defs(tables_defs_config,"mysql_users", ADMIN_SQLITE_TABLE_MYSQL_USERS); + insert_into_tables_defs(tables_defs_config,"mysql_replication_hostgroups", ADMIN_SQLITE_TABLE_MYSQL_REPLICATION_HOSTGROUPS); + insert_into_tables_defs(tables_defs_config,"mysql_group_replication_hostgroups", ADMIN_SQLITE_TABLE_MYSQL_GROUP_REPLICATION_HOSTGROUPS); + insert_into_tables_defs(tables_defs_config,"mysql_query_rules", ADMIN_SQLITE_TABLE_MYSQL_QUERY_RULES); + insert_into_tables_defs(tables_defs_config,"global_variables", ADMIN_SQLITE_TABLE_GLOBAL_VARIABLES); + // the table is not required to be present on disk. Removing it due to #1055 + insert_into_tables_defs(tables_defs_config,"mysql_collations", ADMIN_SQLITE_TABLE_MYSQL_COLLATIONS); + insert_into_tables_defs(tables_defs_config,"scheduler", ADMIN_SQLITE_TABLE_SCHEDULER); +#ifdef DEBUG + insert_into_tables_defs(tables_defs_config,"debug_levels", ADMIN_SQLITE_TABLE_DEBUG_LEVELS); +#endif // DEBUG + + + insert_into_tables_defs(tables_defs_stats,"stats_mysql_query_rules", STATS_SQLITE_TABLE_MYSQL_QUERY_RULES); + insert_into_tables_defs(tables_defs_stats,"stats_mysql_commands_counters", STATS_SQLITE_TABLE_MYSQL_COMMANDS_COUNTERS); + insert_into_tables_defs(tables_defs_stats,"stats_mysql_processlist", STATS_SQLITE_TABLE_MYSQL_PROCESSLIST); + insert_into_tables_defs(tables_defs_stats,"stats_mysql_connection_pool", STATS_SQLITE_TABLE_MYSQL_CONNECTION_POOL); + insert_into_tables_defs(tables_defs_stats,"stats_mysql_connection_pool_reset", STATS_SQLITE_TABLE_MYSQL_CONNECTION_POOL_RESET); + insert_into_tables_defs(tables_defs_stats,"stats_mysql_query_digest", STATS_SQLITE_TABLE_MYSQL_QUERY_DIGEST); + insert_into_tables_defs(tables_defs_stats,"stats_mysql_query_digest_reset", STATS_SQLITE_TABLE_MYSQL_QUERY_DIGEST_RESET); + insert_into_tables_defs(tables_defs_stats,"stats_mysql_global", STATS_SQLITE_TABLE_MYSQL_GLOBAL); + insert_into_tables_defs(tables_defs_stats,"stats_mysql_users", STATS_SQLITE_TABLE_MYSQL_USERS); + insert_into_tables_defs(tables_defs_stats,"global_variables", ADMIN_SQLITE_TABLE_GLOBAL_VARIABLES); // workaround for issue #708 + + // upgrade mysql_servers if needed (upgrade from previous version) + disk_upgrade_mysql_servers(); + + // upgrade mysql_users if needed (upgrade from previous version) + disk_upgrade_mysql_users(); + + // upgrade mysql_query_rules if needed (upgrade from previous version) + disk_upgrade_mysql_query_rules(); + + // upgrade scheduler if needed (upgrade from previous version) + disk_upgrade_scheduler(); + + check_and_build_standard_tables(admindb, tables_defs_admin); + check_and_build_standard_tables(configdb, tables_defs_config); + check_and_build_standard_tables(statsdb, tables_defs_stats); + + __attach_db(admindb, configdb, (char *)"disk"); + __attach_db(admindb, statsdb, (char *)"stats"); + __attach_db(admindb, monitordb, (char *)"monitor"); + __attach_db(statsdb, monitordb, (char *)"monitor"); + + dump_mysql_collations(); + +#ifdef DEBUG + admindb->execute("ATTACH DATABASE 'file:mem_mydb?mode=memory&cache=shared' AS myhgm"); +#endif // DEBUG + +#ifdef DEBUG + flush_debug_levels_runtime_to_database(configdb, false); + flush_debug_levels_runtime_to_database(admindb, true); +#endif // DEBUG + + flush_mysql_variables___runtime_to_database(configdb, false, false, false); + flush_mysql_variables___runtime_to_database(admindb, false, true, false); + + flush_admin_variables___runtime_to_database(configdb, false, false, false); + flush_admin_variables___runtime_to_database(admindb, false, true, false); + + __insert_or_replace_maintable_select_disktable(); + + flush_admin_variables___database_to_runtime(admindb,true); + + // workaround for issue #708 + statsdb->execute("INSERT OR IGNORE INTO global_variables VALUES('mysql-max_allowed_packet',4194304)"); + +#ifdef DEBUG + if (GloVars.global.gdbg==false && GloVars.__cmd_proxysql_gdbg) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Enabling GloVars.global.gdbg because GloVars.__cmd_proxysql_gdbg==%d\n", GloVars.__cmd_proxysql_gdbg); + GloVars.global.gdbg=true; + } +#endif // DEBUG + + if (GloVars.__cmd_proxysql_reload || GloVars.__cmd_proxysql_initial || admindb_file_exists==false) { // see #617 + if (GloVars.configfile_open) { + if (GloVars.confFile->cfg) { + Read_MySQL_Servers_from_configfile(); + Read_Global_Variables_from_configfile("admin"); + Read_Global_Variables_from_configfile("mysql"); + Read_MySQL_Users_from_configfile(); + Read_MySQL_Query_Rules_from_configfile(); + Read_Scheduler_from_configfile(); + __insert_or_replace_disktable_select_maintable(); + } else { + if (GloVars.confFile->OpenFile(GloVars.config_file)==true) { + 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(); + __insert_or_replace_disktable_select_maintable(); + } + } + } + } + flush_admin_variables___database_to_runtime(admindb,true); + flush_mysql_variables___database_to_runtime(admindb,true); + + if (GloVars.__cmd_proxysql_admin_socket) { + set_variable((char *)"mysql_ifaces",GloVars.__cmd_proxysql_admin_socket); + } +*/ + S_amll.update_ifaces(variables.mysql_ifaces, &S_amll.ifaces_mysql); +// S_amll.update_ifaces(variables.telnet_admin_ifaces, &S_amll.ifaces_telnet_admin); +// S_amll.update_ifaces(variables.telnet_stats_ifaces, &S_amll.ifaces_telnet_stats); + + + + pthread_t SQLite3_Server_thr; + struct _main_args *arg=(struct _main_args *)malloc(sizeof(struct _main_args)); + arg->nfds=main_poll_nfds; + arg->fds=main_poll_fds; + arg->shutdown=&main_shutdown; + arg->callback_func=main_callback_func; + if (pthread_create(&SQLite3_Server_thr, NULL, sqlite3server_main_loop, (void *)arg) !=0 ) { + perror("Thread creation"); + exit(EXIT_FAILURE); + } +// do { usleep(50); } while (__sync_fetch_and_sub(&load_main_,0)==0); +// load_main_=0; +#ifdef DEBUG + std::cerr << "SQLite3 Server initialized in "; +#endif + return true; +}; + +/* +void ProxySQL_Admin::admin_shutdown() { + int i; +// do { usleep(50); } while (main_shutdown==0); + pthread_join(admin_thr, NULL); + delete admindb; + delete statsdb; + delete configdb; + delete monitordb; + sqlite3_shutdown(); + if (main_poll_fds) { + for (i=0;iexecute("DELETE FROM mysql_collations"); + do { + sprintf(buf,query,c->nr, c->name, c->csname); + admindb->execute(buf); + ++c; + } while (c[0].nr != 0); + admindb->execute("INSERT OR REPLACE INTO mysql_collations SELECT Id, Collation, Charset, 'Yes' FROM mysql_collations JOIN (SELECT MIN(Id) minid FROM mysql_collations GROUP BY Charset) t ON t.minid=mysql_collations.Id"); + // the table is not required to be present on disk. Removing it due to #1055 +// admindb->execute("DELETE FROM disk.mysql_collations"); +// admindb->execute("INSERT INTO disk.mysql_collations SELECT * FROM main.mysql_collations"); +} + +void ProxySQL_Admin::check_and_build_standard_tables(SQLite3DB *db, std::vector *tables_defs) { +// int i; + table_def_t *td; + db->execute("PRAGMA foreign_keys = OFF"); + for (std::vector::iterator it=tables_defs->begin(); it!=tables_defs->end(); ++it) { + td=*it; + db->check_and_build_table(td->table_name, td->table_def); + } + db->execute("PRAGMA foreign_keys = ON"); +}; + + + +void ProxySQL_Admin::insert_into_tables_defs(std::vector *tables_defs, const char *table_name, const char *table_def) { + table_def_t *td = new table_def_t; + td->table_name=strdup(table_name); + td->table_def=strdup(table_def); + tables_defs->push_back(td); +}; + +void ProxySQL_Admin::drop_tables_defs(std::vector *tables_defs) { + table_def_t *td; + while (!tables_defs->empty()) { + td=tables_defs->back(); + free(td->table_name); + td->table_name=NULL; + free(td->table_def); + td->table_def=NULL; + tables_defs->pop_back(); + delete td; + } +}; + + +void ProxySQL_Admin::flush_admin_variables___database_to_runtime(SQLite3DB *db, bool replace) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Flushing ADMIN variables. Replace:%d\n", replace); + char *error=NULL; + int cols=0; + int affected_rows=0; + SQLite3_result *resultset=NULL; + char *q=(char *)"SELECT substr(variable_name,7) vn, variable_value FROM global_variables WHERE variable_name LIKE 'admin-%'"; + admindb->execute_statement(q, &error , &cols , &affected_rows , &resultset); + if (error) { + proxy_error("Error on %s : %s\n", q, error); + return; + } else { + wrlock(); + for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { + SQLite3_row *r=*it; + bool rc=set_variable(r->fields[0],r->fields[1]); + if (rc==false) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Impossible to set variable %s with value \"%s\"\n", r->fields[0],r->fields[1]); + if (replace) { + char *val=get_variable(r->fields[0]); + char q[1000]; + if (val) { + if (strcmp(r->fields[0],(char *)"version")) { + proxy_warning("Impossible to set variable %s with value \"%s\". Resetting to current \"%s\".\n", r->fields[0],r->fields[1], val); + } + sprintf(q,"INSERT OR REPLACE INTO global_variables VALUES(\"admin-%s\",\"%s\")",r->fields[0],val); + db->execute(q); + free(val); + } else { + if (strcmp(r->fields[0],(char *)"debug")==0) { + sprintf(q,"DELETE FROM disk.global_variables WHERE variable_name=\"admin-%s\"",r->fields[0]); + db->execute(q); + } else { + proxy_warning("Impossible to set not existing variable %s with value \"%s\". Deleting. If the variable name is correct, this version doesn't support it\n", r->fields[0],r->fields[1]); + } + sprintf(q,"DELETE FROM global_variables WHERE variable_name=\"admin-%s\"",r->fields[0]); + db->execute(q); + } + } + } else { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Set variable %s with value \"%s\"\n", r->fields[0],r->fields[1]); + } + } + //commit(); NOT IMPLEMENTED + wrunlock(); + } + if (resultset) delete resultset; +} + +void ProxySQL_Admin::flush_mysql_variables___database_to_runtime(SQLite3DB *db, bool replace) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Flushing MySQL variables. Replace:%d\n", replace); + char *error=NULL; + int cols=0; + int affected_rows=0; + SQLite3_result *resultset=NULL; + char *q=(char *)"SELECT substr(variable_name,7) vn, variable_value FROM global_variables WHERE variable_name LIKE 'mysql-%'"; + admindb->execute_statement(q, &error , &cols , &affected_rows , &resultset); + if (error) { + proxy_error("Error on %s : %s\n", q, error); + return; + } else { + GloMTH->wrlock(); + for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { + SQLite3_row *r=*it; + bool rc=GloMTH->set_variable(r->fields[0],r->fields[1]); + if (rc==false) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Impossible to set variable %s with value \"%s\"\n", r->fields[0],r->fields[1]); + if (replace) { + char *val=GloMTH->get_variable(r->fields[0]); + char q[1000]; + if (val) { + if (strcmp(val,r->fields[1])) { + proxy_warning("Impossible to set variable %s with value \"%s\". Resetting to current \"%s\".\n", r->fields[0],r->fields[1], val); + sprintf(q,"INSERT OR REPLACE INTO global_variables VALUES(\"mysql-%s\",\"%s\")",r->fields[0],val); + db->execute(q); + } + free(val); + } else { + if (strcmp(r->fields[0],(char *)"session_debug")==0) { + sprintf(q,"DELETE FROM disk.global_variables WHERE variable_name=\"mysql-%s\"",r->fields[0]); + db->execute(q); + } else { + proxy_warning("Impossible to set not existing variable %s with value \"%s\". Deleting. If the variable name is correct, this version doesn't support it\n", r->fields[0],r->fields[1]); + } + sprintf(q,"DELETE FROM global_variables WHERE variable_name=\"mysql-%s\"",r->fields[0]); + db->execute(q); + } + } + } else { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Set variable %s with value \"%s\"\n", r->fields[0],r->fields[1]); + } + } + GloMTH->commit(); + GloMTH->wrunlock(); + } + if (resultset) delete resultset; +} + +void ProxySQL_Admin::flush_mysql_variables___runtime_to_database(SQLite3DB *db, bool replace, bool del, bool onlyifempty, bool runtime) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Flushing MySQL variables. Replace:%d, Delete:%d, Only_If_Empty:%d\n", replace, del, onlyifempty); + if (onlyifempty) { + char *error=NULL; + int cols=0; + int affected_rows=0; + SQLite3_result *resultset=NULL; + char *q=(char *)"SELECT COUNT(*) FROM global_variables WHERE variable_name LIKE 'mysql-%'"; + db->execute_statement(q, &error , &cols , &affected_rows , &resultset); + int matching_rows=0; + if (error) { + proxy_error("Error on %s : %s\n", q, error); + return; + } else { + for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { + SQLite3_row *r=*it; + matching_rows+=atoi(r->fields[0]); + } + } + if (resultset) delete resultset; + if (matching_rows) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Table global_variables has MySQL variables - skipping\n"); + return; + } + } + if (del) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Deleting MySQL variables from global_variables\n"); + db->execute("DELETE FROM global_variables WHERE variable_name LIKE 'mysql-%'"); + } + if (runtime) { + db->execute("DELETE FROM runtime_global_variables WHERE variable_name LIKE 'mysql-%'"); + } + char *a; + char *b=(char *)"INSERT INTO runtime_global_variables(variable_name, variable_value) VALUES(\"mysql-%s\",\"%s\")"; + if (replace) { + a=(char *)"REPLACE INTO global_variables(variable_name, variable_value) VALUES(\"mysql-%s\",\"%s\")"; + } else { + a=(char *)"INSERT OR IGNORE INTO global_variables(variable_name, variable_value) VALUES(\"mysql-%s\",\"%s\")"; + } + int l=strlen(a)+200; + GloMTH->wrlock(); + char **varnames=GloMTH->get_variables_list(); + for (int i=0; varnames[i]; i++) { + char *val=GloMTH->get_variable(varnames[i]); + l+=( varnames[i] ? strlen(varnames[i]) : 6); + l+=( val ? strlen(val) : 6); + char *query=(char *)malloc(l); + sprintf(query, a, varnames[i], val); + if (runtime) { + db->execute(query); + sprintf(query, b, varnames[i], val); + } + db->execute(query); + if (val) + free(val); + free(query); + } + GloMTH->wrunlock(); + for (int i=0; varnames[i]; i++) { + free(varnames[i]); + } + free(varnames); +} +*/ +/* +char **ProxySQL_Admin::get_variables_list() { + size_t l=sizeof(admin_variables_names)/sizeof(char *); + unsigned int i; + char **ret=(char **)malloc(sizeof(char *)*l); + for (i=0;iadd(user,pass,USERNAME_FRONTEND,0,hostgroup_id,(char *)"main",0,0,0,1000); + } + free(user); + free(pass); + } + free_tokenizer( &tok ); +} + +#ifdef DEBUG +void ProxySQL_Admin::delete_credentials(char *type, char *credentials) { +#else +void ProxySQL_Admin::delete_credentials(char *credentials) { +#endif // DEBUG + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Removing old %s credentials: %s\n", type, credentials); + tokenizer_t tok = tokenizer( credentials, ";", TOKENIZER_NO_EMPTIES ); + const char* token; + for (token = tokenize( &tok ); token; token = tokenize( &tok )) { + char *user=NULL; + char *pass=NULL; + c_split_2(token, ":", &user, &pass); + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Removing %s credential: \"%s\", user:%s, pass:%s\n", type, token, user, pass); + if (GloMyAuth) { // this check if required if GloMyAuth doesn't exist yet + GloMyAuth->del(user,USERNAME_FRONTEND); + } + free(user); + free(pass); + } + free_tokenizer( &tok ); +} + +bool ProxySQL_Admin::set_variable(char *name, char *value) { // this is the public function, accessible from admin + size_t vallen=strlen(value); + + if (!strcasecmp(name,"admin_credentials")) { + if (vallen) { + bool update_creds=false; + if ((variables.admin_credentials==NULL) || strcasecmp(variables.admin_credentials,value) ) update_creds=true; + if (update_creds && variables.admin_credentials) { +#ifdef DEBUG + delete_credentials((char *)"admin",variables.admin_credentials); +#else + delete_credentials(variables.admin_credentials); +#endif // DEBUG + } + free(variables.admin_credentials); + variables.admin_credentials=strdup(value); + if (update_creds && variables.admin_credentials) { +#ifdef DEBUG + add_credentials((char *)"admin",variables.admin_credentials, ADMIN_HOSTGROUP); +#else + add_credentials(variables.admin_credentials, ADMIN_HOSTGROUP); +#endif // DEBUG + } + return true; + } else { + return false; + } + } + if (!strcasecmp(name,"stats_credentials")) { + if (vallen) { + bool update_creds=false; + if ((variables.stats_credentials==NULL) || strcasecmp(variables.stats_credentials,value) ) update_creds=true; + if (update_creds && variables.stats_credentials) { +#ifdef DEBUG + delete_credentials((char *)"stats",variables.stats_credentials); +#else + delete_credentials(variables.stats_credentials); +#endif // DEBUG + } + free(variables.stats_credentials); + variables.stats_credentials=strdup(value); + if (update_creds && variables.stats_credentials) { +#ifdef DEBUG + add_credentials((char *)"admin",variables.stats_credentials, STATS_HOSTGROUP); +#else + add_credentials(variables.stats_credentials, STATS_HOSTGROUP); +#endif // DEBUG + } + return true; + } else { + return false; + } + } + if (!strcasecmp(name,"mysql_ifaces")) { + if (vallen) { + bool update_creds=false; + if ((variables.mysql_ifaces==NULL) || strcasecmp(variables.mysql_ifaces,value) ) update_creds=true; + if (variables.mysql_ifaces) + free(variables.mysql_ifaces); + variables.mysql_ifaces=strdup(value); + if (update_creds && variables.mysql_ifaces) { + S_amll.update_ifaces(variables.mysql_ifaces, &S_amll.ifaces_mysql); + } + return true; + } else { + return false; + } + } + if (!strcasecmp(name,"telnet_admin_ifaces")) { + if (vallen) { + bool update_creds=false; + if ((variables.telnet_admin_ifaces==NULL) || strcasecmp(variables.telnet_admin_ifaces,value) ) update_creds=true; + if (variables.telnet_admin_ifaces) + free(variables.telnet_admin_ifaces); + variables.telnet_admin_ifaces=strdup(value); + if (update_creds && variables.telnet_admin_ifaces) { + S_amll.update_ifaces(variables.telnet_admin_ifaces, &S_amll.ifaces_telnet_admin); + } + return true; + } else { + return false; + } + } + if (!strcasecmp(name,"telnet_stats_ifaces")) { + if (vallen) { + bool update_creds=false; + if ((variables.telnet_stats_ifaces==NULL) || strcasecmp(variables.telnet_stats_ifaces,value) ) update_creds=true; + if (variables.telnet_stats_ifaces) + free(variables.telnet_stats_ifaces); + variables.telnet_stats_ifaces=strdup(value); + if (update_creds && variables.telnet_stats_ifaces) { + S_amll.update_ifaces(variables.telnet_stats_ifaces, &S_amll.ifaces_telnet_stats); + } + return true; + } else { + return false; + } + } + if (!strcasecmp(name,"refresh_interval")) { + int intv=atoi(value); + if (intv > 100 && intv < 100000) { + variables.refresh_interval=intv; + __admin_refresh_interval=intv; + return true; + } else { + return false; + } + } + if (!strcasecmp(name,"version")) { + if (strcasecmp(value,(char *)PROXYSQL_VERSION)==0) { + return true; + } else { + return false; + } + } + if (!strcasecmp(name,"hash_passwords")) { + if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { + variables.hash_passwords=true; + return true; + } + if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { + variables.hash_passwords=false; + return true; + } + return false; + } + if (!strcasecmp(name,"read_only")) { + if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { + variables.admin_read_only=true; + return true; + } + if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { + variables.admin_read_only=false; + return true; + } + return false; + } +#ifdef DEBUG + if (!strcasecmp(name,"debug")) { + if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { + variables.debug=true; + GloVars.global.gdbg=true; + return true; + } + if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { + variables.debug=false; + GloVars.global.gdbg=false; + return true; + } + return false; + } +#endif // DEBUG + return false; +} +*/ + +/* +void ProxySQL_Admin::flush_admin_variables___runtime_to_database(SQLite3DB *db, bool replace, bool del, bool onlyifempty, bool runtime) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Flushing ADMIN variables. Replace:%d, Delete:%d, Only_If_Empty:%d\n", replace, del, onlyifempty); + if (onlyifempty) { + char *error=NULL; + int cols=0; + int affected_rows=0; + SQLite3_result *resultset=NULL; + char *q=(char *)"SELECT COUNT(*) FROM global_variables WHERE variable_name LIKE 'admin-%'"; + db->execute_statement(q, &error , &cols , &affected_rows , &resultset); + int matching_rows=0; + if (error) { + proxy_error("Error on %s : %s\n", q, error); + return; + } else { + for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { + SQLite3_row *r=*it; + matching_rows+=atoi(r->fields[0]); + } + } + if (resultset) delete resultset; + if (matching_rows) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Table global_variables has ADMIN variables - skipping\n"); + return; + } + } + if (del) { + proxy_debug(PROXY_DEBUG_ADMIN, 4, "Deleting ADMIN variables from global_variables\n"); + db->execute("DELETE FROM global_variables WHERE variable_name LIKE 'admin-%'"); + } + if (runtime) { + db->execute("DELETE FROM runtime_global_variables WHERE variable_name LIKE 'admin-%'"); + } + char *a; + char *b=(char *)"INSERT INTO runtime_global_variables(variable_name, variable_value) VALUES(\"admin-%s\",\"%s\")"; + if (replace) { + a=(char *)"REPLACE INTO global_variables(variable_name, variable_value) VALUES(\"admin-%s\",\"%s\")"; + } else { + a=(char *)"INSERT OR IGNORE INTO global_variables(variable_name, variable_value) VALUES(\"admin-%s\",\"%s\")"; + } + int l=strlen(a)+200; + + char **varnames=get_variables_list(); + for (int i=0; varnames[i]; i++) { + char *val=get_variable(varnames[i]); + l+=( varnames[i] ? strlen(varnames[i]) : 6); + l+=( val ? strlen(val) : 6); + char *query=(char *)malloc(l); + sprintf(query, a, varnames[i], val); + db->execute(query); + if (runtime) { + sprintf(query, b, varnames[i], val); + db->execute(query); + } + if (val) + free(val); + free(query); + } + for (int i=0; varnames[i]; i++) { + free(varnames[i]); + } + free(varnames); + +} + +#ifdef DEBUG +void ProxySQL_Admin::flush_debug_levels_runtime_to_database(SQLite3DB *db, bool replace) { + int i; + char *a=NULL; + db->execute("DELETE FROM debug_levels WHERE verbosity=0"); + if (replace) { + a=(char *)"REPLACE INTO debug_levels(module,verbosity) VALUES(\"%s\",%d)"; + } else { + a=(char *)"INSERT OR IGNORE INTO debug_levels(module,verbosity) VALUES(\"%s\",%d)"; + } + int l=strlen(a)+100; + for (i=0;iexecute(query); + free(query); + } +} +#endif // DEBUG +*/ + +/* +void ProxySQL_Admin::__attach_db(SQLite3DB *db1, SQLite3DB *db2, char *alias) { + const char *a="ATTACH DATABASE '%s' AS %s"; + int l=strlen(a)+strlen(db2->get_url())+strlen(alias)+5; + char *cmd=(char *)malloc(l); + sprintf(cmd,a,db2->get_url(), alias); + db1->execute(cmd); + free(cmd); +} +*/ + + +void SQLite3_Server::send_MySQL_OK(MySQL_Protocol *myprot, char *msg, int rows) { + assert(myprot); + MySQL_Data_Stream *myds=myprot->get_myds(); + myds->DSS=STATE_QUERY_SENT_DS; + myprot->generate_pkt_OK(true,NULL,NULL,1,rows,0,2,0,msg); + myds->DSS=STATE_SLEEP; +} + +void SQLite3_Server::send_MySQL_ERR(MySQL_Protocol *myprot, char *msg) { + assert(myprot); + MySQL_Data_Stream *myds=myprot->get_myds(); + myds->DSS=STATE_QUERY_SENT_DS; + myprot->generate_pkt_ERR(true,NULL,NULL,1,1045,(char *)"28000",msg); + myds->DSS=STATE_SLEEP; +} + +/* +// this fuction will be called a s a deatached thread +void * waitpid_thread(void *arg) { + pid_t *cpid_ptr=(pid_t *)arg; + int status; + waitpid(*cpid_ptr, &status, 0); + free(cpid_ptr); + return NULL; +} +*/ diff --git a/src/main.cpp b/src/main.cpp index 9f8852402..d750be608 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -191,6 +191,7 @@ std::thread *MyMon_thread; MySQL_Logger *GloMyLogger; +SQLite3_Server *GloSQLite3Server; ProxySQL_Cluster *GloProxyCluster = NULL; @@ -395,6 +396,14 @@ void ProxySQL_Main_init_MySQL_Monitor_module() { GloMyMon->print_version(); } + +void ProxySQL_Main_init_SQLite3Server() { + // start SQLite3Server + GloSQLite3Server = new SQLite3_Server(); + GloSQLite3Server->init(); + GloSQLite3Server->print_version(); +} + void ProxySQL_Main_join_all_threads() { cpu_timer t; if (GloMTH) { @@ -615,6 +624,13 @@ void ProxySQL_Main_init_phase3___start_all() { std::cerr << "Main phase3 : MySQL Monitor initialized in "; #endif } + if (1) { // always trye for now + cpu_timer t; + ProxySQL_Main_init_SQLite3Server(); +#ifdef DEBUG + std::cerr << "Main phase3 : SQLite3 Server initialized in "; +#endif + } }